LCOV - code coverage report
Current view: top level - src/inspector - v8-runtime-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 348 396 87.9 %
Date: 2019-02-19 Functions: 47 54 87.0 %

          Line data    Source code
       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/v8-runtime-agent-impl.h"
      32             : 
      33             : #include <inttypes.h>
      34             : 
      35             : #include "src/debug/debug-interface.h"
      36             : #include "src/inspector/injected-script.h"
      37             : #include "src/inspector/inspected-context.h"
      38             : #include "src/inspector/protocol/Protocol.h"
      39             : #include "src/inspector/remote-object-id.h"
      40             : #include "src/inspector/v8-console-message.h"
      41             : #include "src/inspector/v8-debugger-agent-impl.h"
      42             : #include "src/inspector/v8-debugger.h"
      43             : #include "src/inspector/v8-inspector-impl.h"
      44             : #include "src/inspector/v8-inspector-session-impl.h"
      45             : #include "src/inspector/v8-stack-trace-impl.h"
      46             : #include "src/inspector/v8-value-utils.h"
      47             : #include "src/tracing/trace-event.h"
      48             : 
      49             : #include "include/v8-inspector.h"
      50             : 
      51             : namespace v8_inspector {
      52             : 
      53             : namespace V8RuntimeAgentImplState {
      54             : static const char customObjectFormatterEnabled[] =
      55             :     "customObjectFormatterEnabled";
      56             : static const char runtimeEnabled[] = "runtimeEnabled";
      57             : static const char bindings[] = "bindings";
      58             : }  // namespace V8RuntimeAgentImplState
      59             : 
      60             : using protocol::Runtime::RemoteObject;
      61             : 
      62             : namespace {
      63             : 
      64             : template <typename ProtocolCallback>
      65        1300 : class EvaluateCallbackWrapper : public EvaluateCallback {
      66             :  public:
      67             :   static std::unique_ptr<EvaluateCallback> wrap(
      68             :       std::unique_ptr<ProtocolCallback> callback) {
      69             :     return std::unique_ptr<EvaluateCallback>(
      70         650 :         new EvaluateCallbackWrapper(std::move(callback)));
      71             :   }
      72         635 :   void sendSuccess(std::unique_ptr<protocol::Runtime::RemoteObject> result,
      73             :                    protocol::Maybe<protocol::Runtime::ExceptionDetails>
      74             :                        exceptionDetails) override {
      75             :     return m_callback->sendSuccess(std::move(result),
      76        2540 :                                    std::move(exceptionDetails));
      77             :   }
      78          15 :   void sendFailure(const protocol::DispatchResponse& response) override {
      79          15 :     return m_callback->sendFailure(response);
      80             :   }
      81             : 
      82             :  private:
      83             :   explicit EvaluateCallbackWrapper(std::unique_ptr<ProtocolCallback> callback)
      84         650 :       : m_callback(std::move(callback)) {}
      85             : 
      86             :   std::unique_ptr<ProtocolCallback> m_callback;
      87             : };
      88             : 
      89             : template <typename ProtocolCallback>
      90        8672 : bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
      91             :                              v8::MaybeLocal<v8::Value> maybeResultValue,
      92             :                              const v8::TryCatch& tryCatch,
      93             :                              const String16& objectGroup, WrapMode wrapMode,
      94             :                              ProtocolCallback* callback) {
      95        8672 :   std::unique_ptr<RemoteObject> result;
      96             :   Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
      97             : 
      98             :   Response response = injectedScript->wrapEvaluateResult(
      99             :       maybeResultValue, tryCatch, objectGroup, wrapMode, &result,
     100        8672 :       &exceptionDetails);
     101        8672 :   if (response.isSuccess()) {
     102       34452 :     callback->sendSuccess(std::move(result), std::move(exceptionDetails));
     103        8613 :     return true;
     104             :   }
     105          59 :   callback->sendFailure(response);
     106          59 :   return false;
     107             : }
     108             : 
     109         656 : void innerCallFunctionOn(
     110        1452 :     V8InspectorSessionImpl* session, InjectedScript::Scope& scope,
     111             :     v8::Local<v8::Value> recv, const String16& expression,
     112             :     Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
     113             :     bool silent, WrapMode wrapMode, bool userGesture, bool awaitPromise,
     114             :     const String16& objectGroup,
     115             :     std::unique_ptr<V8RuntimeAgentImpl::CallFunctionOnCallback> callback) {
     116        1287 :   V8InspectorImpl* inspector = session->inspector();
     117             : 
     118             :   std::unique_ptr<v8::Local<v8::Value>[]> argv = nullptr;
     119             :   int argc = 0;
     120         656 :   if (optionalArguments.isJust()) {
     121             :     protocol::Array<protocol::Runtime::CallArgument>* arguments =
     122             :         optionalArguments.fromJust();
     123         120 :     argc = static_cast<int>(arguments->length());
     124         260 :     argv.reset(new v8::Local<v8::Value>[argc]);
     125         140 :     for (int i = 0; i < argc; ++i) {
     126             :       v8::Local<v8::Value> argumentValue;
     127             :       Response response = scope.injectedScript()->resolveCallArgument(
     128         280 :           arguments->get(i), &argumentValue);
     129         140 :       if (!response.isSuccess()) {
     130           0 :         callback->sendFailure(response);
     131             :         return;
     132             :       }
     133         140 :       argv[i] = argumentValue;
     134             :     }
     135             :   }
     136             : 
     137         656 :   if (silent) scope.ignoreExceptionsAndMuteConsole();
     138         656 :   if (userGesture) scope.pretendUserGesture();
     139             : 
     140             :   // Temporarily enable allow evals for inspector.
     141         656 :   scope.allowCodeGenerationFromStrings();
     142             : 
     143             :   v8::MaybeLocal<v8::Value> maybeFunctionValue;
     144             :   v8::Local<v8::Script> functionScript;
     145         656 :   if (inspector
     146        3936 :           ->compileScript(scope.context(), "(" + expression + ")", String16())
     147         656 :           .ToLocal(&functionScript)) {
     148             :     v8::MicrotasksScope microtasksScope(inspector->isolate(),
     149         646 :                                         v8::MicrotasksScope::kRunMicrotasks);
     150         646 :     maybeFunctionValue = functionScript->Run(scope.context());
     151             :   }
     152             :   // Re-initialize after running client's code, as it could have destroyed
     153             :   // context or session.
     154         656 :   Response response = scope.initialize();
     155         656 :   if (!response.isSuccess()) {
     156           0 :     callback->sendFailure(response);
     157           0 :     return;
     158             :   }
     159             : 
     160         656 :   if (scope.tryCatch().HasCaught()) {
     161             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue,
     162             :                             scope.tryCatch(), objectGroup, WrapMode::kNoPreview,
     163          15 :                             callback.get());
     164          15 :     return;
     165             :   }
     166             : 
     167             :   v8::Local<v8::Value> functionValue;
     168        1282 :   if (!maybeFunctionValue.ToLocal(&functionValue) ||
     169         641 :       !functionValue->IsFunction()) {
     170             :     callback->sendFailure(
     171           0 :         Response::Error("Given expression does not evaluate to a function"));
     172           0 :     return;
     173             :   }
     174             : 
     175             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     176             :   {
     177             :     v8::MicrotasksScope microtasksScope(inspector->isolate(),
     178         641 :                                         v8::MicrotasksScope::kRunMicrotasks);
     179             :     maybeResultValue = functionValue.As<v8::Function>()->Call(
     180         641 :         scope.context(), recv, argc, argv.get());
     181             :   }
     182             :   // Re-initialize after running client's code, as it could have destroyed
     183             :   // context or session.
     184        1282 :   response = scope.initialize();
     185         641 :   if (!response.isSuccess()) {
     186           0 :     callback->sendFailure(response);
     187           0 :     return;
     188             :   }
     189             : 
     190         641 :   if (!awaitPromise || scope.tryCatch().HasCaught()) {
     191             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     192             :                             scope.tryCatch(), objectGroup, wrapMode,
     193         621 :                             callback.get());
     194         621 :     return;
     195             :   }
     196             : 
     197             :   scope.injectedScript()->addPromiseCallback(
     198             :       session, maybeResultValue, objectGroup, wrapMode,
     199             :       EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
     200          40 :           std::move(callback)));
     201             : }
     202             : 
     203       26721 : Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
     204             :                        Maybe<int> executionContextId, int* contextId) {
     205        8927 :   if (executionContextId.isJust()) {
     206          30 :     *contextId = executionContextId.fromJust();
     207             :   } else {
     208        8897 :     v8::HandleScope handles(inspector->isolate());
     209             :     v8::Local<v8::Context> defaultContext =
     210        8897 :         inspector->client()->ensureDefaultContextInGroup(contextGroupId);
     211        8897 :     if (defaultContext.IsEmpty())
     212           0 :       return Response::Error("Cannot find default execution context");
     213        8897 :     *contextId = InspectedContext::contextId(defaultContext);
     214             :   }
     215        8927 :   return Response::OK();
     216             : }
     217             : 
     218             : }  // namespace
     219             : 
     220        3832 : V8RuntimeAgentImpl::V8RuntimeAgentImpl(
     221        3832 :     V8InspectorSessionImpl* session, protocol::FrontendChannel* FrontendChannel,
     222             :     protocol::DictionaryValue* state)
     223             :     : m_session(session),
     224             :       m_state(state),
     225             :       m_frontend(FrontendChannel),
     226             :       m_inspector(session->inspector()),
     227       11496 :       m_enabled(false) {}
     228             : 
     229             : V8RuntimeAgentImpl::~V8RuntimeAgentImpl() = default;
     230             : 
     231        8498 : void V8RuntimeAgentImpl::evaluate(
     232             :     const String16& expression, Maybe<String16> objectGroup,
     233             :     Maybe<bool> includeCommandLineAPI, Maybe<bool> silent,
     234             :     Maybe<int> executionContextId, Maybe<bool> returnByValue,
     235             :     Maybe<bool> generatePreview, Maybe<bool> userGesture,
     236             :     Maybe<bool> awaitPromise, Maybe<bool> throwOnSideEffect,
     237             :     Maybe<double> timeout, std::unique_ptr<EvaluateCallback> callback) {
     238       16996 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
     239             :                "EvaluateScript");
     240        8498 :   int contextId = 0;
     241             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     242       33965 :                                     std::move(executionContextId), &contextId);
     243        8498 :   if (!response.isSuccess()) {
     244           0 :     callback->sendFailure(response);
     245           0 :     return;
     246             :   }
     247             : 
     248        9078 :   InjectedScript::ContextScope scope(m_session, contextId);
     249       16996 :   response = scope.initialize();
     250        8498 :   if (!response.isSuccess()) {
     251           9 :     callback->sendFailure(response);
     252           9 :     return;
     253             :   }
     254             : 
     255        8489 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     256        8489 :   if (userGesture.fromMaybe(false)) scope.pretendUserGesture();
     257             : 
     258        8489 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     259             : 
     260             :   // Temporarily enable allow evals for inspector.
     261        8489 :   scope.allowCodeGenerationFromStrings();
     262             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     263             :   {
     264        8489 :     V8InspectorImpl::EvaluateScope evaluateScope(scope);
     265        8489 :     if (timeout.isJust()) {
     266          30 :       response = evaluateScope.setTimeout(timeout.fromJust() / 1000.0);
     267          15 :       if (!response.isSuccess()) {
     268           0 :         callback->sendFailure(response);
     269           0 :         return;
     270             :       }
     271             :     }
     272             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     273       25467 :                                         v8::MicrotasksScope::kRunMicrotasks);
     274             :     maybeResultValue = v8::debug::EvaluateGlobal(
     275             :         m_inspector->isolate(), toV8String(m_inspector->isolate(), expression),
     276       33956 :         throwOnSideEffect.fromMaybe(false));
     277             :   }  // Run microtasks before returning result.
     278             : 
     279             :   // Re-initialize after running client's code, as it could have destroyed
     280             :   // context or session.
     281       16978 :   response = scope.initialize();
     282        8489 :   if (!response.isSuccess()) {
     283          20 :     callback->sendFailure(response);
     284          20 :     return;
     285             :   }
     286             : 
     287             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     288        8469 :                                                    : WrapMode::kNoPreview;
     289        8469 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     290        8469 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     291             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     292             :                             scope.tryCatch(), objectGroup.fromMaybe(""), mode,
     293       31556 :                             callback.get());
     294        7889 :     return;
     295             :   }
     296             :   scope.injectedScript()->addPromiseCallback(
     297             :       m_session, maybeResultValue, objectGroup.fromMaybe(""), mode,
     298        3480 :       EvaluateCallbackWrapper<EvaluateCallback>::wrap(std::move(callback)));
     299             : }
     300             : 
     301          35 : void V8RuntimeAgentImpl::awaitPromise(
     302             :     const String16& promiseObjectId, Maybe<bool> returnByValue,
     303             :     Maybe<bool> generatePreview,
     304             :     std::unique_ptr<AwaitPromiseCallback> callback) {
     305          35 :   InjectedScript::ObjectScope scope(m_session, promiseObjectId);
     306          35 :   Response response = scope.initialize();
     307          35 :   if (!response.isSuccess()) {
     308           0 :     callback->sendFailure(response);
     309           0 :     return;
     310             :   }
     311          35 :   if (!scope.object()->IsPromise()) {
     312             :     callback->sendFailure(
     313           0 :         Response::Error("Could not find promise with given id"));
     314           0 :     return;
     315             :   }
     316             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     317          35 :                                                    : WrapMode::kNoPreview;
     318          35 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     319             :   scope.injectedScript()->addPromiseCallback(
     320             :       m_session, scope.object(), scope.objectGroupName(), mode,
     321         105 :       EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
     322             : }
     323             : 
     324         661 : void V8RuntimeAgentImpl::callFunctionOn(
     325             :     const String16& expression, Maybe<String16> objectId,
     326             :     Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
     327             :     Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
     328             :     Maybe<bool> userGesture, Maybe<bool> awaitPromise,
     329             :     Maybe<int> executionContextId, Maybe<String16> objectGroup,
     330             :     std::unique_ptr<CallFunctionOnCallback> callback) {
     331         671 :   if (objectId.isJust() && executionContextId.isJust()) {
     332             :     callback->sendFailure(Response::Error(
     333          15 :         "ObjectId must not be specified together with executionContextId"));
     334           5 :     return;
     335             :   }
     336         661 :   if (!objectId.isJust() && !executionContextId.isJust()) {
     337             :     callback->sendFailure(Response::Error(
     338           0 :         "Either ObjectId or executionContextId must be specified"));
     339           0 :     return;
     340             :   }
     341             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     342         656 :                                                    : WrapMode::kNoPreview;
     343         656 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     344         656 :   if (objectId.isJust()) {
     345        1307 :     InjectedScript::ObjectScope scope(m_session, objectId.fromJust());
     346         651 :     Response response = scope.initialize();
     347         651 :     if (!response.isSuccess()) {
     348           0 :       callback->sendFailure(response);
     349             :       return;
     350             :     }
     351             :     innerCallFunctionOn(m_session, scope, scope.object(), expression,
     352             :                         std::move(optionalArguments), silent.fromMaybe(false),
     353             :                         mode, userGesture.fromMaybe(false),
     354             :                         awaitPromise.fromMaybe(false),
     355         651 :                         objectGroup.isJust() ? objectGroup.fromMaybe(String16())
     356             :                                              : scope.objectGroupName(),
     357        5859 :                         std::move(callback));
     358             :   } else {
     359           5 :     int contextId = 0;
     360             :     Response response =
     361             :         ensureContext(m_inspector, m_session->contextGroupId(),
     362          10 :                       std::move(executionContextId.fromJust()), &contextId);
     363           5 :     if (!response.isSuccess()) {
     364           0 :       callback->sendFailure(response);
     365           0 :       return;
     366             :     }
     367          10 :     InjectedScript::ContextScope scope(m_session, contextId);
     368          10 :     response = scope.initialize();
     369           5 :     if (!response.isSuccess()) {
     370           0 :       callback->sendFailure(response);
     371           0 :       return;
     372             :     }
     373             :     innerCallFunctionOn(m_session, scope, scope.context()->Global(), expression,
     374             :                         std::move(optionalArguments), silent.fromMaybe(false),
     375             :                         mode, userGesture.fromMaybe(false),
     376             :                         awaitPromise.fromMaybe(false),
     377          50 :                         objectGroup.fromMaybe(""), std::move(callback));
     378             :   }
     379             : }
     380             : 
     381       68298 : Response V8RuntimeAgentImpl::getProperties(
     382             :     const String16& objectId, Maybe<bool> ownProperties,
     383             :     Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview,
     384             :     std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
     385             :         result,
     386             :     Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>*
     387             :         internalProperties,
     388             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     389             :   using protocol::Runtime::InternalPropertyDescriptor;
     390             : 
     391       68298 :   InjectedScript::ObjectScope scope(m_session, objectId);
     392       68298 :   Response response = scope.initialize();
     393       68298 :   if (!response.isSuccess()) return response;
     394             : 
     395       68298 :   scope.ignoreExceptionsAndMuteConsole();
     396             :   v8::MicrotasksScope microtasks_scope(m_inspector->isolate(),
     397      136596 :                                        v8::MicrotasksScope::kRunMicrotasks);
     398       68298 :   if (!scope.object()->IsObject())
     399           0 :     return Response::Error("Value with given id is not an object");
     400             : 
     401             :   v8::Local<v8::Object> object = scope.object().As<v8::Object>();
     402      273192 :   response = scope.injectedScript()->getProperties(
     403             :       object, scope.objectGroupName(), ownProperties.fromMaybe(false),
     404             :       accessorPropertiesOnly.fromMaybe(false),
     405             :       generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     406             :                                        : WrapMode::kNoPreview,
     407             :       result, exceptionDetails);
     408       68298 :   if (!response.isSuccess()) return response;
     409      136596 :   if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
     410           5 :     return Response::OK();
     411             :   std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
     412       68293 :       propertiesProtocolArray;
     413      136586 :   response = scope.injectedScript()->getInternalProperties(
     414             :       object, scope.objectGroupName(), &propertiesProtocolArray);
     415       68293 :   if (!response.isSuccess()) return response;
     416       68293 :   if (propertiesProtocolArray->length())
     417             :     *internalProperties = std::move(propertiesProtocolArray);
     418      136591 :   return Response::OK();
     419             : }
     420             : 
     421           5 : Response V8RuntimeAgentImpl::releaseObject(const String16& objectId) {
     422           5 :   InjectedScript::ObjectScope scope(m_session, objectId);
     423           5 :   Response response = scope.initialize();
     424           5 :   if (!response.isSuccess()) return response;
     425           5 :   scope.injectedScript()->releaseObject(objectId);
     426          10 :   return Response::OK();
     427             : }
     428             : 
     429           5 : Response V8RuntimeAgentImpl::releaseObjectGroup(const String16& objectGroup) {
     430           5 :   m_session->releaseObjectGroup(objectGroup);
     431           5 :   return Response::OK();
     432             : }
     433             : 
     434           0 : Response V8RuntimeAgentImpl::runIfWaitingForDebugger() {
     435           0 :   m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId());
     436           0 :   return Response::OK();
     437             : }
     438             : 
     439          10 : Response V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(bool enabled) {
     440             :   m_state->setBoolean(V8RuntimeAgentImplState::customObjectFormatterEnabled,
     441          20 :                       enabled);
     442          10 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     443          10 :   m_session->setCustomObjectFormatterEnabled(enabled);
     444          10 :   return Response::OK();
     445             : }
     446             : 
     447          15 : Response V8RuntimeAgentImpl::setMaxCallStackSizeToCapture(int size) {
     448          15 :   if (size < 0) {
     449           0 :     return Response::Error("maxCallStackSizeToCapture should be non-negative");
     450             :   }
     451          15 :   V8StackTraceImpl::maxCallStackSizeToCapture = size;
     452          15 :   return Response::OK();
     453             : }
     454             : 
     455           5 : Response V8RuntimeAgentImpl::discardConsoleEntries() {
     456             :   V8ConsoleMessageStorage* storage =
     457           5 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     458           5 :   storage->clear();
     459           5 :   return Response::OK();
     460             : }
     461             : 
     462         232 : Response V8RuntimeAgentImpl::compileScript(
     463             :     const String16& expression, const String16& sourceURL, bool persistScript,
     464             :     Maybe<int> executionContextId, Maybe<String16>* scriptId,
     465             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     466         237 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     467             : 
     468         227 :   int contextId = 0;
     469             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     470         419 :                                     std::move(executionContextId), &contextId);
     471         227 :   if (!response.isSuccess()) return response;
     472         454 :   InjectedScript::ContextScope scope(m_session, contextId);
     473         454 :   response = scope.initialize();
     474         227 :   if (!response.isSuccess()) return response;
     475             : 
     476         252 :   if (!persistScript) m_inspector->debugger()->muteScriptParsedEvents();
     477             :   v8::Local<v8::Script> script;
     478         227 :   bool isOk = m_inspector->compileScript(scope.context(), expression, sourceURL)
     479         227 :                   .ToLocal(&script);
     480         252 :   if (!persistScript) m_inspector->debugger()->unmuteScriptParsedEvents();
     481         227 :   if (!isOk) {
     482          25 :     if (scope.tryCatch().HasCaught()) {
     483         100 :       response = scope.injectedScript()->createExceptionDetails(
     484             :           scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails);
     485          25 :       if (!response.isSuccess()) return response;
     486          25 :       return Response::OK();
     487             :     } else {
     488           0 :       return Response::Error("Script compilation failed");
     489             :     }
     490             :   }
     491             : 
     492         202 :   if (!persistScript) return Response::OK();
     493             : 
     494             :   String16 scriptValueId =
     495         384 :       String16::fromInteger(script->GetUnboundScript()->GetId());
     496             :   std::unique_ptr<v8::Global<v8::Script>> global(
     497         384 :       new v8::Global<v8::Script>(m_inspector->isolate(), script));
     498             :   m_compiledScripts[scriptValueId] = std::move(global);
     499         192 :   *scriptId = scriptValueId;
     500         192 :   return Response::OK();
     501             : }
     502             : 
     503         182 : void V8RuntimeAgentImpl::runScript(
     504             :     const String16& scriptId, Maybe<int> executionContextId,
     505             :     Maybe<String16> objectGroup, Maybe<bool> silent,
     506             :     Maybe<bool> includeCommandLineAPI, Maybe<bool> returnByValue,
     507             :     Maybe<bool> generatePreview, Maybe<bool> awaitPromise,
     508             :     std::unique_ptr<RunScriptCallback> callback) {
     509         182 :   if (!m_enabled) {
     510          30 :     callback->sendFailure(Response::Error("Runtime agent is not enabled"));
     511         177 :     return;
     512             :   }
     513             : 
     514             :   auto it = m_compiledScripts.find(scriptId);
     515         172 :   if (it == m_compiledScripts.end()) {
     516          30 :     callback->sendFailure(Response::Error("No script with given id"));
     517          10 :     return;
     518             :   }
     519             : 
     520         162 :   int contextId = 0;
     521             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     522         486 :                                     std::move(executionContextId), &contextId);
     523         162 :   if (!response.isSuccess()) {
     524           0 :     callback->sendFailure(response);
     525           0 :     return;
     526             :   }
     527             : 
     528         177 :   InjectedScript::ContextScope scope(m_session, contextId);
     529         324 :   response = scope.initialize();
     530         162 :   if (!response.isSuccess()) {
     531           0 :     callback->sendFailure(response);
     532         147 :     return;
     533             :   }
     534             : 
     535         162 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     536             : 
     537             :   std::unique_ptr<v8::Global<v8::Script>> scriptWrapper = std::move(it->second);
     538             :   m_compiledScripts.erase(it);
     539         162 :   v8::Local<v8::Script> script = scriptWrapper->Get(m_inspector->isolate());
     540         162 :   if (script.IsEmpty()) {
     541           0 :     callback->sendFailure(Response::Error("Script execution failed"));
     542           0 :     return;
     543             :   }
     544             : 
     545         162 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     546             : 
     547             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     548             :   {
     549             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     550         324 :                                         v8::MicrotasksScope::kRunMicrotasks);
     551         162 :     maybeResultValue = script->Run(scope.context());
     552             :   }
     553             : 
     554             :   // Re-initialize after running client's code, as it could have destroyed
     555             :   // context or session.
     556         324 :   response = scope.initialize();
     557         162 :   if (!response.isSuccess()) {
     558           0 :     callback->sendFailure(response);
     559           0 :     return;
     560             :   }
     561             : 
     562             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     563         162 :                                                    : WrapMode::kNoPreview;
     564         162 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     565         162 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     566             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     567             :                             scope.tryCatch(), objectGroup.fromMaybe(""), mode,
     568         588 :                             callback.get());
     569         147 :     return;
     570             :   }
     571             :   scope.injectedScript()->addPromiseCallback(
     572             :       m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""),
     573             :       mode,
     574          75 :       EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
     575             : }
     576             : 
     577          85 : Response V8RuntimeAgentImpl::queryObjects(
     578             :     const String16& prototypeObjectId, Maybe<String16> objectGroup,
     579             :     std::unique_ptr<protocol::Runtime::RemoteObject>* objects) {
     580          85 :   InjectedScript::ObjectScope scope(m_session, prototypeObjectId);
     581          85 :   Response response = scope.initialize();
     582          85 :   if (!response.isSuccess()) return response;
     583          85 :   if (!scope.object()->IsObject()) {
     584           0 :     return Response::Error("Prototype should be instance of Object");
     585             :   }
     586             :   v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects(
     587         170 :       scope.context(), v8::Local<v8::Object>::Cast(scope.object()));
     588             :   return scope.injectedScript()->wrapObject(
     589             :       resultArray, objectGroup.fromMaybe(scope.objectGroupName()),
     590         255 :       WrapMode::kNoPreview, objects);
     591             : }
     592             : 
     593          35 : Response V8RuntimeAgentImpl::globalLexicalScopeNames(
     594             :     Maybe<int> executionContextId,
     595             :     std::unique_ptr<protocol::Array<String16>>* outNames) {
     596          35 :   int contextId = 0;
     597             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     598         185 :                                     std::move(executionContextId), &contextId);
     599          35 :   if (!response.isSuccess()) return response;
     600             : 
     601          70 :   InjectedScript::ContextScope scope(m_session, contextId);
     602          70 :   response = scope.initialize();
     603          35 :   if (!response.isSuccess()) return response;
     604             : 
     605          70 :   v8::PersistentValueVector<v8::String> names(m_inspector->isolate());
     606          35 :   v8::debug::GlobalLexicalScopeNames(scope.context(), &names);
     607             :   *outNames = protocol::Array<String16>::create();
     608         265 :   for (size_t i = 0; i < names.Size(); ++i) {
     609             :     (*outNames)->addItem(
     610         345 :         toProtocolString(m_inspector->isolate(), names.Get(i)));
     611             :   }
     612          35 :   return Response::OK();
     613             : }
     614             : 
     615           5 : Response V8RuntimeAgentImpl::getIsolateId(String16* outIsolateId) {
     616             :   char buf[40];
     617           5 :   std::snprintf(buf, sizeof(buf), "%" PRIx64, m_inspector->isolateId());
     618          10 :   *outIsolateId = buf;
     619           5 :   return Response::OK();
     620             : }
     621             : 
     622           5 : Response V8RuntimeAgentImpl::getHeapUsage(double* out_usedSize,
     623             :                                           double* out_totalSize) {
     624           5 :   v8::HeapStatistics stats;
     625           5 :   m_inspector->isolate()->GetHeapStatistics(&stats);
     626           5 :   *out_usedSize = stats.used_heap_size();
     627           5 :   *out_totalSize = stats.total_heap_size();
     628           5 :   return Response::OK();
     629             : }
     630             : 
     631          40 : void V8RuntimeAgentImpl::terminateExecution(
     632             :     std::unique_ptr<TerminateExecutionCallback> callback) {
     633         120 :   m_inspector->debugger()->terminateExecution(std::move(callback));
     634          40 : }
     635             : 
     636          25 : Response V8RuntimeAgentImpl::addBinding(const String16& name,
     637             :                                         Maybe<int> executionContextId) {
     638          50 :   if (!m_state->getObject(V8RuntimeAgentImplState::bindings)) {
     639             :     m_state->setObject(V8RuntimeAgentImplState::bindings,
     640          75 :                        protocol::DictionaryValue::create());
     641             :   }
     642             :   protocol::DictionaryValue* bindings =
     643          50 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     644          25 :   if (bindings->booleanProperty(name, false)) return Response::OK();
     645          25 :   if (executionContextId.isJust()) {
     646             :     int contextId = executionContextId.fromJust();
     647             :     InspectedContext* context =
     648          25 :         m_inspector->getContext(m_session->contextGroupId(), contextId);
     649           0 :     if (!context) {
     650             :       return Response::Error(
     651           0 :           "Cannot find execution context with given executionContextId");
     652             :     }
     653           0 :     addBinding(context, name);
     654             :     // false means that we should not add this binding later.
     655           0 :     bindings->setBoolean(name, false);
     656           0 :     return Response::OK();
     657             :   }
     658          25 :   bindings->setBoolean(name, true);
     659             :   m_inspector->forEachContext(
     660             :       m_session->contextGroupId(),
     661         100 :       [&name, this](InspectedContext* context) { addBinding(context, name); });
     662          25 :   return Response::OK();
     663             : }
     664             : 
     665          45 : void V8RuntimeAgentImpl::bindingCallback(
     666         135 :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     667             :   v8::Isolate* isolate = info.GetIsolate();
     668          90 :   if (info.Length() != 1 || !info[0]->IsString()) {
     669             :     info.GetIsolate()->ThrowException(toV8String(
     670           0 :         isolate, "Invalid arguments: should be exactly one string."));
     671          45 :     return;
     672             :   }
     673             :   V8InspectorImpl* inspector =
     674          45 :       static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
     675          45 :   int contextId = InspectedContext::contextId(isolate->GetCurrentContext());
     676          45 :   int contextGroupId = inspector->contextGroupId(contextId);
     677             : 
     678             :   String16 name =
     679          45 :       toProtocolString(isolate, v8::Local<v8::String>::Cast(info.Data()));
     680             :   String16 payload =
     681          45 :       toProtocolString(isolate, v8::Local<v8::String>::Cast(info[0]));
     682             : 
     683             :   inspector->forEachSession(
     684             :       contextGroupId,
     685             :       [&name, &payload, &contextId](V8InspectorSessionImpl* session) {
     686         140 :         session->runtimeAgent()->bindingCalled(name, payload, contextId);
     687          90 :       });
     688             : }
     689             : 
     690          30 : void V8RuntimeAgentImpl::addBinding(InspectedContext* context,
     691             :                                     const String16& name) {
     692          90 :   v8::HandleScope handles(m_inspector->isolate());
     693          30 :   v8::Local<v8::Context> localContext = context->context();
     694          30 :   v8::Local<v8::Object> global = localContext->Global();
     695          60 :   v8::Local<v8::String> v8Name = toV8String(m_inspector->isolate(), name);
     696             :   v8::Local<v8::Value> functionValue;
     697             :   v8::MicrotasksScope microtasks(m_inspector->isolate(),
     698          90 :                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
     699          30 :   if (v8::Function::New(localContext, bindingCallback, v8Name)
     700          30 :           .ToLocal(&functionValue)) {
     701          30 :     v8::Maybe<bool> success = global->Set(localContext, v8Name, functionValue);
     702             :     USE(success);
     703          30 :   }
     704          30 : }
     705             : 
     706           5 : Response V8RuntimeAgentImpl::removeBinding(const String16& name) {
     707             :   protocol::DictionaryValue* bindings =
     708          10 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     709           5 :   if (!bindings) return Response::OK();
     710           5 :   bindings->remove(name);
     711           5 :   return Response::OK();
     712             : }
     713             : 
     714          70 : void V8RuntimeAgentImpl::bindingCalled(const String16& name,
     715             :                                        const String16& payload,
     716             :                                        int executionContextId) {
     717             :   protocol::DictionaryValue* bindings =
     718         140 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     719         140 :   if (!bindings || !bindings->get(name)) return;
     720          35 :   m_frontend.bindingCalled(name, payload, executionContextId);
     721             : }
     722             : 
     723        2597 : void V8RuntimeAgentImpl::addBindings(InspectedContext* context) {
     724        2597 :   if (!m_enabled) return;
     725             :   protocol::DictionaryValue* bindings =
     726         120 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     727          60 :   if (!bindings) return;
     728          15 :   for (size_t i = 0; i < bindings->size(); ++i) {
     729          10 :     if (!bindings->at(i).second) continue;
     730          10 :     addBinding(context, bindings->at(i).first);
     731             :   }
     732             : }
     733             : 
     734          55 : void V8RuntimeAgentImpl::restore() {
     735         110 :   if (!m_state->booleanProperty(V8RuntimeAgentImplState::runtimeEnabled, false))
     736          55 :     return;
     737          40 :   m_frontend.executionContextsCleared();
     738          80 :   enable();
     739          80 :   if (m_state->booleanProperty(
     740          80 :           V8RuntimeAgentImplState::customObjectFormatterEnabled, false))
     741          45 :     m_session->setCustomObjectFormatterEnabled(true);
     742             : 
     743             :   m_inspector->forEachContext(
     744             :       m_session->contextGroupId(),
     745         160 :       [this](InspectedContext* context) { addBindings(context); });
     746             : }
     747             : 
     748         672 : Response V8RuntimeAgentImpl::enable() {
     749         672 :   if (m_enabled) return Response::OK();
     750         662 :   m_inspector->client()->beginEnsureAllContextsInGroup(
     751        1324 :       m_session->contextGroupId());
     752         662 :   m_enabled = true;
     753        1324 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true);
     754         662 :   m_inspector->enableStackCapturingIfNeeded();
     755         662 :   m_session->reportAllContexts(this);
     756             :   V8ConsoleMessageStorage* storage =
     757        1324 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     758        6012 :   for (const auto& message : storage->messages()) {
     759        5350 :     if (!reportMessage(message.get(), false)) break;
     760             :   }
     761         662 :   return Response::OK();
     762             : }
     763             : 
     764        4159 : Response V8RuntimeAgentImpl::disable() {
     765        4159 :   if (!m_enabled) return Response::OK();
     766         662 :   m_enabled = false;
     767        1324 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false);
     768        1324 :   m_state->remove(V8RuntimeAgentImplState::bindings);
     769        1324 :   m_inspector->disableStackCapturingIfNeeded();
     770        1324 :   m_session->setCustomObjectFormatterEnabled(false);
     771         662 :   reset();
     772         662 :   m_inspector->client()->endEnsureAllContextsInGroup(
     773        1324 :       m_session->contextGroupId());
     774        1324 :   if (m_session->debuggerAgent() && !m_session->debuggerAgent()->enabled()) {
     775        1282 :     m_session->debuggerAgent()->setAsyncCallStackDepth(0);
     776             :   }
     777         662 :   return Response::OK();
     778             : }
     779             : 
     780         666 : void V8RuntimeAgentImpl::reset() {
     781             :   m_compiledScripts.clear();
     782         666 :   if (m_enabled) {
     783           0 :     int sessionId = m_session->sessionId();
     784             :     m_inspector->forEachContext(m_session->contextGroupId(),
     785             :                                 [&sessionId](InspectedContext* context) {
     786           0 :                                   context->setReported(sessionId, false);
     787           0 :                                 });
     788           0 :     m_frontend.executionContextsCleared();
     789             :   }
     790         666 : }
     791             : 
     792        3219 : void V8RuntimeAgentImpl::reportExecutionContextCreated(
     793         682 :     InspectedContext* context) {
     794        6438 :   if (!m_enabled) return;
     795         682 :   context->setReported(m_session->sessionId(), true);
     796             :   std::unique_ptr<protocol::Runtime::ExecutionContextDescription> description =
     797             :       protocol::Runtime::ExecutionContextDescription::create()
     798         682 :           .setId(context->contextId())
     799         682 :           .setName(context->humanReadableName())
     800         682 :           .setOrigin(context->origin())
     801             :           .build();
     802         682 :   if (!context->auxData().isEmpty())
     803             :     description->setAuxData(protocol::DictionaryValue::cast(
     804           0 :         protocol::StringUtil::parseJSON(context->auxData())));
     805        1364 :   m_frontend.executionContextCreated(std::move(description));
     806             : }
     807             : 
     808          30 : void V8RuntimeAgentImpl::reportExecutionContextDestroyed(
     809          25 :     InspectedContext* context) {
     810          55 :   if (m_enabled && context->isReported(m_session->sessionId())) {
     811          50 :     context->setReported(m_session->sessionId(), false);
     812          25 :     m_frontend.executionContextDestroyed(context->contextId());
     813             :   }
     814          30 : }
     815             : 
     816          80 : void V8RuntimeAgentImpl::inspect(
     817             :     std::unique_ptr<protocol::Runtime::RemoteObject> objectToInspect,
     818             :     std::unique_ptr<protocol::DictionaryValue> hints) {
     819          80 :   if (m_enabled)
     820         240 :     m_frontend.inspectRequested(std::move(objectToInspect), std::move(hints));
     821          80 : }
     822             : 
     823        7180 : void V8RuntimeAgentImpl::messageAdded(V8ConsoleMessage* message) {
     824        7180 :   if (m_enabled) reportMessage(message, true);
     825        7180 : }
     826             : 
     827        6880 : bool V8RuntimeAgentImpl::reportMessage(V8ConsoleMessage* message,
     828             :                                        bool generatePreview) {
     829       13760 :   message->reportToFrontend(&m_frontend, m_session, generatePreview);
     830        6880 :   m_frontend.flush();
     831       13760 :   return m_inspector->hasConsoleMessageStorage(m_session->contextGroupId());
     832             : }
     833             : }  // namespace v8_inspector

Generated by: LCOV version 1.10