Line data Source code
1 : // Copyright 2018 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/value-mirror.h"
6 :
7 : #include <algorithm>
8 : #include <cmath>
9 :
10 : #include "src/debug/debug-interface.h"
11 : #include "src/inspector/v8-debugger.h"
12 : #include "src/inspector/v8-inspector-impl.h"
13 : #include "src/inspector/v8-value-utils.h"
14 :
15 : namespace v8_inspector {
16 :
17 : using protocol::Response;
18 : using protocol::Runtime::RemoteObject;
19 : using protocol::Runtime::ObjectPreview;
20 : using protocol::Runtime::PropertyPreview;
21 : using protocol::Runtime::EntryPreview;
22 : using protocol::Runtime::InternalPropertyDescriptor;
23 :
24 : namespace {
25 3384941 : V8InspectorClient* clientFor(v8::Local<v8::Context> context) {
26 : return static_cast<V8InspectorImpl*>(
27 3384941 : v8::debug::GetInspector(context->GetIsolate()))
28 3384941 : ->client();
29 : }
30 :
31 972175 : V8InternalValueType v8InternalValueTypeFrom(v8::Local<v8::Context> context,
32 : v8::Local<v8::Value> value) {
33 972175 : if (!value->IsObject()) return V8InternalValueType::kNone;
34 : V8InspectorImpl* inspector = static_cast<V8InspectorImpl*>(
35 972175 : v8::debug::GetInspector(context->GetIsolate()));
36 972175 : int contextId = InspectedContext::contextId(context);
37 972175 : InspectedContext* inspectedContext = inspector->getContext(contextId);
38 972175 : if (!inspectedContext) return V8InternalValueType::kNone;
39 972175 : return inspectedContext->getInternalType(value.As<v8::Object>());
40 : }
41 :
42 89917 : Response toProtocolValue(v8::Local<v8::Context> context,
43 : v8::Local<v8::Value> value, int maxDepth,
44 : std::unique_ptr<protocol::Value>* result) {
45 89922 : if (!maxDepth) return Response::Error("Object reference chain is too long");
46 89912 : maxDepth--;
47 :
48 177162 : if (value->IsNull() || value->IsUndefined()) {
49 : *result = protocol::Value::null();
50 2672 : return Response::OK();
51 : }
52 87240 : if (value->IsBoolean()) {
53 40136 : *result =
54 20068 : protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
55 20068 : return Response::OK();
56 : }
57 67172 : if (value->IsNumber()) {
58 398 : double doubleValue = value.As<v8::Number>()->Value();
59 796 : if (doubleValue >= std::numeric_limits<int>::min() &&
60 791 : doubleValue <= std::numeric_limits<int>::max() &&
61 : bit_cast<int64_t>(doubleValue) != bit_cast<int64_t>(-0.0)) {
62 393 : int intValue = static_cast<int>(doubleValue);
63 393 : if (intValue == doubleValue) {
64 786 : *result = protocol::FundamentalValue::create(intValue);
65 393 : return Response::OK();
66 : }
67 : }
68 10 : *result = protocol::FundamentalValue::create(doubleValue);
69 5 : return Response::OK();
70 : }
71 66774 : if (value->IsString()) {
72 182139 : *result = protocol::StringValue::create(
73 : toProtocolString(context->GetIsolate(), value.As<v8::String>()));
74 60713 : return Response::OK();
75 : }
76 6061 : if (value->IsArray()) {
77 : v8::Local<v8::Array> array = value.As<v8::Array>();
78 : std::unique_ptr<protocol::ListValue> inspectorArray =
79 255 : protocol::ListValue::create();
80 255 : uint32_t length = array->Length();
81 935 : for (uint32_t i = 0; i < length; i++) {
82 : v8::Local<v8::Value> value;
83 1360 : if (!array->Get(context, i).ToLocal(&value))
84 0 : return Response::InternalError();
85 680 : std::unique_ptr<protocol::Value> element;
86 680 : Response response = toProtocolValue(context, value, maxDepth, &element);
87 680 : if (!response.isSuccess()) return response;
88 1360 : inspectorArray->pushValue(std::move(element));
89 : }
90 : *result = std::move(inspectorArray);
91 255 : return Response::OK();
92 : }
93 5806 : if (value->IsObject()) {
94 : std::unique_ptr<protocol::DictionaryValue> jsonObject =
95 5806 : protocol::DictionaryValue::create();
96 : v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value);
97 : v8::Local<v8::Array> propertyNames;
98 11612 : if (!object->GetPropertyNames(context).ToLocal(&propertyNames))
99 0 : return Response::InternalError();
100 5806 : uint32_t length = propertyNames->Length();
101 6675 : for (uint32_t i = 0; i < length; i++) {
102 : v8::Local<v8::Value> name;
103 11748 : if (!propertyNames->Get(context, i).ToLocal(&name))
104 5005 : return Response::InternalError();
105 : // FIXME(yurys): v8::Object should support GetOwnPropertyNames
106 5874 : if (name->IsString()) {
107 : v8::Maybe<bool> hasRealNamedProperty = object->HasRealNamedProperty(
108 5842 : context, v8::Local<v8::String>::Cast(name));
109 11684 : if (hasRealNamedProperty.IsNothing() ||
110 : !hasRealNamedProperty.FromJust())
111 5 : continue;
112 : }
113 : v8::Local<v8::String> propertyName;
114 11738 : if (!name->ToString(context).ToLocal(&propertyName)) continue;
115 : v8::Local<v8::Value> property;
116 11738 : if (!object->Get(context, name).ToLocal(&property))
117 5 : return Response::InternalError();
118 5864 : if (property->IsUndefined()) continue;
119 5844 : std::unique_ptr<protocol::Value> propertyValue;
120 : Response response =
121 5844 : toProtocolValue(context, property, maxDepth, &propertyValue);
122 5844 : if (!response.isSuccess()) return response;
123 : jsonObject->setValue(
124 : toProtocolString(context->GetIsolate(), propertyName),
125 3376 : std::move(propertyValue));
126 : }
127 : *result = std::move(jsonObject);
128 801 : return Response::OK();
129 : }
130 0 : return Response::Error("Object couldn't be returned by value");
131 : }
132 :
133 150409 : Response toProtocolValue(v8::Local<v8::Context> context,
134 : v8::Local<v8::Value> value,
135 : std::unique_ptr<protocol::Value>* result) {
136 150409 : if (value->IsUndefined()) return Response::OK();
137 83393 : return toProtocolValue(context, value, 1000, result);
138 : }
139 :
140 : enum AbbreviateMode { kMiddle, kEnd };
141 :
142 30650 : String16 abbreviateString(const String16& value, AbbreviateMode mode) {
143 : const size_t maxLength = 100;
144 30650 : if (value.length() <= maxLength) return value;
145 30 : UChar ellipsis = static_cast<UChar>(0x2026);
146 30 : if (mode == kMiddle) {
147 : return String16::concat(
148 : value.substring(0, maxLength / 2), String16(&ellipsis, 1),
149 120 : value.substring(value.length() - maxLength / 2 + 1));
150 : }
151 0 : return String16::concat(value.substring(0, maxLength - 1), ellipsis);
152 : }
153 :
154 57613 : String16 descriptionForSymbol(v8::Local<v8::Context> context,
155 : v8::Local<v8::Symbol> symbol) {
156 : return String16::concat(
157 : "Symbol(",
158 : toProtocolStringWithTypeCheck(context->GetIsolate(), symbol->Name()),
159 172839 : ")");
160 : }
161 :
162 118 : String16 descriptionForBigInt(v8::Local<v8::Context> context,
163 : v8::Local<v8::BigInt> value) {
164 118 : v8::Isolate* isolate = context->GetIsolate();
165 118 : v8::TryCatch tryCatch(isolate);
166 : v8::Local<v8::String> description;
167 236 : if (!value->ToString(context).ToLocal(&description)) return String16();
168 354 : return toProtocolString(isolate, description) + "n";
169 : }
170 :
171 20380 : String16 descriptionForPrimitiveType(v8::Local<v8::Context> context,
172 : v8::Local<v8::Value> value) {
173 20380 : if (value->IsUndefined()) return RemoteObject::TypeEnum::Undefined;
174 20365 : if (value->IsNull()) return RemoteObject::SubtypeEnum::Null;
175 20360 : if (value->IsBoolean()) {
176 15 : return value.As<v8::Boolean>()->Value() ? "true" : "false";
177 : }
178 20345 : if (value->IsString()) {
179 20345 : return toProtocolString(context->GetIsolate(), value.As<v8::String>());
180 : }
181 0 : UNREACHABLE();
182 : return String16();
183 : }
184 :
185 80 : String16 descriptionForRegExp(v8::Isolate* isolate,
186 : v8::Local<v8::RegExp> value) {
187 80 : String16Builder description;
188 80 : description.append('/');
189 160 : description.append(toProtocolString(isolate, value->GetSource()));
190 80 : description.append('/');
191 80 : v8::RegExp::Flags flags = value->GetFlags();
192 80 : if (flags & v8::RegExp::Flags::kGlobal) description.append('g');
193 80 : if (flags & v8::RegExp::Flags::kIgnoreCase) description.append('i');
194 80 : if (flags & v8::RegExp::Flags::kMultiline) description.append('m');
195 80 : if (flags & v8::RegExp::Flags::kDotAll) description.append('s');
196 80 : if (flags & v8::RegExp::Flags::kUnicode) description.append('u');
197 80 : if (flags & v8::RegExp::Flags::kSticky) description.append('y');
198 160 : return description.toString();
199 : }
200 :
201 : enum class ErrorType { kNative, kClient };
202 :
203 3604 : String16 descriptionForError(v8::Local<v8::Context> context,
204 : v8::Local<v8::Object> object, ErrorType type) {
205 : v8::Isolate* isolate = context->GetIsolate();
206 3604 : v8::TryCatch tryCatch(isolate);
207 3604 : String16 className = toProtocolString(isolate, object->GetConstructorName());
208 : v8::Local<v8::Value> stackValue;
209 10812 : if (!object->Get(context, toV8String(isolate, "stack"))
210 10812 : .ToLocal(&stackValue) ||
211 : !stackValue->IsString()) {
212 : return className;
213 : }
214 3599 : String16 stack = toProtocolString(isolate, stackValue.As<v8::String>());
215 : String16 description = stack;
216 3599 : if (type == ErrorType::kClient) {
217 0 : if (stack.substring(0, className.length()) != className) {
218 : v8::Local<v8::Value> messageValue;
219 0 : if (!object->Get(context, toV8String(isolate, "message"))
220 0 : .ToLocal(&messageValue) ||
221 : !messageValue->IsString()) {
222 0 : return stack;
223 : }
224 0 : String16 message = toProtocolStringWithTypeCheck(isolate, messageValue);
225 : size_t index = stack.find(message);
226 : String16 stackWithoutMessage =
227 : index != String16::kNotFound
228 : ? stack.substring(index + message.length())
229 0 : : String16();
230 0 : description = className + ": " + message + stackWithoutMessage;
231 : }
232 : }
233 3604 : return description;
234 : }
235 :
236 : String16 descriptionForObject(v8::Isolate* isolate,
237 : v8::Local<v8::Object> object) {
238 831155 : return toProtocolString(isolate, object->GetConstructorName());
239 : }
240 :
241 24 : String16 descriptionForDate(v8::Local<v8::Context> context,
242 : v8::Local<v8::Date> date) {
243 24 : v8::Isolate* isolate = context->GetIsolate();
244 24 : v8::TryCatch tryCatch(isolate);
245 : v8::Local<v8::String> description;
246 48 : if (!date->ToString(context).ToLocal(&description)) {
247 : return descriptionForObject(isolate, date);
248 : }
249 24 : return toProtocolString(isolate, description);
250 : }
251 :
252 95 : String16 descriptionForScopeList(v8::Local<v8::Array> list) {
253 : return String16::concat(
254 95 : "Scopes[", String16::fromInteger(static_cast<size_t>(list->Length())),
255 190 : ']');
256 : }
257 :
258 40 : String16 descriptionForScope(v8::Local<v8::Context> context,
259 : v8::Local<v8::Object> object) {
260 40 : v8::Isolate* isolate = context->GetIsolate();
261 : v8::Local<v8::Value> value;
262 120 : if (!object->GetRealNamedProperty(context, toV8String(isolate, "description"))
263 40 : .ToLocal(&value)) {
264 0 : return String16();
265 : }
266 40 : return toProtocolStringWithTypeCheck(isolate, value);
267 : }
268 :
269 63086 : String16 descriptionForCollection(v8::Isolate* isolate,
270 : v8::Local<v8::Object> object, size_t length) {
271 63086 : String16 className = toProtocolString(isolate, object->GetConstructorName());
272 315430 : return String16::concat(className, '(', String16::fromInteger(length), ')');
273 : }
274 :
275 100 : String16 descriptionForEntry(v8::Local<v8::Context> context,
276 : v8::Local<v8::Object> object) {
277 100 : v8::Isolate* isolate = context->GetIsolate();
278 : String16 key;
279 : v8::Local<v8::Value> tmp;
280 300 : if (object->GetRealNamedProperty(context, toV8String(isolate, "key"))
281 100 : .ToLocal(&tmp)) {
282 55 : auto wrapper = ValueMirror::create(context, tmp);
283 55 : if (wrapper) {
284 55 : std::unique_ptr<ObjectPreview> preview;
285 55 : int limit = 5;
286 55 : wrapper->buildEntryPreview(context, &limit, &limit, &preview);
287 55 : if (preview) {
288 220 : key = preview->getDescription(String16());
289 165 : if (preview->getType() == RemoteObject::TypeEnum::String) {
290 0 : key = String16::concat('\"', key, '\"');
291 : }
292 : }
293 : }
294 : }
295 :
296 : String16 value;
297 300 : if (object->GetRealNamedProperty(context, toV8String(isolate, "value"))
298 100 : .ToLocal(&tmp)) {
299 100 : auto wrapper = ValueMirror::create(context, tmp);
300 100 : if (wrapper) {
301 100 : std::unique_ptr<ObjectPreview> preview;
302 100 : int limit = 5;
303 100 : wrapper->buildEntryPreview(context, &limit, &limit, &preview);
304 100 : if (preview) {
305 400 : value = preview->getDescription(String16());
306 300 : if (preview->getType() == RemoteObject::TypeEnum::String) {
307 0 : value = String16::concat('\"', value, '\"');
308 : }
309 : }
310 : }
311 : }
312 :
313 575 : return key.length() ? ("{" + key + " => " + value + "}") : value;
314 : }
315 :
316 1852593 : String16 descriptionForFunction(v8::Local<v8::Context> context,
317 : v8::Local<v8::Function> value) {
318 1852593 : v8::Isolate* isolate = context->GetIsolate();
319 1852593 : v8::TryCatch tryCatch(isolate);
320 : v8::Local<v8::String> description;
321 3705186 : if (!value->ToString(context).ToLocal(&description)) {
322 : return descriptionForObject(isolate, value);
323 : }
324 1852593 : return toProtocolString(isolate, description);
325 : }
326 :
327 512937 : class PrimitiveValueMirror final : public ValueMirror {
328 : public:
329 : PrimitiveValueMirror(v8::Local<v8::Value> value, const String16& type)
330 170979 : : m_value(value), m_type(type) {}
331 :
332 149909 : v8::Local<v8::Value> v8Value() const override { return m_value; }
333 149894 : Response buildRemoteObject(
334 : v8::Local<v8::Context> context, WrapMode mode,
335 : std::unique_ptr<RemoteObject>* result) const override {
336 149894 : std::unique_ptr<protocol::Value> protocolValue;
337 299788 : toProtocolValue(context, m_value, &protocolValue);
338 : *result = RemoteObject::create()
339 149894 : .setType(m_type)
340 : .setValue(std::move(protocolValue))
341 : .build();
342 149894 : if (m_value->IsNull())
343 7956 : (*result)->setSubtype(RemoteObject::SubtypeEnum::Null);
344 299788 : return Response::OK();
345 : }
346 :
347 15 : void buildEntryPreview(
348 : v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
349 : std::unique_ptr<ObjectPreview>* preview) const override {
350 : *preview =
351 : ObjectPreview::create()
352 15 : .setType(m_type)
353 30 : .setDescription(descriptionForPrimitiveType(context, m_value))
354 : .setOverflow(false)
355 : .setProperties(protocol::Array<PropertyPreview>::create())
356 : .build();
357 15 : if (m_value->IsNull())
358 0 : (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
359 15 : }
360 :
361 20365 : void buildPropertyPreview(
362 : v8::Local<v8::Context> context, const String16& name,
363 : std::unique_ptr<PropertyPreview>* preview) const override {
364 : *preview = PropertyPreview::create()
365 20365 : .setName(name)
366 : .setValue(abbreviateString(
367 61095 : descriptionForPrimitiveType(context, m_value), kMiddle))
368 : .setType(m_type)
369 : .build();
370 20365 : if (m_value->IsNull())
371 15 : (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
372 20365 : }
373 :
374 : private:
375 : v8::Local<v8::Value> m_value;
376 : String16 m_type;
377 : String16 m_subtype;
378 : };
379 :
380 384390 : class NumberMirror final : public ValueMirror {
381 : public:
382 192195 : explicit NumberMirror(v8::Local<v8::Number> value) : m_value(value) {}
383 180250 : v8::Local<v8::Value> v8Value() const override { return m_value; }
384 :
385 180250 : Response buildRemoteObject(
386 : v8::Local<v8::Context> context, WrapMode mode,
387 : std::unique_ptr<RemoteObject>* result) const override {
388 180250 : bool unserializable = false;
389 180250 : String16 descriptionValue = description(&unserializable);
390 : *result = RemoteObject::create()
391 540750 : .setType(RemoteObject::TypeEnum::Number)
392 : .setDescription(descriptionValue)
393 : .build();
394 180250 : if (unserializable) {
395 35874 : (*result)->setUnserializableValue(descriptionValue);
396 : } else {
397 288752 : (*result)->setValue(protocol::FundamentalValue::create(m_value->Value()));
398 : }
399 360500 : return Response::OK();
400 : }
401 1350 : void buildPropertyPreview(
402 : v8::Local<v8::Context> context, const String16& name,
403 : std::unique_ptr<PropertyPreview>* result) const override {
404 1350 : bool unserializable = false;
405 : *result = PropertyPreview::create()
406 1350 : .setName(name)
407 2700 : .setType(RemoteObject::TypeEnum::Number)
408 2700 : .setValue(description(&unserializable))
409 : .build();
410 1350 : }
411 310 : void buildEntryPreview(
412 : v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
413 : std::unique_ptr<ObjectPreview>* preview) const override {
414 310 : bool unserializable = false;
415 : *preview = ObjectPreview::create()
416 930 : .setType(RemoteObject::TypeEnum::Number)
417 620 : .setDescription(description(&unserializable))
418 : .setOverflow(false)
419 : .setProperties(protocol::Array<PropertyPreview>::create())
420 : .build();
421 310 : }
422 :
423 : private:
424 181910 : String16 description(bool* unserializable) const {
425 181910 : *unserializable = true;
426 181910 : double rawValue = m_value->Value();
427 181910 : if (std::isnan(rawValue)) return "NaN";
428 194246 : if (rawValue == 0.0 && std::signbit(rawValue)) return "-0";
429 163934 : if (std::isinf(rawValue)) {
430 17923 : return std::signbit(rawValue) ? "-Infinity" : "Infinity";
431 : }
432 146011 : *unserializable = false;
433 146011 : return String16::fromDouble(rawValue);
434 : }
435 :
436 : v8::Local<v8::Number> m_value;
437 : };
438 :
439 236 : class BigIntMirror final : public ValueMirror {
440 : public:
441 118 : explicit BigIntMirror(v8::Local<v8::BigInt> value) : m_value(value) {}
442 :
443 103 : Response buildRemoteObject(
444 : v8::Local<v8::Context> context, WrapMode mode,
445 : std::unique_ptr<RemoteObject>* result) const override {
446 103 : String16 description = descriptionForBigInt(context, m_value);
447 : *result = RemoteObject::create()
448 309 : .setType(RemoteObject::TypeEnum::Bigint)
449 : .setUnserializableValue(description)
450 : .setDescription(description)
451 : .build();
452 206 : return Response::OK();
453 : }
454 :
455 15 : void buildPropertyPreview(v8::Local<v8::Context> context,
456 : const String16& name,
457 : std::unique_ptr<protocol::Runtime::PropertyPreview>*
458 : preview) const override {
459 : *preview = PropertyPreview::create()
460 15 : .setName(name)
461 30 : .setType(RemoteObject::TypeEnum::Bigint)
462 : .setValue(abbreviateString(
463 45 : descriptionForBigInt(context, m_value), kMiddle))
464 : .build();
465 15 : }
466 :
467 0 : void buildEntryPreview(v8::Local<v8::Context> context, int* nameLimit,
468 : int* indexLimit,
469 : std::unique_ptr<protocol::Runtime::ObjectPreview>*
470 : preview) const override {
471 : *preview = ObjectPreview::create()
472 0 : .setType(RemoteObject::TypeEnum::Bigint)
473 0 : .setDescription(descriptionForBigInt(context, m_value))
474 : .setOverflow(false)
475 : .setProperties(protocol::Array<PropertyPreview>::create())
476 : .build();
477 0 : }
478 :
479 103 : v8::Local<v8::Value> v8Value() const override { return m_value; }
480 :
481 : private:
482 : v8::Local<v8::BigInt> m_value;
483 : };
484 :
485 78486 : class SymbolMirror final : public ValueMirror {
486 : public:
487 : explicit SymbolMirror(v8::Local<v8::Value> value)
488 39243 : : m_symbol(value.As<v8::Symbol>()) {}
489 :
490 18443 : Response buildRemoteObject(
491 : v8::Local<v8::Context> context, WrapMode mode,
492 : std::unique_ptr<RemoteObject>* result) const override {
493 18443 : if (mode == WrapMode::kForceValue) {
494 30 : return Response::Error("Object couldn't be returned by value");
495 : }
496 : *result = RemoteObject::create()
497 55284 : .setType(RemoteObject::TypeEnum::Symbol)
498 36856 : .setDescription(descriptionForSymbol(context, m_symbol))
499 : .build();
500 18428 : return Response::OK();
501 : }
502 :
503 10 : void buildPropertyPreview(v8::Local<v8::Context> context,
504 : const String16& name,
505 : std::unique_ptr<protocol::Runtime::PropertyPreview>*
506 : preview) const override {
507 : *preview = PropertyPreview::create()
508 10 : .setName(name)
509 20 : .setType(RemoteObject::TypeEnum::Symbol)
510 : .setValue(abbreviateString(
511 30 : descriptionForSymbol(context, m_symbol), kEnd))
512 : .build();
513 10 : }
514 :
515 18428 : v8::Local<v8::Value> v8Value() const override { return m_symbol; }
516 :
517 : private:
518 : v8::Local<v8::Symbol> m_symbol;
519 : };
520 :
521 210 : class LocationMirror final : public ValueMirror {
522 : public:
523 70 : static std::unique_ptr<LocationMirror> create(
524 : v8::Local<v8::Function> function) {
525 : return create(function, function->ScriptId(),
526 : function->GetScriptLineNumber(),
527 140 : function->GetScriptColumnNumber());
528 : }
529 50 : static std::unique_ptr<LocationMirror> createForGenerator(
530 : v8::Local<v8::Value> value) {
531 : v8::Local<v8::debug::GeneratorObject> generatorObject =
532 50 : v8::debug::GeneratorObject::Cast(value);
533 50 : if (!generatorObject->IsSuspended()) {
534 10 : return create(generatorObject->Function());
535 : }
536 : v8::Local<v8::debug::Script> script;
537 80 : if (!generatorObject->Script().ToLocal(&script)) return nullptr;
538 : v8::debug::Location suspendedLocation =
539 40 : generatorObject->SuspendedLocation();
540 : return create(value, script->Id(), suspendedLocation.GetLineNumber(),
541 40 : suspendedLocation.GetColumnNumber());
542 : }
543 :
544 95 : Response buildRemoteObject(
545 : v8::Local<v8::Context> context, WrapMode mode,
546 : std::unique_ptr<RemoteObject>* result) const override {
547 95 : auto location = protocol::DictionaryValue::create();
548 380 : location->setString("scriptId", String16::fromInteger(m_scriptId));
549 285 : location->setInteger("lineNumber", m_lineNumber);
550 285 : location->setInteger("columnNumber", m_columnNumber);
551 : *result = RemoteObject::create()
552 285 : .setType(RemoteObject::TypeEnum::Object)
553 190 : .setSubtype("internal#location")
554 190 : .setDescription("Object")
555 : .setValue(std::move(location))
556 : .build();
557 190 : return Response::OK();
558 : }
559 95 : v8::Local<v8::Value> v8Value() const override { return m_value; }
560 :
561 : private:
562 110 : static std::unique_ptr<LocationMirror> create(v8::Local<v8::Value> value,
563 : int scriptId, int lineNumber,
564 : int columnNumber) {
565 110 : if (scriptId == v8::UnboundScript::kNoScriptId) return nullptr;
566 105 : if (lineNumber == v8::Function::kLineOffsetNotFound ||
567 : columnNumber == v8::Function::kLineOffsetNotFound) {
568 : return nullptr;
569 : }
570 : return std::unique_ptr<LocationMirror>(
571 105 : new LocationMirror(value, scriptId, lineNumber, columnNumber));
572 : }
573 :
574 : LocationMirror(v8::Local<v8::Value> value, int scriptId, int lineNumber,
575 : int columnNumber)
576 : : m_value(value),
577 : m_scriptId(scriptId),
578 : m_lineNumber(lineNumber),
579 105 : m_columnNumber(columnNumber) {}
580 :
581 : v8::Local<v8::Value> m_value;
582 : int m_scriptId;
583 : int m_lineNumber;
584 : int m_columnNumber;
585 : };
586 :
587 4679086 : class FunctionMirror final : public ValueMirror {
588 : public:
589 : explicit FunctionMirror(v8::Local<v8::Value> value)
590 2339543 : : m_value(value.As<v8::Function>()) {}
591 :
592 1882838 : v8::Local<v8::Value> v8Value() const override { return m_value; }
593 :
594 1852603 : Response buildRemoteObject(
595 : v8::Local<v8::Context> context, WrapMode mode,
596 : std::unique_ptr<RemoteObject>* result) const override {
597 : // TODO(alph): drop this functionality.
598 1852603 : if (mode == WrapMode::kForceValue) {
599 15 : std::unique_ptr<protocol::Value> protocolValue;
600 15 : Response response = toProtocolValue(context, m_value, &protocolValue);
601 15 : if (!response.isSuccess()) return response;
602 : *result = RemoteObject::create()
603 45 : .setType(RemoteObject::TypeEnum::Function)
604 : .setValue(std::move(protocolValue))
605 : .build();
606 : } else {
607 : *result = RemoteObject::create()
608 5557764 : .setType(RemoteObject::TypeEnum::Function)
609 : .setClassName(toProtocolStringWithTypeCheck(
610 5557764 : context->GetIsolate(), m_value->GetConstructorName()))
611 3705176 : .setDescription(descriptionForFunction(context, m_value))
612 : .build();
613 : }
614 1852603 : return Response::OK();
615 : }
616 :
617 90 : void buildPropertyPreview(
618 : v8::Local<v8::Context> context, const String16& name,
619 : std::unique_ptr<PropertyPreview>* result) const override {
620 : *result = PropertyPreview::create()
621 90 : .setName(name)
622 180 : .setType(RemoteObject::TypeEnum::Function)
623 180 : .setValue(String16())
624 : .build();
625 90 : }
626 5 : void buildEntryPreview(
627 : v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
628 : std::unique_ptr<ObjectPreview>* preview) const override {
629 : *preview = ObjectPreview::create()
630 15 : .setType(RemoteObject::TypeEnum::Function)
631 10 : .setDescription(descriptionForFunction(context, m_value))
632 : .setOverflow(false)
633 : .setProperties(protocol::Array<PropertyPreview>::create())
634 : .build();
635 5 : }
636 :
637 : private:
638 : v8::Local<v8::Function> m_value;
639 : };
640 :
641 838204 : bool isArrayLike(v8::Local<v8::Context> context, v8::Local<v8::Value> value,
642 : size_t* length) {
643 838204 : if (!value->IsObject()) return false;
644 838204 : v8::Isolate* isolate = context->GetIsolate();
645 838204 : v8::TryCatch tryCatch(isolate);
646 : v8::MicrotasksScope microtasksScope(isolate,
647 1676408 : v8::MicrotasksScope::kDoNotRunMicrotasks);
648 : v8::Local<v8::Object> object = value.As<v8::Object>();
649 : v8::Local<v8::Value> spliceValue;
650 2514612 : if (!object->IsArgumentsObject() &&
651 2500134 : (!object->GetRealNamedProperty(context, toV8String(isolate, "splice"))
652 830990 : .ToLocal(&spliceValue) ||
653 25 : !spliceValue->IsFunction())) {
654 : return false;
655 : }
656 : v8::Local<v8::Value> lengthValue;
657 : v8::Maybe<bool> result =
658 21792 : object->HasOwnProperty(context, toV8String(isolate, "length"));
659 7264 : if (result.IsNothing()) return false;
660 14528 : if (!result.FromJust() ||
661 21772 : !object->Get(context, toV8String(isolate, "length"))
662 21772 : .ToLocal(&lengthValue) ||
663 7254 : !lengthValue->IsUint32()) {
664 : return false;
665 : }
666 7249 : *length = v8::Local<v8::Uint32>::Cast(lengthValue)->Value();
667 845453 : return true;
668 : }
669 :
670 1090 : struct EntryMirror {
671 : std::unique_ptr<ValueMirror> key;
672 : std::unique_ptr<ValueMirror> value;
673 :
674 10860 : static bool getEntries(v8::Local<v8::Context> context,
675 : v8::Local<v8::Object> object, size_t limit,
676 335 : bool* overflow, std::vector<EntryMirror>* mirrors) {
677 10860 : bool isKeyValue = false;
678 : v8::Local<v8::Array> entries;
679 21720 : if (!object->PreviewEntries(&isKeyValue).ToLocal(&entries)) return false;
680 200 : for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
681 : v8::Local<v8::Value> tmp;
682 :
683 : std::unique_ptr<ValueMirror> keyMirror;
684 275 : if (isKeyValue && entries->Get(context, i).ToLocal(&tmp)) {
685 120 : keyMirror = ValueMirror::create(context, tmp);
686 : }
687 : std::unique_ptr<ValueMirror> valueMirror;
688 430 : if (entries->Get(context, isKeyValue ? i + 1 : i).ToLocal(&tmp)) {
689 430 : valueMirror = ValueMirror::create(context, tmp);
690 : } else {
691 : continue;
692 : }
693 215 : if (mirrors->size() == limit) {
694 15 : *overflow = true;
695 : return true;
696 : }
697 : mirrors->emplace_back(
698 200 : EntryMirror{std::move(keyMirror), std::move(valueMirror)});
699 : }
700 120 : return mirrors->size() > 0;
701 : }
702 : };
703 :
704 10860 : class PreviewPropertyAccumulator : public ValueMirror::PropertyAccumulator {
705 : public:
706 : PreviewPropertyAccumulator(const std::vector<String16>& blacklist,
707 : int skipIndex, int* nameLimit, int* indexLimit,
708 : bool* overflow,
709 : std::vector<PropertyMirror>* mirrors)
710 : : m_blacklist(blacklist),
711 : m_skipIndex(skipIndex),
712 : m_nameLimit(nameLimit),
713 : m_indexLimit(indexLimit),
714 : m_overflow(overflow),
715 10860 : m_mirrors(mirrors) {}
716 :
717 509660 : bool Add(PropertyMirror mirror) override {
718 509660 : if (mirror.exception) return true;
719 1019335 : if ((!mirror.getter || !mirror.getter->v8Value()->IsFunction()) &&
720 : !mirror.value) {
721 : return true;
722 : }
723 509645 : if (!mirror.isOwn) return true;
724 84620 : if (std::find(m_blacklist.begin(), m_blacklist.end(), mirror.name) !=
725 : m_blacklist.end()) {
726 : return true;
727 : }
728 32090 : if (mirror.isIndex && m_skipIndex > 0) {
729 15 : --m_skipIndex;
730 15 : if (m_skipIndex > 0) return true;
731 : }
732 32075 : int* limit = mirror.isIndex ? m_indexLimit : m_nameLimit;
733 32075 : if (!*limit) {
734 45 : *m_overflow = true;
735 45 : return false;
736 : }
737 32030 : --*limit;
738 32030 : m_mirrors->push_back(std::move(mirror));
739 32030 : return true;
740 : }
741 :
742 : private:
743 : std::vector<String16> m_blacklist;
744 : int m_skipIndex;
745 : int* m_nameLimit;
746 : int* m_indexLimit;
747 : bool* m_overflow;
748 : std::vector<PropertyMirror>* m_mirrors;
749 : };
750 :
751 10860 : bool getPropertiesForPreview(v8::Local<v8::Context> context,
752 : v8::Local<v8::Object> object, int* nameLimit,
753 : int* indexLimit, bool* overflow,
754 : std::vector<PropertyMirror>* properties) {
755 : std::vector<String16> blacklist;
756 10860 : size_t length = 0;
757 12220 : if (object->IsArray() || isArrayLike(context, object, &length) ||
758 680 : object->IsStringObject()) {
759 20370 : blacklist.push_back("length");
760 : } else {
761 1350 : auto clientSubtype = clientFor(context)->valueSubtype(object);
762 675 : if (clientSubtype && toString16(clientSubtype->string()) == "array") {
763 0 : blacklist.push_back("length");
764 : }
765 : }
766 10860 : if (object->IsArrayBuffer() || object->IsSharedArrayBuffer()) {
767 20 : blacklist.push_back("[[Int8Array]]");
768 20 : blacklist.push_back("[[Uint8Array]]");
769 20 : blacklist.push_back("[[Int16Array]]");
770 20 : blacklist.push_back("[[Int32Array]]");
771 : }
772 10860 : int skipIndex = object->IsStringObject()
773 10870 : ? object.As<v8::StringObject>()->ValueOf()->Length() + 1
774 10865 : : -1;
775 : PreviewPropertyAccumulator accumulator(blacklist, skipIndex, nameLimit,
776 : indexLimit, overflow, properties);
777 : return ValueMirror::getProperties(context, object, false, false,
778 21720 : &accumulator);
779 : }
780 :
781 10860 : void getInternalPropertiesForPreview(
782 : v8::Local<v8::Context> context, v8::Local<v8::Object> object,
783 : int* nameLimit, bool* overflow,
784 : std::vector<InternalPropertyMirror>* properties) {
785 : std::vector<InternalPropertyMirror> mirrors;
786 10860 : ValueMirror::getInternalProperties(context, object, &mirrors);
787 10860 : std::vector<String16> whitelist;
788 43425 : if (object->IsBooleanObject() || object->IsNumberObject() ||
789 43395 : object->IsStringObject() || object->IsSymbolObject() ||
790 10840 : object->IsBigIntObject()) {
791 25 : whitelist.emplace_back("[[PrimitiveValue]]");
792 10835 : } else if (object->IsPromise()) {
793 30 : whitelist.emplace_back("[[PromiseStatus]]");
794 30 : whitelist.emplace_back("[[PromiseValue]]");
795 10805 : } else if (object->IsGeneratorObject()) {
796 10 : whitelist.emplace_back("[[GeneratorStatus]]");
797 : }
798 22110 : for (auto& mirror : mirrors) {
799 780 : if (std::find(whitelist.begin(), whitelist.end(), mirror.name) ==
800 : whitelist.end()) {
801 : continue;
802 : }
803 95 : if (!*nameLimit) {
804 0 : *overflow = true;
805 10860 : return;
806 : }
807 95 : --*nameLimit;
808 : properties->push_back(std::move(mirror));
809 10860 : }
810 : }
811 :
812 2694687 : class ObjectMirror final : public ValueMirror {
813 : public:
814 : ObjectMirror(v8::Local<v8::Value> value, const String16& description)
815 : : m_value(value.As<v8::Object>()),
816 : m_description(description),
817 1660550 : m_hasSubtype(false) {}
818 67954 : ObjectMirror(v8::Local<v8::Value> value, const String16& subtype,
819 : const String16& description)
820 : : m_value(value.As<v8::Object>()),
821 : m_description(description),
822 : m_hasSubtype(true),
823 203862 : m_subtype(subtype) {}
824 :
825 877329 : v8::Local<v8::Value> v8Value() const override { return m_value; }
826 :
827 877339 : Response buildRemoteObject(
828 : v8::Local<v8::Context> context, WrapMode mode,
829 : std::unique_ptr<RemoteObject>* result) const override {
830 877339 : if (mode == WrapMode::kForceValue) {
831 500 : std::unique_ptr<protocol::Value> protocolValue;
832 500 : Response response = toProtocolValue(context, m_value, &protocolValue);
833 500 : if (!response.isSuccess()) return response;
834 : *result = RemoteObject::create()
835 1470 : .setType(RemoteObject::TypeEnum::Object)
836 : .setValue(std::move(protocolValue))
837 : .build();
838 : } else {
839 876839 : v8::Isolate* isolate = context->GetIsolate();
840 : *result = RemoteObject::create()
841 2630517 : .setType(RemoteObject::TypeEnum::Object)
842 : .setClassName(toProtocolString(
843 1753678 : isolate, m_value->GetConstructorName()))
844 876839 : .setDescription(m_description)
845 : .build();
846 933998 : if (m_hasSubtype) (*result)->setSubtype(m_subtype);
847 876839 : if (mode == WrapMode::kWithPreview) {
848 580 : std::unique_ptr<ObjectPreview> previewValue;
849 580 : int nameLimit = 5;
850 580 : int indexLimit = 100;
851 : buildObjectPreview(context, false, &nameLimit, &indexLimit,
852 : &previewValue);
853 : (*result)->setPreview(std::move(previewValue));
854 : }
855 : }
856 877329 : return Response::OK();
857 : }
858 :
859 10220 : void buildObjectPreview(
860 : v8::Local<v8::Context> context, bool generatePreviewForTable,
861 : int* nameLimit, int* indexLimit,
862 : std::unique_ptr<ObjectPreview>* result) const override {
863 : buildObjectPreviewInternal(context, false /* forEntry */,
864 : generatePreviewForTable, nameLimit, indexLimit,
865 10800 : result);
866 10220 : }
867 :
868 65 : void buildEntryPreview(
869 : v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
870 : std::unique_ptr<ObjectPreview>* result) const override {
871 : buildObjectPreviewInternal(context, true /* forEntry */,
872 : false /* generatePreviewForTable */, nameLimit,
873 65 : indexLimit, result);
874 65 : }
875 :
876 10260 : void buildPropertyPreview(
877 : v8::Local<v8::Context> context, const String16& name,
878 : std::unique_ptr<PropertyPreview>* result) const override {
879 : *result = PropertyPreview::create()
880 10260 : .setName(name)
881 20520 : .setType(RemoteObject::TypeEnum::Object)
882 : .setValue(abbreviateString(
883 : m_description,
884 20520 : m_subtype == RemoteObject::SubtypeEnum::Regexp ? kMiddle
885 20520 : : kEnd))
886 : .build();
887 20440 : if (m_hasSubtype) (*result)->setSubtype(m_subtype);
888 10260 : }
889 :
890 : private:
891 10865 : void buildObjectPreviewInternal(
892 : v8::Local<v8::Context> context, bool forEntry,
893 : bool generatePreviewForTable, int* nameLimit, int* indexLimit,
894 : std::unique_ptr<ObjectPreview>* result) const {
895 : std::unique_ptr<protocol::Array<PropertyPreview>> properties =
896 : protocol::Array<PropertyPreview>::create();
897 : std::unique_ptr<protocol::Array<EntryPreview>> entriesPreview;
898 10865 : bool overflow = false;
899 :
900 : v8::Local<v8::Value> value = m_value;
901 20 : while (value->IsProxy()) value = value.As<v8::Proxy>()->GetTarget();
902 10865 : if (value->IsObject() && !value->IsProxy()) {
903 10860 : v8::Local<v8::Object> objectForPreview = value.As<v8::Object>();
904 : std::vector<InternalPropertyMirror> internalProperties;
905 : getInternalPropertiesForPreview(context, objectForPreview, nameLimit,
906 10860 : &overflow, &internalProperties);
907 21910 : for (size_t i = 0; i < internalProperties.size(); ++i) {
908 95 : std::unique_ptr<PropertyPreview> propertyPreview;
909 : internalProperties[i].value->buildPropertyPreview(
910 95 : context, internalProperties[i].name, &propertyPreview);
911 95 : if (propertyPreview) {
912 95 : properties->addItem(std::move(propertyPreview));
913 : }
914 : }
915 :
916 10860 : std::vector<PropertyMirror> mirrors;
917 10860 : if (getPropertiesForPreview(context, objectForPreview, nameLimit,
918 : indexLimit, &overflow, &mirrors)) {
919 74920 : for (size_t i = 0; i < mirrors.size(); ++i) {
920 32030 : std::unique_ptr<PropertyPreview> preview;
921 32030 : std::unique_ptr<ObjectPreview> valuePreview;
922 32030 : if (mirrors[i].value) {
923 : mirrors[i].value->buildPropertyPreview(context, mirrors[i].name,
924 31995 : &preview);
925 31995 : if (generatePreviewForTable) {
926 10120 : int tableLimit = 1000;
927 10120 : mirrors[i].value->buildObjectPreview(context, false, &tableLimit,
928 10120 : &tableLimit, &valuePreview);
929 : }
930 : } else {
931 : preview = PropertyPreview::create()
932 70 : .setName(mirrors[i].name)
933 70 : .setType(PropertyPreview::TypeEnum::Accessor)
934 : .build();
935 : }
936 32030 : if (valuePreview) {
937 : preview->setValuePreview(std::move(valuePreview));
938 : }
939 32030 : properties->addItem(std::move(preview));
940 : }
941 : }
942 :
943 10860 : std::vector<EntryMirror> entries;
944 10860 : if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow,
945 : &entries)) {
946 110 : if (forEntry) {
947 10 : overflow = true;
948 : } else {
949 : entriesPreview = protocol::Array<EntryPreview>::create();
950 390 : for (const auto& entry : entries) {
951 190 : std::unique_ptr<ObjectPreview> valuePreview;
952 : entry.value->buildEntryPreview(context, nameLimit, indexLimit,
953 190 : &valuePreview);
954 190 : if (!valuePreview) continue;
955 190 : std::unique_ptr<ObjectPreview> keyPreview;
956 190 : if (entry.key) {
957 : entry.key->buildEntryPreview(context, nameLimit, indexLimit,
958 50 : &keyPreview);
959 50 : if (!keyPreview) continue;
960 : }
961 : std::unique_ptr<EntryPreview> entryPreview =
962 : EntryPreview::create()
963 190 : .setValue(std::move(valuePreview))
964 : .build();
965 190 : if (keyPreview) entryPreview->setKey(std::move(keyPreview));
966 190 : entriesPreview->addItem(std::move(entryPreview));
967 : }
968 : }
969 10860 : }
970 : }
971 : *result = ObjectPreview::create()
972 32595 : .setType(RemoteObject::TypeEnum::Object)
973 10865 : .setDescription(m_description)
974 10865 : .setOverflow(overflow)
975 : .setProperties(std::move(properties))
976 : .build();
977 21375 : if (m_hasSubtype) (*result)->setSubtype(m_subtype);
978 10865 : if (entriesPreview) (*result)->setEntries(std::move(entriesPreview));
979 10865 : }
980 :
981 : v8::Local<v8::Object> m_value;
982 : String16 m_description;
983 : bool m_hasSubtype;
984 : String16 m_subtype;
985 : };
986 :
987 0 : void nativeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
988 : v8::Local<v8::Object> data = info.Data().As<v8::Object>();
989 : v8::Isolate* isolate = info.GetIsolate();
990 0 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
991 : v8::Local<v8::Value> name;
992 0 : if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
993 0 : .ToLocal(&name)) {
994 0 : return;
995 : }
996 : v8::Local<v8::Value> object;
997 0 : if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
998 0 : .ToLocal(&object) ||
999 0 : !object->IsObject()) {
1000 : return;
1001 : }
1002 : v8::Local<v8::Value> value;
1003 0 : if (!object.As<v8::Object>()->Get(context, name).ToLocal(&value)) return;
1004 : info.GetReturnValue().Set(value);
1005 : }
1006 :
1007 20 : std::unique_ptr<ValueMirror> createNativeGetter(v8::Local<v8::Context> context,
1008 : v8::Local<v8::Value> object,
1009 : v8::Local<v8::Name> name) {
1010 20 : v8::Isolate* isolate = context->GetIsolate();
1011 20 : v8::TryCatch tryCatch(isolate);
1012 :
1013 20 : v8::Local<v8::Object> data = v8::Object::New(isolate);
1014 60 : if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1015 : return nullptr;
1016 : }
1017 60 : if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1018 : return nullptr;
1019 : }
1020 :
1021 : v8::Local<v8::Function> function;
1022 20 : if (!v8::Function::New(context, nativeGetterCallback, data, 0,
1023 20 : v8::ConstructorBehavior::kThrow)
1024 20 : .ToLocal(&function)) {
1025 : return nullptr;
1026 : }
1027 20 : return ValueMirror::create(context, function);
1028 : }
1029 :
1030 0 : void nativeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1031 0 : if (info.Length() < 1) return;
1032 : v8::Local<v8::Object> data = info.Data().As<v8::Object>();
1033 : v8::Isolate* isolate = info.GetIsolate();
1034 0 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
1035 : v8::Local<v8::Value> name;
1036 0 : if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
1037 0 : .ToLocal(&name)) {
1038 : return;
1039 : }
1040 : v8::Local<v8::Value> object;
1041 0 : if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
1042 0 : .ToLocal(&object) ||
1043 0 : !object->IsObject()) {
1044 : return;
1045 : }
1046 : v8::Local<v8::Value> value;
1047 0 : if (!object.As<v8::Object>()->Set(context, name, info[0]).IsNothing()) return;
1048 : }
1049 :
1050 10 : std::unique_ptr<ValueMirror> createNativeSetter(v8::Local<v8::Context> context,
1051 : v8::Local<v8::Value> object,
1052 : v8::Local<v8::Name> name) {
1053 10 : v8::Isolate* isolate = context->GetIsolate();
1054 10 : v8::TryCatch tryCatch(isolate);
1055 :
1056 10 : v8::Local<v8::Object> data = v8::Object::New(isolate);
1057 30 : if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1058 : return nullptr;
1059 : }
1060 30 : if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1061 : return nullptr;
1062 : }
1063 :
1064 : v8::Local<v8::Function> function;
1065 10 : if (!v8::Function::New(context, nativeSetterCallback, data, 1,
1066 10 : v8::ConstructorBehavior::kThrow)
1067 10 : .ToLocal(&function)) {
1068 : return nullptr;
1069 : }
1070 10 : return ValueMirror::create(context, function);
1071 : }
1072 :
1073 5 : bool doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context,
1074 : v8::Local<v8::Object> object,
1075 : v8::Local<v8::Name> name) {
1076 : // TODO(dgozman): we should remove this, annotate more embedder properties as
1077 : // side-effect free, and call all getters which do not produce side effects.
1078 5 : if (!name->IsString()) return false;
1079 5 : v8::Isolate* isolate = context->GetIsolate();
1080 10 : if (!name.As<v8::String>()->StringEquals(toV8String(isolate, "body"))) {
1081 : return false;
1082 : }
1083 :
1084 0 : v8::TryCatch tryCatch(isolate);
1085 : v8::Local<v8::Value> request;
1086 0 : if (context->Global()
1087 0 : ->GetRealNamedProperty(context, toV8String(isolate, "Request"))
1088 0 : .ToLocal(&request)) {
1089 0 : if (request->IsObject() &&
1090 : object->InstanceOf(context, request.As<v8::Object>())
1091 0 : .FromMaybe(false)) {
1092 : return true;
1093 : }
1094 : }
1095 0 : if (tryCatch.HasCaught()) tryCatch.Reset();
1096 :
1097 : v8::Local<v8::Value> response;
1098 0 : if (context->Global()
1099 0 : ->GetRealNamedProperty(context, toV8String(isolate, "Response"))
1100 0 : .ToLocal(&response)) {
1101 0 : if (response->IsObject() &&
1102 : object->InstanceOf(context, response.As<v8::Object>())
1103 0 : .FromMaybe(false)) {
1104 : return true;
1105 : }
1106 : }
1107 0 : return false;
1108 : }
1109 : template <typename ArrayView, typename ArrayBuffer>
1110 106 : void addTypedArrayView(v8::Local<v8::Context> context,
1111 : v8::Local<ArrayBuffer> buffer, size_t length,
1112 : const char* name,
1113 : ValueMirror::PropertyAccumulator* accumulator) {
1114 106 : accumulator->Add(PropertyMirror{
1115 : String16(name), false, false, false, true, false,
1116 : ValueMirror::create(context, ArrayView::New(buffer, 0, length)), nullptr,
1117 318 : nullptr, nullptr, nullptr});
1118 106 : }
1119 :
1120 : template <typename ArrayBuffer>
1121 29 : void addTypedArrayViews(v8::Local<v8::Context> context,
1122 : v8::Local<ArrayBuffer> buffer,
1123 : ValueMirror::PropertyAccumulator* accumulator) {
1124 : // TODO(alph): these should be internal properties.
1125 29 : size_t length = buffer->ByteLength();
1126 29 : addTypedArrayView<v8::Int8Array>(context, buffer, length, "[[Int8Array]]",
1127 : accumulator);
1128 29 : addTypedArrayView<v8::Uint8Array>(context, buffer, length, "[[Uint8Array]]",
1129 : accumulator);
1130 29 : if (buffer->ByteLength() % 2 == 0) {
1131 24 : addTypedArrayView<v8::Int16Array>(context, buffer, length / 2,
1132 24 : "[[Int16Array]]", accumulator);
1133 : }
1134 29 : if (buffer->ByteLength() % 4 == 0) {
1135 24 : addTypedArrayView<v8::Int32Array>(context, buffer, length / 4,
1136 24 : "[[Int32Array]]", accumulator);
1137 : }
1138 29 : }
1139 : } // anonymous namespace
1140 :
1141 : ValueMirror::~ValueMirror() = default;
1142 :
1143 : // static
1144 79158 : bool ValueMirror::getProperties(v8::Local<v8::Context> context,
1145 : v8::Local<v8::Object> object,
1146 : bool ownProperties, bool accessorPropertiesOnly,
1147 : PropertyAccumulator* accumulator) {
1148 79158 : v8::Isolate* isolate = context->GetIsolate();
1149 79158 : v8::TryCatch tryCatch(isolate);
1150 79158 : v8::Local<v8::Set> set = v8::Set::New(isolate);
1151 :
1152 : v8::MicrotasksScope microtasksScope(isolate,
1153 158316 : v8::MicrotasksScope::kDoNotRunMicrotasks);
1154 79158 : V8InternalValueType internalType = v8InternalValueTypeFrom(context, object);
1155 79158 : if (internalType == V8InternalValueType::kScope) {
1156 : v8::Local<v8::Value> value;
1157 150 : if (!object->Get(context, toV8String(isolate, "object")).ToLocal(&value) ||
1158 30 : !value->IsObject()) {
1159 : return false;
1160 : } else {
1161 : object = value.As<v8::Object>();
1162 : }
1163 : }
1164 79158 : if (internalType == V8InternalValueType::kScopeList) {
1165 60 : if (!set->Add(context, toV8String(isolate, "length")).ToLocal(&set)) {
1166 : return false;
1167 : }
1168 : }
1169 : bool shouldSkipProto = internalType == V8InternalValueType::kScopeList;
1170 :
1171 : bool formatAccessorsAsProperties =
1172 158316 : clientFor(context)->formatAccessorsAsProperties(object);
1173 :
1174 79158 : if (object->IsArrayBuffer()) {
1175 29 : addTypedArrayViews(context, object.As<v8::ArrayBuffer>(), accumulator);
1176 : }
1177 79158 : if (object->IsSharedArrayBuffer()) {
1178 : addTypedArrayViews(context, object.As<v8::SharedArrayBuffer>(),
1179 0 : accumulator);
1180 : }
1181 :
1182 4627849 : for (auto iterator = v8::debug::PropertyIterator::Create(object);
1183 9018224 : !iterator->Done(); iterator->Advance()) {
1184 4492108 : bool isOwn = iterator->is_own();
1185 4492108 : if (!isOwn && ownProperties) break;
1186 4469578 : v8::Local<v8::Name> v8Name = iterator->name();
1187 4469578 : v8::Maybe<bool> result = set->Has(context, v8Name);
1188 4469623 : if (result.IsNothing()) return false;
1189 5945433 : if (result.FromJust()) continue;
1190 5987466 : if (!set->Add(context, v8Name).ToLocal(&set)) return false;
1191 :
1192 : String16 name;
1193 : std::unique_ptr<ValueMirror> symbolMirror;
1194 2993733 : if (v8Name->IsString()) {
1195 5909116 : name = toProtocolString(isolate, v8Name.As<v8::String>());
1196 : } else {
1197 : v8::Local<v8::Symbol> symbol = v8Name.As<v8::Symbol>();
1198 78350 : name = descriptionForSymbol(context, symbol);
1199 78350 : symbolMirror = ValueMirror::create(context, symbol);
1200 : }
1201 :
1202 : v8::PropertyAttribute attributes;
1203 : std::unique_ptr<ValueMirror> valueMirror;
1204 : std::unique_ptr<ValueMirror> getterMirror;
1205 : std::unique_ptr<ValueMirror> setterMirror;
1206 : std::unique_ptr<ValueMirror> exceptionMirror;
1207 : bool writable = false;
1208 : bool enumerable = false;
1209 : bool configurable = false;
1210 :
1211 : bool isAccessorProperty = false;
1212 5987411 : v8::TryCatch tryCatch(isolate);
1213 5987466 : if (!iterator->attributes().To(&attributes)) {
1214 0 : exceptionMirror = ValueMirror::create(context, tryCatch.Exception());
1215 : } else {
1216 2993733 : if (iterator->is_native_accessor()) {
1217 20 : if (iterator->has_native_getter()) {
1218 40 : getterMirror = createNativeGetter(context, object, v8Name);
1219 : }
1220 20 : if (iterator->has_native_setter()) {
1221 20 : setterMirror = createNativeSetter(context, object, v8Name);
1222 : }
1223 20 : writable = !(attributes & v8::PropertyAttribute::ReadOnly);
1224 20 : enumerable = !(attributes & v8::PropertyAttribute::DontEnum);
1225 20 : configurable = !(attributes & v8::PropertyAttribute::DontDelete);
1226 20 : isAccessorProperty = getterMirror || setterMirror;
1227 : } else {
1228 2993713 : v8::TryCatch tryCatch(isolate);
1229 : v8::debug::PropertyDescriptor descriptor;
1230 5987426 : if (!iterator->descriptor().To(&descriptor)) {
1231 0 : exceptionMirror = ValueMirror::create(context, tryCatch.Exception());
1232 : } else {
1233 2993713 : writable = descriptor.has_writable ? descriptor.writable : false;
1234 : enumerable =
1235 2993713 : descriptor.has_enumerable ? descriptor.enumerable : false;
1236 : configurable =
1237 2993713 : descriptor.has_configurable ? descriptor.configurable : false;
1238 2993713 : if (!descriptor.value.IsEmpty()) {
1239 5926286 : valueMirror = ValueMirror::create(context, descriptor.value);
1240 : }
1241 : bool getterIsNativeFunction = false;
1242 2993713 : if (!descriptor.get.IsEmpty()) {
1243 : v8::Local<v8::Value> get = descriptor.get;
1244 61140 : getterMirror = ValueMirror::create(context, get);
1245 : getterIsNativeFunction =
1246 30570 : get->IsFunction() && get.As<v8::Function>()->ScriptId() ==
1247 : v8::UnboundScript::kNoScriptId;
1248 : }
1249 2993713 : if (!descriptor.set.IsEmpty()) {
1250 61140 : setterMirror = ValueMirror::create(context, descriptor.set);
1251 : }
1252 2993713 : isAccessorProperty = getterMirror || setterMirror;
1253 : bool isSymbolDescription =
1254 2993713 : object->IsSymbol() && name == "description";
1255 8981139 : if (isSymbolDescription ||
1256 11963777 : (name != "__proto__" && getterIsNativeFunction &&
1257 5 : formatAccessorsAsProperties &&
1258 : !doesAttributeHaveObservableSideEffectOnGet(context, object,
1259 5 : v8Name))) {
1260 5 : v8::TryCatch tryCatch(isolate);
1261 : v8::Local<v8::Value> value;
1262 10 : if (object->Get(context, v8Name).ToLocal(&value)) {
1263 10 : valueMirror = ValueMirror::create(context, value);
1264 : isOwn = true;
1265 : setterMirror = nullptr;
1266 : getterMirror = nullptr;
1267 5 : }
1268 : }
1269 2993713 : }
1270 : }
1271 : }
1272 2993743 : if (accessorPropertiesOnly && !isAccessorProperty) continue;
1273 : auto mirror = PropertyMirror{name,
1274 : writable,
1275 : configurable,
1276 : enumerable,
1277 : isOwn,
1278 2993723 : iterator->is_array_index(),
1279 : std::move(valueMirror),
1280 : std::move(getterMirror),
1281 : std::move(setterMirror),
1282 : std::move(symbolMirror),
1283 8981124 : std::move(exceptionMirror)};
1284 2993723 : if (!accumulator->Add(std::move(mirror))) return true;
1285 : }
1286 79113 : if (!shouldSkipProto && ownProperties && !object->IsProxy() &&
1287 : !accessorPropertiesOnly) {
1288 67588 : v8::Local<v8::Value> prototype = object->GetPrototype();
1289 67588 : if (prototype->IsObject()) {
1290 : accumulator->Add(PropertyMirror{String16("__proto__"), true, true, false,
1291 : true, false,
1292 : ValueMirror::create(context, prototype),
1293 45050 : nullptr, nullptr, nullptr, nullptr});
1294 : }
1295 : }
1296 79158 : return true;
1297 : }
1298 :
1299 : // static
1300 79153 : void ValueMirror::getInternalProperties(
1301 : v8::Local<v8::Context> context, v8::Local<v8::Object> object,
1302 : std::vector<InternalPropertyMirror>* mirrors) {
1303 79153 : v8::Isolate* isolate = context->GetIsolate();
1304 : v8::MicrotasksScope microtasksScope(isolate,
1305 79153 : v8::MicrotasksScope::kDoNotRunMicrotasks);
1306 158306 : v8::TryCatch tryCatch(isolate);
1307 79153 : if (object->IsFunction()) {
1308 : v8::Local<v8::Function> function = object.As<v8::Function>();
1309 60 : auto location = LocationMirror::create(function);
1310 60 : if (location) {
1311 : mirrors->emplace_back(InternalPropertyMirror{
1312 110 : String16("[[FunctionLocation]]"), std::move(location)});
1313 : }
1314 60 : if (function->IsGeneratorFunction()) {
1315 : mirrors->emplace_back(InternalPropertyMirror{
1316 : String16("[[IsGenerator]]"),
1317 10 : ValueMirror::create(context, v8::True(context->GetIsolate()))});
1318 60 : }
1319 : }
1320 79153 : if (object->IsGeneratorObject()) {
1321 50 : auto location = LocationMirror::createForGenerator(object);
1322 50 : if (location) {
1323 : mirrors->emplace_back(InternalPropertyMirror{
1324 100 : String16("[[GeneratorLocation]]"), std::move(location)});
1325 50 : }
1326 : }
1327 : V8Debugger* debugger =
1328 79153 : static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate))
1329 : ->debugger();
1330 : v8::Local<v8::Array> properties;
1331 158306 : if (debugger->internalProperties(context, object).ToLocal(&properties)) {
1332 1339 : for (uint32_t i = 0; i < properties->Length(); i += 2) {
1333 : v8::Local<v8::Value> name;
1334 4017 : if (!properties->Get(context, i).ToLocal(&name) || !name->IsString()) {
1335 0 : tryCatch.Reset();
1336 0 : continue;
1337 : }
1338 : v8::Local<v8::Value> value;
1339 2678 : if (!properties->Get(context, i + 1).ToLocal(&value)) {
1340 0 : tryCatch.Reset();
1341 0 : continue;
1342 : }
1343 1339 : auto wrapper = ValueMirror::create(context, value);
1344 1339 : if (wrapper) {
1345 : mirrors->emplace_back(InternalPropertyMirror{
1346 : toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1347 2678 : std::move(wrapper)});
1348 : }
1349 : }
1350 79153 : }
1351 79153 : }
1352 :
1353 0 : String16 descriptionForNode(v8::Local<v8::Context> context,
1354 : v8::Local<v8::Value> value) {
1355 0 : if (!value->IsObject()) return String16();
1356 : v8::Local<v8::Object> object = value.As<v8::Object>();
1357 0 : v8::Isolate* isolate = context->GetIsolate();
1358 0 : v8::TryCatch tryCatch(isolate);
1359 : v8::Local<v8::Value> nodeName;
1360 0 : if (!object->Get(context, toV8String(isolate, "nodeName"))
1361 0 : .ToLocal(&nodeName)) {
1362 0 : return String16();
1363 : }
1364 : String16 description;
1365 : v8::Local<v8::Function> toLowerCase =
1366 0 : v8::debug::GetBuiltin(isolate, v8::debug::kStringToLowerCase);
1367 0 : if (nodeName->IsString()) {
1368 0 : if (!toLowerCase->Call(context, nodeName, 0, nullptr).ToLocal(&nodeName))
1369 0 : return String16();
1370 0 : if (nodeName->IsString()) {
1371 0 : description = toProtocolString(isolate, nodeName.As<v8::String>());
1372 : }
1373 : }
1374 0 : if (!description.length()) {
1375 : v8::Local<v8::Value> value;
1376 0 : if (!object->Get(context, toV8String(isolate, "constructor"))
1377 0 : .ToLocal(&value) ||
1378 0 : !value->IsObject()) {
1379 0 : return String16();
1380 : }
1381 0 : if (!value.As<v8::Object>()
1382 0 : ->Get(context, toV8String(isolate, "name"))
1383 0 : .ToLocal(&value) ||
1384 : !value->IsString()) {
1385 0 : return String16();
1386 : }
1387 0 : description = toProtocolString(isolate, value.As<v8::String>());
1388 : }
1389 : v8::Local<v8::Value> nodeType;
1390 0 : if (!object->Get(context, toV8String(isolate, "nodeType"))
1391 0 : .ToLocal(&nodeType) ||
1392 0 : !nodeType->IsInt32()) {
1393 : return description;
1394 : }
1395 0 : if (nodeType.As<v8::Int32>()->Value() == 1) {
1396 : v8::Local<v8::Value> idValue;
1397 0 : if (!object->Get(context, toV8String(isolate, "id")).ToLocal(&idValue)) {
1398 : return description;
1399 : }
1400 0 : if (idValue->IsString()) {
1401 0 : String16 id = toProtocolString(isolate, idValue.As<v8::String>());
1402 0 : if (id.length()) {
1403 0 : description = String16::concat(description, '#', id);
1404 : }
1405 : }
1406 : v8::Local<v8::Value> classNameValue;
1407 0 : if (!object->Get(context, toV8String(isolate, "className"))
1408 0 : .ToLocal(&classNameValue)) {
1409 : return description;
1410 : }
1411 0 : if (classNameValue->IsString() &&
1412 0 : classNameValue.As<v8::String>()->Length()) {
1413 : String16 classes =
1414 0 : toProtocolString(isolate, classNameValue.As<v8::String>());
1415 0 : String16Builder output;
1416 : bool previousIsDot = false;
1417 0 : for (size_t i = 0; i < classes.length(); ++i) {
1418 0 : if (classes[i] == ' ') {
1419 0 : if (!previousIsDot) {
1420 0 : output.append('.');
1421 : previousIsDot = true;
1422 : }
1423 : } else {
1424 0 : output.append(classes[i]);
1425 0 : previousIsDot = classes[i] == '.';
1426 : }
1427 : }
1428 0 : description = String16::concat(description, '.', output.toString());
1429 : }
1430 0 : } else if (nodeType.As<v8::Int32>()->Value() == 1) {
1431 0 : return String16::concat("<!DOCTYPE ", description, '>');
1432 : }
1433 0 : return description;
1434 : }
1435 :
1436 0 : std::unique_ptr<ValueMirror> clientMirror(v8::Local<v8::Context> context,
1437 : v8::Local<v8::Value> value,
1438 : const String16& subtype) {
1439 : // TODO(alph): description and length retrieval should move to embedder.
1440 0 : if (subtype == "node") {
1441 : return v8::base::make_unique<ObjectMirror>(
1442 0 : value, subtype, descriptionForNode(context, value));
1443 : }
1444 0 : if (subtype == "error") {
1445 : return v8::base::make_unique<ObjectMirror>(
1446 : value, RemoteObject::SubtypeEnum::Error,
1447 : descriptionForError(context, value.As<v8::Object>(),
1448 0 : ErrorType::kClient));
1449 : }
1450 0 : if (subtype == "array" && value->IsObject()) {
1451 0 : v8::Isolate* isolate = context->GetIsolate();
1452 0 : v8::TryCatch tryCatch(isolate);
1453 : v8::Local<v8::Object> object = value.As<v8::Object>();
1454 : v8::Local<v8::Value> lengthValue;
1455 0 : if (object->Get(context, toV8String(isolate, "length"))
1456 0 : .ToLocal(&lengthValue)) {
1457 0 : if (lengthValue->IsInt32()) {
1458 : return v8::base::make_unique<ObjectMirror>(
1459 : value, RemoteObject::SubtypeEnum::Array,
1460 : descriptionForCollection(isolate, object,
1461 0 : lengthValue.As<v8::Int32>()->Value()));
1462 : }
1463 0 : }
1464 : }
1465 : return v8::base::make_unique<ObjectMirror>(
1466 : value,
1467 0 : descriptionForObject(context->GetIsolate(), value.As<v8::Object>()));
1468 : }
1469 :
1470 3640307 : std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
1471 : v8::Local<v8::Value> value) {
1472 3640307 : if (value->IsNull()) {
1473 : return v8::base::make_unique<PrimitiveValueMirror>(
1474 5314 : value, RemoteObject::TypeEnum::Object);
1475 : }
1476 3637650 : if (value->IsBoolean()) {
1477 : return v8::base::make_unique<PrimitiveValueMirror>(
1478 40186 : value, RemoteObject::TypeEnum::Boolean);
1479 : }
1480 3617557 : if (value->IsNumber()) {
1481 192195 : return v8::base::make_unique<NumberMirror>(value.As<v8::Number>());
1482 : }
1483 3425362 : v8::Isolate* isolate = context->GetIsolate();
1484 3425362 : if (value->IsString()) {
1485 : return v8::base::make_unique<PrimitiveValueMirror>(
1486 161786 : value, RemoteObject::TypeEnum::String);
1487 : }
1488 3344469 : if (value->IsBigInt()) {
1489 118 : return v8::base::make_unique<BigIntMirror>(value.As<v8::BigInt>());
1490 : }
1491 3344351 : if (value->IsSymbol()) {
1492 39243 : return v8::base::make_unique<SymbolMirror>(value.As<v8::Symbol>());
1493 : }
1494 3237772 : auto clientSubtype = (value->IsUndefined() || value->IsObject())
1495 3305108 : ? clientFor(context)->valueSubtype(value)
1496 6610216 : : nullptr;
1497 3305108 : if (clientSubtype) {
1498 0 : String16 subtype = toString16(clientSubtype->string());
1499 0 : return clientMirror(context, value, subtype);
1500 : }
1501 3305108 : if (value->IsUndefined()) {
1502 : return v8::base::make_unique<PrimitiveValueMirror>(
1503 134672 : value, RemoteObject::TypeEnum::Undefined);
1504 : }
1505 3237772 : if (value->IsRegExp()) {
1506 : return v8::base::make_unique<ObjectMirror>(
1507 : value, RemoteObject::SubtypeEnum::Regexp,
1508 240 : descriptionForRegExp(isolate, value.As<v8::RegExp>()));
1509 : }
1510 3237692 : if (value->IsFunction()) {
1511 2339543 : return v8::base::make_unique<FunctionMirror>(value);
1512 : }
1513 898149 : if (value->IsProxy()) {
1514 : return v8::base::make_unique<ObjectMirror>(
1515 90 : value, RemoteObject::SubtypeEnum::Proxy, "Proxy");
1516 : }
1517 898104 : if (value->IsDate()) {
1518 : return v8::base::make_unique<ObjectMirror>(
1519 : value, RemoteObject::SubtypeEnum::Date,
1520 72 : descriptionForDate(context, value.As<v8::Date>()));
1521 : }
1522 898080 : if (value->IsPromise()) {
1523 523 : v8::Local<v8::Promise> promise = value.As<v8::Promise>();
1524 : return v8::base::make_unique<ObjectMirror>(
1525 : promise, RemoteObject::SubtypeEnum::Promise,
1526 1569 : descriptionForObject(isolate, promise));
1527 : }
1528 897557 : if (value->IsNativeError()) {
1529 : return v8::base::make_unique<ObjectMirror>(
1530 : value, RemoteObject::SubtypeEnum::Error,
1531 : descriptionForError(context, value.As<v8::Object>(),
1532 10812 : ErrorType::kNative));
1533 : }
1534 893953 : if (value->IsMap()) {
1535 : v8::Local<v8::Map> map = value.As<v8::Map>();
1536 : return v8::base::make_unique<ObjectMirror>(
1537 : value, RemoteObject::SubtypeEnum::Map,
1538 612 : descriptionForCollection(isolate, map, map->Size()));
1539 : }
1540 893800 : if (value->IsSet()) {
1541 : v8::Local<v8::Set> set = value.As<v8::Set>();
1542 : return v8::base::make_unique<ObjectMirror>(
1543 : value, RemoteObject::SubtypeEnum::Set,
1544 356 : descriptionForCollection(isolate, set, set->Size()));
1545 : }
1546 893711 : if (value->IsWeakMap()) {
1547 : return v8::base::make_unique<ObjectMirror>(
1548 : value, RemoteObject::SubtypeEnum::Weakmap,
1549 147 : descriptionForObject(isolate, value.As<v8::Object>()));
1550 : }
1551 893662 : if (value->IsWeakSet()) {
1552 : return v8::base::make_unique<ObjectMirror>(
1553 : value, RemoteObject::SubtypeEnum::Weakset,
1554 147 : descriptionForObject(isolate, value.As<v8::Object>()));
1555 : }
1556 1787114 : if (value->IsMapIterator() || value->IsSetIterator()) {
1557 : return v8::base::make_unique<ObjectMirror>(
1558 : value, RemoteObject::SubtypeEnum::Iterator,
1559 597 : descriptionForObject(isolate, value.As<v8::Object>()));
1560 : }
1561 893414 : if (value->IsGeneratorObject()) {
1562 60 : v8::Local<v8::Object> object = value.As<v8::Object>();
1563 : return v8::base::make_unique<ObjectMirror>(
1564 : object, RemoteObject::SubtypeEnum::Generator,
1565 180 : descriptionForObject(isolate, object));
1566 : }
1567 893354 : if (value->IsTypedArray()) {
1568 : v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
1569 : return v8::base::make_unique<ObjectMirror>(
1570 : value, RemoteObject::SubtypeEnum::Typedarray,
1571 836 : descriptionForCollection(isolate, array, array->Length()));
1572 : }
1573 893145 : if (value->IsArrayBuffer()) {
1574 : v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
1575 : return v8::base::make_unique<ObjectMirror>(
1576 : value, RemoteObject::SubtypeEnum::Arraybuffer,
1577 276 : descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1578 : }
1579 893076 : if (value->IsSharedArrayBuffer()) {
1580 : v8::Local<v8::SharedArrayBuffer> buffer = value.As<v8::SharedArrayBuffer>();
1581 : return v8::base::make_unique<ObjectMirror>(
1582 : value, RemoteObject::SubtypeEnum::Arraybuffer,
1583 80 : descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1584 : }
1585 893056 : if (value->IsDataView()) {
1586 : v8::Local<v8::DataView> view = value.As<v8::DataView>();
1587 : return v8::base::make_unique<ObjectMirror>(
1588 : value, RemoteObject::SubtypeEnum::Dataview,
1589 156 : descriptionForCollection(isolate, view, view->ByteLength()));
1590 : }
1591 : V8InternalValueType internalType =
1592 893017 : v8InternalValueTypeFrom(context, v8::Local<v8::Object>::Cast(value));
1593 893017 : if (value->IsArray() && internalType == V8InternalValueType::kScopeList) {
1594 : return v8::base::make_unique<ObjectMirror>(
1595 : value, "internal#scopeList",
1596 285 : descriptionForScopeList(value.As<v8::Array>()));
1597 : }
1598 892922 : if (value->IsObject() && internalType == V8InternalValueType::kEntry) {
1599 : return v8::base::make_unique<ObjectMirror>(
1600 : value, "internal#entry",
1601 300 : descriptionForEntry(context, value.As<v8::Object>()));
1602 : }
1603 892822 : if (value->IsObject() && internalType == V8InternalValueType::kScope) {
1604 : return v8::base::make_unique<ObjectMirror>(
1605 : value, "internal#scope",
1606 120 : descriptionForScope(context, value.As<v8::Object>()));
1607 : }
1608 892782 : size_t length = 0;
1609 892782 : if (value->IsArray() || isArrayLike(context, value, &length)) {
1610 62507 : length = value->IsArray() ? value.As<v8::Array>()->Length() : length;
1611 : return v8::base::make_unique<ObjectMirror>(
1612 : value, RemoteObject::SubtypeEnum::Array,
1613 187521 : descriptionForCollection(isolate, value.As<v8::Object>(), length));
1614 : }
1615 830275 : if (value->IsObject()) {
1616 : return v8::base::make_unique<ObjectMirror>(
1617 2490825 : value, descriptionForObject(isolate, value.As<v8::Object>()));
1618 : }
1619 : return nullptr;
1620 : }
1621 : } // namespace v8_inspector
|