LCOV - code coverage report
Current view: top level - src/inspector - value-mirror.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 642 766 83.8 %
Date: 2019-02-19 Functions: 73 90 81.1 %

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

Generated by: LCOV version 1.10