LCOV - code coverage report
Current view: top level - src/inspector - v8-runtime-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 370 422 87.7 %
Date: 2019-03-21 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        9156 : 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        9156 :   std::unique_ptr<RemoteObject> result;
      96             :   Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
      97             : 
      98             :   Response response = injectedScript->wrapEvaluateResult(
      99             :       maybeResultValue, tryCatch, objectGroup, wrapMode, &result,
     100        9156 :       &exceptionDetails);
     101        9156 :   if (response.isSuccess()) {
     102       36384 :     callback->sendSuccess(std::move(result), std::move(exceptionDetails));
     103        9096 :     return true;
     104             :   }
     105          60 :   callback->sendFailure(response);
     106          60 :   return false;
     107             : }
     108             : 
     109         716 : void innerCallFunctionOn(
     110             :     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             :   V8InspectorImpl* inspector = session->inspector();
     117             : 
     118             :   std::unique_ptr<v8::Local<v8::Value>[]> argv = nullptr;
     119             :   int argc = 0;
     120         716 :   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         400 :     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         716 :   if (silent) scope.ignoreExceptionsAndMuteConsole();
     138         716 :   if (userGesture) scope.pretendUserGesture();
     139             : 
     140             :   // Temporarily enable allow evals for inspector.
     141         716 :   scope.allowCodeGenerationFromStrings();
     142             : 
     143             :   v8::MaybeLocal<v8::Value> maybeFunctionValue;
     144             :   v8::Local<v8::Script> functionScript;
     145         716 :   if (inspector
     146        4296 :           ->compileScript(scope.context(), "(" + expression + ")", String16())
     147             :           .ToLocal(&functionScript)) {
     148             :     v8::MicrotasksScope microtasksScope(inspector->isolate(),
     149        1412 :                                         v8::MicrotasksScope::kRunMicrotasks);
     150         706 :     maybeFunctionValue = functionScript->Run(scope.context());
     151             :   }
     152             :   // Re-initialize after running client's code, as it could have destroyed
     153             :   // context or session.
     154         716 :   Response response = scope.initialize();
     155         716 :   if (!response.isSuccess()) {
     156           0 :     callback->sendFailure(response);
     157           0 :     return;
     158             :   }
     159             : 
     160         716 :   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        1402 :   if (!maybeFunctionValue.ToLocal(&functionValue) ||
     169         701 :       !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        1402 :                                         v8::MicrotasksScope::kRunMicrotasks);
     179             :     maybeResultValue = functionValue.As<v8::Function>()->Call(
     180         701 :         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        1402 :   response = scope.initialize();
     185         701 :   if (!response.isSuccess()) {
     186           0 :     callback->sendFailure(response);
     187           0 :     return;
     188             :   }
     189             : 
     190         701 :   if (!awaitPromise || scope.tryCatch().HasCaught()) {
     191             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     192             :                             scope.tryCatch(), objectGroup, wrapMode,
     193         681 :                             callback.get());
     194         681 :     return;
     195             :   }
     196             : 
     197             :   scope.injectedScript()->addPromiseCallback(
     198             :       session, maybeResultValue, objectGroup, wrapMode,
     199          20 :       EvaluateCallbackWrapper<V8RuntimeAgentImpl::CallFunctionOnCallback>::wrap(
     200          20 :           std::move(callback)));
     201             : }
     202             : 
     203        9351 : Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
     204             :                        Maybe<int> executionContextId, int* contextId) {
     205        9351 :   if (executionContextId.isJust()) {
     206          30 :     *contextId = executionContextId.fromJust();
     207             :   } else {
     208       18642 :     v8::HandleScope handles(inspector->isolate());
     209             :     v8::Local<v8::Context> defaultContext =
     210        9321 :         inspector->client()->ensureDefaultContextInGroup(contextGroupId);
     211        9321 :     if (defaultContext.IsEmpty())
     212           0 :       return Response::Error("Cannot find default execution context");
     213        9321 :     *contextId = InspectedContext::contextId(defaultContext);
     214             :   }
     215        9351 :   return Response::OK();
     216             : }
     217             : 
     218             : }  // namespace
     219             : 
     220        3866 : V8RuntimeAgentImpl::V8RuntimeAgentImpl(
     221             :     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       11598 :       m_enabled(false) {}
     228             : 
     229             : V8RuntimeAgentImpl::~V8RuntimeAgentImpl() = default;
     230             : 
     231        8922 : 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       18424 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
     239             :                "EvaluateScript");
     240        8922 :   int contextId = 0;
     241        8922 :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     242        8922 :                                     std::move(executionContextId), &contextId);
     243        8922 :   if (!response.isSuccess()) {
     244           0 :     callback->sendFailure(response);
     245           0 :     return;
     246             :   }
     247             : 
     248        9502 :   InjectedScript::ContextScope scope(m_session, contextId);
     249       17844 :   response = scope.initialize();
     250        8922 :   if (!response.isSuccess()) {
     251           9 :     callback->sendFailure(response);
     252           9 :     return;
     253             :   }
     254             : 
     255        8913 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     256        8913 :   if (userGesture.fromMaybe(false)) scope.pretendUserGesture();
     257             : 
     258        8913 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     259             : 
     260             :   // Temporarily enable allow evals for inspector.
     261        8913 :   scope.allowCodeGenerationFromStrings();
     262             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     263             :   {
     264       17826 :     V8InspectorImpl::EvaluateScope evaluateScope(scope);
     265        8913 :     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        8913 :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     273       17826 :                                         v8::MicrotasksScope::kRunMicrotasks);
     274             :     maybeResultValue = v8::debug::EvaluateGlobal(
     275       17826 :         m_inspector->isolate(), toV8String(m_inspector->isolate(), expression),
     276       26739 :         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       17826 :   response = scope.initialize();
     282        8913 :   if (!response.isSuccess()) {
     283          20 :     callback->sendFailure(response);
     284          20 :     return;
     285             :   }
     286             : 
     287             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     288        8893 :                                                    : WrapMode::kNoPreview;
     289        8893 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     290        8893 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     291             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     292       24939 :                             scope.tryCatch(), objectGroup.fromMaybe(""), mode,
     293        8313 :                             callback.get());
     294        8313 :     return;
     295             :   }
     296         580 :   scope.injectedScript()->addPromiseCallback(
     297        1740 :       m_session, maybeResultValue, objectGroup.fromMaybe(""), mode,
     298        1160 :       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          70 :   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          70 :   scope.injectedScript()->addPromiseCallback(
     320             :       m_session, scope.object(), scope.objectGroupName(), mode,
     321          70 :       EvaluateCallbackWrapper<AwaitPromiseCallback>::wrap(std::move(callback)));
     322             : }
     323             : 
     324         781 : 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         781 :   if (objectId.isJust() && executionContextId.isJust()) {
     332          15 :     callback->sendFailure(Response::Error(
     333          10 :         "ObjectId must not be specified together with executionContextId"));
     334           5 :     return;
     335             :   }
     336         776 :   if (!objectId.isJust() && !executionContextId.isJust()) {
     337           0 :     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         776 :                                                    : WrapMode::kNoPreview;
     343         776 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     344         776 :   if (objectId.isJust()) {
     345        2253 :     InjectedScript::ObjectScope scope(m_session, objectId.fromJust());
     346         771 :     Response response = scope.initialize();
     347         771 :     if (!response.isSuccess()) {
     348          60 :       callback->sendFailure(response);
     349             :       return;
     350             :     }
     351        5688 :     innerCallFunctionOn(m_session, scope, scope.object(), expression,
     352             :                         std::move(optionalArguments), silent.fromMaybe(false),
     353             :                         mode, userGesture.fromMaybe(false),
     354             :                         awaitPromise.fromMaybe(false),
     355             :                         objectGroup.isJust() ? objectGroup.fromMaybe(String16())
     356             :                                              : scope.objectGroupName(),
     357         711 :                         std::move(callback));
     358             :   } else {
     359           5 :     int contextId = 0;
     360             :     Response response =
     361           5 :         ensureContext(m_inspector, m_session->contextGroupId(),
     362           5 :                       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          40 :     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          20 :                         objectGroup.fromMaybe(""), std::move(callback));
     378             :   }
     379             : }
     380             : 
     381       68393 : 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::Array<protocol::Runtime::PrivatePropertyDescriptor>>*
     389             :         privateProperties,
     390             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     391             :   using protocol::Runtime::InternalPropertyDescriptor;
     392             :   using protocol::Runtime::PrivatePropertyDescriptor;
     393             : 
     394      136786 :   InjectedScript::ObjectScope scope(m_session, objectId);
     395       68393 :   Response response = scope.initialize();
     396       68393 :   if (!response.isSuccess()) return response;
     397             : 
     398       68393 :   scope.ignoreExceptionsAndMuteConsole();
     399       68393 :   v8::MicrotasksScope microtasks_scope(m_inspector->isolate(),
     400      136786 :                                        v8::MicrotasksScope::kRunMicrotasks);
     401       68393 :   if (!scope.object()->IsObject())
     402           0 :     return Response::Error("Value with given id is not an object");
     403             : 
     404             :   v8::Local<v8::Object> object = scope.object().As<v8::Object>();
     405      273572 :   response = scope.injectedScript()->getProperties(
     406             :       object, scope.objectGroupName(), ownProperties.fromMaybe(false),
     407             :       accessorPropertiesOnly.fromMaybe(false),
     408             :       generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     409             :                                        : WrapMode::kNoPreview,
     410             :       result, exceptionDetails);
     411       68393 :   if (!response.isSuccess()) return response;
     412      136786 :   if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
     413          10 :     return Response::OK();
     414             :   std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
     415      136766 :       internalPropertiesProtocolArray;
     416             :   std::unique_ptr<protocol::Array<PrivatePropertyDescriptor>>
     417      136766 :       privatePropertiesProtocolArray;
     418      136766 :   response = scope.injectedScript()->getInternalAndPrivateProperties(
     419             :       object, scope.objectGroupName(), &internalPropertiesProtocolArray,
     420             :       &privatePropertiesProtocolArray);
     421       68383 :   if (!response.isSuccess()) return response;
     422       68383 :   if (internalPropertiesProtocolArray->length())
     423         457 :     *internalProperties = std::move(internalPropertiesProtocolArray);
     424       68383 :   if (privatePropertiesProtocolArray->length())
     425          15 :     *privateProperties = std::move(privatePropertiesProtocolArray);
     426       68383 :   return Response::OK();
     427             : }
     428             : 
     429          25 : Response V8RuntimeAgentImpl::releaseObject(const String16& objectId) {
     430          50 :   InjectedScript::ObjectScope scope(m_session, objectId);
     431          25 :   Response response = scope.initialize();
     432          25 :   if (!response.isSuccess()) return response;
     433          25 :   scope.injectedScript()->releaseObject(objectId);
     434          25 :   return Response::OK();
     435             : }
     436             : 
     437          25 : Response V8RuntimeAgentImpl::releaseObjectGroup(const String16& objectGroup) {
     438          25 :   m_session->releaseObjectGroup(objectGroup);
     439          25 :   return Response::OK();
     440             : }
     441             : 
     442           0 : Response V8RuntimeAgentImpl::runIfWaitingForDebugger() {
     443           0 :   m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId());
     444           0 :   return Response::OK();
     445             : }
     446             : 
     447          10 : Response V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(bool enabled) {
     448          20 :   m_state->setBoolean(V8RuntimeAgentImplState::customObjectFormatterEnabled,
     449          10 :                       enabled);
     450          10 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     451          10 :   m_session->setCustomObjectFormatterEnabled(enabled);
     452          10 :   return Response::OK();
     453             : }
     454             : 
     455          15 : Response V8RuntimeAgentImpl::setMaxCallStackSizeToCapture(int size) {
     456          15 :   if (size < 0) {
     457           0 :     return Response::Error("maxCallStackSizeToCapture should be non-negative");
     458             :   }
     459          15 :   V8StackTraceImpl::maxCallStackSizeToCapture = size;
     460          15 :   return Response::OK();
     461             : }
     462             : 
     463           5 : Response V8RuntimeAgentImpl::discardConsoleEntries() {
     464             :   V8ConsoleMessageStorage* storage =
     465           5 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     466           5 :   storage->clear();
     467           5 :   return Response::OK();
     468             : }
     469             : 
     470         232 : Response V8RuntimeAgentImpl::compileScript(
     471             :     const String16& expression, const String16& sourceURL, bool persistScript,
     472             :     Maybe<int> executionContextId, Maybe<String16>* scriptId,
     473             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     474         237 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     475             : 
     476         227 :   int contextId = 0;
     477         227 :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     478         227 :                                     std::move(executionContextId), &contextId);
     479         227 :   if (!response.isSuccess()) return response;
     480         454 :   InjectedScript::ContextScope scope(m_session, contextId);
     481         454 :   response = scope.initialize();
     482         227 :   if (!response.isSuccess()) return response;
     483             : 
     484         252 :   if (!persistScript) m_inspector->debugger()->muteScriptParsedEvents();
     485             :   v8::Local<v8::Script> script;
     486         227 :   bool isOk = m_inspector->compileScript(scope.context(), expression, sourceURL)
     487             :                   .ToLocal(&script);
     488         252 :   if (!persistScript) m_inspector->debugger()->unmuteScriptParsedEvents();
     489         227 :   if (!isOk) {
     490          25 :     if (scope.tryCatch().HasCaught()) {
     491         100 :       response = scope.injectedScript()->createExceptionDetails(
     492             :           scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails);
     493          25 :       if (!response.isSuccess()) return response;
     494          25 :       return Response::OK();
     495             :     } else {
     496           0 :       return Response::Error("Script compilation failed");
     497             :     }
     498             :   }
     499             : 
     500         202 :   if (!persistScript) return Response::OK();
     501             : 
     502             :   String16 scriptValueId =
     503         384 :       String16::fromInteger(script->GetUnboundScript()->GetId());
     504             :   std::unique_ptr<v8::Global<v8::Script>> global(
     505         192 :       new v8::Global<v8::Script>(m_inspector->isolate(), script));
     506             :   m_compiledScripts[scriptValueId] = std::move(global);
     507         192 :   *scriptId = scriptValueId;
     508         192 :   return Response::OK();
     509             : }
     510             : 
     511         182 : void V8RuntimeAgentImpl::runScript(
     512             :     const String16& scriptId, Maybe<int> executionContextId,
     513             :     Maybe<String16> objectGroup, Maybe<bool> silent,
     514             :     Maybe<bool> includeCommandLineAPI, Maybe<bool> returnByValue,
     515             :     Maybe<bool> generatePreview, Maybe<bool> awaitPromise,
     516             :     std::unique_ptr<RunScriptCallback> callback) {
     517         182 :   if (!m_enabled) {
     518          30 :     callback->sendFailure(Response::Error("Runtime agent is not enabled"));
     519         177 :     return;
     520             :   }
     521             : 
     522             :   auto it = m_compiledScripts.find(scriptId);
     523         172 :   if (it == m_compiledScripts.end()) {
     524          30 :     callback->sendFailure(Response::Error("No script with given id"));
     525          10 :     return;
     526             :   }
     527             : 
     528         162 :   int contextId = 0;
     529         162 :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     530         162 :                                     std::move(executionContextId), &contextId);
     531         162 :   if (!response.isSuccess()) {
     532           0 :     callback->sendFailure(response);
     533           0 :     return;
     534             :   }
     535             : 
     536         177 :   InjectedScript::ContextScope scope(m_session, contextId);
     537         324 :   response = scope.initialize();
     538         162 :   if (!response.isSuccess()) {
     539           0 :     callback->sendFailure(response);
     540         147 :     return;
     541             :   }
     542             : 
     543         162 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     544             : 
     545             :   std::unique_ptr<v8::Global<v8::Script>> scriptWrapper = std::move(it->second);
     546             :   m_compiledScripts.erase(it);
     547         162 :   v8::Local<v8::Script> script = scriptWrapper->Get(m_inspector->isolate());
     548         162 :   if (script.IsEmpty()) {
     549           0 :     callback->sendFailure(Response::Error("Script execution failed"));
     550           0 :     return;
     551             :   }
     552             : 
     553         162 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     554             : 
     555             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     556             :   {
     557         162 :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     558         324 :                                         v8::MicrotasksScope::kRunMicrotasks);
     559         162 :     maybeResultValue = script->Run(scope.context());
     560             :   }
     561             : 
     562             :   // Re-initialize after running client's code, as it could have destroyed
     563             :   // context or session.
     564         324 :   response = scope.initialize();
     565         162 :   if (!response.isSuccess()) {
     566           0 :     callback->sendFailure(response);
     567           0 :     return;
     568             :   }
     569             : 
     570             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
     571         162 :                                                    : WrapMode::kNoPreview;
     572         162 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
     573         162 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     574             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     575         441 :                             scope.tryCatch(), objectGroup.fromMaybe(""), mode,
     576         147 :                             callback.get());
     577         147 :     return;
     578             :   }
     579          30 :   scope.injectedScript()->addPromiseCallback(
     580          45 :       m_session, maybeResultValue.ToLocalChecked(), objectGroup.fromMaybe(""),
     581             :       mode,
     582          30 :       EvaluateCallbackWrapper<RunScriptCallback>::wrap(std::move(callback)));
     583             : }
     584             : 
     585          85 : Response V8RuntimeAgentImpl::queryObjects(
     586             :     const String16& prototypeObjectId, Maybe<String16> objectGroup,
     587             :     std::unique_ptr<protocol::Runtime::RemoteObject>* objects) {
     588         170 :   InjectedScript::ObjectScope scope(m_session, prototypeObjectId);
     589          85 :   Response response = scope.initialize();
     590          85 :   if (!response.isSuccess()) return response;
     591          85 :   if (!scope.object()->IsObject()) {
     592           0 :     return Response::Error("Prototype should be instance of Object");
     593             :   }
     594          85 :   v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects(
     595          85 :       scope.context(), v8::Local<v8::Object>::Cast(scope.object()));
     596             :   return scope.injectedScript()->wrapObject(
     597          85 :       resultArray, objectGroup.fromMaybe(scope.objectGroupName()),
     598          85 :       WrapMode::kNoPreview, objects);
     599             : }
     600             : 
     601          35 : Response V8RuntimeAgentImpl::globalLexicalScopeNames(
     602             :     Maybe<int> executionContextId,
     603             :     std::unique_ptr<protocol::Array<String16>>* outNames) {
     604          35 :   int contextId = 0;
     605          35 :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     606          35 :                                     std::move(executionContextId), &contextId);
     607          35 :   if (!response.isSuccess()) return response;
     608             : 
     609          70 :   InjectedScript::ContextScope scope(m_session, contextId);
     610          70 :   response = scope.initialize();
     611          35 :   if (!response.isSuccess()) return response;
     612             : 
     613          70 :   v8::PersistentValueVector<v8::String> names(m_inspector->isolate());
     614          35 :   v8::debug::GlobalLexicalScopeNames(scope.context(), &names);
     615          35 :   *outNames = protocol::Array<String16>::create();
     616         265 :   for (size_t i = 0; i < names.Size(); ++i) {
     617             :     (*outNames)->addItem(
     618         230 :         toProtocolString(m_inspector->isolate(), names.Get(i)));
     619             :   }
     620          35 :   return Response::OK();
     621             : }
     622             : 
     623           5 : Response V8RuntimeAgentImpl::getIsolateId(String16* outIsolateId) {
     624             :   char buf[40];
     625           5 :   std::snprintf(buf, sizeof(buf), "%" PRIx64, m_inspector->isolateId());
     626          10 :   *outIsolateId = buf;
     627           5 :   return Response::OK();
     628             : }
     629             : 
     630           5 : Response V8RuntimeAgentImpl::getHeapUsage(double* out_usedSize,
     631             :                                           double* out_totalSize) {
     632           5 :   v8::HeapStatistics stats;
     633           5 :   m_inspector->isolate()->GetHeapStatistics(&stats);
     634           5 :   *out_usedSize = stats.used_heap_size();
     635           5 :   *out_totalSize = stats.total_heap_size();
     636           5 :   return Response::OK();
     637             : }
     638             : 
     639          40 : void V8RuntimeAgentImpl::terminateExecution(
     640             :     std::unique_ptr<TerminateExecutionCallback> callback) {
     641         120 :   m_inspector->debugger()->terminateExecution(std::move(callback));
     642          40 : }
     643             : 
     644          25 : Response V8RuntimeAgentImpl::addBinding(const String16& name,
     645             :                                         Maybe<int> executionContextId) {
     646          50 :   if (!m_state->getObject(V8RuntimeAgentImplState::bindings)) {
     647          50 :     m_state->setObject(V8RuntimeAgentImplState::bindings,
     648          50 :                        protocol::DictionaryValue::create());
     649             :   }
     650             :   protocol::DictionaryValue* bindings =
     651          50 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     652          25 :   if (bindings->booleanProperty(name, false)) return Response::OK();
     653          25 :   if (executionContextId.isJust()) {
     654             :     int contextId = executionContextId.fromJust();
     655             :     InspectedContext* context =
     656           0 :         m_inspector->getContext(m_session->contextGroupId(), contextId);
     657           0 :     if (!context) {
     658             :       return Response::Error(
     659           0 :           "Cannot find execution context with given executionContextId");
     660             :     }
     661           0 :     addBinding(context, name);
     662             :     // false means that we should not add this binding later.
     663           0 :     bindings->setBoolean(name, false);
     664           0 :     return Response::OK();
     665             :   }
     666          25 :   bindings->setBoolean(name, true);
     667          50 :   m_inspector->forEachContext(
     668          25 :       m_session->contextGroupId(),
     669          50 :       [&name, this](InspectedContext* context) { addBinding(context, name); });
     670          25 :   return Response::OK();
     671             : }
     672             : 
     673          45 : void V8RuntimeAgentImpl::bindingCallback(
     674             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     675             :   v8::Isolate* isolate = info.GetIsolate();
     676          90 :   if (info.Length() != 1 || !info[0]->IsString()) {
     677             :     info.GetIsolate()->ThrowException(toV8String(
     678           0 :         isolate, "Invalid arguments: should be exactly one string."));
     679           0 :     return;
     680             :   }
     681             :   V8InspectorImpl* inspector =
     682          45 :       static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
     683          45 :   int contextId = InspectedContext::contextId(isolate->GetCurrentContext());
     684          45 :   int contextGroupId = inspector->contextGroupId(contextId);
     685             : 
     686             :   String16 name =
     687          45 :       toProtocolString(isolate, v8::Local<v8::String>::Cast(info.Data()));
     688             :   String16 payload =
     689          45 :       toProtocolString(isolate, v8::Local<v8::String>::Cast(info[0]));
     690             : 
     691          45 :   inspector->forEachSession(
     692             :       contextGroupId,
     693         140 :       [&name, &payload, &contextId](V8InspectorSessionImpl* session) {
     694         140 :         session->runtimeAgent()->bindingCalled(name, payload, contextId);
     695          45 :       });
     696             : }
     697             : 
     698          30 : void V8RuntimeAgentImpl::addBinding(InspectedContext* context,
     699             :                                     const String16& name) {
     700          60 :   v8::HandleScope handles(m_inspector->isolate());
     701          30 :   v8::Local<v8::Context> localContext = context->context();
     702          30 :   v8::Local<v8::Object> global = localContext->Global();
     703          30 :   v8::Local<v8::String> v8Name = toV8String(m_inspector->isolate(), name);
     704             :   v8::Local<v8::Value> functionValue;
     705          30 :   v8::MicrotasksScope microtasks(m_inspector->isolate(),
     706          60 :                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
     707          60 :   if (v8::Function::New(localContext, bindingCallback, v8Name)
     708             :           .ToLocal(&functionValue)) {
     709          30 :     v8::Maybe<bool> success = global->Set(localContext, v8Name, functionValue);
     710             :     USE(success);
     711             :   }
     712          30 : }
     713             : 
     714           5 : Response V8RuntimeAgentImpl::removeBinding(const String16& name) {
     715             :   protocol::DictionaryValue* bindings =
     716          10 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     717           5 :   if (!bindings) return Response::OK();
     718           5 :   bindings->remove(name);
     719           5 :   return Response::OK();
     720             : }
     721             : 
     722          70 : void V8RuntimeAgentImpl::bindingCalled(const String16& name,
     723             :                                        const String16& payload,
     724             :                                        int executionContextId) {
     725             :   protocol::DictionaryValue* bindings =
     726         140 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     727          70 :   if (!bindings || !bindings->get(name)) return;
     728          35 :   m_frontend.bindingCalled(name, payload, executionContextId);
     729             : }
     730             : 
     731        2597 : void V8RuntimeAgentImpl::addBindings(InspectedContext* context) {
     732        2597 :   if (!m_enabled) return;
     733             :   protocol::DictionaryValue* bindings =
     734         120 :       m_state->getObject(V8RuntimeAgentImplState::bindings);
     735          60 :   if (!bindings) return;
     736          15 :   for (size_t i = 0; i < bindings->size(); ++i) {
     737          10 :     if (!bindings->at(i).second) continue;
     738          10 :     addBinding(context, bindings->at(i).first);
     739             :   }
     740             : }
     741             : 
     742          55 : void V8RuntimeAgentImpl::restore() {
     743         110 :   if (!m_state->booleanProperty(V8RuntimeAgentImplState::runtimeEnabled, false))
     744             :     return;
     745          40 :   m_frontend.executionContextsCleared();
     746          80 :   enable();
     747          80 :   if (m_state->booleanProperty(
     748             :           V8RuntimeAgentImplState::customObjectFormatterEnabled, false))
     749           5 :     m_session->setCustomObjectFormatterEnabled(true);
     750             : 
     751          80 :   m_inspector->forEachContext(
     752          40 :       m_session->contextGroupId(),
     753          80 :       [this](InspectedContext* context) { addBindings(context); });
     754             : }
     755             : 
     756         692 : Response V8RuntimeAgentImpl::enable() {
     757         692 :   if (m_enabled) return Response::OK();
     758         682 :   m_inspector->client()->beginEnsureAllContextsInGroup(
     759         682 :       m_session->contextGroupId());
     760         682 :   m_enabled = true;
     761        1364 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true);
     762         682 :   m_inspector->enableStackCapturingIfNeeded();
     763         682 :   m_session->reportAllContexts(this);
     764             :   V8ConsoleMessageStorage* storage =
     765         682 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     766        6042 :   for (const auto& message : storage->messages()) {
     767        5360 :     if (!reportMessage(message.get(), false)) break;
     768             :   }
     769         682 :   return Response::OK();
     770             : }
     771             : 
     772        4193 : Response V8RuntimeAgentImpl::disable() {
     773        4193 :   if (!m_enabled) return Response::OK();
     774         682 :   m_enabled = false;
     775        1364 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false);
     776        1364 :   m_state->remove(V8RuntimeAgentImplState::bindings);
     777         682 :   m_inspector->disableStackCapturingIfNeeded();
     778         682 :   m_session->setCustomObjectFormatterEnabled(false);
     779         682 :   reset();
     780         682 :   m_inspector->client()->endEnsureAllContextsInGroup(
     781         682 :       m_session->contextGroupId());
     782        1364 :   if (m_session->debuggerAgent() && !m_session->debuggerAgent()->enabled()) {
     783        1322 :     m_session->debuggerAgent()->setAsyncCallStackDepth(0);
     784             :   }
     785         682 :   return Response::OK();
     786             : }
     787             : 
     788         686 : void V8RuntimeAgentImpl::reset() {
     789             :   m_compiledScripts.clear();
     790         686 :   if (m_enabled) {
     791           0 :     int sessionId = m_session->sessionId();
     792           0 :     m_inspector->forEachContext(m_session->contextGroupId(),
     793           0 :                                 [&sessionId](InspectedContext* context) {
     794           0 :                                   context->setReported(sessionId, false);
     795           0 :                                 });
     796           0 :     m_frontend.executionContextsCleared();
     797             :   }
     798         686 : }
     799             : 
     800        3239 : void V8RuntimeAgentImpl::reportExecutionContextCreated(
     801             :     InspectedContext* context) {
     802        3239 :   if (!m_enabled) return;
     803         702 :   context->setReported(m_session->sessionId(), true);
     804             :   std::unique_ptr<protocol::Runtime::ExecutionContextDescription> description =
     805         702 :       protocol::Runtime::ExecutionContextDescription::create()
     806             :           .setId(context->contextId())
     807         702 :           .setName(context->humanReadableName())
     808         702 :           .setOrigin(context->origin())
     809             :           .build();
     810         702 :   if (!context->auxData().isEmpty())
     811             :     description->setAuxData(protocol::DictionaryValue::cast(
     812           0 :         protocol::StringUtil::parseJSON(context->auxData())));
     813        1404 :   m_frontend.executionContextCreated(std::move(description));
     814             : }
     815             : 
     816          30 : void V8RuntimeAgentImpl::reportExecutionContextDestroyed(
     817             :     InspectedContext* context) {
     818          30 :   if (m_enabled && context->isReported(m_session->sessionId())) {
     819          25 :     context->setReported(m_session->sessionId(), false);
     820          25 :     m_frontend.executionContextDestroyed(context->contextId());
     821             :   }
     822          30 : }
     823             : 
     824          80 : void V8RuntimeAgentImpl::inspect(
     825             :     std::unique_ptr<protocol::Runtime::RemoteObject> objectToInspect,
     826             :     std::unique_ptr<protocol::DictionaryValue> hints) {
     827          80 :   if (m_enabled)
     828         240 :     m_frontend.inspectRequested(std::move(objectToInspect), std::move(hints));
     829          80 : }
     830             : 
     831        7210 : void V8RuntimeAgentImpl::messageAdded(V8ConsoleMessage* message) {
     832        7210 :   if (m_enabled) reportMessage(message, true);
     833        7210 : }
     834             : 
     835        6910 : bool V8RuntimeAgentImpl::reportMessage(V8ConsoleMessage* message,
     836             :                                        bool generatePreview) {
     837        6910 :   message->reportToFrontend(&m_frontend, m_session, generatePreview);
     838        6910 :   m_frontend.flush();
     839        6910 :   return m_inspector->hasConsoleMessageStorage(m_session->contextGroupId());
     840             : }
     841             : }  // namespace v8_inspector

Generated by: LCOV version 1.10