• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
v8Value() const400   v8::Local<v8::Value> v8Value() const override { return m_value; }
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const401   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 
buildEntryPreview(v8::Local<v8::Context> context,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * preview) const415   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 
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<PropertyPreview> * preview) const429   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 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const442   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) {}
v8Value() const491   v8::Local<v8::Value> v8Value() const override { return m_value; }
492 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const493   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   }
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<PropertyPreview> * result) const509   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   }
buildEntryPreview(v8::Local<v8::Context> context,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * preview) const519   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 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const532   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 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const571   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 
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<protocol::Runtime::PropertyPreview> * preview) const583   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 
buildEntryPreview(v8::Local<v8::Context> context,int * nameLimit,int * indexLimit,std::unique_ptr<protocol::Runtime::ObjectPreview> * preview) const595   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 
v8Value() const609   v8::Local<v8::Value> v8Value() const override { return m_value; }
610 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const611   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 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const634   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 
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<protocol::Runtime::PropertyPreview> * preview) const647   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 
v8Value() const659   v8::Local<v8::Value> v8Value() const override { return m_symbol; }
660 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const661   protocol::Response buildWebDriverValue(
662       v8::Local<v8::Context> context, int max_depth,
663       std::unique_ptr<protocol::Runtime::WebDriverValue>* result)
664       const override {
665     // https://w3c.github.io/webdriver-bidi/#data-types-protocolValue-RemoteValue-serialization
666     *result = protocol::Runtime::WebDriverValue::create()
667                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Symbol)
668                   .build();
669     return Response::Success();
670   }
671 
672  private:
673   v8::Local<v8::Symbol> m_symbol;
674 };
675 
676 class LocationMirror final : public ValueMirror {
677  public:
create(v8::Local<v8::Function> function)678   static std::unique_ptr<LocationMirror> create(
679       v8::Local<v8::Function> function) {
680     return create(function, function->ScriptId(),
681                   function->GetScriptLineNumber(),
682                   function->GetScriptColumnNumber());
683   }
createForGenerator(v8::Local<v8::Value> value)684   static std::unique_ptr<LocationMirror> createForGenerator(
685       v8::Local<v8::Value> value) {
686     v8::Local<v8::debug::GeneratorObject> generatorObject =
687         v8::debug::GeneratorObject::Cast(value);
688     if (!generatorObject->IsSuspended()) {
689       return create(generatorObject->Function());
690     }
691     v8::Local<v8::debug::Script> script;
692     if (!generatorObject->Script().ToLocal(&script)) return nullptr;
693     v8::debug::Location suspendedLocation =
694         generatorObject->SuspendedLocation();
695     return create(value, script->Id(), suspendedLocation.GetLineNumber(),
696                   suspendedLocation.GetColumnNumber());
697   }
698 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const699   Response buildRemoteObject(
700       v8::Local<v8::Context> context, WrapMode mode,
701       std::unique_ptr<RemoteObject>* result) const override {
702     auto location = protocol::DictionaryValue::create();
703     location->setString("scriptId", String16::fromInteger(m_scriptId));
704     location->setInteger("lineNumber", m_lineNumber);
705     location->setInteger("columnNumber", m_columnNumber);
706     *result = RemoteObject::create()
707                   .setType(RemoteObject::TypeEnum::Object)
708                   .setSubtype("internal#location")
709                   .setDescription("Object")
710                   .setValue(std::move(location))
711                   .build();
712     return Response::Success();
713   }
v8Value() const714   v8::Local<v8::Value> v8Value() const override { return m_value; }
715 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const716   protocol::Response buildWebDriverValue(
717       v8::Local<v8::Context> context, int max_depth,
718       std::unique_ptr<protocol::Runtime::WebDriverValue>* result)
719       const override {
720     *result = protocol::Runtime::WebDriverValue::create()
721                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Object)
722                   .build();
723     return Response::Success();
724   }
725 
726  private:
create(v8::Local<v8::Value> value,int scriptId,int lineNumber,int columnNumber)727   static std::unique_ptr<LocationMirror> create(v8::Local<v8::Value> value,
728                                                 int scriptId, int lineNumber,
729                                                 int columnNumber) {
730     if (scriptId == v8::UnboundScript::kNoScriptId) return nullptr;
731     if (lineNumber == v8::Function::kLineOffsetNotFound ||
732         columnNumber == v8::Function::kLineOffsetNotFound) {
733       return nullptr;
734     }
735     return std::unique_ptr<LocationMirror>(
736         new LocationMirror(value, scriptId, lineNumber, columnNumber));
737   }
738 
LocationMirror(v8::Local<v8::Value> value,int scriptId,int lineNumber,int columnNumber)739   LocationMirror(v8::Local<v8::Value> value, int scriptId, int lineNumber,
740                  int columnNumber)
741       : m_value(value),
742         m_scriptId(scriptId),
743         m_lineNumber(lineNumber),
744         m_columnNumber(columnNumber) {}
745 
746   v8::Local<v8::Value> m_value;
747   int m_scriptId;
748   int m_lineNumber;
749   int m_columnNumber;
750 };
751 
752 class FunctionMirror final : public ValueMirror {
753  public:
FunctionMirror(v8::Local<v8::Value> value)754   explicit FunctionMirror(v8::Local<v8::Value> value)
755       : m_value(value.As<v8::Function>()) {}
756 
v8Value() const757   v8::Local<v8::Value> v8Value() const override { return m_value; }
758 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const759   Response buildRemoteObject(
760       v8::Local<v8::Context> context, WrapMode mode,
761       std::unique_ptr<RemoteObject>* result) const override {
762     // TODO(alph): drop this functionality.
763     if (mode == WrapMode::kForceValue) {
764       std::unique_ptr<protocol::Value> protocolValue;
765       Response response = toProtocolValue(context, m_value, &protocolValue);
766       if (!response.IsSuccess()) return response;
767       *result = RemoteObject::create()
768                     .setType(RemoteObject::TypeEnum::Function)
769                     .setValue(std::move(protocolValue))
770                     .build();
771     } else {
772       *result = RemoteObject::create()
773                     .setType(RemoteObject::TypeEnum::Function)
774                     .setClassName(toProtocolStringWithTypeCheck(
775                         context->GetIsolate(), m_value->GetConstructorName()))
776                     .setDescription(descriptionForFunction(m_value))
777                     .build();
778     }
779     return Response::Success();
780   }
781 
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<PropertyPreview> * result) const782   void buildPropertyPreview(
783       v8::Local<v8::Context> context, const String16& name,
784       std::unique_ptr<PropertyPreview>* result) const override {
785     *result = PropertyPreview::create()
786                   .setName(name)
787                   .setType(RemoteObject::TypeEnum::Function)
788                   .setValue(String16())
789                   .build();
790   }
buildEntryPreview(v8::Local<v8::Context> context,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * preview) const791   void buildEntryPreview(
792       v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
793       std::unique_ptr<ObjectPreview>* preview) const override {
794     *preview =
795         ObjectPreview::create()
796             .setType(RemoteObject::TypeEnum::Function)
797             .setDescription(descriptionForFunction(m_value))
798             .setOverflow(false)
799             .setProperties(std::make_unique<protocol::Array<PropertyPreview>>())
800             .build();
801   }
802 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const803   protocol::Response buildWebDriverValue(
804       v8::Local<v8::Context> context, int max_depth,
805       std::unique_ptr<protocol::Runtime::WebDriverValue>* result)
806       const override {
807     // https://w3c.github.io/webdriver-bidi/#data-types-protocolValue-RemoteValue-serialization
808     *result =
809         protocol::Runtime::WebDriverValue::create()
810             .setType(protocol::Runtime::WebDriverValue::TypeEnum::Function)
811             .build();
812     return Response::Success();
813   }
814 
815  private:
816   v8::Local<v8::Function> m_value;
817 };
818 
isArrayLike(v8::Local<v8::Context> context,v8::Local<v8::Value> value,size_t * length)819 bool isArrayLike(v8::Local<v8::Context> context, v8::Local<v8::Value> value,
820                  size_t* length) {
821   if (!value->IsObject()) return false;
822   v8::Isolate* isolate = context->GetIsolate();
823   v8::TryCatch tryCatch(isolate);
824   v8::MicrotasksScope microtasksScope(isolate,
825                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
826   v8::Local<v8::Object> object = value.As<v8::Object>();
827   v8::Local<v8::Value> spliceValue;
828   if (!object->IsArgumentsObject() &&
829       (!object->GetRealNamedProperty(context, toV8String(isolate, "splice"))
830             .ToLocal(&spliceValue) ||
831        !spliceValue->IsFunction())) {
832     return false;
833   }
834   v8::Local<v8::Value> lengthValue;
835   v8::Maybe<bool> result =
836       object->HasOwnProperty(context, toV8String(isolate, "length"));
837   if (result.IsNothing()) return false;
838   if (!result.FromJust() ||
839       !object->Get(context, toV8String(isolate, "length"))
840            .ToLocal(&lengthValue) ||
841       !lengthValue->IsUint32()) {
842     return false;
843   }
844   *length = lengthValue.As<v8::Uint32>()->Value();
845   return true;
846 }
847 
848 struct EntryMirror {
849   std::unique_ptr<ValueMirror> key;
850   std::unique_ptr<ValueMirror> value;
851 
getEntriesv8_inspector::__anon176de1c60111::EntryMirror852   static bool getEntries(v8::Local<v8::Context> context,
853                          v8::Local<v8::Object> object, size_t limit,
854                          bool* overflow, std::vector<EntryMirror>* mirrors) {
855     bool isKeyValue = false;
856     v8::Local<v8::Array> entries;
857     if (!object->PreviewEntries(&isKeyValue).ToLocal(&entries)) return false;
858     for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) {
859       v8::Local<v8::Value> tmp;
860 
861       std::unique_ptr<ValueMirror> keyMirror;
862       if (isKeyValue && entries->Get(context, i).ToLocal(&tmp)) {
863         keyMirror = ValueMirror::create(context, tmp);
864       }
865       std::unique_ptr<ValueMirror> valueMirror;
866       if (entries->Get(context, isKeyValue ? i + 1 : i).ToLocal(&tmp)) {
867         valueMirror = ValueMirror::create(context, tmp);
868       } else {
869         continue;
870       }
871       if (mirrors->size() == limit) {
872         *overflow = true;
873         return true;
874       }
875       mirrors->emplace_back(
876           EntryMirror{std::move(keyMirror), std::move(valueMirror)});
877     }
878     return mirrors->size() > 0;
879   }
880 };
881 
882 class PreviewPropertyAccumulator : public ValueMirror::PropertyAccumulator {
883  public:
PreviewPropertyAccumulator(const std::vector<String16> & blocklist,int skipIndex,int * nameLimit,int * indexLimit,bool * overflow,std::vector<PropertyMirror> * mirrors)884   PreviewPropertyAccumulator(const std::vector<String16>& blocklist,
885                              int skipIndex, int* nameLimit, int* indexLimit,
886                              bool* overflow,
887                              std::vector<PropertyMirror>* mirrors)
888       : m_blocklist(blocklist),
889         m_skipIndex(skipIndex),
890         m_nameLimit(nameLimit),
891         m_indexLimit(indexLimit),
892         m_overflow(overflow),
893         m_mirrors(mirrors) {}
894 
Add(PropertyMirror mirror)895   bool Add(PropertyMirror mirror) override {
896     if (mirror.exception) return true;
897     if ((!mirror.getter || !mirror.getter->v8Value()->IsFunction()) &&
898         !mirror.value) {
899       return true;
900     }
901     if (!mirror.isOwn && !mirror.isSynthetic) return true;
902     if (std::find(m_blocklist.begin(), m_blocklist.end(), mirror.name) !=
903         m_blocklist.end()) {
904       return true;
905     }
906     if (mirror.isIndex && m_skipIndex > 0) {
907       --m_skipIndex;
908       if (m_skipIndex > 0) return true;
909     }
910     int* limit = mirror.isIndex ? m_indexLimit : m_nameLimit;
911     if (!*limit) {
912       *m_overflow = true;
913       return false;
914     }
915     --*limit;
916     m_mirrors->push_back(std::move(mirror));
917     return true;
918   }
919 
920  private:
921   std::vector<String16> m_blocklist;
922   int m_skipIndex;
923   int* m_nameLimit;
924   int* m_indexLimit;
925   bool* m_overflow;
926   std::vector<PropertyMirror>* m_mirrors;
927 };
928 
getPropertiesForPreview(v8::Local<v8::Context> context,v8::Local<v8::Object> object,int * nameLimit,int * indexLimit,bool * overflow,std::vector<PropertyMirror> * properties)929 bool getPropertiesForPreview(v8::Local<v8::Context> context,
930                              v8::Local<v8::Object> object, int* nameLimit,
931                              int* indexLimit, bool* overflow,
932                              std::vector<PropertyMirror>* properties) {
933   std::vector<String16> blocklist;
934   size_t length = 0;
935   if (object->IsArray() || isArrayLike(context, object, &length) ||
936       object->IsStringObject()) {
937     blocklist.push_back("length");
938 #if V8_ENABLE_WEBASSEMBLY
939   } else if (v8::debug::WasmValueObject::IsWasmValueObject(object)) {
940     blocklist.push_back("type");
941 #endif  // V8_ENABLE_WEBASSEMBLY
942   } else {
943     auto clientSubtype = clientFor(context)->valueSubtype(object);
944     if (clientSubtype && toString16(clientSubtype->string()) == "array") {
945       blocklist.push_back("length");
946     }
947   }
948   if (object->IsArrayBuffer() || object->IsSharedArrayBuffer()) {
949     blocklist.push_back("[[Int8Array]]");
950     blocklist.push_back("[[Uint8Array]]");
951     blocklist.push_back("[[Int16Array]]");
952     blocklist.push_back("[[Int32Array]]");
953   }
954   int skipIndex = object->IsStringObject()
955                       ? object.As<v8::StringObject>()->ValueOf()->Length() + 1
956                       : -1;
957   PreviewPropertyAccumulator accumulator(blocklist, skipIndex, nameLimit,
958                                          indexLimit, overflow, properties);
959   return ValueMirror::getProperties(context, object, false, false, false,
960                                     &accumulator);
961 }
962 
getInternalPropertiesForPreview(v8::Local<v8::Context> context,v8::Local<v8::Object> object,int * nameLimit,bool * overflow,std::vector<InternalPropertyMirror> * properties)963 void getInternalPropertiesForPreview(
964     v8::Local<v8::Context> context, v8::Local<v8::Object> object,
965     int* nameLimit, bool* overflow,
966     std::vector<InternalPropertyMirror>* properties) {
967   std::vector<InternalPropertyMirror> mirrors;
968   ValueMirror::getInternalProperties(context, object, &mirrors);
969   std::vector<String16> allowlist;
970   if (object->IsBooleanObject() || object->IsNumberObject() ||
971       object->IsStringObject() || object->IsSymbolObject() ||
972       object->IsBigIntObject()) {
973     allowlist.emplace_back("[[PrimitiveValue]]");
974   } else if (object->IsPromise()) {
975     allowlist.emplace_back("[[PromiseState]]");
976     allowlist.emplace_back("[[PromiseResult]]");
977   } else if (object->IsGeneratorObject()) {
978     allowlist.emplace_back("[[GeneratorState]]");
979   }
980   for (auto& mirror : mirrors) {
981     if (std::find(allowlist.begin(), allowlist.end(), mirror.name) ==
982         allowlist.end()) {
983       continue;
984     }
985     if (!*nameLimit) {
986       *overflow = true;
987       return;
988     }
989     --*nameLimit;
990     properties->push_back(std::move(mirror));
991   }
992 }
993 
getPrivatePropertiesForPreview(v8::Local<v8::Context> context,v8::Local<v8::Object> object,int * nameLimit,bool * overflow,protocol::Array<PropertyPreview> * privateProperties)994 void getPrivatePropertiesForPreview(
995     v8::Local<v8::Context> context, v8::Local<v8::Object> object,
996     int* nameLimit, bool* overflow,
997     protocol::Array<PropertyPreview>* privateProperties) {
998   std::vector<PrivatePropertyMirror> mirrors =
999       ValueMirror::getPrivateProperties(context, object,
1000                                         /* accessPropertiesOnly */ false);
1001   for (auto& mirror : mirrors) {
1002     std::unique_ptr<PropertyPreview> propertyPreview;
1003     if (mirror.value) {
1004       mirror.value->buildPropertyPreview(context, mirror.name,
1005                                          &propertyPreview);
1006     } else {
1007       propertyPreview = PropertyPreview::create()
1008                             .setName(mirror.name)
1009                             .setType(PropertyPreview::TypeEnum::Accessor)
1010                             .build();
1011     }
1012     if (!propertyPreview) continue;
1013     if (!*nameLimit) {
1014       *overflow = true;
1015       return;
1016     }
1017     --*nameLimit;
1018     privateProperties->emplace_back(std::move(propertyPreview));
1019   }
1020 }
1021 
1022 class ObjectMirror final : public ValueMirror {
1023  public:
ObjectMirror(v8::Local<v8::Value> value,const String16 & description)1024   ObjectMirror(v8::Local<v8::Value> value, const String16& description)
1025       : m_value(value.As<v8::Object>()),
1026         m_description(description),
1027         m_hasSubtype(false) {}
ObjectMirror(v8::Local<v8::Value> value,const String16 & subtype,const String16 & description)1028   ObjectMirror(v8::Local<v8::Value> value, const String16& subtype,
1029                const String16& description)
1030       : m_value(value.As<v8::Object>()),
1031         m_description(description),
1032         m_hasSubtype(true),
1033         m_subtype(subtype) {}
1034 
v8Value() const1035   v8::Local<v8::Value> v8Value() const override { return m_value; }
1036 
buildRemoteObject(v8::Local<v8::Context> context,WrapMode mode,std::unique_ptr<RemoteObject> * result) const1037   Response buildRemoteObject(
1038       v8::Local<v8::Context> context, WrapMode mode,
1039       std::unique_ptr<RemoteObject>* result) const override {
1040     if (mode == WrapMode::kForceValue) {
1041       std::unique_ptr<protocol::Value> protocolValue;
1042       Response response = toProtocolValue(context, m_value, &protocolValue);
1043       if (!response.IsSuccess()) return response;
1044       *result = RemoteObject::create()
1045                     .setType(RemoteObject::TypeEnum::Object)
1046                     .setValue(std::move(protocolValue))
1047                     .build();
1048     } else {
1049       v8::Isolate* isolate = context->GetIsolate();
1050       *result = RemoteObject::create()
1051                     .setType(RemoteObject::TypeEnum::Object)
1052                     .setClassName(toProtocolString(
1053                         isolate, m_value->GetConstructorName()))
1054                     .setDescription(m_description)
1055                     .build();
1056       if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1057       if (mode == WrapMode::kWithPreview) {
1058         std::unique_ptr<ObjectPreview> previewValue;
1059         int nameLimit = 5;
1060         int indexLimit = 100;
1061         buildObjectPreview(context, false, &nameLimit, &indexLimit,
1062                            &previewValue);
1063         (*result)->setPreview(std::move(previewValue));
1064       }
1065     }
1066     return Response::Success();
1067   }
1068 
buildObjectPreview(v8::Local<v8::Context> context,bool generatePreviewForTable,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * result) const1069   void buildObjectPreview(
1070       v8::Local<v8::Context> context, bool generatePreviewForTable,
1071       int* nameLimit, int* indexLimit,
1072       std::unique_ptr<ObjectPreview>* result) const override {
1073     buildObjectPreviewInternal(context, false /* forEntry */,
1074                                generatePreviewForTable, nameLimit, indexLimit,
1075                                result);
1076   }
1077 
buildEntryPreview(v8::Local<v8::Context> context,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * result) const1078   void buildEntryPreview(
1079       v8::Local<v8::Context> context, int* nameLimit, int* indexLimit,
1080       std::unique_ptr<ObjectPreview>* result) const override {
1081     buildObjectPreviewInternal(context, true /* forEntry */,
1082                                false /* generatePreviewForTable */, nameLimit,
1083                                indexLimit, result);
1084   }
1085 
buildPropertyPreview(v8::Local<v8::Context> context,const String16 & name,std::unique_ptr<PropertyPreview> * result) const1086   void buildPropertyPreview(
1087       v8::Local<v8::Context> context, const String16& name,
1088       std::unique_ptr<PropertyPreview>* result) const override {
1089     *result = PropertyPreview::create()
1090                   .setName(name)
1091                   .setType(RemoteObject::TypeEnum::Object)
1092                   .setValue(abbreviateString(
1093                       m_description,
1094                       m_subtype == RemoteObject::SubtypeEnum::Regexp ? kMiddle
1095                                                                      : kEnd))
1096                   .build();
1097     if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1098   }
1099 
buildWebDriverValue(v8::Local<v8::Context> context,int max_depth,std::unique_ptr<protocol::Runtime::WebDriverValue> * result) const1100   protocol::Response buildWebDriverValue(
1101       v8::Local<v8::Context> context, int max_depth,
1102       std::unique_ptr<protocol::Runtime::WebDriverValue>* result)
1103       const override {
1104     // https://w3c.github.io/webdriver-bidi/#data-types-protocolValue-RemoteValue-serialization
1105 
1106     // Check if embedder implemented custom serialization.
1107     std::unique_ptr<v8_inspector::WebDriverValue> embedder_serialized_result =
1108         clientFor(context)->serializeToWebDriverValue(m_value, max_depth);
1109 
1110     if (embedder_serialized_result) {
1111       // Embedder-implemented serialization.
1112       *result = protocol::Runtime::WebDriverValue::create()
1113                     .setType(toString16(embedder_serialized_result->type))
1114                     .build();
1115 
1116       if (!embedder_serialized_result->value.IsEmpty()) {
1117         // Embedder-implemented serialization has value.
1118         std::unique_ptr<protocol::Value> protocol_value;
1119         Response response = toProtocolValue(
1120             context, embedder_serialized_result->value.ToLocalChecked(),
1121             &protocol_value);
1122         if (!response.IsSuccess()) return response;
1123 
1124         (*result)->setValue(std::move(protocol_value));
1125       }
1126       return Response::Success();
1127     }
1128 
1129     // No embedder-implemented serialization. Serialize as V8 Object.
1130     Response response = V8WebDriverSerializer::serializeV8Value(
1131         m_value, context, max_depth, result);
1132     return response;
1133   }
1134 
1135  private:
buildObjectPreviewInternal(v8::Local<v8::Context> context,bool forEntry,bool generatePreviewForTable,int * nameLimit,int * indexLimit,std::unique_ptr<ObjectPreview> * result) const1136   void buildObjectPreviewInternal(
1137       v8::Local<v8::Context> context, bool forEntry,
1138       bool generatePreviewForTable, int* nameLimit, int* indexLimit,
1139       std::unique_ptr<ObjectPreview>* result) const {
1140     auto properties = std::make_unique<protocol::Array<PropertyPreview>>();
1141     std::unique_ptr<protocol::Array<EntryPreview>> entriesPreview;
1142     bool overflow = false;
1143 
1144     v8::Local<v8::Value> value = m_value;
1145     while (value->IsProxy()) value = value.As<v8::Proxy>()->GetTarget();
1146 
1147     if (value->IsObject() && !value->IsProxy()) {
1148       v8::Local<v8::Object> objectForPreview = value.As<v8::Object>();
1149       std::vector<InternalPropertyMirror> internalProperties;
1150       getInternalPropertiesForPreview(context, objectForPreview, nameLimit,
1151                                       &overflow, &internalProperties);
1152       for (size_t i = 0; i < internalProperties.size(); ++i) {
1153         std::unique_ptr<PropertyPreview> propertyPreview;
1154         internalProperties[i].value->buildPropertyPreview(
1155             context, internalProperties[i].name, &propertyPreview);
1156         if (propertyPreview) {
1157           properties->emplace_back(std::move(propertyPreview));
1158         }
1159       }
1160 
1161       getPrivatePropertiesForPreview(context, objectForPreview, nameLimit,
1162                                      &overflow, properties.get());
1163 
1164       std::vector<PropertyMirror> mirrors;
1165       if (getPropertiesForPreview(context, objectForPreview, nameLimit,
1166                                   indexLimit, &overflow, &mirrors)) {
1167         for (size_t i = 0; i < mirrors.size(); ++i) {
1168           std::unique_ptr<PropertyPreview> preview;
1169           std::unique_ptr<ObjectPreview> valuePreview;
1170           if (mirrors[i].value) {
1171             mirrors[i].value->buildPropertyPreview(context, mirrors[i].name,
1172                                                    &preview);
1173             if (generatePreviewForTable) {
1174               int tableLimit = 1000;
1175               mirrors[i].value->buildObjectPreview(context, false, &tableLimit,
1176                                                    &tableLimit, &valuePreview);
1177             }
1178           } else {
1179             preview = PropertyPreview::create()
1180                           .setName(mirrors[i].name)
1181                           .setType(PropertyPreview::TypeEnum::Accessor)
1182                           .build();
1183           }
1184           if (valuePreview) {
1185             preview->setValuePreview(std::move(valuePreview));
1186           }
1187           properties->emplace_back(std::move(preview));
1188         }
1189       }
1190 
1191       std::vector<EntryMirror> entries;
1192       if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow,
1193                                   &entries)) {
1194         if (forEntry) {
1195           overflow = true;
1196         } else {
1197           entriesPreview = std::make_unique<protocol::Array<EntryPreview>>();
1198           for (const auto& entry : entries) {
1199             std::unique_ptr<ObjectPreview> valuePreview;
1200             entry.value->buildEntryPreview(context, nameLimit, indexLimit,
1201                                            &valuePreview);
1202             if (!valuePreview) continue;
1203             std::unique_ptr<ObjectPreview> keyPreview;
1204             if (entry.key) {
1205               entry.key->buildEntryPreview(context, nameLimit, indexLimit,
1206                                            &keyPreview);
1207               if (!keyPreview) continue;
1208             }
1209             std::unique_ptr<EntryPreview> entryPreview =
1210                 EntryPreview::create()
1211                     .setValue(std::move(valuePreview))
1212                     .build();
1213             if (keyPreview) entryPreview->setKey(std::move(keyPreview));
1214             entriesPreview->emplace_back(std::move(entryPreview));
1215           }
1216         }
1217       }
1218     }
1219     *result = ObjectPreview::create()
1220                   .setType(RemoteObject::TypeEnum::Object)
1221                   .setDescription(m_description)
1222                   .setOverflow(overflow)
1223                   .setProperties(std::move(properties))
1224                   .build();
1225     if (m_hasSubtype) (*result)->setSubtype(m_subtype);
1226     if (entriesPreview) (*result)->setEntries(std::move(entriesPreview));
1227   }
1228 
1229   v8::Local<v8::Object> m_value;
1230   String16 m_description;
1231   bool m_hasSubtype;
1232   String16 m_subtype;
1233 };
1234 
nativeGetterCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1235 void nativeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1236   v8::Local<v8::Object> data = info.Data().As<v8::Object>();
1237   v8::Isolate* isolate = info.GetIsolate();
1238   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1239   v8::Local<v8::Value> name;
1240   if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
1241            .ToLocal(&name)) {
1242     return;
1243   }
1244   v8::Local<v8::Value> object;
1245   if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
1246            .ToLocal(&object) ||
1247       !object->IsObject()) {
1248     return;
1249   }
1250   v8::Local<v8::Value> value;
1251   if (!object.As<v8::Object>()->Get(context, name).ToLocal(&value)) return;
1252   info.GetReturnValue().Set(value);
1253 }
1254 
createNativeGetter(v8::Local<v8::Context> context,v8::Local<v8::Value> object,v8::Local<v8::Name> name)1255 std::unique_ptr<ValueMirror> createNativeGetter(v8::Local<v8::Context> context,
1256                                                 v8::Local<v8::Value> object,
1257                                                 v8::Local<v8::Name> name) {
1258   v8::Isolate* isolate = context->GetIsolate();
1259   v8::TryCatch tryCatch(isolate);
1260 
1261   v8::Local<v8::Object> data = v8::Object::New(isolate);
1262   if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1263     return nullptr;
1264   }
1265   if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1266     return nullptr;
1267   }
1268 
1269   v8::Local<v8::Function> function;
1270   if (!v8::Function::New(context, nativeGetterCallback, data, 0,
1271                          v8::ConstructorBehavior::kThrow)
1272            .ToLocal(&function)) {
1273     return nullptr;
1274   }
1275   return ValueMirror::create(context, function);
1276 }
1277 
nativeSetterCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1278 void nativeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1279   if (info.Length() < 1) return;
1280   v8::Local<v8::Object> data = info.Data().As<v8::Object>();
1281   v8::Isolate* isolate = info.GetIsolate();
1282   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1283   v8::Local<v8::Value> name;
1284   if (!data->GetRealNamedProperty(context, toV8String(isolate, "name"))
1285            .ToLocal(&name)) {
1286     return;
1287   }
1288   v8::Local<v8::Value> object;
1289   if (!data->GetRealNamedProperty(context, toV8String(isolate, "object"))
1290            .ToLocal(&object) ||
1291       !object->IsObject()) {
1292     return;
1293   }
1294   v8::Local<v8::Value> value;
1295   if (!object.As<v8::Object>()->Set(context, name, info[0]).IsNothing()) return;
1296 }
1297 
createNativeSetter(v8::Local<v8::Context> context,v8::Local<v8::Value> object,v8::Local<v8::Name> name)1298 std::unique_ptr<ValueMirror> createNativeSetter(v8::Local<v8::Context> context,
1299                                                 v8::Local<v8::Value> object,
1300                                                 v8::Local<v8::Name> name) {
1301   v8::Isolate* isolate = context->GetIsolate();
1302   v8::TryCatch tryCatch(isolate);
1303 
1304   v8::Local<v8::Object> data = v8::Object::New(isolate);
1305   if (data->Set(context, toV8String(isolate, "name"), name).IsNothing()) {
1306     return nullptr;
1307   }
1308   if (data->Set(context, toV8String(isolate, "object"), object).IsNothing()) {
1309     return nullptr;
1310   }
1311 
1312   v8::Local<v8::Function> function;
1313   if (!v8::Function::New(context, nativeSetterCallback, data, 1,
1314                          v8::ConstructorBehavior::kThrow)
1315            .ToLocal(&function)) {
1316     return nullptr;
1317   }
1318   return ValueMirror::create(context, function);
1319 }
1320 
doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context,v8::Local<v8::Object> object,v8::Local<v8::Name> name)1321 bool doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context,
1322                                                 v8::Local<v8::Object> object,
1323                                                 v8::Local<v8::Name> name) {
1324   // TODO(dgozman): we should remove this, annotate more embedder properties as
1325   // side-effect free, and call all getters which do not produce side effects.
1326   if (!name->IsString()) return false;
1327   v8::Isolate* isolate = context->GetIsolate();
1328   if (!name.As<v8::String>()->StringEquals(toV8String(isolate, "body"))) {
1329     return false;
1330   }
1331 
1332   v8::TryCatch tryCatch(isolate);
1333   v8::Local<v8::Value> request;
1334   if (context->Global()
1335           ->GetRealNamedProperty(context, toV8String(isolate, "Request"))
1336           .ToLocal(&request)) {
1337     if (request->IsObject() &&
1338         object->InstanceOf(context, request.As<v8::Object>())
1339             .FromMaybe(false)) {
1340       return true;
1341     }
1342   }
1343   if (tryCatch.HasCaught()) tryCatch.Reset();
1344 
1345   v8::Local<v8::Value> response;
1346   if (context->Global()
1347           ->GetRealNamedProperty(context, toV8String(isolate, "Response"))
1348           .ToLocal(&response)) {
1349     if (response->IsObject() &&
1350         object->InstanceOf(context, response.As<v8::Object>())
1351             .FromMaybe(false)) {
1352       return true;
1353     }
1354   }
1355   return false;
1356 }
1357 
1358 }  // anonymous namespace
1359 
1360 ValueMirror::~ValueMirror() = default;
1361 
1362 // static
getProperties(v8::Local<v8::Context> context,v8::Local<v8::Object> object,bool ownProperties,bool accessorPropertiesOnly,bool nonIndexedPropertiesOnly,PropertyAccumulator * accumulator)1363 bool ValueMirror::getProperties(v8::Local<v8::Context> context,
1364                                 v8::Local<v8::Object> object,
1365                                 bool ownProperties, bool accessorPropertiesOnly,
1366                                 bool nonIndexedPropertiesOnly,
1367                                 PropertyAccumulator* accumulator) {
1368   v8::Isolate* isolate = context->GetIsolate();
1369   v8::TryCatch tryCatch(isolate);
1370   v8::Local<v8::Set> set = v8::Set::New(isolate);
1371 
1372   v8::MicrotasksScope microtasksScope(isolate,
1373                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
1374   V8InternalValueType internalType = v8InternalValueTypeFrom(context, object);
1375   if (internalType == V8InternalValueType::kScope) {
1376     v8::Local<v8::Value> value;
1377     if (!object->Get(context, toV8String(isolate, "object")).ToLocal(&value) ||
1378         !value->IsObject()) {
1379       return false;
1380     } else {
1381       object = value.As<v8::Object>();
1382     }
1383   }
1384   if (internalType == V8InternalValueType::kScopeList) {
1385     if (!set->Add(context, toV8String(isolate, "length")).ToLocal(&set)) {
1386       return false;
1387     }
1388   }
1389 
1390   auto iterator = v8::debug::PropertyIterator::Create(context, object,
1391                                                       nonIndexedPropertiesOnly);
1392   if (!iterator) {
1393     CHECK(tryCatch.HasCaught());
1394     return false;
1395   }
1396   while (!iterator->Done()) {
1397     bool isOwn = iterator->is_own();
1398     if (!isOwn && ownProperties) break;
1399     v8::Local<v8::Name> v8Name = iterator->name();
1400     v8::Maybe<bool> result = set->Has(context, v8Name);
1401     if (result.IsNothing()) return false;
1402     if (result.FromJust()) {
1403       if (!iterator->Advance().FromMaybe(false)) {
1404         CHECK(tryCatch.HasCaught());
1405         return false;
1406       }
1407       continue;
1408     }
1409     if (!set->Add(context, v8Name).ToLocal(&set)) return false;
1410 
1411     String16 name;
1412     std::unique_ptr<ValueMirror> symbolMirror;
1413     if (v8Name->IsString()) {
1414       name = toProtocolString(isolate, v8Name.As<v8::String>());
1415     } else {
1416       v8::Local<v8::Symbol> symbol = v8Name.As<v8::Symbol>();
1417       name = descriptionForSymbol(context, symbol);
1418       symbolMirror = ValueMirror::create(context, symbol);
1419     }
1420 
1421     v8::PropertyAttribute attributes;
1422     std::unique_ptr<ValueMirror> valueMirror;
1423     std::unique_ptr<ValueMirror> getterMirror;
1424     std::unique_ptr<ValueMirror> setterMirror;
1425     std::unique_ptr<ValueMirror> exceptionMirror;
1426     bool writable = false;
1427     bool enumerable = false;
1428     bool configurable = false;
1429 
1430     bool isAccessorProperty = false;
1431     v8::TryCatch tryCatchAttributes(isolate);
1432     if (!iterator->attributes().To(&attributes)) {
1433       exceptionMirror =
1434           ValueMirror::create(context, tryCatchAttributes.Exception());
1435     } else {
1436       if (iterator->is_native_accessor()) {
1437         if (iterator->has_native_getter()) {
1438           getterMirror = createNativeGetter(context, object, v8Name);
1439         }
1440         if (iterator->has_native_setter()) {
1441           setterMirror = createNativeSetter(context, object, v8Name);
1442         }
1443         writable = !(attributes & v8::PropertyAttribute::ReadOnly);
1444         enumerable = !(attributes & v8::PropertyAttribute::DontEnum);
1445         configurable = !(attributes & v8::PropertyAttribute::DontDelete);
1446         isAccessorProperty = getterMirror || setterMirror;
1447       } else {
1448         v8::TryCatch tryCatchDescriptor(isolate);
1449         v8::debug::PropertyDescriptor descriptor;
1450         if (!iterator->descriptor().To(&descriptor)) {
1451           exceptionMirror =
1452               ValueMirror::create(context, tryCatchDescriptor.Exception());
1453         } else {
1454           writable = descriptor.has_writable ? descriptor.writable : false;
1455           enumerable =
1456               descriptor.has_enumerable ? descriptor.enumerable : false;
1457           configurable =
1458               descriptor.has_configurable ? descriptor.configurable : false;
1459           if (!descriptor.value.IsEmpty()) {
1460             valueMirror = ValueMirror::create(context, descriptor.value);
1461           }
1462           v8::Local<v8::Function> getterFunction;
1463           if (!descriptor.get.IsEmpty()) {
1464             v8::Local<v8::Value> get = descriptor.get;
1465             getterMirror = ValueMirror::create(context, get);
1466             if (get->IsFunction()) getterFunction = get.As<v8::Function>();
1467           }
1468           if (!descriptor.set.IsEmpty()) {
1469             setterMirror = ValueMirror::create(context, descriptor.set);
1470           }
1471           isAccessorProperty = getterMirror || setterMirror;
1472           if (name != "__proto__" && !getterFunction.IsEmpty() &&
1473               getterFunction->ScriptId() == v8::UnboundScript::kNoScriptId &&
1474               !doesAttributeHaveObservableSideEffectOnGet(context, object,
1475                                                           v8Name)) {
1476             v8::TryCatch tryCatchFunction(isolate);
1477             v8::Local<v8::Value> value;
1478             if (object->Get(context, v8Name).ToLocal(&value)) {
1479               if (value->IsPromise() &&
1480                   value.As<v8::Promise>()->State() == v8::Promise::kRejected) {
1481                 value.As<v8::Promise>()->MarkAsHandled();
1482               } else {
1483                 valueMirror = ValueMirror::create(context, value);
1484                 setterMirror = nullptr;
1485                 getterMirror = nullptr;
1486               }
1487             }
1488           }
1489         }
1490       }
1491     }
1492     if (accessorPropertiesOnly && !isAccessorProperty) continue;
1493     auto mirror = PropertyMirror{name,
1494                                  writable,
1495                                  configurable,
1496                                  enumerable,
1497                                  isOwn,
1498                                  iterator->is_array_index(),
1499                                  isAccessorProperty && valueMirror,
1500                                  std::move(valueMirror),
1501                                  std::move(getterMirror),
1502                                  std::move(setterMirror),
1503                                  std::move(symbolMirror),
1504                                  std::move(exceptionMirror)};
1505     if (!accumulator->Add(std::move(mirror))) return true;
1506 
1507     if (!iterator->Advance().FromMaybe(false)) {
1508       CHECK(tryCatch.HasCaught());
1509       return false;
1510     }
1511   }
1512   return true;
1513 }
1514 
1515 // static
getInternalProperties(v8::Local<v8::Context> context,v8::Local<v8::Object> object,std::vector<InternalPropertyMirror> * mirrors)1516 void ValueMirror::getInternalProperties(
1517     v8::Local<v8::Context> context, v8::Local<v8::Object> object,
1518     std::vector<InternalPropertyMirror>* mirrors) {
1519   v8::Isolate* isolate = context->GetIsolate();
1520   v8::MicrotasksScope microtasksScope(isolate,
1521                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
1522   v8::TryCatch tryCatch(isolate);
1523   if (object->IsFunction()) {
1524     v8::Local<v8::Function> function = object.As<v8::Function>();
1525     auto location = LocationMirror::create(function);
1526     if (location) {
1527       mirrors->emplace_back(InternalPropertyMirror{
1528           String16("[[FunctionLocation]]"), std::move(location)});
1529     }
1530     if (function->IsGeneratorFunction()) {
1531       mirrors->emplace_back(InternalPropertyMirror{
1532           String16("[[IsGenerator]]"),
1533           ValueMirror::create(context, v8::True(context->GetIsolate()))});
1534     }
1535   }
1536   if (object->IsGeneratorObject()) {
1537     auto location = LocationMirror::createForGenerator(object);
1538     if (location) {
1539       mirrors->emplace_back(InternalPropertyMirror{
1540           String16("[[GeneratorLocation]]"), std::move(location)});
1541     }
1542   }
1543   V8Debugger* debugger =
1544       static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate))
1545           ->debugger();
1546   v8::Local<v8::Array> properties;
1547   if (debugger->internalProperties(context, object).ToLocal(&properties)) {
1548     for (uint32_t i = 0; i < properties->Length(); i += 2) {
1549       v8::Local<v8::Value> name;
1550       if (!properties->Get(context, i).ToLocal(&name) || !name->IsString()) {
1551         tryCatch.Reset();
1552         continue;
1553       }
1554       v8::Local<v8::Value> value;
1555       if (!properties->Get(context, i + 1).ToLocal(&value)) {
1556         tryCatch.Reset();
1557         continue;
1558       }
1559       auto wrapper = ValueMirror::create(context, value);
1560       if (wrapper) {
1561         mirrors->emplace_back(InternalPropertyMirror{
1562             toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1563             std::move(wrapper)});
1564       }
1565     }
1566   }
1567 }
1568 
1569 // static
getPrivateProperties(v8::Local<v8::Context> context,v8::Local<v8::Object> object,bool accessorPropertiesOnly)1570 std::vector<PrivatePropertyMirror> ValueMirror::getPrivateProperties(
1571     v8::Local<v8::Context> context, v8::Local<v8::Object> object,
1572     bool accessorPropertiesOnly) {
1573   std::vector<PrivatePropertyMirror> mirrors;
1574   v8::Isolate* isolate = context->GetIsolate();
1575   v8::MicrotasksScope microtasksScope(isolate,
1576                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
1577   v8::TryCatch tryCatch(isolate);
1578   v8::Local<v8::Array> privateProperties;
1579 
1580   std::vector<v8::Local<v8::Value>> names;
1581   std::vector<v8::Local<v8::Value>> values;
1582   if (!v8::debug::GetPrivateMembers(context, object, &names, &values))
1583     return mirrors;
1584 
1585   size_t len = values.size();
1586   for (size_t i = 0; i < len; i++) {
1587     v8::Local<v8::Value> name = names[i];
1588     DCHECK(name->IsString());
1589     v8::Local<v8::Value> value = values[i];
1590 
1591     std::unique_ptr<ValueMirror> valueMirror;
1592     std::unique_ptr<ValueMirror> getterMirror;
1593     std::unique_ptr<ValueMirror> setterMirror;
1594     if (v8::debug::AccessorPair::IsAccessorPair(value)) {
1595       v8::Local<v8::debug::AccessorPair> accessors =
1596           value.As<v8::debug::AccessorPair>();
1597       v8::Local<v8::Value> getter = accessors->getter();
1598       v8::Local<v8::Value> setter = accessors->setter();
1599       if (!getter->IsNull()) {
1600         getterMirror = ValueMirror::create(context, getter);
1601       }
1602       if (!setter->IsNull()) {
1603         setterMirror = ValueMirror::create(context, setter);
1604       }
1605     } else if (accessorPropertiesOnly) {
1606       continue;
1607     } else {
1608       valueMirror = ValueMirror::create(context, value);
1609     }
1610 
1611     mirrors.emplace_back(PrivatePropertyMirror{
1612         toProtocolStringWithTypeCheck(context->GetIsolate(), name),
1613         std::move(valueMirror), std::move(getterMirror),
1614         std::move(setterMirror)});
1615   }
1616   return mirrors;
1617 }
1618 
clientMirror(v8::Local<v8::Context> context,v8::Local<v8::Value> value,const String16 & subtype)1619 std::unique_ptr<ValueMirror> clientMirror(v8::Local<v8::Context> context,
1620                                           v8::Local<v8::Value> value,
1621                                           const String16& subtype) {
1622   auto descriptionForValueSubtype =
1623       clientFor(context)->descriptionForValueSubtype(context, value);
1624   if (descriptionForValueSubtype) {
1625     return std::make_unique<ObjectMirror>(
1626         value, subtype, toString16(descriptionForValueSubtype->string()));
1627   }
1628   if (subtype == "error") {
1629     return std::make_unique<ObjectMirror>(
1630         value, RemoteObject::SubtypeEnum::Error,
1631         descriptionForError(context, value.As<v8::Object>(),
1632                             ErrorType::kClient));
1633   }
1634   if (subtype == "array" && value->IsObject()) {
1635     v8::Isolate* isolate = context->GetIsolate();
1636     v8::TryCatch tryCatch(isolate);
1637     v8::Local<v8::Object> object = value.As<v8::Object>();
1638     v8::Local<v8::Value> lengthValue;
1639     if (object->Get(context, toV8String(isolate, "length"))
1640             .ToLocal(&lengthValue)) {
1641       if (lengthValue->IsInt32()) {
1642         return std::make_unique<ObjectMirror>(
1643             value, RemoteObject::SubtypeEnum::Array,
1644             descriptionForCollection(isolate, object,
1645                                      lengthValue.As<v8::Int32>()->Value()));
1646       }
1647     }
1648   }
1649   return std::make_unique<ObjectMirror>(
1650       value,
1651       descriptionForObject(context->GetIsolate(), value.As<v8::Object>()));
1652 }
1653 
create(v8::Local<v8::Context> context,v8::Local<v8::Value> value)1654 std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
1655                                                  v8::Local<v8::Value> value) {
1656   if (value->IsNull()) {
1657     return std::make_unique<PrimitiveValueMirror>(
1658         value, RemoteObject::TypeEnum::Object);
1659   }
1660   if (value->IsBoolean()) {
1661     return std::make_unique<PrimitiveValueMirror>(
1662         value, RemoteObject::TypeEnum::Boolean);
1663   }
1664   if (value->IsNumber()) {
1665     return std::make_unique<NumberMirror>(value.As<v8::Number>());
1666   }
1667   v8::Isolate* isolate = context->GetIsolate();
1668   if (value->IsString()) {
1669     return std::make_unique<PrimitiveValueMirror>(
1670         value, RemoteObject::TypeEnum::String);
1671   }
1672   if (value->IsBigInt()) {
1673     return std::make_unique<BigIntMirror>(value.As<v8::BigInt>());
1674   }
1675   if (value->IsSymbol()) {
1676     return std::make_unique<SymbolMirror>(value.As<v8::Symbol>());
1677   }
1678   auto clientSubtype = (value->IsUndefined() || value->IsObject())
1679                            ? clientFor(context)->valueSubtype(value)
1680                            : nullptr;
1681   if (clientSubtype) {
1682     String16 subtype = toString16(clientSubtype->string());
1683     return clientMirror(context, value, subtype);
1684   }
1685   if (value->IsUndefined()) {
1686     return std::make_unique<PrimitiveValueMirror>(
1687         value, RemoteObject::TypeEnum::Undefined);
1688   }
1689   if (value->IsRegExp()) {
1690     return std::make_unique<ObjectMirror>(
1691         value, RemoteObject::SubtypeEnum::Regexp,
1692         descriptionForRegExp(isolate, value.As<v8::RegExp>()));
1693   }
1694   if (value->IsProxy()) {
1695     return std::make_unique<ObjectMirror>(
1696         value, RemoteObject::SubtypeEnum::Proxy, "Proxy");
1697   }
1698   if (value->IsFunction()) {
1699     return std::make_unique<FunctionMirror>(value);
1700   }
1701   if (value->IsDate()) {
1702     return std::make_unique<ObjectMirror>(
1703         value, RemoteObject::SubtypeEnum::Date,
1704         descriptionForDate(context, value.As<v8::Date>()));
1705   }
1706   if (value->IsPromise()) {
1707     v8::Local<v8::Promise> promise = value.As<v8::Promise>();
1708     return std::make_unique<ObjectMirror>(
1709         promise, RemoteObject::SubtypeEnum::Promise,
1710         descriptionForObject(isolate, promise));
1711   }
1712   if (value->IsNativeError()) {
1713     return std::make_unique<ObjectMirror>(
1714         value, RemoteObject::SubtypeEnum::Error,
1715         descriptionForError(context, value.As<v8::Object>(),
1716                             ErrorType::kNative));
1717   }
1718   if (value->IsMap()) {
1719     v8::Local<v8::Map> map = value.As<v8::Map>();
1720     return std::make_unique<ObjectMirror>(
1721         value, RemoteObject::SubtypeEnum::Map,
1722         descriptionForCollection(isolate, map, map->Size()));
1723   }
1724   if (value->IsSet()) {
1725     v8::Local<v8::Set> set = value.As<v8::Set>();
1726     return std::make_unique<ObjectMirror>(
1727         value, RemoteObject::SubtypeEnum::Set,
1728         descriptionForCollection(isolate, set, set->Size()));
1729   }
1730   if (value->IsWeakMap()) {
1731     return std::make_unique<ObjectMirror>(
1732         value, RemoteObject::SubtypeEnum::Weakmap,
1733         descriptionForObject(isolate, value.As<v8::Object>()));
1734   }
1735   if (value->IsWeakSet()) {
1736     return std::make_unique<ObjectMirror>(
1737         value, RemoteObject::SubtypeEnum::Weakset,
1738         descriptionForObject(isolate, value.As<v8::Object>()));
1739   }
1740   if (value->IsMapIterator() || value->IsSetIterator()) {
1741     return std::make_unique<ObjectMirror>(
1742         value, RemoteObject::SubtypeEnum::Iterator,
1743         descriptionForObject(isolate, value.As<v8::Object>()));
1744   }
1745   if (value->IsGeneratorObject()) {
1746     v8::Local<v8::Object> object = value.As<v8::Object>();
1747     return std::make_unique<ObjectMirror>(
1748         object, RemoteObject::SubtypeEnum::Generator,
1749         descriptionForObject(isolate, object));
1750   }
1751   if (value->IsTypedArray()) {
1752     v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
1753     return std::make_unique<ObjectMirror>(
1754         value, RemoteObject::SubtypeEnum::Typedarray,
1755         descriptionForCollection(isolate, array, array->Length()));
1756   }
1757   if (value->IsArrayBuffer()) {
1758     v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
1759     return std::make_unique<ObjectMirror>(
1760         value, RemoteObject::SubtypeEnum::Arraybuffer,
1761         descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1762   }
1763   if (value->IsSharedArrayBuffer()) {
1764     v8::Local<v8::SharedArrayBuffer> buffer = value.As<v8::SharedArrayBuffer>();
1765     return std::make_unique<ObjectMirror>(
1766         value, RemoteObject::SubtypeEnum::Arraybuffer,
1767         descriptionForCollection(isolate, buffer, buffer->ByteLength()));
1768   }
1769   if (value->IsDataView()) {
1770     v8::Local<v8::DataView> view = value.As<v8::DataView>();
1771     return std::make_unique<ObjectMirror>(
1772         value, RemoteObject::SubtypeEnum::Dataview,
1773         descriptionForCollection(isolate, view, view->ByteLength()));
1774   }
1775   if (value->IsWasmMemoryObject()) {
1776     v8::Local<v8::WasmMemoryObject> memory = value.As<v8::WasmMemoryObject>();
1777     return std::make_unique<ObjectMirror>(
1778         value, RemoteObject::SubtypeEnum::Webassemblymemory,
1779         descriptionForCollection(
1780             isolate, memory, memory->Buffer()->ByteLength() / kWasmPageSize));
1781   }
1782 #if V8_ENABLE_WEBASSEMBLY
1783   if (v8::debug::WasmValueObject::IsWasmValueObject(value)) {
1784     v8::Local<v8::debug::WasmValueObject> object =
1785         value.As<v8::debug::WasmValueObject>();
1786     return std::make_unique<ObjectMirror>(
1787         value, RemoteObject::SubtypeEnum::Wasmvalue,
1788         descriptionForWasmValueObject(context, object));
1789   }
1790 #endif  // V8_ENABLE_WEBASSEMBLY
1791   V8InternalValueType internalType =
1792       v8InternalValueTypeFrom(context, value.As<v8::Object>());
1793   if (value->IsArray() && internalType == V8InternalValueType::kScopeList) {
1794     return std::make_unique<ObjectMirror>(
1795         value, "internal#scopeList",
1796         descriptionForScopeList(value.As<v8::Array>()));
1797   }
1798   if (value->IsObject() && internalType == V8InternalValueType::kEntry) {
1799     return std::make_unique<ObjectMirror>(
1800         value, "internal#entry",
1801         descriptionForEntry(context, value.As<v8::Object>()));
1802   }
1803   if (value->IsObject() && internalType == V8InternalValueType::kScope) {
1804     return std::make_unique<ObjectMirror>(
1805         value, "internal#scope",
1806         descriptionForScope(context, value.As<v8::Object>()));
1807   }
1808   size_t length = 0;
1809   if (value->IsArray() || isArrayLike(context, value, &length)) {
1810     length = value->IsArray() ? value.As<v8::Array>()->Length() : length;
1811     return std::make_unique<ObjectMirror>(
1812         value, RemoteObject::SubtypeEnum::Array,
1813         descriptionForCollection(isolate, value.As<v8::Object>(), length));
1814   }
1815   if (value->IsObject()) {
1816     return std::make_unique<ObjectMirror>(
1817         value, descriptionForObject(isolate, value.As<v8::Object>()));
1818   }
1819   return nullptr;
1820 }
1821 }  // namespace v8_inspector
1822