LCOV - code coverage report
Current view: top level - src/inspector - value-mirror.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 646 774 83.5 %
Date: 2019-01-20 Functions: 72 89 80.9 %

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

Generated by: LCOV version 1.10