5 #include "src/inspector/value-mirror.h" 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" 17 using protocol::Response;
18 using protocol::Runtime::RemoteObject;
19 using protocol::Runtime::ObjectPreview;
20 using protocol::Runtime::PropertyPreview;
21 using protocol::Runtime::EntryPreview;
22 using protocol::Runtime::InternalPropertyDescriptor;
26 return static_cast<V8InspectorImpl*
>(
27 v8::debug::GetInspector(context->GetIsolate()))
33 if (!value->IsObject())
return V8InternalValueType::kNone;
34 V8InspectorImpl* inspector =
static_cast<V8InspectorImpl*
>(
35 v8::debug::GetInspector(context->GetIsolate()));
36 int contextId = InspectedContext::contextId(context);
37 InspectedContext* inspectedContext = inspector->getContext(contextId);
38 if (!inspectedContext)
return V8InternalValueType::kNone;
39 return inspectedContext->getInternalType(value.As<
v8::Object>());
44 std::unique_ptr<protocol::Value>* result) {
45 if (!maxDepth)
return Response::Error(
"Object reference chain is too long");
48 if (value->IsNull() || value->IsUndefined()) {
49 *result = protocol::Value::null();
50 return Response::OK();
52 if (value->IsBoolean()) {
54 protocol::FundamentalValue::create(value.As<
v8::Boolean>()->Value());
55 return Response::OK();
57 if (value->IsNumber()) {
59 int intValue =
static_cast<int>(doubleValue);
60 if (intValue == doubleValue) {
61 *result = protocol::FundamentalValue::create(intValue);
62 return Response::OK();
64 *result = protocol::FundamentalValue::create(doubleValue);
65 return Response::OK();
67 if (value->IsString()) {
68 *result = protocol::StringValue::create(
69 toProtocolString(context->GetIsolate(), value.As<
v8::String>()));
70 return Response::OK();
72 if (value->IsArray()) {
74 std::unique_ptr<protocol::ListValue> inspectorArray =
75 protocol::ListValue::create();
79 if (!array->Get(context,
i).
ToLocal(&value))
80 return Response::InternalError();
81 std::unique_ptr<protocol::Value> element;
82 Response response = toProtocolValue(context, value, maxDepth, &element);
83 if (!response.isSuccess())
return response;
84 inspectorArray->pushValue(std::move(element));
86 *result = std::move(inspectorArray);
87 return Response::OK();
89 if (value->IsObject()) {
90 std::unique_ptr<protocol::DictionaryValue> jsonObject =
91 protocol::DictionaryValue::create();
94 if (!object->GetPropertyNames(context).ToLocal(&propertyNames))
95 return Response::InternalError();
96 uint32_t length = propertyNames->Length();
99 if (!propertyNames->Get(context,
i).
ToLocal(&name))
100 return Response::InternalError();
102 if (name->IsString()) {
105 if (hasRealNamedProperty.IsNothing() ||
110 if (!name->ToString(context).ToLocal(&propertyName))
continue;
112 if (!object->Get(context, name).
ToLocal(&property))
113 return Response::InternalError();
114 if (property->IsUndefined())
continue;
115 std::unique_ptr<protocol::Value> propertyValue;
117 toProtocolValue(context, property, maxDepth, &propertyValue);
118 if (!response.isSuccess())
return response;
119 jsonObject->setValue(
120 toProtocolString(context->GetIsolate(), propertyName),
121 std::move(propertyValue));
123 *result = std::move(jsonObject);
124 return Response::OK();
126 return Response::Error(
"Object couldn't be returned by value");
131 std::unique_ptr<protocol::Value>* result) {
132 if (value->IsUndefined())
return Response::OK();
133 return toProtocolValue(context, value, 1000, result);
136 enum AbbreviateMode { kMiddle, kEnd };
138 String16 abbreviateString(
const String16& value, AbbreviateMode mode) {
139 const size_t maxLength = 100;
140 if (value.length() <= maxLength)
return value;
141 UChar ellipsis =
static_cast<UChar
>(0x2026);
142 if (mode == kMiddle) {
143 return String16::concat(
144 value.substring(0, maxLength / 2), String16(&ellipsis, 1),
145 value.substring(value.length() - maxLength / 2 + 1));
147 return String16::concat(value.substring(0, maxLength - 1), ellipsis);
152 return String16::concat(
154 toProtocolStringWithTypeCheck(context->GetIsolate(), symbol->
Name()),
160 v8::Isolate* isolate = context->GetIsolate();
161 v8::TryCatch tryCatch(isolate);
163 if (!value->ToString(context).ToLocal(&description))
return String16();
164 return toProtocolString(isolate, description) +
"n";
169 if (value->IsUndefined())
return RemoteObject::TypeEnum::Undefined;
170 if (value->IsNull())
return RemoteObject::SubtypeEnum::Null;
171 if (value->IsBoolean()) {
174 if (value->IsString()) {
175 return toProtocolString(context->GetIsolate(), value.As<
v8::String>());
181 String16 descriptionForRegExp(v8::Isolate* isolate,
183 String16Builder description;
184 description.append(
'/');
185 description.append(toProtocolString(isolate, value->GetSource()));
186 description.append(
'/');
188 if (flags & v8::RegExp::Flags::kGlobal) description.append(
'g');
189 if (flags & v8::RegExp::Flags::kIgnoreCase) description.append(
'i');
190 if (flags & v8::RegExp::Flags::kMultiline) description.append(
'm');
191 if (flags & v8::RegExp::Flags::kDotAll) description.append(
's');
192 if (flags & v8::RegExp::Flags::kUnicode) description.append(
'u');
193 if (flags & v8::RegExp::Flags::kSticky) description.append(
'y');
194 return description.toString();
197 enum class ErrorType { kNative, kClient };
201 v8::Isolate* isolate = context->GetIsolate();
202 v8::TryCatch tryCatch(isolate);
205 if (!object->Get(context, toV8String(isolate,
"stack"))
207 !stackValue->IsString()) {
210 String16 stack = toProtocolString(isolate, stackValue.As<
v8::String>());
211 String16 description = stack;
212 if (type == ErrorType::kClient) {
213 if (stack.substring(0, className.length()) != className) {
215 if (!object->Get(context, toV8String(isolate,
"message"))
220 String16 message = toProtocolStringWithTypeCheck(isolate, messageValue);
221 size_t index = stack.find(message);
222 String16 stackWithoutMessage =
223 index != String16::kNotFound
224 ? stack.substring(index + message.length())
226 description = className +
": " + message + stackWithoutMessage;
232 String16 descriptionForObject(v8::Isolate* isolate,
239 v8::Isolate* isolate = context->GetIsolate();
240 v8::TryCatch tryCatch(isolate);
242 if (!date->ToString(context).ToLocal(&description)) {
243 return descriptionForObject(isolate, date);
245 return toProtocolString(isolate, description);
249 return String16::concat(
250 "Scopes[", String16::fromInteger(static_cast<size_t>(list->Length())),
256 v8::Isolate* isolate = context->GetIsolate();
262 return toProtocolStringWithTypeCheck(isolate, value);
265 String16 descriptionForCollection(v8::Isolate* isolate,
268 return String16::concat(className,
'(', String16::fromInteger(length),
')');
273 v8::Isolate* isolate = context->GetIsolate();
278 auto wrapper = ValueMirror::create(context, tmp);
280 std::unique_ptr<ObjectPreview> preview;
282 wrapper->buildEntryPreview(context, &limit, &limit, &preview);
284 key = preview->getDescription(String16());
285 if (preview->getType() == RemoteObject::TypeEnum::String) {
286 key = String16::concat(
'\"', key,
'\"');
295 auto wrapper = ValueMirror::create(context, tmp);
297 std::unique_ptr<ObjectPreview> preview;
299 wrapper->buildEntryPreview(context, &limit, &limit, &preview);
301 value = preview->getDescription(String16());
302 if (preview->getType() == RemoteObject::TypeEnum::String) {
303 value = String16::concat(
'\"', value,
'\"');
309 return key.length() ? (
"{" + key +
" => " + value +
"}") : value;
314 v8::Isolate* isolate = context->GetIsolate();
315 v8::TryCatch tryCatch(isolate);
317 if (!value->ToString(context).ToLocal(&description)) {
318 return descriptionForObject(isolate, value);
320 return toProtocolString(isolate, description);
323 class PrimitiveValueMirror final :
public ValueMirror {
326 : m_value(value), m_type(type) {}
330 std::unique_ptr<RemoteObject>* result)
override {
331 std::unique_ptr<protocol::Value> protocolValue;
332 toProtocolValue(context, m_value, &protocolValue);
333 *result = RemoteObject::create()
335 .setValue(std::move(protocolValue))
338 (*result)->setSubtype(RemoteObject::SubtypeEnum::Null);
339 return Response::OK();
344 std::unique_ptr<ObjectPreview>* preview)
override {
346 ObjectPreview::create()
348 .setDescription(descriptionForPrimitiveType(context, m_value))
350 .setProperties(protocol::Array<PropertyPreview>::create())
353 (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
356 void buildPropertyPreview(
358 std::unique_ptr<PropertyPreview>* preview)
override {
359 *preview = PropertyPreview::create()
361 .setValue(abbreviateString(
362 descriptionForPrimitiveType(context, m_value), kMiddle))
366 (*preview)->setSubtype(RemoteObject::SubtypeEnum::Null);
375 class NumberMirror final :
public ValueMirror {
381 std::unique_ptr<RemoteObject>* result)
override {
382 bool unserializable =
false;
383 String16 descriptionValue = description(&unserializable);
384 *result = RemoteObject::create()
385 .setType(RemoteObject::TypeEnum::Number)
386 .setDescription(descriptionValue)
388 if (unserializable) {
389 (*result)->setUnserializableValue(descriptionValue);
391 (*result)->setValue(protocol::FundamentalValue::create(m_value->Value()));
393 return Response::OK();
396 const String16& name,
397 std::unique_ptr<PropertyPreview>* result)
override {
398 bool unserializable =
false;
399 *result = PropertyPreview::create()
401 .setType(RemoteObject::TypeEnum::Number)
402 .setValue(description(&unserializable))
407 std::unique_ptr<ObjectPreview>* preview)
override {
408 bool unserializable =
false;
409 *preview = ObjectPreview::create()
410 .setType(RemoteObject::TypeEnum::Number)
411 .setDescription(description(&unserializable))
413 .setProperties(protocol::Array<PropertyPreview>::create())
418 String16 description(
bool* unserializable) {
419 *unserializable =
true;
420 double rawValue = m_value->Value();
421 if (std::isnan(rawValue))
return "NaN";
422 if (rawValue == 0.0 && std::signbit(rawValue))
return "-0";
423 if (std::isinf(rawValue)) {
424 return std::signbit(rawValue) ?
"-Infinity" :
"Infinity";
426 *unserializable =
false;
427 return String16::fromDouble(rawValue);
433 class BigIntMirror final :
public ValueMirror {
438 std::unique_ptr<RemoteObject>* result)
override {
439 String16 description = descriptionForBigInt(context, m_value);
440 *result = RemoteObject::create()
441 .setType(RemoteObject::TypeEnum::Bigint)
442 .setUnserializableValue(description)
443 .setDescription(description)
445 return Response::OK();
448 void buildPropertyPreview(
450 std::unique_ptr<protocol::Runtime::PropertyPreview>* preview)
override {
451 *preview = PropertyPreview::create()
453 .setType(RemoteObject::TypeEnum::Bigint)
454 .setValue(abbreviateString(
455 descriptionForBigInt(context, m_value), kMiddle))
459 void buildEntryPreview(
461 std::unique_ptr<protocol::Runtime::ObjectPreview>* preview)
override {
462 *preview = ObjectPreview::create()
463 .setType(RemoteObject::TypeEnum::Bigint)
464 .setDescription(descriptionForBigInt(context, m_value))
466 .setProperties(protocol::Array<PropertyPreview>::create())
476 class SymbolMirror final :
public ValueMirror {
479 : m_symbol(value.As<
v8::Symbol>()) {}
482 std::unique_ptr<RemoteObject>* result)
override {
483 if (mode == WrapMode::kForceValue) {
484 return Response::Error(
"Object couldn't be returned by value");
486 *result = RemoteObject::create()
487 .setType(RemoteObject::TypeEnum::Symbol)
488 .setDescription(descriptionForSymbol(context, m_symbol))
490 return Response::OK();
493 void buildPropertyPreview(
495 std::unique_ptr<protocol::Runtime::PropertyPreview>* preview)
override {
496 *preview = PropertyPreview::create()
498 .setType(RemoteObject::TypeEnum::Symbol)
499 .setValue(abbreviateString(
500 descriptionForSymbol(context, m_symbol), kEnd))
510 class LocationMirror final :
public ValueMirror {
512 static std::unique_ptr<LocationMirror> create(
514 return create(
function, function->ScriptId(),
515 function->GetScriptLineNumber(),
516 function->GetScriptColumnNumber());
518 static std::unique_ptr<LocationMirror> createForGenerator(
521 v8::debug::GeneratorObject::Cast(value);
522 if (!generatorObject->IsSuspended()) {
523 return create(generatorObject->Function());
526 if (!generatorObject->Script().ToLocal(&script))
return nullptr;
528 generatorObject->SuspendedLocation();
529 return create(value, script->Id(), suspendedLocation.GetLineNumber(),
530 suspendedLocation.GetColumnNumber());
534 std::unique_ptr<RemoteObject>* result)
override {
535 auto location = protocol::DictionaryValue::create();
536 location->setString(
"scriptId", String16::fromInteger(m_scriptId));
537 location->setInteger(
"lineNumber", m_lineNumber);
538 location->setInteger(
"columnNumber", m_columnNumber);
539 *result = RemoteObject::create()
540 .setType(RemoteObject::TypeEnum::Object)
541 .setSubtype(
"internal#location")
542 .setDescription(
"Object")
543 .setValue(std::move(location))
545 return Response::OK();
551 int scriptId,
int lineNumber,
553 if (scriptId == v8::UnboundScript::kNoScriptId)
return nullptr;
554 if (lineNumber == v8::Function::kLineOffsetNotFound ||
555 columnNumber == v8::Function::kLineOffsetNotFound) {
558 return std::unique_ptr<LocationMirror>(
559 new LocationMirror(value, scriptId, lineNumber, columnNumber));
565 m_scriptId(scriptId),
566 m_lineNumber(lineNumber),
567 m_columnNumber(columnNumber) {}
575 class FunctionMirror final :
public ValueMirror {
578 : m_value(value.As<
v8::Function>()) {}
583 std::unique_ptr<RemoteObject>* result)
override {
585 if (mode == WrapMode::kForceValue) {
586 std::unique_ptr<protocol::Value> protocolValue;
587 Response response = toProtocolValue(context, m_value, &protocolValue);
588 if (!response.isSuccess())
return response;
589 *result = RemoteObject::create()
590 .setType(RemoteObject::TypeEnum::Function)
591 .setValue(std::move(protocolValue))
594 *result = RemoteObject::create()
595 .setType(RemoteObject::TypeEnum::Function)
596 .setClassName(toProtocolStringWithTypeCheck(
597 context->GetIsolate(), m_value->GetConstructorName()))
598 .setDescription(descriptionForFunction(context, m_value))
601 return Response::OK();
605 const String16& name,
606 std::unique_ptr<PropertyPreview>* result)
override {
607 *result = PropertyPreview::create()
609 .setType(RemoteObject::TypeEnum::Function)
610 .setValue(String16())
615 std::unique_ptr<ObjectPreview>* preview)
override {
616 *preview = ObjectPreview::create()
617 .setType(RemoteObject::TypeEnum::Function)
618 .setDescription(descriptionForFunction(context, m_value))
620 .setProperties(protocol::Array<PropertyPreview>::create())
630 if (!value->IsObject())
return false;
631 v8::Isolate* isolate = context->GetIsolate();
632 v8::TryCatch tryCatch(isolate);
633 v8::MicrotasksScope microtasksScope(isolate,
634 v8::MicrotasksScope::kDoNotRunMicrotasks);
638 (!
object->GetRealNamedProperty(context, toV8String(isolate,
"splice"))
639 .ToLocal(&spliceValue) ||
640 !spliceValue->IsFunction())) {
645 object->HasOwnProperty(context, toV8String(isolate,
"length"));
646 if (result.IsNothing())
return false;
647 if (!result.FromJust() ||
648 !
object->Get(context, toV8String(isolate,
"length"))
649 .ToLocal(&lengthValue) ||
658 std::unique_ptr<ValueMirror> key;
659 std::unique_ptr<ValueMirror> value;
663 bool* overflow, std::vector<EntryMirror>* mirrors) {
664 bool isKeyValue =
false;
666 if (!object->
PreviewEntries(&isKeyValue).ToLocal(&entries))
return false;
667 for (
uint32_t i = 0;
i < entries->Length();
i += isKeyValue ? 2 : 1) {
670 std::unique_ptr<ValueMirror> keyMirror;
671 if (isKeyValue && entries->Get(context,
i).
ToLocal(&tmp)) {
672 keyMirror = ValueMirror::create(context, tmp);
674 std::unique_ptr<ValueMirror> valueMirror;
675 if (entries->Get(context, isKeyValue ?
i + 1 :
i).
ToLocal(&tmp)) {
676 valueMirror = ValueMirror::create(context, tmp);
680 if (mirrors->size() == limit) {
684 mirrors->emplace_back(
685 EntryMirror{std::move(keyMirror), std::move(valueMirror)});
687 return mirrors->size() > 0;
691 class PreviewPropertyAccumulator :
public ValueMirror::PropertyAccumulator {
693 PreviewPropertyAccumulator(
const std::vector<String16>& blacklist,
694 int skipIndex,
int* nameLimit,
int* indexLimit,
696 std::vector<PropertyMirror>* mirrors)
697 : m_blacklist(blacklist),
698 m_skipIndex(skipIndex),
699 m_nameLimit(nameLimit),
700 m_indexLimit(indexLimit),
701 m_overflow(overflow),
702 m_mirrors(mirrors) {}
704 bool Add(PropertyMirror mirror)
override {
705 if (mirror.exception)
return true;
706 if ((!mirror.getter || !mirror.getter->v8Value()->IsFunction()) &&
710 if (!mirror.isOwn)
return true;
711 if (std::find(m_blacklist.begin(), m_blacklist.end(), mirror.name) !=
715 if (mirror.isIndex && m_skipIndex > 0) {
717 if (m_skipIndex > 0)
return true;
719 int* limit = mirror.isIndex ? m_indexLimit : m_nameLimit;
725 m_mirrors->push_back(std::move(mirror));
730 std::vector<String16> m_blacklist;
735 std::vector<PropertyMirror>* m_mirrors;
740 int* indexLimit,
bool* overflow,
741 std::vector<PropertyMirror>* properties) {
742 std::vector<String16> blacklist;
744 if (object->
IsArray() || isArrayLike(context,
object, &length) ||
745 object->IsStringObject()) {
746 blacklist.push_back(
"length");
748 auto clientSubtype = clientFor(context)->valueSubtype(
object);
749 if (clientSubtype && toString16(clientSubtype->string()) ==
"array") {
750 blacklist.push_back(
"length");
753 if (object->
IsArrayBuffer() ||
object->IsSharedArrayBuffer()) {
754 blacklist.push_back(
"[[Int8Array]]");
755 blacklist.push_back(
"[[Uint8Array]]");
756 blacklist.push_back(
"[[Int16Array]]");
757 blacklist.push_back(
"[[Int32Array]]");
759 int skipIndex =
object->IsStringObject()
762 PreviewPropertyAccumulator accumulator(blacklist, skipIndex, nameLimit,
763 indexLimit, overflow, properties);
764 return ValueMirror::getProperties(context,
object,
false,
false,
768 void getInternalPropertiesForPreview(
770 int* nameLimit,
bool* overflow,
771 std::vector<InternalPropertyMirror>* properties) {
772 std::vector<InternalPropertyMirror> mirrors;
773 ValueMirror::getInternalProperties(context,
object, &mirrors);
774 std::vector<String16> whitelist;
776 object->IsStringObject() ||
object->IsSymbolObject() ||
777 object->IsBigIntObject()) {
778 whitelist.emplace_back(
"[[PrimitiveValue]]");
780 whitelist.emplace_back(
"[[PromiseStatus]]");
781 whitelist.emplace_back(
"[[PromiseValue]]");
783 whitelist.emplace_back(
"[[GeneratorStatus]]");
785 for (
auto& mirror : mirrors) {
786 if (std::find(whitelist.begin(), whitelist.end(), mirror.name) ==
795 properties->push_back(std::move(mirror));
799 class ObjectMirror final :
public ValueMirror {
802 : m_value(value.As<
v8::Object>()),
803 m_description(description),
804 m_hasSubtype(false) {}
806 const String16& description)
807 : m_value(value.As<
v8::Object>()),
808 m_description(description),
810 m_subtype(subtype) {}
815 std::unique_ptr<RemoteObject>* result)
override {
816 if (mode == WrapMode::kForceValue) {
817 std::unique_ptr<protocol::Value> protocolValue;
818 Response response = toProtocolValue(context, m_value, &protocolValue);
819 if (!response.isSuccess())
return response;
820 *result = RemoteObject::create()
821 .setType(RemoteObject::TypeEnum::Object)
822 .setValue(std::move(protocolValue))
825 v8::Isolate* isolate = context->GetIsolate();
826 *result = RemoteObject::create()
827 .setType(RemoteObject::TypeEnum::Object)
828 .setClassName(toProtocolString(
829 isolate, m_value->GetConstructorName()))
830 .setDescription(m_description)
832 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
833 if (mode == WrapMode::kWithPreview) {
834 std::unique_ptr<ObjectPreview> previewValue;
836 int indexLimit = 100;
837 buildObjectPreview(context,
false, &nameLimit, &indexLimit,
839 (*result)->setPreview(std::move(previewValue));
842 return Response::OK();
846 bool generatePreviewForTable,
int* nameLimit,
848 std::unique_ptr<ObjectPreview>* result)
override {
849 buildObjectPreviewInternal(context,
false ,
850 generatePreviewForTable, nameLimit, indexLimit,
856 std::unique_ptr<ObjectPreview>* result)
override {
857 buildObjectPreviewInternal(context,
true ,
863 const String16& name,
864 std::unique_ptr<PropertyPreview>* result)
override {
865 *result = PropertyPreview::create()
867 .setType(RemoteObject::TypeEnum::Object)
868 .setValue(abbreviateString(
870 m_subtype == RemoteObject::SubtypeEnum::Regexp ? kMiddle
873 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
878 bool generatePreviewForTable,
int* nameLimit,
880 std::unique_ptr<ObjectPreview>* result) {
881 std::unique_ptr<protocol::Array<PropertyPreview>> properties =
882 protocol::Array<PropertyPreview>::create();
883 std::unique_ptr<protocol::Array<EntryPreview>> entriesPreview;
884 bool overflow =
false;
887 while (value->IsProxy()) value = value.As<
v8::Proxy>()->GetTarget();
888 if (value->IsObject() && !value->IsProxy()) {
890 std::vector<InternalPropertyMirror> internalProperties;
891 getInternalPropertiesForPreview(context, objectForPreview, nameLimit,
892 &overflow, &internalProperties);
893 for (
size_t i = 0;
i < internalProperties.size(); ++
i) {
894 std::unique_ptr<PropertyPreview> propertyPreview;
895 internalProperties[
i].value->buildPropertyPreview(
896 context, internalProperties[
i].name, &propertyPreview);
897 if (propertyPreview) {
898 properties->addItem(std::move(propertyPreview));
902 std::vector<PropertyMirror> mirrors;
903 if (getPropertiesForPreview(context, objectForPreview, nameLimit,
904 indexLimit, &overflow, &mirrors)) {
905 for (
size_t i = 0;
i < mirrors.size(); ++
i) {
906 std::unique_ptr<PropertyPreview> preview;
907 std::unique_ptr<ObjectPreview> valuePreview;
908 if (mirrors[
i].value) {
909 mirrors[
i].value->buildPropertyPreview(context, mirrors[
i].name,
911 if (generatePreviewForTable) {
912 int tableLimit = 1000;
913 mirrors[
i].value->buildObjectPreview(context,
false, &tableLimit,
914 &tableLimit, &valuePreview);
917 preview = PropertyPreview::create()
918 .setName(mirrors[
i].name)
919 .setType(PropertyPreview::TypeEnum::Accessor)
923 preview->setValuePreview(std::move(valuePreview));
925 properties->addItem(std::move(preview));
929 std::vector<EntryMirror> entries;
930 if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow,
935 entriesPreview = protocol::Array<EntryPreview>::create();
936 for (
const auto& entry : entries) {
937 std::unique_ptr<ObjectPreview> valuePreview;
938 entry.value->buildEntryPreview(context, nameLimit, indexLimit,
940 if (!valuePreview)
continue;
941 std::unique_ptr<ObjectPreview> keyPreview;
943 entry.key->buildEntryPreview(context, nameLimit, indexLimit,
945 if (!keyPreview)
continue;
947 std::unique_ptr<EntryPreview> entryPreview =
948 EntryPreview::create()
949 .setValue(std::move(valuePreview))
951 if (keyPreview) entryPreview->setKey(std::move(keyPreview));
952 entriesPreview->addItem(std::move(entryPreview));
957 *result = ObjectPreview::create()
958 .setType(RemoteObject::TypeEnum::Object)
959 .setDescription(m_description)
960 .setOverflow(overflow)
961 .setProperties(std::move(properties))
963 if (m_hasSubtype) (*result)->setSubtype(m_subtype);
964 if (entriesPreview) (*result)->setEntries(std::move(entriesPreview));
968 String16 m_description;
978 if (!data->GetRealNamedProperty(context, toV8String(isolate,
"name"))
983 if (!data->GetRealNamedProperty(context, toV8String(isolate,
"object"))
985 !
object->IsObject()) {
989 if (!
object.As<v8::Object>()->Get(context, name).ToLocal(&value))
return;
996 v8::Isolate* isolate = context->GetIsolate();
997 v8::TryCatch tryCatch(isolate);
1000 if (data->Set(context, toV8String(isolate,
"name"), name).IsNothing()) {
1003 if (data->Set(context, toV8String(isolate,
"object"),
object).IsNothing()) {
1009 v8::ConstructorBehavior::kThrow)
1010 .ToLocal(&
function)) {
1013 return ValueMirror::create(context,
function);
1017 if (info.
Length() < 1)
return;
1022 if (!data->GetRealNamedProperty(context, toV8String(isolate,
"name"))
1027 if (!data->GetRealNamedProperty(context, toV8String(isolate,
"object"))
1028 .ToLocal(&
object) ||
1029 !
object->IsObject()) {
1033 if (!
object.As<v8::Object>()->Set(context, name, info[0]).IsNothing())
return;
1039 v8::Isolate* isolate = context->GetIsolate();
1040 v8::TryCatch tryCatch(isolate);
1043 if (data->Set(context, toV8String(isolate,
"name"), name).IsNothing()) {
1046 if (data->Set(context, toV8String(isolate,
"object"),
object).IsNothing()) {
1052 v8::ConstructorBehavior::kThrow)
1053 .ToLocal(&
function)) {
1056 return ValueMirror::create(context,
function);
1064 if (!name->IsString())
return false;
1065 v8::Isolate* isolate = context->GetIsolate();
1070 v8::TryCatch tryCatch(isolate);
1072 if (context->Global()
1073 ->GetRealNamedProperty(context, toV8String(isolate,
"Request"))
1074 .ToLocal(&request)) {
1077 .FromMaybe(
false)) {
1081 if (tryCatch.HasCaught()) tryCatch.Reset();
1084 if (context->Global()
1085 ->GetRealNamedProperty(context, toV8String(isolate,
"Response"))
1086 .ToLocal(&response)) {
1089 .FromMaybe(
false)) {
1095 template <
typename ArrayView,
typename ArrayBuffer>
1099 ValueMirror::PropertyAccumulator* accumulator) {
1100 accumulator->Add(PropertyMirror{
1101 String16(name),
false,
false,
false,
true,
false,
1102 ValueMirror::create(context, ArrayView::New(buffer, 0, length)),
nullptr,
1103 nullptr,
nullptr,
nullptr});
1106 template <
typename ArrayBuffer>
1109 ValueMirror::PropertyAccumulator* accumulator) {
1111 size_t length = buffer->ByteLength();
1112 addTypedArrayView<v8::Int8Array>(context, buffer, length,
"[[Int8Array]]",
1114 addTypedArrayView<v8::Uint8Array>(context, buffer, length,
"[[Uint8Array]]",
1116 if (buffer->ByteLength() % 2 == 0) {
1117 addTypedArrayView<v8::Int16Array>(context, buffer, length / 2,
1118 "[[Int16Array]]", accumulator);
1120 if (buffer->ByteLength() % 4 == 0) {
1121 addTypedArrayView<v8::Int32Array>(context, buffer, length / 4,
1122 "[[Int32Array]]", accumulator);
1127 ValueMirror::~ValueMirror() =
default;
1132 bool ownProperties,
bool accessorPropertiesOnly,
1133 PropertyAccumulator* accumulator) {
1134 v8::Isolate* isolate = context->GetIsolate();
1135 v8::TryCatch tryCatch(isolate);
1138 v8::MicrotasksScope microtasksScope(isolate,
1139 v8::MicrotasksScope::kDoNotRunMicrotasks);
1140 V8InternalValueType internalType = v8InternalValueTypeFrom(context,
object);
1141 if (internalType == V8InternalValueType::kScope) {
1143 if (!object->Get(context, toV8String(isolate,
"object")).
ToLocal(&value) ||
1144 !value->IsObject()) {
1150 if (internalType == V8InternalValueType::kScopeList) {
1151 if (!set->Add(context, toV8String(isolate,
"length")).ToLocal(&
set)) {
1155 bool shouldSkipProto = internalType == V8InternalValueType::kScopeList;
1157 bool formatAccessorsAsProperties =
1158 clientFor(context)->formatAccessorsAsProperties(
object);
1161 addTypedArrayViews(context,
object.As<v8::ArrayBuffer>(), accumulator);
1164 addTypedArrayViews(context,
object.As<v8::SharedArrayBuffer>(),
1168 for (
auto iterator = v8::debug::PropertyIterator::Create(
object);
1169 !iterator->Done(); iterator->Advance()) {
1170 bool isOwn = iterator->is_own();
1171 if (!isOwn && ownProperties)
break;
1174 if (result.IsNothing())
return false;
1175 if (result.FromJust())
continue;
1176 if (!set->Add(context, v8Name).ToLocal(&
set))
return false;
1179 std::unique_ptr<ValueMirror> symbolMirror;
1181 name = toProtocolString(isolate, v8Name.
As<
v8::String>());
1184 name = descriptionForSymbol(context, symbol);
1185 symbolMirror = ValueMirror::create(context, symbol);
1189 std::unique_ptr<ValueMirror> valueMirror;
1190 std::unique_ptr<ValueMirror> getterMirror;
1191 std::unique_ptr<ValueMirror> setterMirror;
1192 std::unique_ptr<ValueMirror> exceptionMirror;
1193 bool writable =
false;
1194 bool enumerable =
false;
1195 bool configurable =
false;
1197 bool isAccessorProperty =
false;
1198 v8::TryCatch tryCatch(isolate);
1199 if (!iterator->attributes().To(&attributes)) {
1200 exceptionMirror = ValueMirror::create(context, tryCatch.Exception());
1202 if (iterator->is_native_accessor()) {
1203 if (iterator->has_native_getter()) {
1204 getterMirror = createNativeGetter(context,
object, v8Name);
1206 if (iterator->has_native_setter()) {
1207 setterMirror = createNativeSetter(context,
object, v8Name);
1209 writable = !(attributes & v8::PropertyAttribute::ReadOnly);
1210 enumerable = !(attributes & v8::PropertyAttribute::DontEnum);
1211 configurable = !(attributes & v8::PropertyAttribute::DontDelete);
1212 isAccessorProperty = getterMirror || setterMirror;
1214 v8::TryCatch tryCatch(isolate);
1216 if (!iterator->descriptor().To(&descriptor)) {
1217 exceptionMirror = ValueMirror::create(context, tryCatch.Exception());
1219 writable = descriptor.has_writable ? descriptor.writable :
false;
1221 descriptor.has_enumerable ? descriptor.enumerable :
false;
1223 descriptor.has_configurable ? descriptor.configurable :
false;
1224 if (!descriptor.value.
IsEmpty()) {
1225 valueMirror = ValueMirror::create(context, descriptor.value);
1227 bool getterIsNativeFunction =
false;
1228 if (!descriptor.get.
IsEmpty()) {
1230 getterMirror = ValueMirror::create(context,
get);
1231 getterIsNativeFunction =
1232 get->IsFunction() &&
get.As<
v8::Function>()->ScriptId() ==
1233 v8::UnboundScript::kNoScriptId;
1235 if (!descriptor.set.
IsEmpty()) {
1236 setterMirror = ValueMirror::create(context, descriptor.set);
1238 isAccessorProperty = getterMirror || setterMirror;
1239 bool isSymbolDescription =
1240 object->IsSymbol() && name ==
"description";
1241 if (isSymbolDescription ||
1242 (name !=
"__proto__" && getterIsNativeFunction &&
1243 formatAccessorsAsProperties &&
1244 !doesAttributeHaveObservableSideEffectOnGet(context,
object,
1246 v8::TryCatch tryCatch(isolate);
1248 if (object->Get(context, v8Name).
ToLocal(&value)) {
1249 valueMirror = ValueMirror::create(context, value);
1251 setterMirror =
nullptr;
1252 getterMirror =
nullptr;
1258 if (accessorPropertiesOnly && !isAccessorProperty)
continue;
1259 auto mirror = PropertyMirror{name,
1264 iterator->is_array_index(),
1265 std::move(valueMirror),
1266 std::move(getterMirror),
1267 std::move(setterMirror),
1268 std::move(symbolMirror),
1269 std::move(exceptionMirror)};
1270 if (!accumulator->Add(std::move(mirror)))
return true;
1272 if (!shouldSkipProto && ownProperties && !object->
IsProxy() &&
1273 !accessorPropertiesOnly) {
1276 accumulator->Add(PropertyMirror{String16(
"__proto__"),
true,
true,
false,
1278 ValueMirror::create(context, prototype),
1279 nullptr,
nullptr,
nullptr,
nullptr});
1286 void ValueMirror::getInternalProperties(
1288 std::vector<InternalPropertyMirror>* mirrors) {
1289 v8::Isolate* isolate = context->GetIsolate();
1290 v8::MicrotasksScope microtasksScope(isolate,
1291 v8::MicrotasksScope::kDoNotRunMicrotasks);
1292 v8::TryCatch tryCatch(isolate);
1295 auto location = LocationMirror::create(
function);
1297 mirrors->emplace_back(InternalPropertyMirror{
1298 String16(
"[[FunctionLocation]]"), std::move(location)});
1300 if (function->IsGeneratorFunction()) {
1301 mirrors->emplace_back(InternalPropertyMirror{
1302 String16(
"[[IsGenerator]]"),
1303 ValueMirror::create(context, v8::True(context->GetIsolate()))});
1307 auto location = LocationMirror::createForGenerator(
object);
1309 mirrors->emplace_back(InternalPropertyMirror{
1310 String16(
"[[GeneratorLocation]]"), std::move(location)});
1313 V8Debugger* debugger =
1314 static_cast<V8InspectorImpl*
>(v8::debug::GetInspector(isolate))
1317 if (debugger->internalProperties(context,
object).ToLocal(&properties)) {
1318 for (
uint32_t i = 0;
i < properties->Length();
i += 2) {
1320 if (!properties->Get(context,
i).
ToLocal(&name) || !name->IsString()) {
1325 if (!properties->Get(context,
i + 1).
ToLocal(&value)) {
1329 auto wrapper = ValueMirror::create(context, value);
1331 mirrors->emplace_back(InternalPropertyMirror{
1332 toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1333 std::move(wrapper)});
1341 if (!value->IsObject())
return String16();
1343 v8::Isolate* isolate = context->GetIsolate();
1344 v8::TryCatch tryCatch(isolate);
1346 if (!object->Get(context, toV8String(isolate,
"nodeName"))
1350 String16 description;
1352 v8::debug::GetBuiltin(isolate, v8::debug::kStringToLowerCase);
1354 if (!toLowerCase->Call(context, nodeName, 0,
nullptr).
ToLocal(&nodeName))
1357 description = toProtocolString(isolate, nodeName.
As<
v8::String>());
1360 if (!description.length()) {
1362 if (!object->Get(context, toV8String(isolate,
"constructor"))
1364 !value->IsObject()) {
1368 ->Get(context, toV8String(isolate,
"name"))
1370 !value->IsString()) {
1373 description = toProtocolString(isolate, value.As<
v8::String>());
1376 if (!object->Get(context, toV8String(isolate,
"nodeType"))
1383 if (!object->Get(context, toV8String(isolate,
"id")).
ToLocal(&idValue)) {
1387 String16
id = toProtocolString(isolate, idValue.
As<
v8::String>());
1389 description = String16::concat(description,
'#',
id);
1393 if (!object->Get(context, toV8String(isolate,
"className"))
1400 toProtocolString(isolate, classNameValue.
As<
v8::String>());
1401 String16Builder output;
1402 bool previousIsDot =
false;
1403 for (
size_t i = 0;
i < classes.length(); ++
i) {
1404 if (classes[
i] ==
' ') {
1405 if (!previousIsDot) {
1407 previousIsDot =
true;
1410 output.append(classes[
i]);
1411 previousIsDot = classes[
i] ==
'.';
1414 description = String16::concat(description,
'.', output.toString());
1416 }
else if (nodeType.
As<
v8::Int32>()->Value() == 1) {
1417 return String16::concat(
"<!DOCTYPE ", description,
'>');
1424 const String16& subtype) {
1426 if (subtype ==
"node") {
1427 return v8::base::make_unique<ObjectMirror>(
1428 value, subtype, descriptionForNode(context, value));
1430 if (subtype ==
"error") {
1431 return v8::base::make_unique<ObjectMirror>(
1432 value, RemoteObject::SubtypeEnum::Error,
1433 descriptionForError(context, value.As<
v8::Object>(),
1434 ErrorType::kClient));
1436 if (subtype ==
"array" && value->IsObject()) {
1437 v8::Isolate* isolate = context->GetIsolate();
1438 v8::TryCatch tryCatch(isolate);
1441 if (object->Get(context, toV8String(isolate,
"length"))
1443 if (lengthValue->IsInt32()) {
1444 return v8::base::make_unique<ObjectMirror>(
1445 value, RemoteObject::SubtypeEnum::Array,
1446 descriptionForCollection(isolate,
object,
1451 return v8::base::make_unique<ObjectMirror>(
1453 descriptionForObject(context->GetIsolate(), value.As<
v8::Object>()));
1458 if (value->IsNull()) {
1459 return v8::base::make_unique<PrimitiveValueMirror>(
1460 value, RemoteObject::TypeEnum::Object);
1462 if (value->IsBoolean()) {
1463 return v8::base::make_unique<PrimitiveValueMirror>(
1464 value, RemoteObject::TypeEnum::Boolean);
1466 if (value->IsNumber()) {
1467 return v8::base::make_unique<NumberMirror>(value.As<
v8::Number>());
1469 v8::Isolate* isolate = context->GetIsolate();
1470 if (value->IsString()) {
1471 return v8::base::make_unique<PrimitiveValueMirror>(
1472 value, RemoteObject::TypeEnum::String);
1474 if (value->IsBigInt()) {
1475 return v8::base::make_unique<BigIntMirror>(value.As<
v8::BigInt>());
1477 if (value->IsSymbol()) {
1478 return v8::base::make_unique<SymbolMirror>(value.As<
v8::Symbol>());
1480 auto clientSubtype = (value->IsUndefined() || value->IsObject())
1481 ? clientFor(context)->valueSubtype(value)
1483 if (clientSubtype) {
1484 String16 subtype = toString16(clientSubtype->string());
1485 return clientMirror(context, value, subtype);
1487 if (value->IsUndefined()) {
1488 return v8::base::make_unique<PrimitiveValueMirror>(
1489 value, RemoteObject::TypeEnum::Undefined);
1491 if (value->IsRegExp()) {
1492 return v8::base::make_unique<ObjectMirror>(
1493 value, RemoteObject::SubtypeEnum::Regexp,
1494 descriptionForRegExp(isolate, value.As<
v8::RegExp>()));
1496 if (value->IsFunction()) {
1497 return v8::base::make_unique<FunctionMirror>(value);
1499 if (value->IsProxy()) {
1500 return v8::base::make_unique<ObjectMirror>(
1501 value, RemoteObject::SubtypeEnum::Proxy,
"Proxy");
1503 if (value->IsDate()) {
1504 return v8::base::make_unique<ObjectMirror>(
1505 value, RemoteObject::SubtypeEnum::Date,
1506 descriptionForDate(context, value.As<
v8::Date>()));
1508 if (value->IsPromise()) {
1510 return v8::base::make_unique<ObjectMirror>(
1511 promise, RemoteObject::SubtypeEnum::Promise,
1512 descriptionForObject(isolate, promise));
1514 if (value->IsNativeError()) {
1515 return v8::base::make_unique<ObjectMirror>(
1516 value, RemoteObject::SubtypeEnum::Error,
1517 descriptionForError(context, value.As<
v8::Object>(),
1518 ErrorType::kNative));
1520 if (value->IsMap()) {
1522 return v8::base::make_unique<ObjectMirror>(
1523 value, RemoteObject::SubtypeEnum::Map,
1524 descriptionForCollection(isolate, map, map->Size()));
1526 if (value->IsSet()) {
1528 return v8::base::make_unique<ObjectMirror>(
1529 value, RemoteObject::SubtypeEnum::Set,
1530 descriptionForCollection(isolate,
set, set->Size()));
1532 if (value->IsWeakMap()) {
1533 return v8::base::make_unique<ObjectMirror>(
1534 value, RemoteObject::SubtypeEnum::Weakmap,
1535 descriptionForObject(isolate, value.As<
v8::Object>()));
1537 if (value->IsWeakSet()) {
1538 return v8::base::make_unique<ObjectMirror>(
1539 value, RemoteObject::SubtypeEnum::Weakset,
1540 descriptionForObject(isolate, value.As<
v8::Object>()));
1542 if (value->IsMapIterator() || value->IsSetIterator()) {
1543 return v8::base::make_unique<ObjectMirror>(
1544 value, RemoteObject::SubtypeEnum::Iterator,
1545 descriptionForObject(isolate, value.As<
v8::Object>()));
1547 if (value->IsGeneratorObject()) {
1549 return v8::base::make_unique<ObjectMirror>(
1550 object, RemoteObject::SubtypeEnum::Generator,
1551 descriptionForObject(isolate,
object));
1553 if (value->IsTypedArray()) {
1555 return v8::base::make_unique<ObjectMirror>(
1556 value, RemoteObject::SubtypeEnum::Typedarray,
1557 descriptionForCollection(isolate, array, array->
Length()));
1559 if (value->IsArrayBuffer()) {
1561 return v8::base::make_unique<ObjectMirror>(
1562 value, RemoteObject::SubtypeEnum::Arraybuffer,
1563 descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1565 if (value->IsSharedArrayBuffer()) {
1567 return v8::base::make_unique<ObjectMirror>(
1568 value, RemoteObject::SubtypeEnum::Arraybuffer,
1569 descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1571 if (value->IsDataView()) {
1573 return v8::base::make_unique<ObjectMirror>(
1574 value, RemoteObject::SubtypeEnum::Dataview,
1575 descriptionForCollection(isolate, view, view->
ByteLength()));
1577 V8InternalValueType internalType =
1579 if (value->IsArray() && internalType == V8InternalValueType::kScopeList) {
1580 return v8::base::make_unique<ObjectMirror>(
1581 value,
"internal#scopeList",
1582 descriptionForScopeList(value.As<
v8::Array>()));
1584 if (value->IsObject() && internalType == V8InternalValueType::kEntry) {
1585 return v8::base::make_unique<ObjectMirror>(
1586 value,
"internal#entry",
1587 descriptionForEntry(context, value.As<
v8::Object>()));
1589 if (value->IsObject() && internalType == V8InternalValueType::kScope) {
1590 return v8::base::make_unique<ObjectMirror>(
1591 value,
"internal#scope",
1592 descriptionForScope(context, value.As<
v8::Object>()));
1595 if (value->IsArray() || isArrayLike(context, value, &length)) {
1596 length = value->IsArray() ? value.As<
v8::Array>()->Length() : length;
1597 return v8::base::make_unique<ObjectMirror>(
1598 value, RemoteObject::SubtypeEnum::Array,
1599 descriptionForCollection(isolate, value.As<
v8::Object>(), length));
1601 if (value->IsObject()) {
1602 return v8::base::make_unique<ObjectMirror>(
1603 value, descriptionForObject(isolate, value.As<
v8::Object>()));
bool StringEquals(Local< String > str)
static Local< Set > New(Isolate *isolate)
V8_INLINE bool IsString() const
V8_INLINE int Length() const
static V8_INLINE Local< T > Cast(Local< S > that)
V8_INLINE bool IsEmpty() const
MaybeLocal< Array > PreviewEntries(bool *is_key_value)
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)
V8_INLINE T FromJust() const
V8_INLINE Local< S > As() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
V8_INLINE Local< Value > Data() const
V8_INLINE ReturnValue< T > GetReturnValue() const
bool IsBooleanObject() const
bool IsSharedArrayBuffer() const
V8_INLINE bool IsNull() const
Local< String > GetConstructorName()
Local< Value > Name() const
bool IsArrayBuffer() const
V8_INLINE Isolate * GetIsolate() const
bool IsArgumentsObject() const
bool IsGeneratorObject() const
V8_WARN_UNUSED_RESULT MaybeLocal< Value > GetRealNamedProperty(Local< Context > context, Local< Name > key)