Line data Source code
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:
16 468 : v8::MaybeLocal<v8::Value> copy(v8::Local<v8::Value> value, int depth) {
17 468 : if (++m_calls > kMaxCalls || depth > kMaxDepth)
18 0 : return v8::MaybeLocal<v8::Value>();
19 :
20 468 : if (value.IsEmpty()) return v8::MaybeLocal<v8::Value>();
21 1398 : if (value->IsNull() || value->IsUndefined() || value->IsBoolean() ||
22 738 : value->IsString() || value->IsNumber())
23 216 : return value;
24 252 : if (!value->IsObject()) return v8::MaybeLocal<v8::Value>();
25 : v8::Local<v8::Object> object = value.As<v8::Object>();
26 504 : if (object->CreationContext() != m_from) return value;
27 :
28 192 : if (object->IsArray()) {
29 : v8::Local<v8::Array> array = object.As<v8::Array>();
30 60 : v8::Local<v8::Array> result = v8::Array::New(m_isolate, array->Length());
31 180 : if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
32 0 : return v8::MaybeLocal<v8::Value>();
33 96 : for (uint32_t i = 0; i < array->Length(); ++i) {
34 : v8::Local<v8::Value> item;
35 192 : if (!array->Get(m_from, i).ToLocal(&item))
36 0 : return v8::MaybeLocal<v8::Value>();
37 : v8::Local<v8::Value> copied;
38 192 : if (!copy(item, depth + 1).ToLocal(&copied))
39 0 : return v8::MaybeLocal<v8::Value>();
40 192 : if (!createDataProperty(m_to, result, i, copied).FromMaybe(false))
41 0 : return v8::MaybeLocal<v8::Value>();
42 : }
43 60 : return result;
44 : }
45 :
46 132 : v8::Local<v8::Object> result = v8::Object::New(m_isolate);
47 396 : if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
48 0 : return v8::MaybeLocal<v8::Value>();
49 : v8::Local<v8::Array> properties;
50 264 : if (!object->GetOwnPropertyNames(m_from).ToLocal(&properties))
51 0 : return v8::MaybeLocal<v8::Value>();
52 312 : for (uint32_t i = 0; i < properties->Length(); ++i) {
53 : v8::Local<v8::Value> name;
54 936 : if (!properties->Get(m_from, i).ToLocal(&name) || !name->IsString())
55 0 : return v8::MaybeLocal<v8::Value>();
56 : v8::Local<v8::Value> property;
57 624 : if (!object->Get(m_from, name).ToLocal(&property))
58 0 : return v8::MaybeLocal<v8::Value>();
59 : v8::Local<v8::Value> copied;
60 624 : if (!copy(property, depth + 1).ToLocal(&copied))
61 0 : return v8::MaybeLocal<v8::Value>();
62 312 : if (!createDataProperty(m_to, result, v8::Local<v8::String>::Cast(name),
63 312 : copied)
64 624 : .FromMaybe(false))
65 0 : return v8::MaybeLocal<v8::Value>();
66 : }
67 132 : 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 :
76 45912258 : 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 45912258 : if (value.IsEmpty()) {
81 0 : UNREACHABLE();
82 : return Response::InternalError();
83 : }
84 :
85 45912258 : if (!maxDepth) return Response::Error("Object reference chain is too long");
86 45912258 : maxDepth--;
87 :
88 91820874 : if (value->IsNull() || value->IsUndefined()) {
89 : *result = protocol::Value::null();
90 3648 : return Response::OK();
91 : }
92 45908610 : if (value->IsBoolean()) {
93 27796864 : *result =
94 13898432 : protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
95 13898432 : return Response::OK();
96 : }
97 32010178 : if (value->IsNumber()) {
98 1476233 : double doubleValue = value.As<v8::Number>()->Value();
99 1476233 : int intValue = static_cast<int>(doubleValue);
100 1476233 : if (intValue == doubleValue) {
101 2899238 : *result = protocol::FundamentalValue::create(intValue);
102 1449619 : return Response::OK();
103 : }
104 53228 : *result = protocol::FundamentalValue::create(doubleValue);
105 26614 : return Response::OK();
106 : }
107 30533945 : if (value->IsString()) {
108 63399639 : *result =
109 : protocol::StringValue::create(toProtocolString(value.As<v8::String>()));
110 21133213 : return Response::OK();
111 : }
112 9400732 : if (value->IsArray()) {
113 : v8::Local<v8::Array> array = value.As<v8::Array>();
114 : std::unique_ptr<protocol::ListValue> inspectorArray =
115 375450 : protocol::ListValue::create();
116 375450 : uint32_t length = array->Length();
117 4532792 : for (uint32_t i = 0; i < length; i++) {
118 : v8::Local<v8::Value> value;
119 8314684 : if (!array->Get(context, i).ToLocal(&value))
120 0 : return Response::InternalError();
121 4157342 : std::unique_ptr<protocol::Value> element;
122 4157342 : Response response = toProtocolValue(context, value, maxDepth, &element);
123 4157342 : if (!response.isSuccess()) return response;
124 8314684 : inspectorArray->pushValue(std::move(element));
125 : }
126 : *result = std::move(inspectorArray);
127 375450 : return Response::OK();
128 : }
129 9025282 : if (value->IsObject()) {
130 : std::unique_ptr<protocol::DictionaryValue> jsonObject =
131 9025276 : protocol::DictionaryValue::create();
132 : v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value);
133 : v8::Local<v8::Array> propertyNames;
134 18050552 : if (!object->GetPropertyNames(context).ToLocal(&propertyNames))
135 0 : return Response::InternalError();
136 9025276 : uint32_t length = propertyNames->Length();
137 75918042 : for (uint32_t i = 0; i < length; i++) {
138 : v8::Local<v8::Value> name;
139 133785544 : if (!propertyNames->Get(context, i).ToLocal(&name))
140 6 : return Response::InternalError();
141 : // FIXME(yurys): v8::Object should support GetOwnPropertyNames
142 66892772 : if (name->IsString()) {
143 : v8::Maybe<bool> hasRealNamedProperty = object->HasRealNamedProperty(
144 66892772 : context, v8::Local<v8::String>::Cast(name));
145 133785544 : if (!hasRealNamedProperty.IsJust() || !hasRealNamedProperty.FromJust())
146 25353384 : continue;
147 : }
148 : v8::Local<v8::String> propertyName;
149 83078776 : if (!name->ToString(context).ToLocal(&propertyName)) continue;
150 : v8::Local<v8::Value> property;
151 83078776 : if (!object->Get(context, name).ToLocal(&property))
152 0 : return Response::InternalError();
153 41539388 : std::unique_ptr<protocol::Value> propertyValue;
154 : Response response =
155 41539388 : toProtocolValue(context, property, maxDepth, &propertyValue);
156 41539388 : if (!response.isSuccess()) return response;
157 : jsonObject->setValue(toProtocolString(propertyName),
158 166157528 : std::move(propertyValue));
159 : }
160 : *result = std::move(jsonObject);
161 9025270 : return Response::OK();
162 : }
163 12 : return Response::Error("Object couldn't be returned by value");
164 : }
165 :
166 : } // namespace
167 :
168 60 : 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 60 : copier.m_isolate = isolate;
173 60 : copier.m_from = debuggerContext;
174 60 : copier.m_to = toContext;
175 60 : copier.m_calls = 0;
176 60 : return copier.copy(value, 0);
177 : }
178 :
179 278644 : 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 278644 : v8::TryCatch tryCatch(context->GetIsolate());
184 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
185 : context->GetIsolate(),
186 557288 : v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
187 557288 : return object->CreateDataProperty(context, key, value);
188 : }
189 :
190 13690 : v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
191 : v8::Local<v8::Array> array, int index,
192 : v8::Local<v8::Value> value) {
193 13690 : v8::TryCatch tryCatch(context->GetIsolate());
194 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
195 : context->GetIsolate(),
196 27380 : v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
197 41070 : return array->CreateDataProperty(context, index, value);
198 : }
199 :
200 215528 : protocol::Response toProtocolValue(v8::Local<v8::Context> context,
201 : v8::Local<v8::Value> value,
202 : std::unique_ptr<protocol::Value>* result) {
203 215528 : return toProtocolValue(context, value, 1000, result);
204 : }
205 :
206 : } // namespace v8_inspector
|