LCOV - code coverage report
Current view: top level - src/inspector - value-mirror.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 683 809 84.4 %
Date: 2019-04-17 Functions: 76 93 81.7 %

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

Generated by: LCOV version 1.10