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