OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 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/V8RuntimeAgentImpl.h" | |
32 | |
33 #include "src/inspector/InjectedScript.h" | |
34 #include "src/inspector/InspectedContext.h" | |
35 #include "src/inspector/RemoteObjectId.h" | |
36 #include "src/inspector/StringUtil.h" | |
37 #include "src/inspector/V8Compat.h" | |
38 #include "src/inspector/V8ConsoleMessage.h" | |
39 #include "src/inspector/V8Debugger.h" | |
40 #include "src/inspector/V8DebuggerAgentImpl.h" | |
41 #include "src/inspector/V8InspectorImpl.h" | |
42 #include "src/inspector/V8InspectorSessionImpl.h" | |
43 #include "src/inspector/V8StackTraceImpl.h" | |
44 #include "src/inspector/protocol/Protocol.h" | |
45 #include "src/inspector/public/V8InspectorClient.h" | |
46 | |
47 namespace v8_inspector { | |
48 | |
49 namespace V8RuntimeAgentImplState { | |
50 static const char customObjectFormatterEnabled[] = "customObjectFormatterEnabled
"; | |
51 static const char runtimeEnabled[] = "runtimeEnabled"; | |
52 }; | |
53 | |
54 using protocol::Runtime::RemoteObject; | |
55 | |
56 static bool hasInternalError(ErrorString* errorString, bool hasError) | |
57 { | |
58 if (hasError) | |
59 *errorString = "Internal error"; | |
60 return hasError; | |
61 } | |
62 | |
63 namespace { | |
64 | |
65 template<typename Callback> | |
66 class ProtocolPromiseHandler { | |
67 public: | |
68 static void add(V8InspectorImpl* inspector, v8::Local<v8::Context> context,
v8::MaybeLocal<v8::Value> value, const String16& notPromiseError, int contextGro
upId, int executionContextId, const String16& objectGroup, bool returnByValue, b
ool generatePreview, std::unique_ptr<Callback> callback) | |
69 { | |
70 if (value.IsEmpty()) { | |
71 callback->sendFailure("Internal error"); | |
72 return; | |
73 } | |
74 if (!value.ToLocalChecked()->IsPromise()) { | |
75 callback->sendFailure(notPromiseError); | |
76 return; | |
77 } | |
78 v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(value.ToLo
calChecked()); | |
79 Callback* rawCallback = callback.get(); | |
80 ProtocolPromiseHandler<Callback>* handler = new ProtocolPromiseHandler(i
nspector, contextGroupId, executionContextId, objectGroup, returnByValue, genera
tePreview, std::move(callback)); | |
81 v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate
()); | |
82 | |
83 v8::Local<v8::Function> thenCallbackFunction = V8_FUNCTION_NEW_REMOVE_PR
OTOTYPE(context, thenCallback, wrapper, 0).ToLocalChecked(); | |
84 if (promise->Then(context, thenCallbackFunction).IsEmpty()) { | |
85 rawCallback->sendFailure("Internal error"); | |
86 return; | |
87 } | |
88 v8::Local<v8::Function> catchCallbackFunction = V8_FUNCTION_NEW_REMOVE_P
ROTOTYPE(context, catchCallback, wrapper, 0).ToLocalChecked(); | |
89 if (promise->Catch(context, catchCallbackFunction).IsEmpty()) { | |
90 rawCallback->sendFailure("Internal error"); | |
91 return; | |
92 } | |
93 } | |
94 private: | |
95 static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
96 { | |
97 ProtocolPromiseHandler<Callback>* handler = static_cast<ProtocolPromiseH
andler<Callback>*>(info.Data().As<v8::External>()->Value()); | |
98 DCHECK(handler); | |
99 v8::Local<v8::Value> value = info.Length() > 0 ? info[0] : v8::Local<v8:
:Value>::Cast(v8::Undefined(info.GetIsolate())); | |
100 handler->m_callback->sendSuccess(handler->wrapObject(value), Maybe<proto
col::Runtime::ExceptionDetails>()); | |
101 } | |
102 | |
103 static void catchCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
104 { | |
105 ProtocolPromiseHandler<Callback>* handler = static_cast<ProtocolPromiseH
andler<Callback>*>(info.Data().As<v8::External>()->Value()); | |
106 DCHECK(handler); | |
107 v8::Local<v8::Value> value = info.Length() > 0 ? info[0] : v8::Local<v8:
:Value>::Cast(v8::Undefined(info.GetIsolate())); | |
108 | |
109 std::unique_ptr<V8StackTraceImpl> stack = handler->m_inspector->debugger
()->captureStackTrace(true); | |
110 std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
protocol::Runtime::ExceptionDetails::create() | |
111 .setExceptionId(handler->m_inspector->nextExceptionId()) | |
112 .setText("Uncaught (in promise)") | |
113 .setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber() :
0) | |
114 .setColumnNumber(stack && !stack->isEmpty() ? stack->topColumnNumber
() : 0) | |
115 .setException(handler->wrapObject(value)) | |
116 .build(); | |
117 if (stack) | |
118 exceptionDetails->setStackTrace(stack->buildInspectorObjectImpl()); | |
119 if (stack && !stack->isEmpty()) | |
120 exceptionDetails->setScriptId(toString16(stack->topScriptId())); | |
121 handler->m_callback->sendSuccess(handler->wrapObject(value), std::move(e
xceptionDetails)); | |
122 } | |
123 | |
124 ProtocolPromiseHandler(V8InspectorImpl* inspector, int contextGroupId, int e
xecutionContextId, const String16& objectGroup, bool returnByValue, bool generat
ePreview, std::unique_ptr<Callback> callback) | |
125 : m_inspector(inspector) | |
126 , m_contextGroupId(contextGroupId) | |
127 , m_executionContextId(executionContextId) | |
128 , m_objectGroup(objectGroup) | |
129 , m_returnByValue(returnByValue) | |
130 , m_generatePreview(generatePreview) | |
131 , m_callback(std::move(callback)) | |
132 , m_wrapper(inspector->isolate(), v8::External::New(inspector->isolate()
, this)) | |
133 { | |
134 m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter); | |
135 } | |
136 | |
137 static void cleanup(const v8::WeakCallbackInfo<ProtocolPromiseHandler<Callba
ck>>& data) | |
138 { | |
139 if (!data.GetParameter()->m_wrapper.IsEmpty()) { | |
140 data.GetParameter()->m_wrapper.Reset(); | |
141 data.SetSecondPassCallback(cleanup); | |
142 } else { | |
143 data.GetParameter()->m_callback->sendFailure("Promise was collected"
); | |
144 delete data.GetParameter(); | |
145 } | |
146 } | |
147 | |
148 std::unique_ptr<protocol::Runtime::RemoteObject> wrapObject(v8::Local<v8::Va
lue> value) | |
149 { | |
150 ErrorString errorString; | |
151 InjectedScript::ContextScope scope(&errorString, m_inspector, m_contextG
roupId, m_executionContextId); | |
152 if (!scope.initialize()) { | |
153 m_callback->sendFailure(errorString); | |
154 return nullptr; | |
155 } | |
156 std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue = scope.in
jectedScript()->wrapObject(&errorString, value, m_objectGroup, m_returnByValue,
m_generatePreview); | |
157 if (!wrappedValue) { | |
158 m_callback->sendFailure(errorString); | |
159 return nullptr; | |
160 } | |
161 return wrappedValue; | |
162 } | |
163 | |
164 V8InspectorImpl* m_inspector; | |
165 int m_contextGroupId; | |
166 int m_executionContextId; | |
167 String16 m_objectGroup; | |
168 bool m_returnByValue; | |
169 bool m_generatePreview; | |
170 std::unique_ptr<Callback> m_callback; | |
171 v8::Global<v8::External> m_wrapper; | |
172 }; | |
173 | |
174 template<typename Callback> | |
175 bool wrapEvaluateResultAsync(InjectedScript* injectedScript, v8::MaybeLocal<v8::
Value> maybeResultValue, const v8::TryCatch& tryCatch, const String16& objectGro
up, bool returnByValue, bool generatePreview, Callback* callback) | |
176 { | |
177 std::unique_ptr<RemoteObject> result; | |
178 Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails; | |
179 | |
180 ErrorString errorString; | |
181 injectedScript->wrapEvaluateResult(&errorString, | |
182 maybeResultValue, | |
183 tryCatch, | |
184 objectGroup, | |
185 returnByValue, | |
186 generatePreview, | |
187 &result, | |
188 &exceptionDetails); | |
189 if (errorString.isEmpty()) { | |
190 callback->sendSuccess(std::move(result), exceptionDetails); | |
191 return true; | |
192 } | |
193 callback->sendFailure(errorString); | |
194 return false; | |
195 } | |
196 | |
197 int ensureContext(ErrorString* errorString, V8InspectorImpl* inspector, int cont
extGroupId, const Maybe<int>& executionContextId) | |
198 { | |
199 int contextId; | |
200 if (executionContextId.isJust()) { | |
201 contextId = executionContextId.fromJust(); | |
202 } else { | |
203 v8::HandleScope handles(inspector->isolate()); | |
204 v8::Local<v8::Context> defaultContext = inspector->client()->ensureDefau
ltContextInGroup(contextGroupId); | |
205 if (defaultContext.IsEmpty()) { | |
206 *errorString = "Cannot find default execution context"; | |
207 return 0; | |
208 } | |
209 contextId = V8Debugger::contextId(defaultContext); | |
210 } | |
211 return contextId; | |
212 } | |
213 | |
214 } // namespace | |
215 | |
216 V8RuntimeAgentImpl::V8RuntimeAgentImpl(V8InspectorSessionImpl* session, protocol
::FrontendChannel* FrontendChannel, protocol::DictionaryValue* state) | |
217 : m_session(session) | |
218 , m_state(state) | |
219 , m_frontend(FrontendChannel) | |
220 , m_inspector(session->inspector()) | |
221 , m_enabled(false) | |
222 { | |
223 } | |
224 | |
225 V8RuntimeAgentImpl::~V8RuntimeAgentImpl() | |
226 { | |
227 } | |
228 | |
229 void V8RuntimeAgentImpl::evaluate( | |
230 const String16& expression, | |
231 const Maybe<String16>& objectGroup, | |
232 const Maybe<bool>& includeCommandLineAPI, | |
233 const Maybe<bool>& silent, | |
234 const Maybe<int>& executionContextId, | |
235 const Maybe<bool>& returnByValue, | |
236 const Maybe<bool>& generatePreview, | |
237 const Maybe<bool>& userGesture, | |
238 const Maybe<bool>& awaitPromise, | |
239 std::unique_ptr<EvaluateCallback> callback) | |
240 { | |
241 ErrorString errorString; | |
242 int contextId = ensureContext(&errorString, m_inspector, m_session->contextG
roupId(), executionContextId); | |
243 if (!errorString.isEmpty()) { | |
244 callback->sendFailure(errorString); | |
245 return; | |
246 } | |
247 | |
248 InjectedScript::ContextScope scope(&errorString, m_inspector, m_session->con
textGroupId(), contextId); | |
249 if (!scope.initialize()) { | |
250 callback->sendFailure(errorString); | |
251 return; | |
252 } | |
253 | |
254 if (silent.fromMaybe(false)) | |
255 scope.ignoreExceptionsAndMuteConsole(); | |
256 if (userGesture.fromMaybe(false)) | |
257 scope.pretendUserGesture(); | |
258 | |
259 if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()
) { | |
260 callback->sendFailure(errorString); | |
261 return; | |
262 } | |
263 | |
264 bool evalIsDisabled = !scope.context()->IsCodeGenerationFromStringsAllowed()
; | |
265 // Temporarily enable allow evals for inspector. | |
266 if (evalIsDisabled) | |
267 scope.context()->AllowCodeGenerationFromStrings(true); | |
268 | |
269 v8::MaybeLocal<v8::Value> maybeResultValue; | |
270 v8::Local<v8::Script> script = m_inspector->compileScript(scope.context(), t
oV8String(m_inspector->isolate(), expression), String16(), false); | |
271 if (!script.IsEmpty()) | |
272 maybeResultValue = m_inspector->runCompiledScript(scope.context(), scrip
t); | |
273 | |
274 if (evalIsDisabled) | |
275 scope.context()->AllowCodeGenerationFromStrings(false); | |
276 | |
277 // Re-initialize after running client's code, as it could have destroyed con
text or session. | |
278 if (!scope.initialize()) { | |
279 callback->sendFailure(errorString); | |
280 return; | |
281 } | |
282 | |
283 if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { | |
284 wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.
tryCatch(), objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), generateP
review.fromMaybe(false), callback.get()); | |
285 return; | |
286 } | |
287 ProtocolPromiseHandler<EvaluateCallback>::add( | |
288 m_inspector, | |
289 scope.context(), | |
290 maybeResultValue, | |
291 "Result of the evaluation is not a promise", | |
292 m_session->contextGroupId(), | |
293 scope.injectedScript()->context()->contextId(), | |
294 objectGroup.fromMaybe(""), | |
295 returnByValue.fromMaybe(false), | |
296 generatePreview.fromMaybe(false), | |
297 std::move(callback)); | |
298 } | |
299 | |
300 void V8RuntimeAgentImpl::awaitPromise( | |
301 const String16& promiseObjectId, | |
302 const Maybe<bool>& returnByValue, | |
303 const Maybe<bool>& generatePreview, | |
304 std::unique_ptr<AwaitPromiseCallback> callback) | |
305 { | |
306 ErrorString errorString; | |
307 InjectedScript::ObjectScope scope(&errorString, m_inspector, m_session->cont
extGroupId(), promiseObjectId); | |
308 if (!scope.initialize()) { | |
309 callback->sendFailure(errorString); | |
310 return; | |
311 } | |
312 ProtocolPromiseHandler<AwaitPromiseCallback>::add( | |
313 m_inspector, | |
314 scope.context(), | |
315 scope.object(), | |
316 "Could not find promise with given id", | |
317 m_session->contextGroupId(), | |
318 scope.injectedScript()->context()->contextId(), | |
319 scope.objectGroupName(), | |
320 returnByValue.fromMaybe(false), | |
321 generatePreview.fromMaybe(false), | |
322 std::move(callback)); | |
323 } | |
324 | |
325 void V8RuntimeAgentImpl::callFunctionOn( | |
326 const String16& objectId, | |
327 const String16& expression, | |
328 const Maybe<protocol::Array<protocol::Runtime::CallArgument>>& optionalArgum
ents, | |
329 const Maybe<bool>& silent, | |
330 const Maybe<bool>& returnByValue, | |
331 const Maybe<bool>& generatePreview, | |
332 const Maybe<bool>& userGesture, | |
333 const Maybe<bool>& awaitPromise, | |
334 std::unique_ptr<CallFunctionOnCallback> callback) | |
335 { | |
336 ErrorString errorString; | |
337 InjectedScript::ObjectScope scope(&errorString, m_inspector, m_session->cont
extGroupId(), objectId); | |
338 if (!scope.initialize()) { | |
339 callback->sendFailure(errorString); | |
340 return; | |
341 } | |
342 | |
343 std::unique_ptr<v8::Local<v8::Value>[]> argv = nullptr; | |
344 int argc = 0; | |
345 if (optionalArguments.isJust()) { | |
346 protocol::Array<protocol::Runtime::CallArgument>* arguments = optionalAr
guments.fromJust(); | |
347 argc = arguments->length(); | |
348 argv.reset(new v8::Local<v8::Value>[argc]); | |
349 for (int i = 0; i < argc; ++i) { | |
350 v8::Local<v8::Value> argumentValue; | |
351 if (!scope.injectedScript()->resolveCallArgument(&errorString, argum
ents->get(i)).ToLocal(&argumentValue)) { | |
352 callback->sendFailure(errorString); | |
353 return; | |
354 } | |
355 argv[i] = argumentValue; | |
356 } | |
357 } | |
358 | |
359 if (silent.fromMaybe(false)) | |
360 scope.ignoreExceptionsAndMuteConsole(); | |
361 if (userGesture.fromMaybe(false)) | |
362 scope.pretendUserGesture(); | |
363 | |
364 v8::MaybeLocal<v8::Value> maybeFunctionValue = m_inspector->compileAndRunInt
ernalScript(scope.context(), toV8String(m_inspector->isolate(), "(" + expression
+ ")")); | |
365 // Re-initialize after running client's code, as it could have destroyed con
text or session. | |
366 if (!scope.initialize()) { | |
367 callback->sendFailure(errorString); | |
368 return; | |
369 } | |
370 | |
371 if (scope.tryCatch().HasCaught()) { | |
372 wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue, scop
e.tryCatch(), scope.objectGroupName(), false, false, callback.get()); | |
373 return; | |
374 } | |
375 | |
376 v8::Local<v8::Value> functionValue; | |
377 if (!maybeFunctionValue.ToLocal(&functionValue) || !functionValue->IsFunctio
n()) { | |
378 callback->sendFailure("Given expression does not evaluate to a function"
); | |
379 return; | |
380 } | |
381 | |
382 v8::MaybeLocal<v8::Value> maybeResultValue = m_inspector->callFunction(funct
ionValue.As<v8::Function>(), scope.context(), scope.object(), argc, argv.get()); | |
383 // Re-initialize after running client's code, as it could have destroyed con
text or session. | |
384 if (!scope.initialize()) { | |
385 callback->sendFailure(errorString); | |
386 return; | |
387 } | |
388 | |
389 if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { | |
390 wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.
tryCatch(), scope.objectGroupName(), returnByValue.fromMaybe(false), generatePre
view.fromMaybe(false), callback.get()); | |
391 return; | |
392 } | |
393 | |
394 ProtocolPromiseHandler<CallFunctionOnCallback>::add( | |
395 m_inspector, | |
396 scope.context(), | |
397 maybeResultValue, | |
398 "Result of the function call is not a promise", | |
399 m_session->contextGroupId(), | |
400 scope.injectedScript()->context()->contextId(), | |
401 scope.objectGroupName(), | |
402 returnByValue.fromMaybe(false), | |
403 generatePreview.fromMaybe(false), | |
404 std::move(callback)); | |
405 } | |
406 | |
407 void V8RuntimeAgentImpl::getProperties( | |
408 ErrorString* errorString, | |
409 const String16& objectId, | |
410 const Maybe<bool>& ownProperties, | |
411 const Maybe<bool>& accessorPropertiesOnly, | |
412 const Maybe<bool>& generatePreview, | |
413 std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>* res
ult, | |
414 Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>* inter
nalProperties, | |
415 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) | |
416 { | |
417 using protocol::Runtime::InternalPropertyDescriptor; | |
418 | |
419 InjectedScript::ObjectScope scope(errorString, m_inspector, m_session->conte
xtGroupId(), objectId); | |
420 if (!scope.initialize()) | |
421 return; | |
422 | |
423 scope.ignoreExceptionsAndMuteConsole(); | |
424 if (!scope.object()->IsObject()) { | |
425 *errorString = "Value with given id is not an object"; | |
426 return; | |
427 } | |
428 | |
429 v8::Local<v8::Object> object = scope.object().As<v8::Object>(); | |
430 scope.injectedScript()->getProperties(errorString, object, scope.objectGroup
Name(), ownProperties.fromMaybe(false), accessorPropertiesOnly.fromMaybe(false),
generatePreview.fromMaybe(false), result, exceptionDetails); | |
431 if (!errorString->isEmpty() || exceptionDetails->isJust() || accessorPropert
iesOnly.fromMaybe(false)) | |
432 return; | |
433 v8::Local<v8::Array> propertiesArray; | |
434 if (hasInternalError(errorString, !m_inspector->debugger()->internalProperti
es(scope.context(), scope.object()).ToLocal(&propertiesArray))) | |
435 return; | |
436 std::unique_ptr<protocol::Array<InternalPropertyDescriptor>> propertiesProto
colArray = protocol::Array<InternalPropertyDescriptor>::create(); | |
437 for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) { | |
438 v8::Local<v8::Value> name; | |
439 if (hasInternalError(errorString, !propertiesArray->Get(scope.context(),
i).ToLocal(&name)) || !name->IsString()) | |
440 return; | |
441 v8::Local<v8::Value> value; | |
442 if (hasInternalError(errorString, !propertiesArray->Get(scope.context(),
i + 1).ToLocal(&value))) | |
443 return; | |
444 std::unique_ptr<RemoteObject> wrappedValue = scope.injectedScript()->wra
pObject(errorString, value, scope.objectGroupName()); | |
445 if (!wrappedValue) | |
446 return; | |
447 propertiesProtocolArray->addItem(InternalPropertyDescriptor::create() | |
448 .setName(toProtocolString(name.As<v8::String>())) | |
449 .setValue(std::move(wrappedValue)).build()); | |
450 } | |
451 if (!propertiesProtocolArray->length()) | |
452 return; | |
453 *internalProperties = std::move(propertiesProtocolArray); | |
454 } | |
455 | |
456 void V8RuntimeAgentImpl::releaseObject(ErrorString* errorString, const String16&
objectId) | |
457 { | |
458 InjectedScript::ObjectScope scope(errorString, m_inspector, m_session->conte
xtGroupId(), objectId); | |
459 if (!scope.initialize()) | |
460 return; | |
461 scope.injectedScript()->releaseObject(objectId); | |
462 } | |
463 | |
464 void V8RuntimeAgentImpl::releaseObjectGroup(ErrorString*, const String16& object
Group) | |
465 { | |
466 m_session->releaseObjectGroup(objectGroup); | |
467 } | |
468 | |
469 void V8RuntimeAgentImpl::runIfWaitingForDebugger(ErrorString* errorString) | |
470 { | |
471 m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId()); | |
472 } | |
473 | |
474 void V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(ErrorString*, bool enab
led) | |
475 { | |
476 m_state->setBoolean(V8RuntimeAgentImplState::customObjectFormatterEnabled, e
nabled); | |
477 m_session->setCustomObjectFormatterEnabled(enabled); | |
478 } | |
479 | |
480 void V8RuntimeAgentImpl::discardConsoleEntries(ErrorString*) | |
481 { | |
482 V8ConsoleMessageStorage* storage = m_inspector->ensureConsoleMessageStorage(
m_session->contextGroupId()); | |
483 storage->clear(); | |
484 } | |
485 | |
486 void V8RuntimeAgentImpl::compileScript(ErrorString* errorString, | |
487 const String16& expression, | |
488 const String16& sourceURL, | |
489 bool persistScript, | |
490 const Maybe<int>& executionContextId, | |
491 Maybe<String16>* scriptId, | |
492 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) | |
493 { | |
494 if (!m_enabled) { | |
495 *errorString = "Runtime agent is not enabled"; | |
496 return; | |
497 } | |
498 int contextId = ensureContext(errorString, m_inspector, m_session->contextGr
oupId(), executionContextId); | |
499 if (!errorString->isEmpty()) | |
500 return; | |
501 InjectedScript::ContextScope scope(errorString, m_inspector, m_session->cont
extGroupId(), contextId); | |
502 if (!scope.initialize()) | |
503 return; | |
504 | |
505 if (!persistScript) | |
506 m_inspector->debugger()->muteScriptParsedEvents(); | |
507 v8::Local<v8::Script> script = m_inspector->compileScript(scope.context(), t
oV8String(m_inspector->isolate(), expression), sourceURL, false); | |
508 if (!persistScript) | |
509 m_inspector->debugger()->unmuteScriptParsedEvents(); | |
510 if (script.IsEmpty()) { | |
511 if (scope.tryCatch().HasCaught()) | |
512 *exceptionDetails = scope.injectedScript()->createExceptionDetails(e
rrorString, scope.tryCatch(), String16(), false); | |
513 else | |
514 *errorString = "Script compilation failed"; | |
515 return; | |
516 } | |
517 | |
518 if (!persistScript) | |
519 return; | |
520 | |
521 String16 scriptValueId = String16::fromInteger(script->GetUnboundScript()->G
etId()); | |
522 std::unique_ptr<v8::Global<v8::Script>> global(new v8::Global<v8::Script>(m_
inspector->isolate(), script)); | |
523 m_compiledScripts[scriptValueId] = std::move(global); | |
524 *scriptId = scriptValueId; | |
525 } | |
526 | |
527 void V8RuntimeAgentImpl::runScript( | |
528 const String16& scriptId, | |
529 const Maybe<int>& executionContextId, | |
530 const Maybe<String16>& objectGroup, | |
531 const Maybe<bool>& silent, | |
532 const Maybe<bool>& includeCommandLineAPI, | |
533 const Maybe<bool>& returnByValue, | |
534 const Maybe<bool>& generatePreview, | |
535 const Maybe<bool>& awaitPromise, | |
536 std::unique_ptr<RunScriptCallback> callback) | |
537 { | |
538 if (!m_enabled) { | |
539 callback->sendFailure("Runtime agent is not enabled"); | |
540 return; | |
541 } | |
542 | |
543 auto it = m_compiledScripts.find(scriptId); | |
544 if (it == m_compiledScripts.end()) { | |
545 callback->sendFailure("No script with given id"); | |
546 return; | |
547 } | |
548 | |
549 ErrorString errorString; | |
550 int contextId = ensureContext(&errorString, m_inspector, m_session->contextG
roupId(), executionContextId); | |
551 if (!errorString.isEmpty()) { | |
552 callback->sendFailure(errorString); | |
553 return; | |
554 } | |
555 | |
556 InjectedScript::ContextScope scope(&errorString, m_inspector, m_session->con
textGroupId(), contextId); | |
557 if (!scope.initialize()) { | |
558 callback->sendFailure(errorString); | |
559 return; | |
560 } | |
561 | |
562 if (silent.fromMaybe(false)) | |
563 scope.ignoreExceptionsAndMuteConsole(); | |
564 | |
565 std::unique_ptr<v8::Global<v8::Script>> scriptWrapper = std::move(it->second
); | |
566 m_compiledScripts.erase(it); | |
567 v8::Local<v8::Script> script = scriptWrapper->Get(m_inspector->isolate()); | |
568 if (script.IsEmpty()) { | |
569 callback->sendFailure("Script execution failed"); | |
570 return; | |
571 } | |
572 | |
573 if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()
) | |
574 return; | |
575 | |
576 v8::MaybeLocal<v8::Value> maybeResultValue = m_inspector->runCompiledScript(
scope.context(), script); | |
577 | |
578 // Re-initialize after running client's code, as it could have destroyed con
text or session. | |
579 if (!scope.initialize()) | |
580 return; | |
581 | |
582 if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { | |
583 wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.
tryCatch(), objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), generateP
review.fromMaybe(false), callback.get()); | |
584 return; | |
585 } | |
586 ProtocolPromiseHandler<RunScriptCallback>::add( | |
587 m_inspector, | |
588 scope.context(), | |
589 maybeResultValue.ToLocalChecked(), | |
590 "Result of the script execution is not a promise", | |
591 m_session->contextGroupId(), | |
592 scope.injectedScript()->context()->contextId(), | |
593 objectGroup.fromMaybe(""), | |
594 returnByValue.fromMaybe(false), | |
595 generatePreview.fromMaybe(false), | |
596 std::move(callback)); | |
597 } | |
598 | |
599 void V8RuntimeAgentImpl::restore() | |
600 { | |
601 if (!m_state->booleanProperty(V8RuntimeAgentImplState::runtimeEnabled, false
)) | |
602 return; | |
603 m_frontend.executionContextsCleared(); | |
604 ErrorString error; | |
605 enable(&error); | |
606 if (m_state->booleanProperty(V8RuntimeAgentImplState::customObjectFormatterE
nabled, false)) | |
607 m_session->setCustomObjectFormatterEnabled(true); | |
608 } | |
609 | |
610 void V8RuntimeAgentImpl::enable(ErrorString* errorString) | |
611 { | |
612 if (m_enabled) | |
613 return; | |
614 m_inspector->client()->beginEnsureAllContextsInGroup(m_session->contextGroup
Id()); | |
615 m_enabled = true; | |
616 m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true); | |
617 m_inspector->enableStackCapturingIfNeeded(); | |
618 m_session->reportAllContexts(this); | |
619 V8ConsoleMessageStorage* storage = m_inspector->ensureConsoleMessageStorage(
m_session->contextGroupId()); | |
620 for (const auto& message : storage->messages()) | |
621 reportMessage(message.get(), false); | |
622 } | |
623 | |
624 void V8RuntimeAgentImpl::disable(ErrorString* errorString) | |
625 { | |
626 if (!m_enabled) | |
627 return; | |
628 m_enabled = false; | |
629 m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false); | |
630 m_inspector->disableStackCapturingIfNeeded(); | |
631 m_session->discardInjectedScripts(); | |
632 reset(); | |
633 m_inspector->client()->endEnsureAllContextsInGroup(m_session->contextGroupId
()); | |
634 } | |
635 | |
636 void V8RuntimeAgentImpl::reset() | |
637 { | |
638 m_compiledScripts.clear(); | |
639 if (m_enabled) { | |
640 if (const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->conte
xtGroup(m_session->contextGroupId())) { | |
641 for (auto& idContext : *contexts) | |
642 idContext.second->setReported(false); | |
643 } | |
644 m_frontend.executionContextsCleared(); | |
645 } | |
646 } | |
647 | |
648 void V8RuntimeAgentImpl::reportExecutionContextCreated(InspectedContext* context
) | |
649 { | |
650 if (!m_enabled) | |
651 return; | |
652 context->setReported(true); | |
653 std::unique_ptr<protocol::Runtime::ExecutionContextDescription> description
= protocol::Runtime::ExecutionContextDescription::create() | |
654 .setId(context->contextId()) | |
655 .setName(context->humanReadableName()) | |
656 .setOrigin(context->origin()).build(); | |
657 if (!context->auxData().isEmpty()) | |
658 description->setAuxData(protocol::DictionaryValue::cast(protocol::parseJ
SON(context->auxData()))); | |
659 m_frontend.executionContextCreated(std::move(description)); | |
660 } | |
661 | |
662 void V8RuntimeAgentImpl::reportExecutionContextDestroyed(InspectedContext* conte
xt) | |
663 { | |
664 if (m_enabled && context->isReported()) { | |
665 context->setReported(false); | |
666 m_frontend.executionContextDestroyed(context->contextId()); | |
667 } | |
668 } | |
669 | |
670 void V8RuntimeAgentImpl::inspect(std::unique_ptr<protocol::Runtime::RemoteObject
> objectToInspect, std::unique_ptr<protocol::DictionaryValue> hints) | |
671 { | |
672 if (m_enabled) | |
673 m_frontend.inspectRequested(std::move(objectToInspect), std::move(hints)
); | |
674 } | |
675 | |
676 void V8RuntimeAgentImpl::messageAdded(V8ConsoleMessage* message) | |
677 { | |
678 if (m_enabled) | |
679 reportMessage(message, true); | |
680 } | |
681 | |
682 void V8RuntimeAgentImpl::reportMessage(V8ConsoleMessage* message, bool generateP
review) | |
683 { | |
684 message->reportToFrontend(&m_frontend, m_session, generatePreview); | |
685 m_frontend.flush(); | |
686 } | |
687 | |
688 } // namespace v8_inspector | |
OLD | NEW |