v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
value-mirror.cc
Go to the documentation of this file.
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
6
7#include <algorithm>
8#include <cmath>
9#include <optional>
10
12#include "include/v8-date.h"
13#include "include/v8-function.h"
16#include "include/v8-proxy.h"
17#include "include/v8-regexp.h"
19#include "include/v8-wasm.h"
25
26namespace v8_inspector {
27
28using protocol::Response;
29using protocol::Runtime::EntryPreview;
30using protocol::Runtime::ObjectPreview;
31using protocol::Runtime::PropertyPreview;
32using protocol::Runtime::RemoteObject;
33
34#if defined(V8_USE_ADDRESS_SANITIZER) && V8_OS_DARWIN
35// For whatever reason, ASan on MacOS has bigger stack frames.
36static const int kMaxProtocolDepth = 900;
37#else
38static const int kMaxProtocolDepth = 1000;
39#endif
40
42 v8::Local<v8::Value> value, int maxDepth,
43 std::unique_ptr<protocol::Value>* result);
44
46 v8::Local<v8::Array> array, int maxDepth,
47 std::unique_ptr<protocol::ListValue>* result) {
48 std::unique_ptr<protocol::ListValue> inspectorArray =
49 protocol::ListValue::create();
50 uint32_t length = array->Length();
51 for (uint32_t i = 0; i < length; i++) {
53 if (!array->Get(context, i).ToLocal(&value))
54 return Response::InternalError();
55 std::unique_ptr<protocol::Value> element;
56 Response response = toProtocolValue(context, value, maxDepth - 1, &element);
57 if (!response.IsSuccess()) return response;
58 inspectorArray->pushValue(std::move(element));
59 }
60 *result = std::move(inspectorArray);
61 return Response::Success();
62}
63
65 v8::Local<v8::Context> context, v8::Local<v8::Object> object, int maxDepth,
66 std::unique_ptr<protocol::DictionaryValue>* result) {
67 std::unique_ptr<protocol::DictionaryValue> jsonObject =
68 protocol::DictionaryValue::create();
69 v8::Local<v8::Array> propertyNames;
70 if (!object->GetOwnPropertyNames(context).ToLocal(&propertyNames))
71 return Response::InternalError();
72 uint32_t length = propertyNames->Length();
73 for (uint32_t i = 0; i < length; i++) {
75 if (!propertyNames->Get(context, i).ToLocal(&name))
76 return Response::InternalError();
77 if (name->IsString()) {
78 v8::Maybe<bool> hasRealNamedProperty =
79 object->HasRealNamedProperty(context, name.As<v8::String>());
80 // Don't access properties with interceptors.
81 if (hasRealNamedProperty.IsNothing() || !hasRealNamedProperty.FromJust())
82 continue;
83 }
84 v8::Local<v8::String> propertyName;
85 if (!name->ToString(context).ToLocal(&propertyName)) continue;
87 if (!object->Get(context, name).ToLocal(&property))
88 return Response::InternalError();
89 if (property->IsUndefined()) continue;
90 std::unique_ptr<protocol::Value> propertyValue;
91 Response response =
92 toProtocolValue(context, property, maxDepth - 1, &propertyValue);
93 if (!response.IsSuccess()) return response;
94 jsonObject->setValue(toProtocolString(context->GetIsolate(), propertyName),
95 std::move(propertyValue));
96 }
97 *result = std::move(jsonObject);
98 return Response::Success();
99}
100
101std::unique_ptr<protocol::FundamentalValue> toProtocolValue(
102 double doubleValue) {
103 if (doubleValue >= std::numeric_limits<int>::min() &&
104 doubleValue <= std::numeric_limits<int>::max() &&
105 v8::base::bit_cast<int64_t>(doubleValue) !=
107 int intValue = static_cast<int>(doubleValue);
108 if (intValue == doubleValue) {
109 return protocol::FundamentalValue::create(intValue);
110 }
111 }
112 return protocol::FundamentalValue::create(doubleValue);
113}
114
116 v8::Local<v8::Value> value, int maxDepth,
117 std::unique_ptr<protocol::Value>* result) {
118 if (maxDepth <= 0)
119 return Response::ServerError("Object reference chain is too long");
120
121 if (value->IsNull() || value->IsUndefined()) {
122 *result = protocol::Value::null();
123 return Response::Success();
124 }
125 if (value->IsBoolean()) {
126 *result =
127 protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
128 return Response::Success();
129 }
130 if (value->IsNumber()) {
131 double doubleValue = value.As<v8::Number>()->Value();
132 *result = toProtocolValue(doubleValue);
133 return Response::Success();
134 }
135 if (value->IsString()) {
136 *result = protocol::StringValue::create(
137 toProtocolString(context->GetIsolate(), value.As<v8::String>()));
138 return Response::Success();
139 }
140 if (value->IsArray()) {
141 v8::Local<v8::Array> array = value.As<v8::Array>();
142 std::unique_ptr<protocol::ListValue> list_result;
143 auto response =
144 arrayToProtocolValue(context, array, maxDepth, &list_result);
145 *result = std::move(list_result);
146 return response;
147 }
148 if (value->IsObject()) {
149 v8::Local<v8::Object> object = value.As<v8::Object>();
150 std::unique_ptr<protocol::DictionaryValue> dict_result;
151 auto response =
152 objectToProtocolValue(context, object, maxDepth, &dict_result);
153 *result = std::move(dict_result);
154 return response;
155 }
156
157 return Response::ServerError("Object couldn't be returned by value");
158}
159
162 std::unique_ptr<protocol::Value>* result) {
163 if (value->IsUndefined()) return Response::Success();
164 return toProtocolValue(context, value, kMaxProtocolDepth, result);
165}
166
167namespace {
168
169// WebAssembly memory is organized in pages of size 64KiB.
170const size_t kWasmPageSize = 64 * 1024;
171
172V8InspectorClient* clientFor(v8::Local<v8::Context> context) {
173 return static_cast<V8InspectorImpl*>(
174 v8::debug::GetInspector(context->GetIsolate()))
175 ->client();
176}
177
178V8InternalValueType v8InternalValueTypeFrom(v8::Local<v8::Context> context,
179 v8::Local<v8::Value> value) {
180 if (!value->IsObject()) return V8InternalValueType::kNone;
181 V8InspectorImpl* inspector = static_cast<V8InspectorImpl*>(
182 v8::debug::GetInspector(context->GetIsolate()));
183 int contextId = InspectedContext::contextId(context);
184 InspectedContext* inspectedContext = inspector->getContext(contextId);
185 if (!inspectedContext) return V8InternalValueType::kNone;
186 return inspectedContext->getInternalType(value.As<v8::Object>());
187}
188
189enum AbbreviateMode { kMiddle, kEnd };
190
191String16 abbreviateString(const String16& value, AbbreviateMode mode) {
192 const size_t maxLength = 100;
193 if (value.length() <= maxLength) return value;
194 UChar ellipsis = static_cast<UChar>(0x2026);
195 if (mode == kMiddle) {
196 return String16::concat(
197 value.substring(0, maxLength / 2), String16(&ellipsis, 1),
198 value.substring(value.length() - maxLength / 2 + 1));
199 }
200 return String16::concat(value.substring(0, maxLength - 1), ellipsis);
201}
202
203String16 descriptionForSymbol(v8::Local<v8::Context> context,
204 v8::Local<v8::Symbol> symbol) {
205 v8::Isolate* isolate = context->GetIsolate();
206 return String16::concat(
207 "Symbol(",
208 toProtocolStringWithTypeCheck(isolate, symbol->Description(isolate)),
209 ")");
210}
211
212String16 descriptionForBigInt(v8::Local<v8::Context> context,
213 v8::Local<v8::BigInt> value) {
214 v8::Isolate* isolate = context->GetIsolate();
215 v8::Local<v8::String> description =
216 v8::debug::GetBigIntDescription(isolate, value);
217 return toProtocolString(isolate, description);
218}
219
220String16 descriptionForPrimitiveType(v8::Local<v8::Context> context,
221 v8::Local<v8::Value> value) {
222 if (value->IsUndefined()) return RemoteObject::TypeEnum::Undefined;
223 if (value->IsNull()) return RemoteObject::SubtypeEnum::Null;
224 if (value->IsBoolean()) {
225 return value.As<v8::Boolean>()->Value() ? "true" : "false";
226 }
227 if (value->IsString()) {
228 return toProtocolString(context->GetIsolate(), value.As<v8::String>());
229 }
230 UNREACHABLE();
231}
232
233String16 descriptionForRegExp(v8::Isolate* isolate,
234 v8::Local<v8::RegExp> value) {
235 String16Builder description;
236 description.append('/');
237 description.append(toProtocolString(isolate, value->GetSource()));
238 description.append('/');
239 v8::RegExp::Flags flags = value->GetFlags();
240 if (flags & v8::RegExp::Flags::kHasIndices) description.append('d');
241 if (flags & v8::RegExp::Flags::kGlobal) description.append('g');
242 if (flags & v8::RegExp::Flags::kIgnoreCase) description.append('i');
243 if (flags & v8::RegExp::Flags::kLinear) description.append('l');
244 if (flags & v8::RegExp::Flags::kMultiline) description.append('m');
245 if (flags & v8::RegExp::Flags::kDotAll) description.append('s');
246 if (flags & v8::RegExp::Flags::kUnicode) description.append('u');
247 if (flags & v8::RegExp::Flags::kUnicodeSets) description.append('v');
248 if (flags & v8::RegExp::Flags::kSticky) description.append('y');
249 return description.toString();
250}
251
252// Build a description from an exception using the following pattern:
253// * The first line is "<name || constructor name>: <message property>". We
254// use the constructor name if the "name" property is "Error". Most custom
255// Error subclasses don't overwrite the "name" property.
256// * The rest is the content of the "stack" property but only with the actual
257// stack trace part.
258String16 descriptionForError(v8::Local<v8::Context> context,
259 v8::Local<v8::Object> object) {
260 v8::Isolate* isolate = context->GetIsolate();
261 v8::TryCatch tryCatch(isolate);
262
263 String16 name = toProtocolString(isolate, object->GetConstructorName());
264 {
265 v8::Local<v8::Value> nameValue;
266 if (object->Get(context, toV8String(isolate, "name")).ToLocal(&nameValue) &&
267 nameValue->IsString()) {
268 v8::Local<v8::String> nameString = nameValue.As<v8::String>();
269 if (nameString->Length() > 0 &&
270 !nameString->StringEquals(toV8String(isolate, "Error"))) {
271 name = toProtocolString(isolate, nameString);
272 }
273 }
274 }
275
276 std::optional<String16> stack;
277 {
278 v8::Local<v8::Value> stackValue;
279 if (object->Get(context, toV8String(isolate, "stack"))
280 .ToLocal(&stackValue) &&
281 stackValue->IsString()) {
282 String16 stackString =
283 toProtocolString(isolate, stackValue.As<v8::String>());
284 size_t pos = stackString.find("\n at ");
285 if (pos != String16::kNotFound) {
286 stack = stackString.substring(pos);
287 }
288 }
289 }
290
291 std::optional<String16> message;
292 {
293 v8::Local<v8::Value> messageValue;
294 if (object->Get(context, toV8String(isolate, "message"))
295 .ToLocal(&messageValue) &&
296 messageValue->IsString()) {
297 String16 msg = toProtocolStringWithTypeCheck(isolate, messageValue);
298 if (!msg.isEmpty()) message = msg;
299 }
300 }
301
302 String16 description = name;
303 if (message.has_value() && message->length() > 0) {
304 description += ": " + *message;
305 }
306
307 if (stack.has_value() && stack->length() > 0) {
308 description += *stack;
309 }
310 return description;
311}
312
313String16 descriptionForObject(v8::Isolate* isolate,
314 v8::Local<v8::Object> object) {
315 return toProtocolString(isolate, object->GetConstructorName());
316}
317
318String16 descriptionForProxy(v8::Isolate* isolate, v8::Local<v8::Proxy> proxy) {
319 v8::Local<v8::Value> target = proxy->GetTarget();
320 if (target->IsObject()) {
321 return String16::concat(
322 "Proxy(", descriptionForObject(isolate, target.As<v8::Object>()), ")");
323 }
324 return String16("Proxy");
325}
326
327String16 descriptionForDate(v8::Local<v8::Context> context,
329 v8::Isolate* isolate = context->GetIsolate();
331 return toProtocolString(isolate, description);
332}
333
334String16 descriptionForScopeList(v8::Local<v8::Array> list) {
335 return String16::concat(
336 "Scopes[", String16::fromInteger(static_cast<size_t>(list->Length())),
337 ']');
338}
339
340String16 descriptionForScope(v8::Local<v8::Context> context,
341 v8::Local<v8::Object> object) {
342 v8::Isolate* isolate = context->GetIsolate();
344 if (!object->GetRealNamedProperty(context, toV8String(isolate, "description"))
345 .ToLocal(&value)) {
346 return String16();
347 }
348 return toProtocolStringWithTypeCheck(isolate, value);
349}
350
351String16 descriptionForCollection(v8::Isolate* isolate,
352 v8::Local<v8::Object> object, size_t length) {
353 String16 className = toProtocolString(isolate, object->GetConstructorName());
354 return String16::concat(className, '(', String16::fromInteger(length), ')');
355}
356
357#if V8_ENABLE_WEBASSEMBLY
358String16 descriptionForWasmValueObject(
361 v8::Isolate* isolate = context->GetIsolate();
362 return toProtocolString(isolate, object->type());
363}
364#endif // V8_ENABLE_WEBASSEMBLY
365
366String16 descriptionForEntry(v8::Local<v8::Context> context,
367 v8::Local<v8::Object> object) {
368 v8::Isolate* isolate = context->GetIsolate();
369 String16 key;
371 if (object->GetRealNamedProperty(context, toV8String(isolate, "key"))
372 .ToLocal(&tmp)) {
373 auto wrapper = ValueMirror::create(context, tmp);
374 if (wrapper) {
375 std::unique_ptr<ObjectPreview> preview;
376 int limit = 5;
377 wrapper->buildEntryPreview(context, &limit, &limit, &preview);
378 if (preview) {
379 key = preview->getDescription(String16());
380 if (preview->getType() == RemoteObject::TypeEnum::String) {
381 key = String16::concat('\"', key, '\"');
382 }
383 }
384 }
385 }
386
387 String16 value;
388 if (object->GetRealNamedProperty(context, toV8String(isolate, "value"))
389 .ToLocal(&tmp)) {
390 auto wrapper = ValueMirror::create(context, tmp);
391 if (wrapper) {
392 std::unique_ptr<ObjectPreview> preview;
393 int limit = 5;
394 wrapper->buildEntryPreview(context, &limit, &limit, &preview);
395 if (preview) {
396 value = preview->getDescription(String16());
397 if (preview->getType() == RemoteObject::TypeEnum::String) {
398 value = String16::concat('\"', value, '\"');
399 }
400 }
401 }
402 }
403
404 return key.length() ? ("{" + key + " => " + value + "}") : value;
405}
406
407String16 descriptionForFunction(v8::Local<v8::Function> value) {
408 v8::Isolate* isolate = value->GetIsolate();
410 return toProtocolString(isolate, description);
411}
412
413String16 descriptionForPrivateMethodList(v8::Local<v8::Array> list) {
414 return String16::concat(
415 "PrivateMethods[",
416 String16::fromInteger(static_cast<size_t>(list->Length())), ']');
417}
418
419String16 descriptionForPrivateMethod(v8::Local<v8::Context> context,
420 v8::Local<v8::Object> object) {
421 v8::Isolate* isolate = context->GetIsolate();
423 if (!object->GetRealNamedProperty(context, toV8String(isolate, "value"))
424 .ToLocal(&value)) {
425 return String16();
426 }
427 DCHECK(value->IsFunction());
428 return descriptionForFunction(value.As<v8::Function>());
429}
430
431String16 descriptionForNumber(v8::Local<v8::Number> value,
432 bool* unserializable) {
433 *unserializable = true;
434 double rawValue = value->Value();
435 if (std::isnan(rawValue)) return "NaN";
436 if (rawValue == 0.0 && std::signbit(rawValue)) return "-0";
437 if (std::isinf(rawValue)) {
438 return std::signbit(rawValue) ? "-Infinity" : "Infinity";
439 }
440 *unserializable = false;
441 return String16::fromDouble(rawValue);
442}
443
444class ValueMirrorBase : public ValueMirror {
445 public:
446 ValueMirrorBase(v8::Isolate* isolate, v8::Local<v8::Value> value)
447 : m_value(isolate, value) {}
448
449 v8::Local<v8::Value> v8Value(v8::Isolate* isolate) const final {
450 return m_value.Get(isolate);
451 }
452
453 private:
455};
456
457class PrimitiveValueMirror final : public ValueMirrorBase {
458 public:
459 PrimitiveValueMirror(v8::Isolate* isolate, v8::Local<v8::Primitive> value,
460 const String16& type)
461 : ValueMirrorBase(isolate, value), m_type(type) {}
462
463 Response buildRemoteObject(
464 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
465 std::unique_ptr<RemoteObject>* result) const override {
466 std::unique_ptr<protocol::Value> protocolValue;
467 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
468 toProtocolValue(context, value, &protocolValue);
469 *result = RemoteObject::create()
470 .setType(m_type)
471 .setValue(std::move(protocolValue))
472 .build();
473 if (value->IsNull()) (*result)->setSubtype(RemoteObject::SubtypeEnum::Null);
474 return Response::Success();
475 }
476
477 void buildEntryPreview(
478 v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
479 std::unique_ptr<ObjectPreview>* preview) const override {
480 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
481 *preview =
482 ObjectPreview::create()
483 .setType(m_type)
484 .setDescription(descriptionForPrimitiveType(context, value))
485 .setOverflow(false)
486 .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
487 .build();
488 if (value->IsNull())
489 (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
490 }
491
492 void buildPropertyPreview(
493 v8::Local<v8::Context> context, const String16& name,
494 std::unique_ptr<PropertyPreview>* preview) const override {
495 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
496 *preview = PropertyPreview::create()
497 .setName(name)
498 .setValue(abbreviateString(
499 descriptionForPrimitiveType(context, value), kMiddle))
500 .setType(m_type)
501 .build();
502 if (value->IsNull())
503 (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
504 }
505
506 Response buildDeepSerializedValue(
507 v8::Local<v8::Context> context, int maxDepth,
508 v8::Local<v8::Object> additionalParameters,
509 V8SerializationDuplicateTracker& duplicateTracker,
510 std::unique_ptr<protocol::DictionaryValue>* result) const override {
511 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
512 if (value->IsUndefined()) {
513 *result = protocol::DictionaryValue::create();
514 (*result)->setString(
515 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Undefined);
516 return Response::Success();
517 }
518 if (value->IsNull()) {
519 *result = protocol::DictionaryValue::create();
520 (*result)->setString(
521 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Null);
522 return Response::Success();
523 }
524 if (value->IsString()) {
525 *result = protocol::DictionaryValue::create();
526 (*result)->setString(
527 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::String);
528 (*result)->setString("value", toProtocolString(context->GetIsolate(),
529 value.As<v8::String>()));
530 return Response::Success();
531 }
532 if (value->IsBoolean()) {
533 *result = protocol::DictionaryValue::create();
534 (*result)->setString(
535 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Boolean);
536 (*result)->setBoolean("value", value.As<v8::Boolean>()->Value());
537 return Response::Success();
538 }
539
540 // Fallback in case of unexpected type.
541 bool isKnown;
542 *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown);
543 if (isKnown) {
544 return Response::Success();
545 }
546
547 (*result)->setString(
548 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Object);
549 return Response::Success();
550 }
551
552 private:
553 String16 m_type;
554 String16 m_subtype;
555};
556
557class NumberMirror final : public ValueMirrorBase {
558 public:
559 NumberMirror(v8::Isolate* isolate, v8::Local<v8::Number> value)
560 : ValueMirrorBase(isolate, value) {}
561
562 Response buildRemoteObject(
563 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
564 std::unique_ptr<RemoteObject>* result) const override {
566 v8Value(context->GetIsolate()).As<v8::Number>();
567 bool unserializable = false;
568 String16 descriptionValue = descriptionForNumber(value, &unserializable);
569 *result = RemoteObject::create()
570 .setType(RemoteObject::TypeEnum::Number)
571 .setDescription(descriptionValue)
572 .build();
573 if (unserializable) {
574 (*result)->setUnserializableValue(descriptionValue);
575 } else {
576 (*result)->setValue(protocol::FundamentalValue::create(value->Value()));
577 }
578 return Response::Success();
579 }
580 void buildPropertyPreview(
581 v8::Local<v8::Context> context, const String16& name,
582 std::unique_ptr<PropertyPreview>* result) const override {
584 v8Value(context->GetIsolate()).As<v8::Number>();
585 bool unserializable = false;
586 *result = PropertyPreview::create()
587 .setName(name)
588 .setType(RemoteObject::TypeEnum::Number)
589 .setValue(descriptionForNumber(value, &unserializable))
590 .build();
591 }
592 void buildEntryPreview(
593 v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
594 std::unique_ptr<ObjectPreview>* preview) const override {
596 v8Value(context->GetIsolate()).As<v8::Number>();
597 bool unserializable = false;
598 *preview =
599 ObjectPreview::create()
600 .setType(RemoteObject::TypeEnum::Number)
601 .setDescription(descriptionForNumber(value, &unserializable))
602 .setOverflow(false)
603 .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
604 .build();
605 }
606
607 Response buildDeepSerializedValue(
608 v8::Local<v8::Context> context, int maxDepth,
609 v8::Local<v8::Object> additionalParameters,
610 V8SerializationDuplicateTracker& duplicateTracker,
611 std::unique_ptr<protocol::DictionaryValue>* result) const override {
612 *result = protocol::DictionaryValue::create();
613 (*result)->setString(
614 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Number);
615
617 v8Value(context->GetIsolate()).As<v8::Number>();
618 bool unserializable = false;
619 String16 descriptionValue = descriptionForNumber(value, &unserializable);
620 if (unserializable) {
621 (*result)->setValue("value",
622 protocol::StringValue::create(descriptionValue));
623 } else {
624 (*result)->setValue("value", toProtocolValue(value->Value()));
625 }
626 return Response::Success();
627 }
628};
629
630class BigIntMirror final : public ValueMirrorBase {
631 public:
632 BigIntMirror(v8::Isolate* isolate, v8::Local<v8::BigInt> value)
633 : ValueMirrorBase(isolate, value) {}
634
635 Response buildRemoteObject(
636 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
637 std::unique_ptr<RemoteObject>* result) const override {
639 v8Value(context->GetIsolate()).As<v8::BigInt>();
640 String16 description = descriptionForBigInt(context, value);
641 *result = RemoteObject::create()
642 .setType(RemoteObject::TypeEnum::Bigint)
643 .setUnserializableValue(description)
644 .setDescription(abbreviateString(description, kMiddle))
645 .build();
646 return Response::Success();
647 }
648
649 void buildPropertyPreview(v8::Local<v8::Context> context,
650 const String16& name,
651 std::unique_ptr<protocol::Runtime::PropertyPreview>*
652 preview) const override {
654 v8Value(context->GetIsolate()).As<v8::BigInt>();
655 *preview = PropertyPreview::create()
656 .setName(name)
657 .setType(RemoteObject::TypeEnum::Bigint)
658 .setValue(abbreviateString(
659 descriptionForBigInt(context, value), kMiddle))
660 .build();
661 }
662
663 void buildEntryPreview(v8::Local<v8::Context> context, int* nameLimit,
664 int* indexLimit,
665 std::unique_ptr<protocol::Runtime::ObjectPreview>*
666 preview) const override {
668 v8Value(context->GetIsolate()).As<v8::BigInt>();
669 *preview =
670 ObjectPreview::create()
671 .setType(RemoteObject::TypeEnum::Bigint)
672 .setDescription(
673 abbreviateString(descriptionForBigInt(context, value), kMiddle))
674 .setOverflow(false)
675 .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
676 .build();
677 }
678
679 Response buildDeepSerializedValue(
680 v8::Local<v8::Context> context, int maxDepth,
681 v8::Local<v8::Object> additionalParameters,
682 V8SerializationDuplicateTracker& duplicateTracker,
683 std::unique_ptr<protocol::DictionaryValue>* result) const override {
685 v8Value(context->GetIsolate()).As<v8::BigInt>();
686 v8::Local<v8::String> stringValue =
687 v8::debug::GetBigIntStringValue(context->GetIsolate(), value);
688
689 *result = protocol::DictionaryValue::create();
690 (*result)->setString(
691 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Bigint);
692
693 (*result)->setValue("value", protocol::StringValue::create(toProtocolString(
694 context->GetIsolate(), stringValue)));
695 return Response::Success();
696 }
697};
698
699class SymbolMirror final : public ValueMirrorBase {
700 public:
701 SymbolMirror(v8::Isolate* isolate, v8::Local<v8::Symbol> value)
702 : ValueMirrorBase(isolate, value) {}
703
704 Response buildRemoteObject(
705 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
706 std::unique_ptr<RemoteObject>* result) const override {
707 if (wrapOptions.mode == WrapMode::kJson) {
708 return Response::ServerError("Object couldn't be returned by value");
709 }
711 v8Value(context->GetIsolate()).As<v8::Symbol>();
712 *result = RemoteObject::create()
713 .setType(RemoteObject::TypeEnum::Symbol)
714 .setDescription(descriptionForSymbol(context, value))
715 .build();
716 return Response::Success();
717 }
718
719 void buildPropertyPreview(v8::Local<v8::Context> context,
720 const String16& name,
721 std::unique_ptr<protocol::Runtime::PropertyPreview>*
722 preview) const override {
724 v8Value(context->GetIsolate()).As<v8::Symbol>();
725 *preview = PropertyPreview::create()
726 .setName(name)
727 .setType(RemoteObject::TypeEnum::Symbol)
728 .setValue(abbreviateString(
729 descriptionForSymbol(context, value), kEnd))
730 .build();
731 }
732
733 void buildEntryPreview(
734 v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
735 std::unique_ptr<ObjectPreview>* preview) const override {
737 v8Value(context->GetIsolate()).As<v8::Symbol>();
738 *preview =
739 ObjectPreview::create()
740 .setType(RemoteObject::TypeEnum::Symbol)
741 .setDescription(descriptionForSymbol(context, value))
742 .setOverflow(false)
743 .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
744 .build();
745 }
746
747 Response buildDeepSerializedValue(
748 v8::Local<v8::Context> context, int maxDepth,
749 v8::Local<v8::Object> additionalParameters,
750 V8SerializationDuplicateTracker& duplicateTracker,
751 std::unique_ptr<protocol::DictionaryValue>* result) const override {
752 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
753 bool isKnown;
754 *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown);
755 if (isKnown) {
756 return Response::Success();
757 }
758
759 (*result)->setString(
760 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Symbol);
761 return Response::Success();
762 }
763};
764
765class LocationMirror final : public ValueMirrorBase {
766 public:
767 static std::unique_ptr<LocationMirror> create(
768 v8::Local<v8::Function> function) {
769 return create(function, function->ScriptId(),
770 function->GetScriptLineNumber(),
771 function->GetScriptColumnNumber());
772 }
773 static std::unique_ptr<LocationMirror> createForGenerator(
774 v8::Local<v8::Object> value) {
777 if (!generatorObject->IsSuspended()) {
778 return create(generatorObject->Function());
779 }
781 if (!generatorObject->Script().ToLocal(&script)) return nullptr;
782 v8::debug::Location suspendedLocation =
783 generatorObject->SuspendedLocation();
784 return create(value, script->Id(), suspendedLocation.GetLineNumber(),
785 suspendedLocation.GetColumnNumber());
786 }
787
788 Response buildRemoteObject(
789 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
790 std::unique_ptr<RemoteObject>* result) const override {
791 auto location = protocol::DictionaryValue::create();
792 location->setString("scriptId", String16::fromInteger(m_scriptId));
793 location->setInteger("lineNumber", m_lineNumber);
794 location->setInteger("columnNumber", m_columnNumber);
795 *result = RemoteObject::create()
796 .setType(RemoteObject::TypeEnum::Object)
797 .setSubtype("internal#location")
798 .setDescription("Object")
799 .setValue(std::move(location))
800 .build();
801 return Response::Success();
802 }
803
804 Response buildDeepSerializedValue(
805 v8::Local<v8::Context> context, int maxDepth,
806 v8::Local<v8::Object> additionalParameters,
807 V8SerializationDuplicateTracker& duplicateTracker,
808 std::unique_ptr<protocol::DictionaryValue>* result) const override {
809 bool isKnown;
810 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
811 *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown);
812 if (isKnown) {
813 return Response::Success();
814 }
815
816 (*result)->setString(
817 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Object);
818 return Response::Success();
819 }
820
821 private:
822 static std::unique_ptr<LocationMirror> create(v8::Local<v8::Object> value,
823 int scriptId, int lineNumber,
824 int columnNumber) {
825 if (scriptId == v8::UnboundScript::kNoScriptId) return nullptr;
826 if (lineNumber == v8::Function::kLineOffsetNotFound ||
827 columnNumber == v8::Function::kLineOffsetNotFound) {
828 return nullptr;
829 }
830 return std::unique_ptr<LocationMirror>(
831 new LocationMirror(value, scriptId, lineNumber, columnNumber));
832 }
833
834 LocationMirror(v8::Local<v8::Object> value, int scriptId, int lineNumber,
835 int columnNumber)
836 : ValueMirrorBase(value->GetIsolate(), value),
837 m_scriptId(scriptId),
838 m_lineNumber(lineNumber),
839 m_columnNumber(columnNumber) {}
840
844};
845
846class FunctionMirror final : public ValueMirrorBase {
847 public:
848 explicit FunctionMirror(v8::Local<v8::Function> value)
849 : ValueMirrorBase(value->GetIsolate(), value) {}
850
851 Response buildRemoteObject(
852 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
853 std::unique_ptr<RemoteObject>* result) const override {
855 v8Value(context->GetIsolate()).As<v8::Function>();
856 // TODO(alph): drop this functionality.
857 if (wrapOptions.mode == WrapMode::kJson) {
858 std::unique_ptr<protocol::Value> protocolValue;
859 Response response = toProtocolValue(context, value, &protocolValue);
860 if (!response.IsSuccess()) return response;
861 *result = RemoteObject::create()
862 .setType(RemoteObject::TypeEnum::Function)
863 .setValue(std::move(protocolValue))
864 .build();
865 } else {
866 *result = RemoteObject::create()
867 .setType(RemoteObject::TypeEnum::Function)
868 .setClassName(toProtocolStringWithTypeCheck(
869 context->GetIsolate(), value->GetConstructorName()))
870 .setDescription(descriptionForFunction(value))
871 .build();
872 }
873 return Response::Success();
874 }
875
876 void buildPropertyPreview(
877 v8::Local<v8::Context> context, const String16& name,
878 std::unique_ptr<PropertyPreview>* result) const override {
879 *result = PropertyPreview::create()
880 .setName(name)
881 .setType(RemoteObject::TypeEnum::Function)
882 .setValue(String16())
883 .build();
884 }
885 void buildEntryPreview(
886 v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
887 std::unique_ptr<ObjectPreview>* preview) const override {
889 v8Value(context->GetIsolate()).As<v8::Function>();
890 *preview =
891 ObjectPreview::create()
892 .setType(RemoteObject::TypeEnum::Function)
893 .setDescription(descriptionForFunction(value))
894 .setOverflow(false)
895 .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
896 .build();
897 }
898
899 Response buildDeepSerializedValue(
900 v8::Local<v8::Context> context, int maxDepth,
901 v8::Local<v8::Object> additionalParameters,
902 V8SerializationDuplicateTracker& duplicateTracker,
903 std::unique_ptr<protocol::DictionaryValue>* result) const override {
904 bool isKnown;
905 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
906 *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown);
907 if (isKnown) {
908 return Response::Success();
909 }
910
911 (*result)->setString(
912 "type", protocol::Runtime::DeepSerializedValue::TypeEnum::Function);
913 return Response::Success();
914 }
915};
916
917bool isArrayLike(v8::Local<v8::Context> context, v8::Local<v8::Object> object,
918 size_t* length) {
919 if (object->IsArray()) {
920 *length = object.As<v8::Array>()->Length();
921 return true;
922 }
923 if (object->IsArgumentsObject()) {
924 v8::Isolate* isolate = context->GetIsolate();
925 v8::TryCatch tryCatch(isolate);
926 v8::MicrotasksScope microtasksScope(
928 v8::Local<v8::Value> lengthDescriptor;
929 if (!object
930 ->GetOwnPropertyDescriptor(context, toV8String(isolate, "length"))
931 .ToLocal(&lengthDescriptor)) {
932 return false;
933 }
934 v8::Local<v8::Value> lengthValue;
935 if (!lengthDescriptor->IsObject() ||
936 !lengthDescriptor.As<v8::Object>()
937 ->Get(context, toV8String(isolate, "value"))
938 .ToLocal(&lengthValue) ||
939 !lengthValue->IsUint32()) {
940 return false;
941 }
942 *length = lengthValue.As<v8::Uint32>()->Value();
943 return true;
944 }
945 return false;
946}
947
948struct EntryMirror {
949 std::unique_ptr<ValueMirror> key;
950 std::unique_ptr<ValueMirror> value;
951
952 static bool getEntries(v8::Local<v8::Context> context,
953 v8::Local<v8::Object> object, size_t limit,
954 bool* overflow, std::vector<EntryMirror>* mirrors) {
955 bool isKeyValue = false;
957 if (!object->PreviewEntries(&isKeyValue).ToLocal(&entries)) return false;
958 for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
960
961 std::unique_ptr<ValueMirror> keyMirror;
962 if (isKeyValue && entries->Get(context, i).ToLocal(&tmp)) {
963 keyMirror = ValueMirror::create(context, tmp);
964 }
965 std::unique_ptr<ValueMirror> valueMirror;
966 if (entries->Get(context, isKeyValue ? i + 1 : i).ToLocal(&tmp)) {
967 valueMirror = ValueMirror::create(context, tmp);
968 } else {
969 continue;
970 }
971 if (mirrors->size() == limit) {
972 *overflow = true;
973 return true;
974 }
975 mirrors->emplace_back(
976 EntryMirror{std::move(keyMirror), std::move(valueMirror)});
977 }
978 return !mirrors->empty();
979 }
980};
981
982class PreviewPropertyAccumulator : public ValueMirror::PropertyAccumulator {
983 public:
984 PreviewPropertyAccumulator(v8::Isolate* isolate,
985 const std::vector<String16>& blocklist,
986 int skipIndex, int* nameLimit, int* indexLimit,
987 bool* overflow,
988 std::vector<PropertyMirror>* mirrors)
989 : m_isolate(isolate),
990 m_blocklist(blocklist),
991 m_skipIndex(skipIndex),
992 m_nameLimit(nameLimit),
993 m_indexLimit(indexLimit),
994 m_overflow(overflow),
995 m_mirrors(mirrors) {}
996
997 bool Add(PropertyMirror mirror) override {
998 if (mirror.exception) return true;
999 if ((!mirror.getter || !mirror.getter->v8Value(m_isolate)->IsFunction()) &&
1000 !mirror.value) {
1001 return true;
1002 }
1003 if (!mirror.isOwn && !mirror.isSynthetic) return true;
1004 if (std::find(m_blocklist.begin(), m_blocklist.end(), mirror.name) !=
1005 m_blocklist.end()) {
1006 return true;
1007 }
1008 if (mirror.isIndex && m_skipIndex > 0) {
1009 --m_skipIndex;
1010 if (m_skipIndex > 0) return true;
1011 }
1012 int* limit = mirror.isIndex ? m_indexLimit : m_nameLimit;
1013 if (!*limit) {
1014 *m_overflow = true;
1015 return false;
1016 }
1017 --*limit;
1018 m_mirrors->push_back(std::move(mirror));
1019 return true;
1020 }
1021
1022 private:
1024 std::vector<String16> m_blocklist;
1029 std::vector<PropertyMirror>* m_mirrors;
1030};
1031
1032bool getPropertiesForPreview(v8::Local<v8::Context> context,
1033 v8::Local<v8::Object> object, int* nameLimit,
1034 int* indexLimit, bool* overflow,
1035 std::vector<PropertyMirror>* properties) {
1036 std::vector<String16> blocklist;
1037 size_t length = 0;
1038 if (isArrayLike(context, object, &length) || object->IsStringObject()) {
1039 blocklist.push_back("length");
1040#if V8_ENABLE_WEBASSEMBLY
1041 } else if (v8::debug::WasmValueObject::IsWasmValueObject(object)) {
1042 blocklist.push_back("type");
1043#endif // V8_ENABLE_WEBASSEMBLY
1044 } else {
1045 auto clientSubtype = clientFor(context)->valueSubtype(object);
1046 if (clientSubtype && toString16(clientSubtype->string()) == "array") {
1047 blocklist.push_back("length");
1048 }
1049 }
1050 if (object->IsArrayBuffer() || object->IsSharedArrayBuffer()) {
1051 blocklist.push_back("[[Int8Array]]");
1052 blocklist.push_back("[[Uint8Array]]");
1053 blocklist.push_back("[[Int16Array]]");
1054 blocklist.push_back("[[Int32Array]]");
1055 }
1056 blocklist.push_back("constructor");
1057 int skipIndex = object->IsStringObject()
1058 ? object.As<v8::StringObject>()->ValueOf()->Length() + 1
1059 : -1;
1060 PreviewPropertyAccumulator accumulator(context->GetIsolate(), blocklist,
1061 skipIndex, nameLimit, indexLimit,
1062 overflow, properties);
1063 return ValueMirror::getProperties(context, object, false, false, false,
1064 &accumulator);
1065}
1066
1067void getInternalPropertiesForPreview(
1069 int* nameLimit, bool* overflow,
1070 std::vector<InternalPropertyMirror>* properties) {
1071 std::vector<InternalPropertyMirror> mirrors;
1072 ValueMirror::getInternalProperties(context, object, &mirrors);
1073 std::vector<String16> allowlist;
1074 if (object->IsBooleanObject() || object->IsNumberObject() ||
1075 object->IsStringObject() || object->IsSymbolObject() ||
1076 object->IsBigIntObject()) {
1077 allowlist.emplace_back("[[PrimitiveValue]]");
1078 } else if (object->IsPromise()) {
1079 allowlist.emplace_back("[[PromiseState]]");
1080 allowlist.emplace_back("[[PromiseResult]]");
1081 } else if (object->IsGeneratorObject()) {
1082 allowlist.emplace_back("[[GeneratorState]]");
1083 } else if (object->IsWeakRef()) {
1084 allowlist.emplace_back("[[WeakRefTarget]]");
1085 }
1086 for (auto& mirror : mirrors) {
1087 if (std::find(allowlist.begin(), allowlist.end(), mirror.name) ==
1088 allowlist.end()) {
1089 continue;
1090 }
1091 if (!*nameLimit) {
1092 *overflow = true;
1093 return;
1094 }
1095 --*nameLimit;
1096 properties->push_back(std::move(mirror));
1097 }
1098}
1099
1100void getPrivatePropertiesForPreview(
1102 int* nameLimit, bool* overflow,
1103 protocol::Array<PropertyPreview>* privateProperties) {
1104 std::vector<PrivatePropertyMirror> mirrors =
1105 ValueMirror::getPrivateProperties(context, object,
1106 /* accessPropertiesOnly */ false);
1107 for (auto& mirror : mirrors) {
1108 std::unique_ptr<PropertyPreview> propertyPreview;
1109 if (mirror.value) {
1110 mirror.value->buildPropertyPreview(context, mirror.name,
1111 &propertyPreview);
1112 } else {
1113 propertyPreview = PropertyPreview::create()
1114 .setName(mirror.name)
1115 .setType(PropertyPreview::TypeEnum::Accessor)
1116 .build();
1117 }
1118 if (!propertyPreview) continue;
1119 if (!*nameLimit) {
1120 *overflow = true;
1121 return;
1122 }
1123 --*nameLimit;
1124 privateProperties->emplace_back(std::move(propertyPreview));
1125 }
1126}
1127
1128class ObjectMirror final : public ValueMirrorBase {
1129 public:
1130 ObjectMirror(v8::Local<v8::Object> value, const String16& description)
1131 : ValueMirrorBase(value->GetIsolate(), value),
1132 m_description(description),
1133 m_hasSubtype(false) {}
1134 ObjectMirror(v8::Local<v8::Object> value, const String16& subtype,
1135 const String16& description)
1136 : ValueMirrorBase(value->GetIsolate(), value),
1137 m_description(description),
1138 m_hasSubtype(true),
1139 m_subtype(subtype) {}
1140
1141 Response buildRemoteObject(
1142 v8::Local<v8::Context> context, const WrapOptions& wrapOptions,
1143 std::unique_ptr<RemoteObject>* result) const override {
1144 v8::Isolate* isolate = context->GetIsolate();
1145 v8::Local<v8::Object> value = v8Value(isolate).As<v8::Object>();
1146 if (wrapOptions.mode == WrapMode::kJson) {
1147 std::unique_ptr<protocol::Value> protocolValue;
1148 Response response = toProtocolValue(context, value, &protocolValue);
1149 if (!response.IsSuccess()) return response;
1150 *result = RemoteObject::create()
1151 .setType(RemoteObject::TypeEnum::Object)
1152 .setValue(std::move(protocolValue))
1153 .build();
1154 } else {
1155 *result = RemoteObject::create()
1156 .setType(RemoteObject::TypeEnum::Object)
1157 .setClassName(
1158 toProtocolString(isolate, value->GetConstructorName()))
1159 .setDescription(m_description)
1160 .build();
1161 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1162 if (wrapOptions.mode == WrapMode::kPreview) {
1163 std::unique_ptr<ObjectPreview> previewValue;
1164 int nameLimit = 5;
1165 int indexLimit = 100;
1166 buildObjectPreview(context, false, &nameLimit, &indexLimit,
1167 &previewValue);
1168 (*result)->setPreview(std::move(previewValue));
1169 }
1170 }
1171 return Response::Success();
1172 }
1173
1174 void buildObjectPreview(
1175 v8::Local<v8::Context> context, bool generatePreviewForTable,
1176 int* nameLimit, int* indexLimit,
1177 std::unique_ptr<ObjectPreview>* result) const override {
1178 buildObjectPreviewInternal(context, false /* forEntry */,
1179 generatePreviewForTable, nameLimit, indexLimit,
1180 result);
1181 }
1182
1183 void buildEntryPreview(
1184 v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
1185 std::unique_ptr<ObjectPreview>* result) const override {
1186 buildObjectPreviewInternal(context, true /* forEntry */,
1187 false /* generatePreviewForTable */, nameLimit,
1188 indexLimit, result);
1189 }
1190
1191 void buildPropertyPreview(
1192 v8::Local<v8::Context> context, const String16& name,
1193 std::unique_ptr<PropertyPreview>* result) const override {
1194 *result = PropertyPreview::create()
1195 .setName(name)
1196 .setType(RemoteObject::TypeEnum::Object)
1197 .setValue(abbreviateString(
1198 m_description,
1199 m_subtype == RemoteObject::SubtypeEnum::Regexp ? kMiddle
1200 : kEnd))
1201 .build();
1202 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1203 }
1204
1205 Response buildDeepSerializedValue(
1206 v8::Local<v8::Context> context, int maxDepth,
1207 v8::Local<v8::Object> additionalParameters,
1208 V8SerializationDuplicateTracker& duplicateTracker,
1209 std::unique_ptr<protocol::DictionaryValue>* result) const override {
1210 v8::Local<v8::Object> value =
1211 v8Value(context->GetIsolate()).As<v8::Object>();
1212 maxDepth = std::min(kMaxProtocolDepth, maxDepth);
1213 bool isKnown;
1214 *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown);
1215 if (isKnown) {
1216 return Response::Success();
1217 }
1218
1219 // Check if embedder implemented custom serialization.
1220 std::unique_ptr<v8_inspector::DeepSerializationResult>
1221 embedderDeepSerializedResult = clientFor(context)->deepSerialize(
1222 value, maxDepth, additionalParameters);
1223 if (embedderDeepSerializedResult) {
1224 // Embedder-implemented serialization.
1225
1226 if (!embedderDeepSerializedResult->isSuccess)
1227 return Response::ServerError(
1228 toString16(embedderDeepSerializedResult->errorMessage->string())
1229 .utf8());
1230
1231 (*result)->setString(
1232 "type",
1233 toString16(
1234 embedderDeepSerializedResult->serializedValue->type->string()));
1235 v8::Local<v8::Value> v8Value;
1236 if (embedderDeepSerializedResult->serializedValue->value.ToLocal(
1237 &v8Value)) {
1238 // Embedder-implemented serialization has value.
1239 std::unique_ptr<protocol::Value> protocolValue;
1240 Response response = toProtocolValue(context, v8Value, &protocolValue);
1241 if (!response.IsSuccess()) return response;
1242 (*result)->setValue("value", std::move(protocolValue));
1243 }
1244 return Response::Success();
1245 }
1246
1247 // No embedder-implemented serialization. Serialize as V8 Object.
1248 return V8DeepSerializer::serializeV8Value(value, context, maxDepth,
1249 additionalParameters,
1250 duplicateTracker, *(*result));
1251 }
1252
1253 private:
1254 void buildObjectPreviewInternal(
1255 v8::Local<v8::Context> context, bool forEntry,
1256 bool generatePreviewForTable, int* nameLimit, int* indexLimit,
1257 std::unique_ptr<ObjectPreview>* result) const {
1258 auto properties = std::make_unique<protocol::Array<PropertyPreview>>();
1259 std::unique_ptr<protocol::Array<EntryPreview>> entriesPreview;
1260 bool overflow = false;
1261
1262 v8::Local<v8::Value> value = v8Value(context->GetIsolate());
1263 while (value->IsProxy()) value = value.As<v8::Proxy>()->GetTarget();
1264
1265 if (value->IsObject() && !value->IsProxy()) {
1266 v8::Local<v8::Object> objectForPreview = value.As<v8::Object>();
1267 std::vector<InternalPropertyMirror> internalProperties;
1268 getInternalPropertiesForPreview(context, objectForPreview, nameLimit,
1269 &overflow, &internalProperties);
1270 for (size_t i = 0; i < internalProperties.size(); ++i) {
1271 std::unique_ptr<PropertyPreview> propertyPreview;
1272 internalProperties[i].value->buildPropertyPreview(
1273 context, internalProperties[i].name, &propertyPreview);
1274 if (propertyPreview) {
1275 properties->emplace_back(std::move(propertyPreview));
1276 }
1277 }
1278
1279 getPrivatePropertiesForPreview(context, objectForPreview, nameLimit,
1280 &overflow, properties.get());
1281
1282 std::vector<PropertyMirror> mirrors;
1283 if (getPropertiesForPreview(context, objectForPreview, nameLimit,
1284 indexLimit, &overflow, &mirrors)) {
1285 for (size_t i = 0; i < mirrors.size(); ++i) {
1286 std::unique_ptr<PropertyPreview> preview;
1287 std::unique_ptr<ObjectPreview> valuePreview;
1288 if (mirrors[i].value) {
1289 mirrors[i].value->buildPropertyPreview(context, mirrors[i].name,
1290 &preview);
1291 if (generatePreviewForTable) {
1292 int tableLimit = 1000;
1293 mirrors[i].value->buildObjectPreview(context, false, &tableLimit,
1294 &tableLimit, &valuePreview);
1295 }
1296 } else {
1297 preview = PropertyPreview::create()
1298 .setName(mirrors[i].name)
1299 .setType(PropertyPreview::TypeEnum::Accessor)
1300 .build();
1301 }
1302 if (valuePreview) {
1303 preview->setValuePreview(std::move(valuePreview));
1304 }
1305 properties->emplace_back(std::move(preview));
1306 }
1307 }
1308
1309 std::vector<EntryMirror> entries;
1310 if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow,
1311 &entries)) {
1312 if (forEntry) {
1313 overflow = true;
1314 } else {
1315 entriesPreview = std::make_unique<protocol::Array<EntryPreview>>();
1316 for (const auto& entry : entries) {
1317 std::unique_ptr<ObjectPreview> valuePreview;
1318 entry.value->buildEntryPreview(context, nameLimit, indexLimit,
1319 &valuePreview);
1320 if (!valuePreview) continue;
1321 std::unique_ptr<ObjectPreview> keyPreview;
1322 if (entry.key) {
1323 entry.key->buildEntryPreview(context, nameLimit, indexLimit,
1324 &keyPreview);
1325 if (!keyPreview) continue;
1326 }
1327 std::unique_ptr<EntryPreview> entryPreview =
1328 EntryPreview::create()
1329 .setValue(std::move(valuePreview))
1330 .build();
1331 if (keyPreview) entryPreview->setKey(std::move(keyPreview));
1332 entriesPreview->emplace_back(std::move(entryPreview));
1333 }
1334 }
1335 }
1336 }
1337 *result = ObjectPreview::create()
1338 .setType(RemoteObject::TypeEnum::Object)
1339 .setDescription(m_description)
1340 .setOverflow(overflow)
1341 .setProperties(std::move(properties))
1342 .build();
1343 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1344 if (entriesPreview) (*result)->setEntries(std::move(entriesPreview));
1345 }
1346
1349 String16 m_subtype;
1350};
1351
1352void nativeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1353 v8::Local<v8::Object> data = info.Data().As<v8::Object>();
1354 v8::Isolate* isolate = info.GetIsolate();
1355 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1357 if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
1358 .ToLocal(&name)) {
1359 return;
1360 }
1361 v8::Local<v8::Value> object;
1362 if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
1363 .ToLocal(&object) ||
1364 !object->IsObject()) {
1365 return;
1366 }
1368 if (!object.As<v8::Object>()->Get(context, name).ToLocal(&value)) return;
1369 info.GetReturnValue().Set(value);
1370}
1371
1372std::unique_ptr<ValueMirror> createNativeGetter(v8::Local<v8::Context> context,
1373 v8::Local<v8::Value> object,
1374 v8::Local<v8::Name> name) {
1375 v8::Isolate* isolate = context->GetIsolate();
1376 v8::TryCatch tryCatch(isolate);
1377
1378 v8::Local<v8::Object> data = v8::Object::New(isolate);
1379 if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1380 return nullptr;
1381 }
1382 if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1383 return nullptr;
1384 }
1385
1386 v8::Local<v8::Function> function;
1387 if (!v8::Function::New(context, nativeGetterCallback, data, 0,
1389 .ToLocal(&function)) {
1390 return nullptr;
1391 }
1392 return ValueMirror::create(context, function);
1393}
1394
1395void nativeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1396 if (info.Length() < 1) return;
1397 v8::Local<v8::Object> data = info.Data().As<v8::Object>();
1398 v8::Isolate* isolate = info.GetIsolate();
1399 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1401 if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
1402 .ToLocal(&name)) {
1403 return;
1404 }
1405 v8::Local<v8::Value> object;
1406 if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
1407 .ToLocal(&object) ||
1408 !object->IsObject()) {
1409 return;
1410 }
1411 if (!object.As<v8::Object>()->Set(context, name, info[0]).IsNothing()) return;
1412}
1413
1414std::unique_ptr<ValueMirror> createNativeSetter(v8::Local<v8::Context> context,
1415 v8::Local<v8::Value> object,
1416 v8::Local<v8::Name> name) {
1417 v8::Isolate* isolate = context->GetIsolate();
1418 v8::TryCatch tryCatch(isolate);
1419
1420 v8::Local<v8::Object> data = v8::Object::New(isolate);
1421 if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1422 return nullptr;
1423 }
1424 if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1425 return nullptr;
1426 }
1427
1428 v8::Local<v8::Function> function;
1429 if (!v8::Function::New(context, nativeSetterCallback, data, 1,
1431 .ToLocal(&function)) {
1432 return nullptr;
1433 }
1434 return ValueMirror::create(context, function);
1435}
1436
1437bool doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context,
1438 v8::Local<v8::Object> object,
1439 v8::Local<v8::Name> name) {
1440 // TODO(dgozman): we should remove this, annotate more embedder properties as
1441 // side-effect free, and call all getters which do not produce side effects.
1442 if (!name->IsString()) return false;
1443 v8::Isolate* isolate = context->GetIsolate();
1444 if (!name.As<v8::String>()->StringEquals(toV8String(isolate, "body"))) {
1445 return false;
1446 }
1447
1448 v8::TryCatch tryCatch(isolate);
1449 v8::Local<v8::Value> request;
1450 if (context->Global()
1451 ->GetRealNamedProperty(context, toV8String(isolate, "Request"))
1452 .ToLocal(&request)) {
1453 if (request->IsObject() &&
1454 object->InstanceOf(context, request.As<v8::Object>())
1455 .FromMaybe(false)) {
1456 return true;
1457 }
1458 }
1459 if (tryCatch.HasCaught()) tryCatch.Reset();
1460
1461 v8::Local<v8::Value> response;
1462 if (context->Global()
1463 ->GetRealNamedProperty(context, toV8String(isolate, "Response"))
1464 .ToLocal(&response)) {
1465 if (response->IsObject() &&
1466 object->InstanceOf(context, response.As<v8::Object>())
1467 .FromMaybe(false)) {
1468 return true;
1469 }
1470 }
1471 return false;
1472}
1473
1474} // anonymous namespace
1475
1476ValueMirror::~ValueMirror() = default;
1477
1478// static
1480 v8::Local<v8::Object> object,
1481 bool ownProperties, bool accessorPropertiesOnly,
1482 bool nonIndexedPropertiesOnly,
1483 PropertyAccumulator* accumulator) {
1484 v8::Isolate* isolate = context->GetIsolate();
1485 v8::TryCatch tryCatch(isolate);
1486 v8::Local<v8::Set> set = v8::Set::New(isolate);
1487
1488 v8::MicrotasksScope microtasksScope(context,
1490 V8InternalValueType internalType = v8InternalValueTypeFrom(context, object);
1491 if (internalType == V8InternalValueType::kScope) {
1493 if (!object->Get(context, toV8String(isolate, "object")).ToLocal(&value) ||
1494 !value->IsObject()) {
1495 return false;
1496 } else {
1497 object = value.As<v8::Object>();
1498 }
1499 }
1500 if (internalType == V8InternalValueType::kScopeList ||
1502 if (!set->Add(context, toV8String(isolate, "length")).ToLocal(&set)) {
1503 return false;
1504 }
1505 }
1506
1507 auto iterator = v8::debug::PropertyIterator::Create(context, object,
1508 nonIndexedPropertiesOnly);
1509 if (!iterator) {
1510 CHECK(tryCatch.HasCaught());
1511 return false;
1512 }
1513 while (!iterator->Done()) {
1514 bool isOwn = iterator->is_own();
1515 if (!isOwn && ownProperties) break;
1516 v8::Local<v8::Name> v8Name = iterator->name();
1517 v8::Maybe<bool> result = set->Has(context, v8Name);
1518 if (result.IsNothing()) return false;
1519 if (result.FromJust()) {
1520 if (!iterator->Advance().FromMaybe(false)) {
1521 CHECK(tryCatch.HasCaught());
1522 return false;
1523 }
1524 continue;
1525 }
1526 if (!set->Add(context, v8Name).ToLocal(&set)) return false;
1527
1528 String16 name;
1529 std::unique_ptr<ValueMirror> symbolMirror;
1530 if (v8Name->IsString()) {
1531 name = toProtocolString(isolate, v8Name.As<v8::String>());
1532 } else {
1533 v8::Local<v8::Symbol> symbol = v8Name.As<v8::Symbol>();
1534 name = descriptionForSymbol(context, symbol);
1535 symbolMirror = ValueMirror::create(context, symbol);
1536 }
1537
1538 v8::PropertyAttribute attributes;
1539 std::unique_ptr<ValueMirror> valueMirror;
1540 std::unique_ptr<ValueMirror> getterMirror;
1541 std::unique_ptr<ValueMirror> setterMirror;
1542 std::unique_ptr<ValueMirror> exceptionMirror;
1543 bool writable = false;
1544 bool enumerable = false;
1545 bool configurable = false;
1546
1547 bool isAccessorProperty = false;
1548 v8::TryCatch tryCatchAttributes(isolate);
1549 if (!iterator->attributes().To(&attributes)) {
1550 exceptionMirror =
1551 ValueMirror::create(context, tryCatchAttributes.Exception());
1552 } else {
1553 if (iterator->is_native_accessor()) {
1554 if (iterator->has_native_getter()) {
1555 getterMirror = createNativeGetter(context, object, v8Name);
1556 }
1557 if (iterator->has_native_setter()) {
1558 setterMirror = createNativeSetter(context, object, v8Name);
1559 }
1560 writable = !(attributes & v8::PropertyAttribute::ReadOnly);
1561 enumerable = !(attributes & v8::PropertyAttribute::DontEnum);
1562 configurable = !(attributes & v8::PropertyAttribute::DontDelete);
1563 isAccessorProperty = getterMirror || setterMirror;
1564 } else {
1565 v8::TryCatch tryCatchDescriptor(isolate);
1567 if (!iterator->descriptor().To(&descriptor)) {
1568 exceptionMirror =
1569 ValueMirror::create(context, tryCatchDescriptor.Exception());
1570 } else {
1571 writable = descriptor.has_writable ? descriptor.writable : false;
1572 enumerable =
1573 descriptor.has_enumerable ? descriptor.enumerable : false;
1574 configurable =
1575 descriptor.has_configurable ? descriptor.configurable : false;
1576 if (!descriptor.value.IsEmpty()) {
1577 valueMirror = ValueMirror::create(context, descriptor.value);
1578 }
1579 v8::Local<v8::Function> getterFunction;
1580 if (!descriptor.get.IsEmpty()) {
1581 v8::Local<v8::Value> get = descriptor.get;
1582 getterMirror = ValueMirror::create(context, get);
1583 if (get->IsFunction()) getterFunction = get.As<v8::Function>();
1584 }
1585 if (!descriptor.set.IsEmpty()) {
1586 setterMirror = ValueMirror::create(context, descriptor.set);
1587 }
1588 isAccessorProperty = getterMirror || setterMirror;
1589 if (name != "__proto__" && !getterFunction.IsEmpty() &&
1590 getterFunction->ScriptId() == v8::UnboundScript::kNoScriptId &&
1591 !doesAttributeHaveObservableSideEffectOnGet(context, object,
1592 v8Name)) {
1593 v8::TryCatch tryCatchFunction(isolate);
1595 if (object->Get(context, v8Name).ToLocal(&value)) {
1596 if (value->IsPromise() &&
1597 value.As<v8::Promise>()->State() == v8::Promise::kRejected) {
1598 value.As<v8::Promise>()->MarkAsHandled();
1599 } else {
1600 valueMirror = ValueMirror::create(context, value);
1601 setterMirror = nullptr;
1602 getterMirror = nullptr;
1603 }
1604 }
1605 }
1606 }
1607 }
1608 }
1609 if (accessorPropertiesOnly && !isAccessorProperty) continue;
1610 auto mirror = PropertyMirror{name,
1611 writable,
1612 configurable,
1613 enumerable,
1614 isOwn,
1615 iterator->is_array_index(),
1616 isAccessorProperty && valueMirror,
1617 std::move(valueMirror),
1618 std::move(getterMirror),
1619 std::move(setterMirror),
1620 std::move(symbolMirror),
1621 std::move(exceptionMirror)};
1622 if (!accumulator->Add(std::move(mirror))) return true;
1623
1624 if (!iterator->Advance().FromMaybe(false)) {
1625 CHECK(tryCatchAttributes.HasCaught());
1626 return false;
1627 }
1628 }
1629 return true;
1630}
1631
1632// static
1635 std::vector<InternalPropertyMirror>* mirrors) {
1636 v8::Isolate* isolate = context->GetIsolate();
1637 v8::MicrotasksScope microtasksScope(context,
1639 v8::TryCatch tryCatch(isolate);
1640 if (object->IsFunction()) {
1641 v8::Local<v8::Function> function = object.As<v8::Function>();
1642 auto location = LocationMirror::create(function);
1643 if (location) {
1644 mirrors->emplace_back(InternalPropertyMirror{
1645 String16("[[FunctionLocation]]"), std::move(location)});
1646 }
1647 if (function->IsGeneratorFunction()) {
1648 mirrors->emplace_back(InternalPropertyMirror{
1649 String16("[[IsGenerator]]"),
1650 ValueMirror::create(context, v8::True(context->GetIsolate()))});
1651 }
1652 }
1653 if (object->IsGeneratorObject()) {
1654 auto location = LocationMirror::createForGenerator(object);
1655 if (location) {
1656 mirrors->emplace_back(InternalPropertyMirror{
1657 String16("[[GeneratorLocation]]"), std::move(location)});
1658 }
1659 }
1660 V8Debugger* debugger =
1661 static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate))
1662 ->debugger();
1663 v8::Local<v8::Array> properties;
1664 if (debugger->internalProperties(context, object).ToLocal(&properties)) {
1665 for (uint32_t i = 0; i < properties->Length(); i += 2) {
1667 if (!properties->Get(context, i).ToLocal(&name) || !name->IsString()) {
1668 tryCatch.Reset();
1669 continue;
1670 }
1672 if (!properties->Get(context, i + 1).ToLocal(&value)) {
1673 tryCatch.Reset();
1674 continue;
1675 }
1676 auto wrapper = ValueMirror::create(context, value);
1677 if (wrapper) {
1678 mirrors->emplace_back(InternalPropertyMirror{
1679 toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1680 std::move(wrapper)});
1681 }
1682 }
1683 }
1684}
1685
1686// static
1687std::vector<PrivatePropertyMirror> ValueMirror::getPrivateProperties(
1689 bool accessorPropertiesOnly) {
1690 std::vector<PrivatePropertyMirror> mirrors;
1691 v8::Isolate* isolate = context->GetIsolate();
1692 v8::MicrotasksScope microtasksScope(context,
1694 v8::TryCatch tryCatch(isolate);
1695
1696 v8::LocalVector<v8::Value> names(isolate);
1697 v8::LocalVector<v8::Value> values(isolate);
1698 int filter =
1701 if (!v8::debug::GetPrivateMembers(context, object, filter, &names, &values))
1702 return mirrors;
1703
1704 size_t len = values.size();
1705 for (size_t i = 0; i < len; i++) {
1706 v8::Local<v8::Value> name = names[i];
1707 DCHECK(name->IsString());
1708 v8::Local<v8::Value> value = values[i];
1709
1710 std::unique_ptr<ValueMirror> valueMirror;
1711 std::unique_ptr<ValueMirror> getterMirror;
1712 std::unique_ptr<ValueMirror> setterMirror;
1715 value.As<v8::debug::AccessorPair>();
1716 v8::Local<v8::Value> getter = accessors->getter();
1717 v8::Local<v8::Value> setter = accessors->setter();
1718 if (!getter->IsNull()) {
1719 getterMirror = ValueMirror::create(context, getter);
1720 }
1721 if (!setter->IsNull()) {
1722 setterMirror = ValueMirror::create(context, setter);
1723 }
1724 } else if (accessorPropertiesOnly) {
1725 continue;
1726 } else {
1727 valueMirror = ValueMirror::create(context, value);
1728 }
1729
1730 mirrors.emplace_back(PrivatePropertyMirror{
1731 toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1732 std::move(valueMirror), std::move(getterMirror),
1733 std::move(setterMirror)});
1734 }
1735 return mirrors;
1736}
1737
1738std::unique_ptr<ValueMirror> clientMirror(v8::Local<v8::Context> context,
1740 const String16& subtype) {
1741 auto descriptionForValueSubtype =
1742 clientFor(context)->descriptionForValueSubtype(context, value);
1743 if (descriptionForValueSubtype) {
1744 return std::make_unique<ObjectMirror>(
1745 value, subtype, toString16(descriptionForValueSubtype->string()));
1746 }
1747 if (subtype == "error") {
1748 return std::make_unique<ObjectMirror>(value,
1749 RemoteObject::SubtypeEnum::Error,
1750 descriptionForError(context, value));
1751 }
1752 if (subtype == "array" && value->IsObject()) {
1753 v8::Isolate* isolate = context->GetIsolate();
1754 v8::TryCatch tryCatch(isolate);
1755 v8::Local<v8::Value> lengthValue;
1756 if (value->Get(context, toV8String(isolate, "length"))
1757 .ToLocal(&lengthValue)) {
1758 if (lengthValue->IsInt32()) {
1759 return std::make_unique<ObjectMirror>(
1760 value, RemoteObject::SubtypeEnum::Array,
1761 descriptionForCollection(isolate, value,
1762 lengthValue.As<v8::Int32>()->Value()));
1763 }
1764 }
1765 }
1766 return std::make_unique<ObjectMirror>(
1767 value, descriptionForObject(context->GetIsolate(), value));
1768}
1769
1770std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
1771 v8::Local<v8::Value> value) {
1772 v8::Isolate* isolate = context->GetIsolate();
1773 if (value->IsNull()) {
1774 return std::make_unique<PrimitiveValueMirror>(
1775 isolate, value.As<v8::Primitive>(), RemoteObject::TypeEnum::Object);
1776 }
1777 if (value->IsBoolean()) {
1778 return std::make_unique<PrimitiveValueMirror>(
1779 isolate, value.As<v8::Primitive>(), RemoteObject::TypeEnum::Boolean);
1780 }
1781 if (value->IsNumber()) {
1782 return std::make_unique<NumberMirror>(isolate, value.As<v8::Number>());
1783 }
1784 if (value->IsString()) {
1785 return std::make_unique<PrimitiveValueMirror>(
1786 isolate, value.As<v8::Primitive>(), RemoteObject::TypeEnum::String);
1787 }
1788 if (value->IsBigInt()) {
1789 return std::make_unique<BigIntMirror>(isolate, value.As<v8::BigInt>());
1790 }
1791 if (value->IsSymbol()) {
1792 return std::make_unique<SymbolMirror>(isolate, value.As<v8::Symbol>());
1793 }
1794 if (value->IsUndefined()) {
1795 return std::make_unique<PrimitiveValueMirror>(
1796 isolate, value.As<v8::Primitive>(), RemoteObject::TypeEnum::Undefined);
1797 }
1798 if (!value->IsObject()) {
1799 return nullptr;
1800 }
1801 v8::Local<v8::Object> object = value.As<v8::Object>();
1802 auto clientSubtype = clientFor(context)->valueSubtype(object);
1803 if (clientSubtype) {
1804 String16 subtype = toString16(clientSubtype->string());
1805 return clientMirror(context, object, subtype);
1806 }
1807 if (object->IsRegExp()) {
1808 v8::Local<v8::RegExp> regexp = object.As<v8::RegExp>();
1809 return std::make_unique<ObjectMirror>(
1810 regexp, RemoteObject::SubtypeEnum::Regexp,
1811 descriptionForRegExp(isolate, regexp));
1812 }
1813 if (object->IsProxy()) {
1814 v8::Local<v8::Proxy> proxy = object.As<v8::Proxy>();
1815 return std::make_unique<ObjectMirror>(proxy,
1816 RemoteObject::SubtypeEnum::Proxy,
1817 descriptionForProxy(isolate, proxy));
1818 }
1819 if (object->IsFunction()) {
1820 v8::Local<v8::Function> function = object.As<v8::Function>();
1821 return std::make_unique<FunctionMirror>(function);
1822 }
1823 if (object->IsDate()) {
1824 v8::Local<v8::Date> date = object.As<v8::Date>();
1825 return std::make_unique<ObjectMirror>(date, RemoteObject::SubtypeEnum::Date,
1826 descriptionForDate(context, date));
1827 }
1828 if (object->IsPromise()) {
1829 v8::Local<v8::Promise> promise = object.As<v8::Promise>();
1830 return std::make_unique<ObjectMirror>(
1831 promise, RemoteObject::SubtypeEnum::Promise,
1832 descriptionForObject(isolate, promise));
1833 }
1834 if (object->IsNativeError()) {
1835 return std::make_unique<ObjectMirror>(object,
1836 RemoteObject::SubtypeEnum::Error,
1837 descriptionForError(context, object));
1838 }
1839 if (object->IsMap()) {
1840 v8::Local<v8::Map> map = object.As<v8::Map>();
1841 return std::make_unique<ObjectMirror>(
1842 map, RemoteObject::SubtypeEnum::Map,
1843 descriptionForCollection(isolate, map, map->Size()));
1844 }
1845 if (object->IsSet()) {
1846 v8::Local<v8::Set> set = object.As<v8::Set>();
1847 return std::make_unique<ObjectMirror>(
1848 set, RemoteObject::SubtypeEnum::Set,
1849 descriptionForCollection(isolate, set, set->Size()));
1850 }
1851 if (object->IsWeakMap()) {
1852 return std::make_unique<ObjectMirror>(
1853 object, RemoteObject::SubtypeEnum::Weakmap,
1854 descriptionForObject(isolate, object));
1855 }
1856 if (object->IsWeakSet()) {
1857 return std::make_unique<ObjectMirror>(
1858 object, RemoteObject::SubtypeEnum::Weakset,
1859 descriptionForObject(isolate, object));
1860 }
1861 if (object->IsMapIterator() || object->IsSetIterator()) {
1862 return std::make_unique<ObjectMirror>(
1863 object, RemoteObject::SubtypeEnum::Iterator,
1864 descriptionForObject(isolate, object));
1865 }
1866 if (object->IsGeneratorObject()) {
1867 return std::make_unique<ObjectMirror>(
1868 object, RemoteObject::SubtypeEnum::Generator,
1869 descriptionForObject(isolate, object));
1870 }
1871 if (object->IsTypedArray()) {
1873 return std::make_unique<ObjectMirror>(
1874 array, RemoteObject::SubtypeEnum::Typedarray,
1875 descriptionForCollection(isolate, array, array->Length()));
1876 }
1877 if (object->IsArrayBuffer()) {
1879 return std::make_unique<ObjectMirror>(
1880 buffer, RemoteObject::SubtypeEnum::Arraybuffer,
1881 descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1882 }
1883 if (object->IsSharedArrayBuffer()) {
1885 object.As<v8::SharedArrayBuffer>();
1886 return std::make_unique<ObjectMirror>(
1887 buffer, RemoteObject::SubtypeEnum::Arraybuffer,
1888 descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1889 }
1890 if (object->IsDataView()) {
1891 v8::Local<v8::DataView> view = object.As<v8::DataView>();
1892 return std::make_unique<ObjectMirror>(
1893 view, RemoteObject::SubtypeEnum::Dataview,
1894 descriptionForCollection(isolate, view, view->ByteLength()));
1895 }
1896 if (object->IsWasmMemoryObject()) {
1898 return std::make_unique<ObjectMirror>(
1899 memory, RemoteObject::SubtypeEnum::Webassemblymemory,
1900 descriptionForCollection(
1901 isolate, memory, memory->Buffer()->ByteLength() / kWasmPageSize));
1902 }
1903#if V8_ENABLE_WEBASSEMBLY
1904 if (v8::debug::WasmValueObject::IsWasmValueObject(object)) {
1906 object.As<v8::debug::WasmValueObject>();
1907 return std::make_unique<ObjectMirror>(
1908 value_object, RemoteObject::SubtypeEnum::Wasmvalue,
1909 descriptionForWasmValueObject(context, value_object));
1910 }
1911#endif // V8_ENABLE_WEBASSEMBLY
1912 if (!value->IsObject()) {
1913 return nullptr;
1914 }
1915 V8InternalValueType internalType = v8InternalValueTypeFrom(context, object);
1916 if (internalType == V8InternalValueType::kScopeList) {
1917 v8::Local<v8::Array> array = value.As<v8::Array>();
1918 return std::make_unique<ObjectMirror>(array, "internal#scopeList",
1919 descriptionForScopeList(array));
1920 }
1921 if (internalType == V8InternalValueType::kPrivateMethodList) {
1922 v8::Local<v8::Array> array = object.As<v8::Array>();
1923 return std::make_unique<ObjectMirror>(
1924 array, "internal#privateMethodList",
1925 descriptionForPrivateMethodList(array));
1926 }
1927 if (internalType == V8InternalValueType::kEntry) {
1928 return std::make_unique<ObjectMirror>(object, "internal#entry",
1929 descriptionForEntry(context, object));
1930 }
1931 if (internalType == V8InternalValueType::kScope) {
1932 return std::make_unique<ObjectMirror>(object, "internal#scope",
1933 descriptionForScope(context, object));
1934 }
1935 if (internalType == V8InternalValueType::kPrivateMethod) {
1936 return std::make_unique<ObjectMirror>(
1937 object, "internal#privateMethod",
1938 descriptionForPrivateMethod(context, object));
1939 }
1940 size_t length = 0;
1941 if (isArrayLike(context, object, &length)) {
1942 return std::make_unique<ObjectMirror>(
1943 object, RemoteObject::SubtypeEnum::Array,
1944 descriptionForCollection(isolate, object, length));
1945 }
1946 return std::make_unique<ObjectMirror>(object,
1947 descriptionForObject(isolate, object));
1948}
1949
1950} // namespace v8_inspector
const char * name
Definition builtins.cc:39
PropertyT * setter
PropertyT * getter
SourcePosition pos
bool Value() const
Definition api.cc:6245
static MaybeLocal< Function > New(Local< Context > context, FunctionCallback callback, Local< Value > data=Local< Value >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)
Definition api.cc:5348
static const int kLineOffsetNotFound
int32_t Value() const
Definition api.cc:6258
V8_INLINE Local< S > As() const
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
V8_INLINE bool IsNothing() const
Definition v8-maybe.h:35
static Local< Object > New(Isolate *isolate)
Definition api.cc:7756
V8_WARN_UNUSED_RESULT MaybeLocal< Value > Get(Local< Context > context, Local< Value > key)
Definition api.cc:4577
V8_INLINE Local< T > Get(Isolate *isolate) const
PromiseState State()
Definition api.cc:8759
static Local< Set > New(Isolate *isolate)
Definition api.cc:8538
bool StringEquals(Local< String > str) const
Definition api.cc:7745
void Reset()
Definition api.cc:2839
Local< Value > Exception() const
Definition api.cc:2798
bool HasCaught() const
Definition api.cc:2781
static const int kNoScriptId
Definition v8-script.h:91
static bool IsAccessorPair(v8::Local< v8::Value > obj)
static v8::Local< debug::GeneratorObject > Cast(v8::Local< v8::Value > value)
static V8_WARN_UNUSED_RESULT std::unique_ptr< PropertyIterator > Create(v8::Local< v8::Context > context, v8::Local< v8::Object > object, bool skip_indices=false)
static String16 fromInteger(int)
Definition string-16.cc:71
static String16 concat(T... args)
Definition string-16.h:158
static String16 fromDouble(double)
Definition string-16.cc:98
V8_EXPORT std::string utf8() const
Definition string-16.cc:254
static const size_t kNotFound
Definition string-16.h:26
v8::MaybeLocal< v8::Array > internalProperties(v8::Local< v8::Context >, v8::Local< v8::Value >)
static protocol::Response serializeV8Value(v8::Local< v8::Object > value, v8::Local< v8::Context > context, int maxDepth, v8::Local< v8::Object > additionalParameters, V8SerializationDuplicateTracker &duplicateTracker, protocol::DictionaryValue &result)
virtual bool Add(PropertyMirror mirror)=0
static std::unique_ptr< ValueMirror > create(v8::Local< v8::Context > context, v8::Local< v8::Value > value)
static bool getProperties(v8::Local< v8::Context > context, v8::Local< v8::Object > object, bool ownProperties, bool accessorPropertiesOnly, bool nonIndexedPropertiesOnly, PropertyAccumulator *accumulator)
static void getInternalProperties(v8::Local< v8::Context > context, v8::Local< v8::Object > object, std::vector< InternalPropertyMirror > *mirrors)
static std::vector< PrivatePropertyMirror > getPrivateProperties(v8::Local< v8::Context > context, v8::Local< v8::Object > object, bool accessorPropertiesOnly)
std::vector< PropertyMirror > * m_mirrors
const std::string property
DateRecord date
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
Register tmp
ZoneVector< Entry > entries
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
void Add(RWDigits Z, Digits X, Digits Y)
bool GetPrivateMembers(Local< Context > context, Local< Object > object, int filter, LocalVector< Value > *names_out, LocalVector< Value > *values_out)
Local< String > GetDateDescription(Local< Date > date)
Local< String > GetFunctionDescription(Local< Function > function)
Local< String > GetBigIntStringValue(Isolate *isolate, Local< BigInt > bigint)
v8_inspector::V8Inspector * GetInspector(Isolate *isolate)
Local< String > GetBigIntDescription(Isolate *isolate, Local< BigInt > bigint)
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
char16_t UChar
Definition string-16.h:22
Response toProtocolValue(v8::Local< v8::Context > context, v8::Local< v8::Value > value, int maxDepth, std::unique_ptr< protocol::Value > *result)
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
Response objectToProtocolValue(v8::Local< v8::Context > context, v8::Local< v8::Object > object, int maxDepth, std::unique_ptr< protocol::DictionaryValue > *result)
std::unique_ptr< ValueMirror > clientMirror(v8::Local< v8::Context > context, v8::Local< v8::Object > value, const String16 &subtype)
v8::Local< v8::String > toV8String(v8::Isolate *isolate, const String16 &string)
String16 toProtocolStringWithTypeCheck(v8::Isolate *isolate, v8::Local< v8::Value > value)
String16 toString16(const StringView &string)
static const int kMaxProtocolDepth
Response arrayToProtocolValue(v8::Local< v8::Context > context, v8::Local< v8::Array > array, int maxDepth, std::unique_ptr< protocol::ListValue > *result)
PropertyAttribute
Definition v8-object.h:139
@ DontEnum
Definition v8-object.h:145
@ DontDelete
Definition v8-object.h:147
@ ReadOnly
Definition v8-object.h:143
V8_INLINE Local< Boolean > True(Isolate *isolate)
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
#define UNREACHABLE()
Definition logging.h:67
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482
v8::Local< v8::Value > value
v8::Local< v8::Value > set
v8::Local< v8::Value > get
v8::Isolate * m_isolate
String16 m_subtype
v8::Global< v8::Value > m_value
std::unique_ptr< ValueMirror > value
int * m_indexLimit
bool m_hasSubtype
std::vector< String16 > m_blocklist
String16 m_type
int m_lineNumber
int m_columnNumber
String16 m_description
int m_scriptId
int * m_nameLimit
bool * m_overflow
int m_skipIndex
std::unique_ptr< ValueMirror > key