• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/inspector/v8-value-copier.h"
6 
7 namespace v8_inspector {
8 
9 namespace {
10 
11 static int kMaxDepth = 20;
12 static int kMaxCalls = 1000;
13 
14 class V8ValueCopier {
15  public:
copy(v8::Local<v8::Value> value,int depth)16   v8::MaybeLocal<v8::Value> copy(v8::Local<v8::Value> value, int depth) {
17     if (++m_calls > kMaxCalls || depth > kMaxDepth)
18       return v8::MaybeLocal<v8::Value>();
19 
20     if (value.IsEmpty()) return v8::MaybeLocal<v8::Value>();
21     if (value->IsNull() || value->IsUndefined() || value->IsBoolean() ||
22         value->IsString() || value->IsNumber())
23       return value;
24     if (!value->IsObject()) return v8::MaybeLocal<v8::Value>();
25     v8::Local<v8::Object> object = value.As<v8::Object>();
26     if (object->CreationContext() != m_from) return value;
27 
28     if (object->IsArray()) {
29       v8::Local<v8::Array> array = object.As<v8::Array>();
30       v8::Local<v8::Array> result = v8::Array::New(m_isolate, array->Length());
31       if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
32         return v8::MaybeLocal<v8::Value>();
33       for (uint32_t i = 0; i < array->Length(); ++i) {
34         v8::Local<v8::Value> item;
35         if (!array->Get(m_from, i).ToLocal(&item))
36           return v8::MaybeLocal<v8::Value>();
37         v8::Local<v8::Value> copied;
38         if (!copy(item, depth + 1).ToLocal(&copied))
39           return v8::MaybeLocal<v8::Value>();
40         if (!createDataProperty(m_to, result, i, copied).FromMaybe(false))
41           return v8::MaybeLocal<v8::Value>();
42       }
43       return result;
44     }
45 
46     v8::Local<v8::Object> result = v8::Object::New(m_isolate);
47     if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
48       return v8::MaybeLocal<v8::Value>();
49     v8::Local<v8::Array> properties;
50     if (!object->GetOwnPropertyNames(m_from).ToLocal(&properties))
51       return v8::MaybeLocal<v8::Value>();
52     for (uint32_t i = 0; i < properties->Length(); ++i) {
53       v8::Local<v8::Value> name;
54       if (!properties->Get(m_from, i).ToLocal(&name) || !name->IsString())
55         return v8::MaybeLocal<v8::Value>();
56       v8::Local<v8::Value> property;
57       if (!object->Get(m_from, name).ToLocal(&property))
58         return v8::MaybeLocal<v8::Value>();
59       v8::Local<v8::Value> copied;
60       if (!copy(property, depth + 1).ToLocal(&copied))
61         return v8::MaybeLocal<v8::Value>();
62       if (!createDataProperty(m_to, result, v8::Local<v8::String>::Cast(name),
63                               copied)
64                .FromMaybe(false))
65         return v8::MaybeLocal<v8::Value>();
66     }
67     return result;
68   }
69 
70   v8::Isolate* m_isolate;
71   v8::Local<v8::Context> m_from;
72   v8::Local<v8::Context> m_to;
73   int m_calls;
74 };
75 
toProtocolValue(v8::Local<v8::Context> context,v8::Local<v8::Value> value,int maxDepth,std::unique_ptr<protocol::Value> * result)76 protocol::Response toProtocolValue(v8::Local<v8::Context> context,
77                                    v8::Local<v8::Value> value, int maxDepth,
78                                    std::unique_ptr<protocol::Value>* result) {
79   using protocol::Response;
80   if (value.IsEmpty()) {
81     UNREACHABLE();
82     return Response::InternalError();
83   }
84 
85   if (!maxDepth) return Response::Error("Object reference chain is too long");
86   maxDepth--;
87 
88   if (value->IsNull() || value->IsUndefined()) {
89     *result = protocol::Value::null();
90     return Response::OK();
91   }
92   if (value->IsBoolean()) {
93     *result =
94         protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
95     return Response::OK();
96   }
97   if (value->IsNumber()) {
98     double doubleValue = value.As<v8::Number>()->Value();
99     int intValue = static_cast<int>(doubleValue);
100     if (intValue == doubleValue) {
101       *result = protocol::FundamentalValue::create(intValue);
102       return Response::OK();
103     }
104     *result = protocol::FundamentalValue::create(doubleValue);
105     return Response::OK();
106   }
107   if (value->IsString()) {
108     *result =
109         protocol::StringValue::create(toProtocolString(value.As<v8::String>()));
110     return Response::OK();
111   }
112   if (value->IsArray()) {
113     v8::Local<v8::Array> array = value.As<v8::Array>();
114     std::unique_ptr<protocol::ListValue> inspectorArray =
115         protocol::ListValue::create();
116     uint32_t length = array->Length();
117     for (uint32_t i = 0; i < length; i++) {
118       v8::Local<v8::Value> value;
119       if (!array->Get(context, i).ToLocal(&value))
120         return Response::InternalError();
121       std::unique_ptr<protocol::Value> element;
122       Response response = toProtocolValue(context, value, maxDepth, &element);
123       if (!response.isSuccess()) return response;
124       inspectorArray->pushValue(std::move(element));
125     }
126     *result = std::move(inspectorArray);
127     return Response::OK();
128   }
129   if (value->IsObject()) {
130     std::unique_ptr<protocol::DictionaryValue> jsonObject =
131         protocol::DictionaryValue::create();
132     v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value);
133     v8::Local<v8::Array> propertyNames;
134     if (!object->GetPropertyNames(context).ToLocal(&propertyNames))
135       return Response::InternalError();
136     uint32_t length = propertyNames->Length();
137     for (uint32_t i = 0; i < length; i++) {
138       v8::Local<v8::Value> name;
139       if (!propertyNames->Get(context, i).ToLocal(&name))
140         return Response::InternalError();
141       // FIXME(yurys): v8::Object should support GetOwnPropertyNames
142       if (name->IsString()) {
143         v8::Maybe<bool> hasRealNamedProperty = object->HasRealNamedProperty(
144             context, v8::Local<v8::String>::Cast(name));
145         if (!hasRealNamedProperty.IsJust() || !hasRealNamedProperty.FromJust())
146           continue;
147       }
148       v8::Local<v8::String> propertyName;
149       if (!name->ToString(context).ToLocal(&propertyName)) continue;
150       v8::Local<v8::Value> property;
151       if (!object->Get(context, name).ToLocal(&property))
152         return Response::InternalError();
153       std::unique_ptr<protocol::Value> propertyValue;
154       Response response =
155           toProtocolValue(context, property, maxDepth, &propertyValue);
156       if (!response.isSuccess()) return response;
157       jsonObject->setValue(toProtocolString(propertyName),
158                            std::move(propertyValue));
159     }
160     *result = std::move(jsonObject);
161     return Response::OK();
162   }
163   return Response::Error("Object couldn't be returned by value");
164 }
165 
166 }  // namespace
167 
copyValueFromDebuggerContext(v8::Isolate * isolate,v8::Local<v8::Context> debuggerContext,v8::Local<v8::Context> toContext,v8::Local<v8::Value> value)168 v8::MaybeLocal<v8::Value> copyValueFromDebuggerContext(
169     v8::Isolate* isolate, v8::Local<v8::Context> debuggerContext,
170     v8::Local<v8::Context> toContext, v8::Local<v8::Value> value) {
171   V8ValueCopier copier;
172   copier.m_isolate = isolate;
173   copier.m_from = debuggerContext;
174   copier.m_to = toContext;
175   copier.m_calls = 0;
176   return copier.copy(value, 0);
177 }
178 
createDataProperty(v8::Local<v8::Context> context,v8::Local<v8::Object> object,v8::Local<v8::Name> key,v8::Local<v8::Value> value)179 v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
180                                    v8::Local<v8::Object> object,
181                                    v8::Local<v8::Name> key,
182                                    v8::Local<v8::Value> value) {
183   v8::TryCatch tryCatch(context->GetIsolate());
184   v8::Isolate::DisallowJavascriptExecutionScope throwJs(
185       context->GetIsolate(),
186       v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
187   return object->CreateDataProperty(context, key, value);
188 }
189 
createDataProperty(v8::Local<v8::Context> context,v8::Local<v8::Array> array,int index,v8::Local<v8::Value> value)190 v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
191                                    v8::Local<v8::Array> array, int index,
192                                    v8::Local<v8::Value> value) {
193   v8::TryCatch tryCatch(context->GetIsolate());
194   v8::Isolate::DisallowJavascriptExecutionScope throwJs(
195       context->GetIsolate(),
196       v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
197   return array->CreateDataProperty(context, index, value);
198 }
199 
toProtocolValue(v8::Local<v8::Context> context,v8::Local<v8::Value> value,std::unique_ptr<protocol::Value> * result)200 protocol::Response toProtocolValue(v8::Local<v8::Context> context,
201                                    v8::Local<v8::Value> value,
202                                    std::unique_ptr<protocol::Value>* result) {
203   return toProtocolValue(context, value, 1000, result);
204 }
205 
206 }  // namespace v8_inspector
207