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