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