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