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