• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "src/inspector/injected-script.h"
32 
33 #include <cmath>
34 #include <unordered_set>
35 
36 #include "../../third_party/inspector_protocol/crdtp/json.h"
37 #include "include/v8-inspector.h"
38 #include "src/debug/debug-interface.h"
39 #include "src/inspector/custom-preview.h"
40 #include "src/inspector/inspected-context.h"
41 #include "src/inspector/protocol/Protocol.h"
42 #include "src/inspector/remote-object-id.h"
43 #include "src/inspector/string-util.h"
44 #include "src/inspector/v8-console.h"
45 #include "src/inspector/v8-inspector-impl.h"
46 #include "src/inspector/v8-inspector-session-impl.h"
47 #include "src/inspector/v8-stack-trace-impl.h"
48 #include "src/inspector/v8-value-utils.h"
49 #include "src/inspector/value-mirror.h"
50 
51 namespace v8_inspector {
52 
53 namespace {
54 const char kGlobalHandleLabel[] = "DevTools console";
isResolvableNumberLike(String16 query)55 bool isResolvableNumberLike(String16 query) {
56   return query == "Infinity" || query == "-Infinity" || query == "NaN";
57 }
58 }  // namespace
59 
60 using protocol::Array;
61 using protocol::Maybe;
62 using protocol::Runtime::InternalPropertyDescriptor;
63 using protocol::Runtime::PrivatePropertyDescriptor;
64 using protocol::Runtime::PropertyDescriptor;
65 using protocol::Runtime::RemoteObject;
66 
67 class InjectedScript::ProtocolPromiseHandler {
68  public:
add(V8InspectorSessionImpl * session,v8::Local<v8::Context> context,v8::Local<v8::Value> value,int executionContextId,const String16 & objectGroup,WrapMode wrapMode,bool replMode,EvaluateCallback * callback)69   static bool add(V8InspectorSessionImpl* session,
70                   v8::Local<v8::Context> context, v8::Local<v8::Value> value,
71                   int executionContextId, const String16& objectGroup,
72                   WrapMode wrapMode, bool replMode,
73                   EvaluateCallback* callback) {
74     v8::Local<v8::Promise::Resolver> resolver;
75     if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) {
76       callback->sendFailure(Response::InternalError());
77       return false;
78     }
79     if (!resolver->Resolve(context, value).FromMaybe(false)) {
80       callback->sendFailure(Response::InternalError());
81       return false;
82     }
83 
84     v8::MaybeLocal<v8::Promise> originalPromise =
85         value->IsPromise() ? v8::Local<v8::Promise>::Cast(value)
86                            : v8::MaybeLocal<v8::Promise>();
87     V8InspectorImpl* inspector = session->inspector();
88     ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(
89         session, executionContextId, objectGroup, wrapMode, replMode, callback,
90         originalPromise);
91     v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
92     v8::Local<v8::Function> thenCallbackFunction =
93         v8::Function::New(context, thenCallback, wrapper, 0,
94                           v8::ConstructorBehavior::kThrow)
95             .ToLocalChecked();
96     v8::Local<v8::Function> catchCallbackFunction =
97         v8::Function::New(context, catchCallback, wrapper, 0,
98                           v8::ConstructorBehavior::kThrow)
99             .ToLocalChecked();
100     v8::Local<v8::Promise> promise = resolver->GetPromise();
101     if (promise->Then(context, thenCallbackFunction, catchCallbackFunction)
102             .IsEmpty()) {
103       callback->sendFailure(Response::InternalError());
104       return false;
105     }
106     return true;
107   }
108 
109  private:
GetDotReplResultString(v8::Isolate * isolate)110   static v8::Local<v8::String> GetDotReplResultString(v8::Isolate* isolate) {
111     // TODO(szuend): Cache the string in a v8::Persistent handle.
112     return v8::String::NewFromOneByte(
113                isolate, reinterpret_cast<const uint8_t*>(".repl_result"))
114         .ToLocalChecked();
115   }
116 
thenCallback(const v8::FunctionCallbackInfo<v8::Value> & info)117   static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
118     ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
119         info.Data().As<v8::External>()->Value());
120     DCHECK(handler);
121     v8::Local<v8::Value> value =
122         info.Length() > 0
123             ? info[0]
124             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
125     handler->thenCallback(value);
126     delete handler;
127   }
128 
catchCallback(const v8::FunctionCallbackInfo<v8::Value> & info)129   static void catchCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
130     ProtocolPromiseHandler* handler = static_cast<ProtocolPromiseHandler*>(
131         info.Data().As<v8::External>()->Value());
132     DCHECK(handler);
133     v8::Local<v8::Value> value =
134         info.Length() > 0
135             ? info[0]
136             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
137     handler->catchCallback(value);
138     delete handler;
139   }
140 
ProtocolPromiseHandler(V8InspectorSessionImpl * session,int executionContextId,const String16 & objectGroup,WrapMode wrapMode,bool replMode,EvaluateCallback * callback,v8::MaybeLocal<v8::Promise> maybeEvaluationResult)141   ProtocolPromiseHandler(V8InspectorSessionImpl* session,
142                          int executionContextId, const String16& objectGroup,
143                          WrapMode wrapMode, bool replMode,
144                          EvaluateCallback* callback,
145                          v8::MaybeLocal<v8::Promise> maybeEvaluationResult)
146       : m_inspector(session->inspector()),
147         m_sessionId(session->sessionId()),
148         m_contextGroupId(session->contextGroupId()),
149         m_executionContextId(executionContextId),
150         m_objectGroup(objectGroup),
151         m_wrapMode(wrapMode),
152         m_replMode(replMode),
153         m_callback(std::move(callback)),
154         m_wrapper(m_inspector->isolate(),
155                   v8::External::New(m_inspector->isolate(), this)) {
156     m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter);
157     v8::Local<v8::Promise> promise;
158     if (maybeEvaluationResult.ToLocal(&promise)) {
159       m_evaluationResult =
160           v8::Global<v8::Promise>(m_inspector->isolate(), promise);
161     }
162   }
163 
cleanup(const v8::WeakCallbackInfo<ProtocolPromiseHandler> & data)164   static void cleanup(
165       const v8::WeakCallbackInfo<ProtocolPromiseHandler>& data) {
166     if (!data.GetParameter()->m_wrapper.IsEmpty()) {
167       data.GetParameter()->m_wrapper.Reset();
168       data.GetParameter()->m_evaluationResult.Reset();
169       data.SetSecondPassCallback(cleanup);
170     } else {
171       data.GetParameter()->sendPromiseCollected();
172       delete data.GetParameter();
173     }
174   }
175 
thenCallback(v8::Local<v8::Value> value)176   void thenCallback(v8::Local<v8::Value> value) {
177     V8InspectorSessionImpl* session =
178         m_inspector->sessionById(m_contextGroupId, m_sessionId);
179     if (!session) return;
180     InjectedScript::ContextScope scope(session, m_executionContextId);
181     Response response = scope.initialize();
182     if (!response.IsSuccess()) return;
183 
184     std::unique_ptr<EvaluateCallback> callback =
185         scope.injectedScript()->takeEvaluateCallback(m_callback);
186     if (!callback) return;
187 
188     // In REPL mode the result is additionally wrapped in an object.
189     // The evaluation result can be found at ".repl_result".
190     v8::Local<v8::Value> result = value;
191     if (m_replMode) {
192       v8::Local<v8::Object> object;
193       if (!result->ToObject(scope.context()).ToLocal(&object)) {
194         callback->sendFailure(response);
195         return;
196       }
197 
198       v8::Local<v8::String> name =
199           GetDotReplResultString(m_inspector->isolate());
200       if (!object->Get(scope.context(), name).ToLocal(&result)) {
201         callback->sendFailure(response);
202         return;
203       }
204     }
205 
206     if (m_objectGroup == "console") {
207       scope.injectedScript()->setLastEvaluationResult(result);
208     }
209 
210     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
211     response = scope.injectedScript()->wrapObject(result, m_objectGroup,
212                                                   m_wrapMode, &wrappedValue);
213     if (!response.IsSuccess()) {
214       callback->sendFailure(response);
215       return;
216     }
217     callback->sendSuccess(std::move(wrappedValue),
218                           Maybe<protocol::Runtime::ExceptionDetails>());
219   }
220 
catchCallback(v8::Local<v8::Value> result)221   void catchCallback(v8::Local<v8::Value> result) {
222     V8InspectorSessionImpl* session =
223         m_inspector->sessionById(m_contextGroupId, m_sessionId);
224     if (!session) return;
225     InjectedScript::ContextScope scope(session, m_executionContextId);
226     Response response = scope.initialize();
227     if (!response.IsSuccess()) return;
228     std::unique_ptr<EvaluateCallback> callback =
229         scope.injectedScript()->takeEvaluateCallback(m_callback);
230     if (!callback) return;
231     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
232     response = scope.injectedScript()->wrapObject(result, m_objectGroup,
233                                                   m_wrapMode, &wrappedValue);
234     if (!response.IsSuccess()) {
235       callback->sendFailure(response);
236       return;
237     }
238     v8::Isolate* isolate = session->inspector()->isolate();
239 
240     v8::MaybeLocal<v8::Message> maybeMessage =
241         m_evaluationResult.IsEmpty()
242             ? v8::MaybeLocal<v8::Message>()
243             : v8::debug::GetMessageFromPromise(m_evaluationResult.Get(isolate));
244     v8::Local<v8::Message> message;
245     // In case a MessageObject was attached to the rejected promise, we
246     // construct the exception details from the message object. Otherwise
247     // we try to capture a fresh stack trace.
248     if (maybeMessage.ToLocal(&message)) {
249       v8::Local<v8::Value> exception = result;
250       protocol::PtrMaybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
251       response = scope.injectedScript()->createExceptionDetails(
252           message, exception, m_objectGroup, &exceptionDetails);
253       if (!response.IsSuccess()) {
254         callback->sendFailure(response);
255         return;
256       }
257 
258       callback->sendSuccess(std::move(wrappedValue),
259                             std::move(exceptionDetails));
260       return;
261     }
262 
263     String16 messageString;
264     std::unique_ptr<V8StackTraceImpl> stack;
265     if (result->IsNativeError()) {
266       messageString =
267           " " +
268           toProtocolString(isolate,
269                            result->ToDetailString(isolate->GetCurrentContext())
270                                .ToLocalChecked());
271       v8::Local<v8::StackTrace> stackTrace = v8::debug::GetDetailedStackTrace(
272           isolate, v8::Local<v8::Object>::Cast(result));
273       if (!stackTrace.IsEmpty()) {
274         stack = m_inspector->debugger()->createStackTrace(stackTrace);
275       }
276     }
277     if (!stack) {
278       stack = m_inspector->debugger()->captureStackTrace(true);
279     }
280 
281     // REPL mode implicitly handles the script like an async function.
282     // Do not prepend the '(in promise)' prefix for these exceptions since that
283     // would be confusing for the user. The stringified error is part of the
284     // exception and does not need to be added in REPL mode, otherwise it would
285     // be printed twice.
286     String16 exceptionDetailsText =
287         m_replMode ? "Uncaught" : "Uncaught (in promise)" + messageString;
288     std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
289         protocol::Runtime::ExceptionDetails::create()
290             .setExceptionId(m_inspector->nextExceptionId())
291             .setText(exceptionDetailsText)
292             .setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber()
293                                                       : 0)
294             .setColumnNumber(
295                 stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
296             .build();
297     response = scope.injectedScript()->addExceptionToDetails(
298         result, exceptionDetails.get(), m_objectGroup);
299     if (!response.IsSuccess()) {
300       callback->sendFailure(response);
301       return;
302     }
303     if (stack)
304       exceptionDetails->setStackTrace(
305           stack->buildInspectorObjectImpl(m_inspector->debugger()));
306     if (stack && !stack->isEmpty())
307       exceptionDetails->setScriptId(toString16(stack->topScriptId()));
308     callback->sendSuccess(std::move(wrappedValue), std::move(exceptionDetails));
309   }
310 
sendPromiseCollected()311   void sendPromiseCollected() {
312     V8InspectorSessionImpl* session =
313         m_inspector->sessionById(m_contextGroupId, m_sessionId);
314     if (!session) return;
315     InjectedScript::ContextScope scope(session, m_executionContextId);
316     Response response = scope.initialize();
317     if (!response.IsSuccess()) return;
318     std::unique_ptr<EvaluateCallback> callback =
319         scope.injectedScript()->takeEvaluateCallback(m_callback);
320     if (!callback) return;
321     callback->sendFailure(Response::ServerError("Promise was collected"));
322   }
323 
324   V8InspectorImpl* m_inspector;
325   int m_sessionId;
326   int m_contextGroupId;
327   int m_executionContextId;
328   String16 m_objectGroup;
329   WrapMode m_wrapMode;
330   bool m_replMode;
331   EvaluateCallback* m_callback;
332   v8::Global<v8::External> m_wrapper;
333   v8::Global<v8::Promise> m_evaluationResult;
334 };
335 
InjectedScript(InspectedContext * context,int sessionId)336 InjectedScript::InjectedScript(InspectedContext* context, int sessionId)
337     : m_context(context), m_sessionId(sessionId) {}
338 
~InjectedScript()339 InjectedScript::~InjectedScript() { discardEvaluateCallbacks(); }
340 
341 namespace {
342 class PropertyAccumulator : public ValueMirror::PropertyAccumulator {
343  public:
PropertyAccumulator(std::vector<PropertyMirror> * mirrors)344   explicit PropertyAccumulator(std::vector<PropertyMirror>* mirrors)
345       : m_mirrors(mirrors) {}
Add(PropertyMirror mirror)346   bool Add(PropertyMirror mirror) override {
347     m_mirrors->push_back(std::move(mirror));
348     return true;
349   }
350 
351  private:
352   std::vector<PropertyMirror>* m_mirrors;
353 };
354 }  // anonymous namespace
355 
getProperties(v8::Local<v8::Object> object,const String16 & groupName,bool ownProperties,bool accessorPropertiesOnly,WrapMode wrapMode,std::unique_ptr<Array<PropertyDescriptor>> * properties,Maybe<protocol::Runtime::ExceptionDetails> * exceptionDetails)356 Response InjectedScript::getProperties(
357     v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
358     bool accessorPropertiesOnly, WrapMode wrapMode,
359     std::unique_ptr<Array<PropertyDescriptor>>* properties,
360     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
361   v8::HandleScope handles(m_context->isolate());
362   v8::Local<v8::Context> context = m_context->context();
363   v8::Isolate* isolate = m_context->isolate();
364   int sessionId = m_sessionId;
365   v8::TryCatch tryCatch(isolate);
366 
367   *properties = std::make_unique<Array<PropertyDescriptor>>();
368   std::vector<PropertyMirror> mirrors;
369   PropertyAccumulator accumulator(&mirrors);
370   if (!ValueMirror::getProperties(context, object, ownProperties,
371                                   accessorPropertiesOnly, &accumulator)) {
372     return createExceptionDetails(tryCatch, groupName, exceptionDetails);
373   }
374   for (const PropertyMirror& mirror : mirrors) {
375     std::unique_ptr<PropertyDescriptor> descriptor =
376         PropertyDescriptor::create()
377             .setName(mirror.name)
378             .setConfigurable(mirror.configurable)
379             .setEnumerable(mirror.enumerable)
380             .setIsOwn(mirror.isOwn)
381             .build();
382     std::unique_ptr<RemoteObject> remoteObject;
383     if (mirror.value) {
384       Response response = wrapObjectMirror(
385           *mirror.value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(),
386           kMaxCustomPreviewDepth, &remoteObject);
387       if (!response.IsSuccess()) return response;
388       descriptor->setValue(std::move(remoteObject));
389       descriptor->setWritable(mirror.writable);
390     }
391     if (mirror.getter) {
392       Response response =
393           mirror.getter->buildRemoteObject(context, wrapMode, &remoteObject);
394       if (!response.IsSuccess()) return response;
395       response =
396           bindRemoteObjectIfNeeded(sessionId, context, mirror.getter->v8Value(),
397                                    groupName, remoteObject.get());
398       if (!response.IsSuccess()) return response;
399       descriptor->setGet(std::move(remoteObject));
400     }
401     if (mirror.setter) {
402       Response response =
403           mirror.setter->buildRemoteObject(context, wrapMode, &remoteObject);
404       if (!response.IsSuccess()) return response;
405       response =
406           bindRemoteObjectIfNeeded(sessionId, context, mirror.setter->v8Value(),
407                                    groupName, remoteObject.get());
408       if (!response.IsSuccess()) return response;
409       descriptor->setSet(std::move(remoteObject));
410     }
411     if (mirror.symbol) {
412       Response response =
413           mirror.symbol->buildRemoteObject(context, wrapMode, &remoteObject);
414       if (!response.IsSuccess()) return response;
415       response =
416           bindRemoteObjectIfNeeded(sessionId, context, mirror.symbol->v8Value(),
417                                    groupName, remoteObject.get());
418       if (!response.IsSuccess()) return response;
419       descriptor->setSymbol(std::move(remoteObject));
420     }
421     if (mirror.exception) {
422       Response response =
423           mirror.exception->buildRemoteObject(context, wrapMode, &remoteObject);
424       if (!response.IsSuccess()) return response;
425       response = bindRemoteObjectIfNeeded(sessionId, context,
426                                           mirror.exception->v8Value(),
427                                           groupName, remoteObject.get());
428       if (!response.IsSuccess()) return response;
429       descriptor->setValue(std::move(remoteObject));
430       descriptor->setWasThrown(true);
431     }
432     (*properties)->emplace_back(std::move(descriptor));
433   }
434   return Response::Success();
435 }
436 
getInternalAndPrivateProperties(v8::Local<v8::Value> value,const String16 & groupName,std::unique_ptr<protocol::Array<InternalPropertyDescriptor>> * internalProperties,std::unique_ptr<protocol::Array<PrivatePropertyDescriptor>> * privateProperties)437 Response InjectedScript::getInternalAndPrivateProperties(
438     v8::Local<v8::Value> value, const String16& groupName,
439     std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>*
440         internalProperties,
441     std::unique_ptr<protocol::Array<PrivatePropertyDescriptor>>*
442         privateProperties) {
443   *internalProperties = std::make_unique<Array<InternalPropertyDescriptor>>();
444   *privateProperties = std::make_unique<Array<PrivatePropertyDescriptor>>();
445 
446   if (!value->IsObject()) return Response::Success();
447 
448   v8::Local<v8::Object> value_obj = value.As<v8::Object>();
449 
450   v8::Local<v8::Context> context = m_context->context();
451   int sessionId = m_sessionId;
452   std::vector<InternalPropertyMirror> internalPropertiesWrappers;
453   ValueMirror::getInternalProperties(m_context->context(), value_obj,
454                                      &internalPropertiesWrappers);
455   for (const auto& internalProperty : internalPropertiesWrappers) {
456     std::unique_ptr<RemoteObject> remoteObject;
457     Response response = internalProperty.value->buildRemoteObject(
458         m_context->context(), WrapMode::kNoPreview, &remoteObject);
459     if (!response.IsSuccess()) return response;
460     response = bindRemoteObjectIfNeeded(sessionId, context,
461                                         internalProperty.value->v8Value(),
462                                         groupName, remoteObject.get());
463     if (!response.IsSuccess()) return response;
464     (*internalProperties)
465         ->emplace_back(InternalPropertyDescriptor::create()
466                            .setName(internalProperty.name)
467                            .setValue(std::move(remoteObject))
468                            .build());
469   }
470 
471   std::vector<PrivatePropertyMirror> privatePropertyWrappers =
472       ValueMirror::getPrivateProperties(context, value_obj);
473   for (const auto& privateProperty : privatePropertyWrappers) {
474     std::unique_ptr<PrivatePropertyDescriptor> descriptor =
475         PrivatePropertyDescriptor::create()
476             .setName(privateProperty.name)
477             .build();
478 
479     std::unique_ptr<RemoteObject> remoteObject;
480     DCHECK((privateProperty.getter || privateProperty.setter) ^
481            (!!privateProperty.value));
482     if (privateProperty.value) {
483       Response response = privateProperty.value->buildRemoteObject(
484           context, WrapMode::kNoPreview, &remoteObject);
485       if (!response.IsSuccess()) return response;
486       response = bindRemoteObjectIfNeeded(sessionId, context,
487                                           privateProperty.value->v8Value(),
488                                           groupName, remoteObject.get());
489       if (!response.IsSuccess()) return response;
490       descriptor->setValue(std::move(remoteObject));
491     }
492 
493     if (privateProperty.getter) {
494       Response response = privateProperty.getter->buildRemoteObject(
495           context, WrapMode::kNoPreview, &remoteObject);
496       if (!response.IsSuccess()) return response;
497       response = bindRemoteObjectIfNeeded(sessionId, context,
498                                           privateProperty.getter->v8Value(),
499                                           groupName, remoteObject.get());
500       if (!response.IsSuccess()) return response;
501       descriptor->setGet(std::move(remoteObject));
502     }
503 
504     if (privateProperty.setter) {
505       Response response = privateProperty.setter->buildRemoteObject(
506           context, WrapMode::kNoPreview, &remoteObject);
507       if (!response.IsSuccess()) return response;
508       response = bindRemoteObjectIfNeeded(sessionId, context,
509                                           privateProperty.setter->v8Value(),
510                                           groupName, remoteObject.get());
511       if (!response.IsSuccess()) return response;
512       descriptor->setSet(std::move(remoteObject));
513     }
514 
515     (*privateProperties)->emplace_back(std::move(descriptor));
516   }
517   return Response::Success();
518 }
519 
releaseObject(const String16 & objectId)520 void InjectedScript::releaseObject(const String16& objectId) {
521   std::unique_ptr<RemoteObjectId> remoteId;
522   Response response = RemoteObjectId::parse(objectId, &remoteId);
523   if (response.IsSuccess()) unbindObject(remoteId->id());
524 }
525 
wrapObject(v8::Local<v8::Value> value,const String16 & groupName,WrapMode wrapMode,std::unique_ptr<protocol::Runtime::RemoteObject> * result)526 Response InjectedScript::wrapObject(
527     v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
528     std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
529   return wrapObject(value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(),
530                     kMaxCustomPreviewDepth, result);
531 }
532 
wrapObject(v8::Local<v8::Value> value,const String16 & groupName,WrapMode wrapMode,v8::MaybeLocal<v8::Value> customPreviewConfig,int maxCustomPreviewDepth,std::unique_ptr<protocol::Runtime::RemoteObject> * result)533 Response InjectedScript::wrapObject(
534     v8::Local<v8::Value> value, const String16& groupName, WrapMode wrapMode,
535     v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
536     std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
537   v8::Local<v8::Context> context = m_context->context();
538   v8::Context::Scope contextScope(context);
539   std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);
540   if (!mirror) return Response::InternalError();
541   return wrapObjectMirror(*mirror, groupName, wrapMode, customPreviewConfig,
542                           maxCustomPreviewDepth, result);
543 }
544 
wrapObjectMirror(const ValueMirror & mirror,const String16 & groupName,WrapMode wrapMode,v8::MaybeLocal<v8::Value> customPreviewConfig,int maxCustomPreviewDepth,std::unique_ptr<protocol::Runtime::RemoteObject> * result)545 Response InjectedScript::wrapObjectMirror(
546     const ValueMirror& mirror, const String16& groupName, WrapMode wrapMode,
547     v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
548     std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
549   int customPreviewEnabled = m_customPreviewEnabled;
550   int sessionId = m_sessionId;
551   v8::Local<v8::Context> context = m_context->context();
552   v8::Context::Scope contextScope(context);
553   Response response = mirror.buildRemoteObject(context, wrapMode, result);
554   if (!response.IsSuccess()) return response;
555   v8::Local<v8::Value> value = mirror.v8Value();
556   response = bindRemoteObjectIfNeeded(sessionId, context, value, groupName,
557                                       result->get());
558   if (!response.IsSuccess()) return response;
559   if (customPreviewEnabled && value->IsObject()) {
560     std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
561     generateCustomPreview(sessionId, groupName, value.As<v8::Object>(),
562                           customPreviewConfig, maxCustomPreviewDepth,
563                           &customPreview);
564     if (customPreview) (*result)->setCustomPreview(std::move(customPreview));
565   }
566   return Response::Success();
567 }
568 
wrapTable(v8::Local<v8::Object> table,v8::MaybeLocal<v8::Array> maybeColumns)569 std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
570     v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> maybeColumns) {
571   using protocol::Runtime::RemoteObject;
572   using protocol::Runtime::ObjectPreview;
573   using protocol::Runtime::PropertyPreview;
574   using protocol::Array;
575 
576   v8::Isolate* isolate = m_context->isolate();
577   v8::HandleScope handles(isolate);
578   v8::Local<v8::Context> context = m_context->context();
579 
580   std::unique_ptr<RemoteObject> remoteObject;
581   Response response =
582       wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject);
583   if (!remoteObject || !response.IsSuccess()) return nullptr;
584 
585   auto mirror = ValueMirror::create(context, table);
586   std::unique_ptr<ObjectPreview> preview;
587   int limit = 1000;
588   mirror->buildObjectPreview(context, true /* generatePreviewForTable */,
589                              &limit, &limit, &preview);
590   if (!preview) return nullptr;
591 
592   std::vector<String16> selectedColumns;
593   std::unordered_set<String16> columnSet;
594   v8::Local<v8::Array> v8Columns;
595   if (maybeColumns.ToLocal(&v8Columns)) {
596     for (uint32_t i = 0; i < v8Columns->Length(); ++i) {
597       v8::Local<v8::Value> column;
598       if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) {
599         String16 name = toProtocolString(isolate, column.As<v8::String>());
600         if (columnSet.find(name) == columnSet.end()) {
601           columnSet.insert(name);
602           selectedColumns.push_back(name);
603         }
604       }
605     }
606   }
607   if (!selectedColumns.empty()) {
608     for (const std::unique_ptr<PropertyPreview>& column :
609          *preview->getProperties()) {
610       ObjectPreview* columnPreview = column->getValuePreview(nullptr);
611       if (!columnPreview) continue;
612       // Use raw pointer here since the lifetime of each PropertyPreview is
613       // ensured by columnPreview. This saves an additional clone.
614       std::unordered_map<String16, PropertyPreview*> columnMap;
615       for (const std::unique_ptr<PropertyPreview>& property :
616            *columnPreview->getProperties()) {
617         if (columnSet.find(property->getName()) == columnSet.end()) continue;
618         columnMap[property->getName()] = property.get();
619       }
620       auto filtered = std::make_unique<Array<PropertyPreview>>();
621       for (const String16& column : selectedColumns) {
622         if (columnMap.find(column) == columnMap.end()) continue;
623         filtered->push_back(columnMap[column]->clone());
624       }
625       columnPreview->setProperties(std::move(filtered));
626     }
627   }
628   remoteObject->setPreview(std::move(preview));
629   return remoteObject;
630 }
631 
addPromiseCallback(V8InspectorSessionImpl * session,v8::MaybeLocal<v8::Value> value,const String16 & objectGroup,WrapMode wrapMode,bool replMode,std::unique_ptr<EvaluateCallback> callback)632 void InjectedScript::addPromiseCallback(
633     V8InspectorSessionImpl* session, v8::MaybeLocal<v8::Value> value,
634     const String16& objectGroup, WrapMode wrapMode, bool replMode,
635     std::unique_ptr<EvaluateCallback> callback) {
636   if (value.IsEmpty()) {
637     callback->sendFailure(Response::InternalError());
638     return;
639   }
640   v8::MicrotasksScope microtasksScope(m_context->isolate(),
641                                       v8::MicrotasksScope::kRunMicrotasks);
642   if (ProtocolPromiseHandler::add(session, m_context->context(),
643                                   value.ToLocalChecked(),
644                                   m_context->contextId(), objectGroup, wrapMode,
645                                   replMode, callback.get())) {
646     m_evaluateCallbacks.insert(callback.release());
647   }
648 }
649 
discardEvaluateCallbacks()650 void InjectedScript::discardEvaluateCallbacks() {
651   for (auto& callback : m_evaluateCallbacks) {
652     callback->sendFailure(
653         Response::ServerError("Execution context was destroyed."));
654     delete callback;
655   }
656   m_evaluateCallbacks.clear();
657 }
658 
takeEvaluateCallback(EvaluateCallback * callback)659 std::unique_ptr<EvaluateCallback> InjectedScript::takeEvaluateCallback(
660     EvaluateCallback* callback) {
661   auto it = m_evaluateCallbacks.find(callback);
662   if (it == m_evaluateCallbacks.end()) return nullptr;
663   std::unique_ptr<EvaluateCallback> value(*it);
664   m_evaluateCallbacks.erase(it);
665   return value;
666 }
667 
findObject(const RemoteObjectId & objectId,v8::Local<v8::Value> * outObject) const668 Response InjectedScript::findObject(const RemoteObjectId& objectId,
669                                     v8::Local<v8::Value>* outObject) const {
670   auto it = m_idToWrappedObject.find(objectId.id());
671   if (it == m_idToWrappedObject.end())
672     return Response::ServerError("Could not find object with given id");
673   *outObject = it->second.Get(m_context->isolate());
674   return Response::Success();
675 }
676 
objectGroupName(const RemoteObjectId & objectId) const677 String16 InjectedScript::objectGroupName(const RemoteObjectId& objectId) const {
678   if (objectId.id() <= 0) return String16();
679   auto it = m_idToObjectGroupName.find(objectId.id());
680   return it != m_idToObjectGroupName.end() ? it->second : String16();
681 }
682 
releaseObjectGroup(const String16 & objectGroup)683 void InjectedScript::releaseObjectGroup(const String16& objectGroup) {
684   if (objectGroup == "console") m_lastEvaluationResult.Reset();
685   if (objectGroup.isEmpty()) return;
686   auto it = m_nameToObjectGroup.find(objectGroup);
687   if (it == m_nameToObjectGroup.end()) return;
688   for (int id : it->second) unbindObject(id);
689   m_nameToObjectGroup.erase(it);
690 }
691 
setCustomObjectFormatterEnabled(bool enabled)692 void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) {
693   m_customPreviewEnabled = enabled;
694 }
695 
lastEvaluationResult() const696 v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
697   if (m_lastEvaluationResult.IsEmpty())
698     return v8::Undefined(m_context->isolate());
699   return m_lastEvaluationResult.Get(m_context->isolate());
700 }
701 
setLastEvaluationResult(v8::Local<v8::Value> result)702 void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) {
703   m_lastEvaluationResult.Reset(m_context->isolate(), result);
704   m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
705 }
706 
resolveCallArgument(protocol::Runtime::CallArgument * callArgument,v8::Local<v8::Value> * result)707 Response InjectedScript::resolveCallArgument(
708     protocol::Runtime::CallArgument* callArgument,
709     v8::Local<v8::Value>* result) {
710   if (callArgument->hasObjectId()) {
711     std::unique_ptr<RemoteObjectId> remoteObjectId;
712     Response response =
713         RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId);
714     if (!response.IsSuccess()) return response;
715     if (remoteObjectId->contextId() != m_context->contextId() ||
716         remoteObjectId->isolateId() != m_context->inspector()->isolateId()) {
717       return Response::ServerError(
718           "Argument should belong to the same JavaScript world as target "
719           "object");
720     }
721     return findObject(*remoteObjectId, result);
722   }
723   if (callArgument->hasValue() || callArgument->hasUnserializableValue()) {
724     String16 value;
725     if (callArgument->hasValue()) {
726       std::vector<uint8_t> json;
727       v8_crdtp::json::ConvertCBORToJSON(
728           v8_crdtp::SpanFrom(callArgument->getValue(nullptr)->Serialize()),
729           &json);
730       value =
731           "(" +
732           String16(reinterpret_cast<const char*>(json.data()), json.size()) +
733           ")";
734     } else {
735       String16 unserializableValue = callArgument->getUnserializableValue("");
736       // Protect against potential identifier resolution for NaN and Infinity.
737       if (isResolvableNumberLike(unserializableValue))
738         value = "Number(\"" + unserializableValue + "\")";
739       else
740         value = unserializableValue;
741     }
742     if (!m_context->inspector()
743              ->compileAndRunInternalScript(
744                  m_context->context(), toV8String(m_context->isolate(), value))
745              .ToLocal(result)) {
746       return Response::ServerError(
747           "Couldn't parse value object in call argument");
748     }
749     return Response::Success();
750   }
751   *result = v8::Undefined(m_context->isolate());
752   return Response::Success();
753 }
754 
addExceptionToDetails(v8::Local<v8::Value> exception,protocol::Runtime::ExceptionDetails * exceptionDetails,const String16 & objectGroup)755 Response InjectedScript::addExceptionToDetails(
756     v8::Local<v8::Value> exception,
757     protocol::Runtime::ExceptionDetails* exceptionDetails,
758     const String16& objectGroup) {
759   if (exception.IsEmpty()) return Response::Success();
760   std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
761   Response response =
762       wrapObject(exception, objectGroup,
763                  exception->IsNativeError() ? WrapMode::kNoPreview
764                                             : WrapMode::kWithPreview,
765                  &wrapped);
766   if (!response.IsSuccess()) return response;
767   exceptionDetails->setException(std::move(wrapped));
768   return Response::Success();
769 }
770 
createExceptionDetails(const v8::TryCatch & tryCatch,const String16 & objectGroup,Maybe<protocol::Runtime::ExceptionDetails> * result)771 Response InjectedScript::createExceptionDetails(
772     const v8::TryCatch& tryCatch, const String16& objectGroup,
773     Maybe<protocol::Runtime::ExceptionDetails>* result) {
774   if (!tryCatch.HasCaught()) return Response::InternalError();
775   v8::Local<v8::Message> message = tryCatch.Message();
776   v8::Local<v8::Value> exception = tryCatch.Exception();
777   return createExceptionDetails(message, exception, objectGroup, result);
778 }
779 
createExceptionDetails(v8::Local<v8::Message> message,v8::Local<v8::Value> exception,const String16 & objectGroup,Maybe<protocol::Runtime::ExceptionDetails> * result)780 Response InjectedScript::createExceptionDetails(
781     v8::Local<v8::Message> message, v8::Local<v8::Value> exception,
782     const String16& objectGroup,
783     Maybe<protocol::Runtime::ExceptionDetails>* result) {
784   String16 messageText =
785       message.IsEmpty()
786           ? String16()
787           : toProtocolString(m_context->isolate(), message->Get());
788   std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
789       protocol::Runtime::ExceptionDetails::create()
790           .setExceptionId(m_context->inspector()->nextExceptionId())
791           .setText(exception.IsEmpty() ? messageText : String16("Uncaught"))
792           .setLineNumber(
793               message.IsEmpty()
794                   ? 0
795                   : message->GetLineNumber(m_context->context()).FromMaybe(1) -
796                         1)
797           .setColumnNumber(
798               message.IsEmpty()
799                   ? 0
800                   : message->GetStartColumn(m_context->context()).FromMaybe(0))
801           .build();
802   if (!message.IsEmpty()) {
803     exceptionDetails->setScriptId(String16::fromInteger(
804         static_cast<int>(message->GetScriptOrigin().ScriptID()->Value())));
805     v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
806     if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
807       exceptionDetails->setStackTrace(
808           m_context->inspector()
809               ->debugger()
810               ->createStackTrace(stackTrace)
811               ->buildInspectorObjectImpl(m_context->inspector()->debugger()));
812   }
813   Response response =
814       addExceptionToDetails(exception, exceptionDetails.get(), objectGroup);
815   if (!response.IsSuccess()) return response;
816   *result = std::move(exceptionDetails);
817   return Response::Success();
818 }
819 
wrapEvaluateResult(v8::MaybeLocal<v8::Value> maybeResultValue,const v8::TryCatch & tryCatch,const String16 & objectGroup,WrapMode wrapMode,std::unique_ptr<protocol::Runtime::RemoteObject> * result,Maybe<protocol::Runtime::ExceptionDetails> * exceptionDetails)820 Response InjectedScript::wrapEvaluateResult(
821     v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch& tryCatch,
822     const String16& objectGroup, WrapMode wrapMode,
823     std::unique_ptr<protocol::Runtime::RemoteObject>* result,
824     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
825   v8::Local<v8::Value> resultValue;
826   if (!tryCatch.HasCaught()) {
827     if (!maybeResultValue.ToLocal(&resultValue))
828       return Response::InternalError();
829     Response response = wrapObject(resultValue, objectGroup, wrapMode, result);
830     if (!response.IsSuccess()) return response;
831     if (objectGroup == "console") {
832       m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
833       m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
834     }
835   } else {
836     if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) {
837       return Response::ServerError("Execution was terminated");
838     }
839     v8::Local<v8::Value> exception = tryCatch.Exception();
840     Response response =
841         wrapObject(exception, objectGroup,
842                    exception->IsNativeError() ? WrapMode::kNoPreview
843                                               : WrapMode::kWithPreview,
844                    result);
845     if (!response.IsSuccess()) return response;
846     // We send exception in result for compatibility reasons, even though it's
847     // accessible through exceptionDetails.exception.
848     response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails);
849     if (!response.IsSuccess()) return response;
850   }
851   return Response::Success();
852 }
853 
commandLineAPI()854 v8::Local<v8::Object> InjectedScript::commandLineAPI() {
855   if (m_commandLineAPI.IsEmpty()) {
856     v8::debug::DisableBreakScope disable_break(m_context->isolate());
857     m_commandLineAPI.Reset(
858         m_context->isolate(),
859         m_context->inspector()->console()->createCommandLineAPI(
860             m_context->context(), m_sessionId));
861     m_commandLineAPI.AnnotateStrongRetainer(kGlobalHandleLabel);
862   }
863   return m_commandLineAPI.Get(m_context->isolate());
864 }
865 
Scope(V8InspectorSessionImpl * session)866 InjectedScript::Scope::Scope(V8InspectorSessionImpl* session)
867     : m_inspector(session->inspector()),
868       m_injectedScript(nullptr),
869       m_handleScope(m_inspector->isolate()),
870       m_tryCatch(m_inspector->isolate()),
871       m_ignoreExceptionsAndMuteConsole(false),
872       m_previousPauseOnExceptionsState(v8::debug::NoBreakOnException),
873       m_userGesture(false),
874       m_allowEval(false),
875       m_contextGroupId(session->contextGroupId()),
876       m_sessionId(session->sessionId()) {}
877 
initialize()878 Response InjectedScript::Scope::initialize() {
879   cleanup();
880   V8InspectorSessionImpl* session =
881       m_inspector->sessionById(m_contextGroupId, m_sessionId);
882   if (!session) return Response::InternalError();
883   Response response = findInjectedScript(session);
884   if (!response.IsSuccess()) return response;
885   m_context = m_injectedScript->context()->context();
886   m_context->Enter();
887   if (m_allowEval) m_context->AllowCodeGenerationFromStrings(true);
888   return Response::Success();
889 }
890 
installCommandLineAPI()891 void InjectedScript::Scope::installCommandLineAPI() {
892   DCHECK(m_injectedScript && !m_context.IsEmpty() &&
893          !m_commandLineAPIScope.get());
894   m_commandLineAPIScope.reset(new V8Console::CommandLineAPIScope(
895       m_context, m_injectedScript->commandLineAPI(), m_context->Global()));
896 }
897 
ignoreExceptionsAndMuteConsole()898 void InjectedScript::Scope::ignoreExceptionsAndMuteConsole() {
899   DCHECK(!m_ignoreExceptionsAndMuteConsole);
900   m_ignoreExceptionsAndMuteConsole = true;
901   m_inspector->client()->muteMetrics(m_contextGroupId);
902   m_inspector->muteExceptions(m_contextGroupId);
903   m_previousPauseOnExceptionsState =
904       setPauseOnExceptionsState(v8::debug::NoBreakOnException);
905 }
906 
setPauseOnExceptionsState(v8::debug::ExceptionBreakState newState)907 v8::debug::ExceptionBreakState InjectedScript::Scope::setPauseOnExceptionsState(
908     v8::debug::ExceptionBreakState newState) {
909   if (!m_inspector->debugger()->enabled()) return newState;
910   v8::debug::ExceptionBreakState presentState =
911       m_inspector->debugger()->getPauseOnExceptionsState();
912   if (presentState != newState)
913     m_inspector->debugger()->setPauseOnExceptionsState(newState);
914   return presentState;
915 }
916 
pretendUserGesture()917 void InjectedScript::Scope::pretendUserGesture() {
918   DCHECK(!m_userGesture);
919   m_userGesture = true;
920   m_inspector->client()->beginUserGesture();
921 }
922 
allowCodeGenerationFromStrings()923 void InjectedScript::Scope::allowCodeGenerationFromStrings() {
924   DCHECK(!m_allowEval);
925   if (m_context->IsCodeGenerationFromStringsAllowed()) return;
926   m_allowEval = true;
927   m_context->AllowCodeGenerationFromStrings(true);
928 }
929 
cleanup()930 void InjectedScript::Scope::cleanup() {
931   m_commandLineAPIScope.reset();
932   if (!m_context.IsEmpty()) {
933     if (m_allowEval) m_context->AllowCodeGenerationFromStrings(false);
934     m_context->Exit();
935     m_context.Clear();
936   }
937 }
938 
~Scope()939 InjectedScript::Scope::~Scope() {
940   if (m_ignoreExceptionsAndMuteConsole) {
941     setPauseOnExceptionsState(m_previousPauseOnExceptionsState);
942     m_inspector->client()->unmuteMetrics(m_contextGroupId);
943     m_inspector->unmuteExceptions(m_contextGroupId);
944   }
945   if (m_userGesture) m_inspector->client()->endUserGesture();
946   cleanup();
947 }
948 
ContextScope(V8InspectorSessionImpl * session,int executionContextId)949 InjectedScript::ContextScope::ContextScope(V8InspectorSessionImpl* session,
950                                            int executionContextId)
951     : InjectedScript::Scope(session),
952       m_executionContextId(executionContextId) {}
953 
954 InjectedScript::ContextScope::~ContextScope() = default;
955 
findInjectedScript(V8InspectorSessionImpl * session)956 Response InjectedScript::ContextScope::findInjectedScript(
957     V8InspectorSessionImpl* session) {
958   return session->findInjectedScript(m_executionContextId, m_injectedScript);
959 }
960 
ObjectScope(V8InspectorSessionImpl * session,const String16 & remoteObjectId)961 InjectedScript::ObjectScope::ObjectScope(V8InspectorSessionImpl* session,
962                                          const String16& remoteObjectId)
963     : InjectedScript::Scope(session), m_remoteObjectId(remoteObjectId) {}
964 
965 InjectedScript::ObjectScope::~ObjectScope() = default;
966 
findInjectedScript(V8InspectorSessionImpl * session)967 Response InjectedScript::ObjectScope::findInjectedScript(
968     V8InspectorSessionImpl* session) {
969   std::unique_ptr<RemoteObjectId> remoteId;
970   Response response = RemoteObjectId::parse(m_remoteObjectId, &remoteId);
971   if (!response.IsSuccess()) return response;
972   InjectedScript* injectedScript = nullptr;
973   response = session->findInjectedScript(remoteId.get(), injectedScript);
974   if (!response.IsSuccess()) return response;
975   m_objectGroupName = injectedScript->objectGroupName(*remoteId);
976   response = injectedScript->findObject(*remoteId, &m_object);
977   if (!response.IsSuccess()) return response;
978   m_injectedScript = injectedScript;
979   return Response::Success();
980 }
981 
CallFrameScope(V8InspectorSessionImpl * session,const String16 & remoteObjectId)982 InjectedScript::CallFrameScope::CallFrameScope(V8InspectorSessionImpl* session,
983                                                const String16& remoteObjectId)
984     : InjectedScript::Scope(session), m_remoteCallFrameId(remoteObjectId) {}
985 
986 InjectedScript::CallFrameScope::~CallFrameScope() = default;
987 
findInjectedScript(V8InspectorSessionImpl * session)988 Response InjectedScript::CallFrameScope::findInjectedScript(
989     V8InspectorSessionImpl* session) {
990   std::unique_ptr<RemoteCallFrameId> remoteId;
991   Response response = RemoteCallFrameId::parse(m_remoteCallFrameId, &remoteId);
992   if (!response.IsSuccess()) return response;
993   m_frameOrdinal = static_cast<size_t>(remoteId->frameOrdinal());
994   return session->findInjectedScript(remoteId.get(), m_injectedScript);
995 }
996 
bindObject(v8::Local<v8::Value> value,const String16 & groupName)997 String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
998                                     const String16& groupName) {
999   if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
1000   int id = m_lastBoundObjectId++;
1001   m_idToWrappedObject[id].Reset(m_context->isolate(), value);
1002   m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel);
1003   if (!groupName.isEmpty() && id > 0) {
1004     m_idToObjectGroupName[id] = groupName;
1005     m_nameToObjectGroup[groupName].push_back(id);
1006   }
1007   return RemoteObjectId::serialize(m_context->inspector()->isolateId(),
1008                                    m_context->contextId(), id);
1009 }
1010 
1011 // static
bindRemoteObjectIfNeeded(int sessionId,v8::Local<v8::Context> context,v8::Local<v8::Value> value,const String16 & groupName,protocol::Runtime::RemoteObject * remoteObject)1012 Response InjectedScript::bindRemoteObjectIfNeeded(
1013     int sessionId, v8::Local<v8::Context> context, v8::Local<v8::Value> value,
1014     const String16& groupName, protocol::Runtime::RemoteObject* remoteObject) {
1015   if (!remoteObject) return Response::Success();
1016   if (remoteObject->hasValue()) return Response::Success();
1017   if (remoteObject->hasUnserializableValue()) return Response::Success();
1018   if (remoteObject->getType() != RemoteObject::TypeEnum::Undefined) {
1019     v8::Isolate* isolate = context->GetIsolate();
1020     V8InspectorImpl* inspector =
1021         static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
1022     InspectedContext* inspectedContext =
1023         inspector->getContext(InspectedContext::contextId(context));
1024     InjectedScript* injectedScript =
1025         inspectedContext ? inspectedContext->getInjectedScript(sessionId)
1026                          : nullptr;
1027     if (!injectedScript) {
1028       return Response::ServerError("Cannot find context with specified id");
1029     }
1030     remoteObject->setObjectId(injectedScript->bindObject(value, groupName));
1031   }
1032   return Response::Success();
1033 }
1034 
unbindObject(int id)1035 void InjectedScript::unbindObject(int id) {
1036   m_idToWrappedObject.erase(id);
1037   m_idToObjectGroupName.erase(id);
1038 }
1039 
1040 }  // namespace v8_inspector
1041