// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/inspector/v8-value-utils.h" namespace v8_inspector { namespace { protocol::Response toProtocolValue(v8::Local context, v8::Local value, int maxDepth, std::unique_ptr* result) { using protocol::Response; if (value.IsEmpty()) { UNREACHABLE(); } if (!maxDepth) return Response::Error("Object reference chain is too long"); maxDepth--; if (value->IsNull() || value->IsUndefined()) { *result = protocol::Value::null(); return Response::OK(); } if (value->IsBoolean()) { *result = protocol::FundamentalValue::create(value.As()->Value()); return Response::OK(); } if (value->IsNumber()) { double doubleValue = value.As()->Value(); int intValue = static_cast(doubleValue); if (intValue == doubleValue) { *result = protocol::FundamentalValue::create(intValue); return Response::OK(); } *result = protocol::FundamentalValue::create(doubleValue); return Response::OK(); } if (value->IsString()) { *result = protocol::StringValue::create( toProtocolString(context->GetIsolate(), value.As())); return Response::OK(); } if (value->IsArray()) { v8::Local array = value.As(); std::unique_ptr inspectorArray = protocol::ListValue::create(); uint32_t length = array->Length(); for (uint32_t i = 0; i < length; i++) { v8::Local value; if (!array->Get(context, i).ToLocal(&value)) return Response::InternalError(); std::unique_ptr element; Response response = toProtocolValue(context, value, maxDepth, &element); if (!response.isSuccess()) return response; inspectorArray->pushValue(std::move(element)); } *result = std::move(inspectorArray); return Response::OK(); } if (value->IsObject()) { std::unique_ptr jsonObject = protocol::DictionaryValue::create(); v8::Local object = v8::Local::Cast(value); v8::Local propertyNames; if (!object->GetPropertyNames(context).ToLocal(&propertyNames)) return Response::InternalError(); uint32_t length = propertyNames->Length(); for (uint32_t i = 0; i < length; i++) { v8::Local name; if (!propertyNames->Get(context, i).ToLocal(&name)) return Response::InternalError(); // FIXME(yurys): v8::Object should support GetOwnPropertyNames if (name->IsString()) { v8::Maybe hasRealNamedProperty = object->HasRealNamedProperty( context, v8::Local::Cast(name)); if (hasRealNamedProperty.IsNothing() || !hasRealNamedProperty.FromJust()) continue; } v8::Local propertyName; if (!name->ToString(context).ToLocal(&propertyName)) continue; v8::Local property; if (!object->Get(context, name).ToLocal(&property)) return Response::InternalError(); if (property->IsUndefined()) continue; std::unique_ptr propertyValue; Response response = toProtocolValue(context, property, maxDepth, &propertyValue); if (!response.isSuccess()) return response; jsonObject->setValue( toProtocolString(context->GetIsolate(), propertyName), std::move(propertyValue)); } *result = std::move(jsonObject); return Response::OK(); } return Response::Error("Object couldn't be returned by value"); } } // namespace v8::Maybe createDataProperty(v8::Local context, v8::Local object, v8::Local key, v8::Local value) { v8::TryCatch tryCatch(context->GetIsolate()); v8::Isolate::DisallowJavascriptExecutionScope throwJs( context->GetIsolate(), v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); return object->CreateDataProperty(context, key, value); } v8::Maybe createDataProperty(v8::Local context, v8::Local array, int index, v8::Local value) { v8::TryCatch tryCatch(context->GetIsolate()); v8::Isolate::DisallowJavascriptExecutionScope throwJs( context->GetIsolate(), v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); return array->CreateDataProperty(context, index, value); } protocol::Response toProtocolValue(v8::Local context, v8::Local value, std::unique_ptr* result) { return toProtocolValue(context, value, 1000, result); } } // namespace v8_inspector