LCOV - code coverage report
Current view: top level - src/inspector - v8-runtime-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 277 327 84.7 %
Date: 2017-04-26 Functions: 48 55 87.3 %

          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 "src/debug/debug-interface.h"
      34             : #include "src/inspector/injected-script.h"
      35             : #include "src/inspector/inspected-context.h"
      36             : #include "src/inspector/protocol/Protocol.h"
      37             : #include "src/inspector/remote-object-id.h"
      38             : #include "src/inspector/string-util.h"
      39             : #include "src/inspector/v8-console-message.h"
      40             : #include "src/inspector/v8-debugger-agent-impl.h"
      41             : #include "src/inspector/v8-debugger.h"
      42             : #include "src/inspector/v8-inspector-impl.h"
      43             : #include "src/inspector/v8-inspector-session-impl.h"
      44             : #include "src/inspector/v8-stack-trace-impl.h"
      45             : #include "src/tracing/trace-event.h"
      46             : 
      47             : #include "include/v8-inspector.h"
      48             : 
      49             : namespace v8_inspector {
      50             : 
      51             : namespace V8RuntimeAgentImplState {
      52             : static const char customObjectFormatterEnabled[] =
      53             :     "customObjectFormatterEnabled";
      54             : static const char runtimeEnabled[] = "runtimeEnabled";
      55             : };
      56             : 
      57             : using protocol::Runtime::RemoteObject;
      58             : 
      59             : namespace {
      60             : 
      61             : template <typename Callback>
      62          84 : class ProtocolPromiseHandler {
      63             :  public:
      64        1302 :   static void add(V8InspectorImpl* inspector, v8::Local<v8::Context> context,
      65             :                   v8::MaybeLocal<v8::Value> value,
      66             :                   const String16& notPromiseError, int contextGroupId,
      67             :                   int executionContextId, const String16& objectGroup,
      68             :                   bool returnByValue, bool generatePreview,
      69             :                   std::unique_ptr<Callback> callback) {
      70         450 :     if (value.IsEmpty()) {
      71           0 :       callback->sendFailure(Response::InternalError());
      72          24 :       return;
      73             :     }
      74         450 :     if (!value.ToLocalChecked()->IsPromise()) {
      75          48 :       callback->sendFailure(Response::Error(notPromiseError));
      76          24 :       return;
      77             :     }
      78             :     v8::MicrotasksScope microtasks_scope(inspector->isolate(),
      79         426 :                                          v8::MicrotasksScope::kRunMicrotasks);
      80             :     v8::Local<v8::Promise> promise =
      81             :         v8::Local<v8::Promise>::Cast(value.ToLocalChecked());
      82             :     Callback* rawCallback = callback.get();
      83             :     ProtocolPromiseHandler<Callback>* handler = new ProtocolPromiseHandler(
      84             :         inspector, contextGroupId, executionContextId, objectGroup,
      85         852 :         returnByValue, generatePreview, std::move(callback));
      86             :     v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate());
      87             : 
      88             :     v8::Local<v8::Function> thenCallbackFunction =
      89             :         v8::Function::New(context, thenCallback, wrapper, 0,
      90             :                           v8::ConstructorBehavior::kThrow)
      91         852 :             .ToLocalChecked();
      92         852 :     if (promise->Then(context, thenCallbackFunction).IsEmpty()) {
      93           0 :       rawCallback->sendFailure(Response::InternalError());
      94           0 :       return;
      95             :     }
      96             :     v8::Local<v8::Function> catchCallbackFunction =
      97             :         v8::Function::New(context, catchCallback, wrapper, 0,
      98             :                           v8::ConstructorBehavior::kThrow)
      99         852 :             .ToLocalChecked();
     100         852 :     if (promise->Catch(context, catchCallbackFunction).IsEmpty()) {
     101           0 :       rawCallback->sendFailure(Response::InternalError());
     102           0 :       return;
     103         426 :     }
     104             :   }
     105             : 
     106             :  private:
     107         780 :   static void thenCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     108             :     ProtocolPromiseHandler<Callback>* handler =
     109             :         static_cast<ProtocolPromiseHandler<Callback>*>(
     110         390 :             info.Data().As<v8::External>()->Value());
     111             :     DCHECK(handler);
     112             :     v8::Local<v8::Value> value =
     113             :         info.Length() > 0
     114             :             ? info[0]
     115         780 :             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
     116             :     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue(
     117         390 :         handler->wrapObject(value));
     118         780 :     if (!wrappedValue) return;
     119        1536 :     handler->m_callback->sendSuccess(
     120             :         std::move(wrappedValue), Maybe<protocol::Runtime::ExceptionDetails>());
     121             :   }
     122             : 
     123          60 :   static void catchCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     124             :     ProtocolPromiseHandler<Callback>* handler =
     125             :         static_cast<ProtocolPromiseHandler<Callback>*>(
     126          30 :             info.Data().As<v8::External>()->Value());
     127             :     DCHECK(handler);
     128             :     v8::Local<v8::Value> value =
     129             :         info.Length() > 0
     130             :             ? info[0]
     131          60 :             : v8::Local<v8::Value>::Cast(v8::Undefined(info.GetIsolate()));
     132             : 
     133             :     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue(
     134          30 :         handler->wrapObject(value));
     135          60 :     if (!wrappedValue) return;
     136             : 
     137             :     std::unique_ptr<V8StackTraceImpl> stack =
     138          60 :         handler->m_inspector->debugger()->captureStackTrace(true);
     139             :     std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
     140             :         protocol::Runtime::ExceptionDetails::create()
     141             :             .setExceptionId(handler->m_inspector->nextExceptionId())
     142             :             .setText("Uncaught (in promise)")
     143          12 :             .setLineNumber(stack && !stack->isEmpty() ? stack->topLineNumber()
     144             :                                                       : 0)
     145             :             .setColumnNumber(
     146          12 :                 stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
     147             :             .setException(wrappedValue->clone())
     148         234 :             .build();
     149          30 :     if (stack)
     150          24 :       exceptionDetails->setStackTrace(stack->buildInspectorObjectImpl());
     151          30 :     if (stack && !stack->isEmpty())
     152           0 :       exceptionDetails->setScriptId(toString16(stack->topScriptId()));
     153         120 :     handler->m_callback->sendSuccess(std::move(wrappedValue),
     154             :                                      std::move(exceptionDetails));
     155             :   }
     156             : 
     157        1278 :   ProtocolPromiseHandler(V8InspectorImpl* inspector, int contextGroupId,
     158             :                          int executionContextId, const String16& objectGroup,
     159             :                          bool returnByValue, bool generatePreview,
     160             :                          std::unique_ptr<Callback> callback)
     161             :       : m_inspector(inspector),
     162             :         m_contextGroupId(contextGroupId),
     163             :         m_executionContextId(executionContextId),
     164             :         m_objectGroup(objectGroup),
     165             :         m_returnByValue(returnByValue),
     166             :         m_generatePreview(generatePreview),
     167             :         m_callback(std::move(callback)),
     168             :         m_wrapper(inspector->isolate(),
     169        1278 :                   v8::External::New(inspector->isolate(), this)) {
     170             :     m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter);
     171         426 :   }
     172             : 
     173         138 :   static void cleanup(
     174         276 :       const v8::WeakCallbackInfo<ProtocolPromiseHandler<Callback>>& data) {
     175         138 :     if (!data.GetParameter()->m_wrapper.IsEmpty()) {
     176             :       data.GetParameter()->m_wrapper.Reset();
     177             :       data.SetSecondPassCallback(cleanup);
     178             :     } else {
     179         126 :       data.GetParameter()->m_callback->sendFailure(
     180             :           Response::Error("Promise was collected"));
     181          42 :       delete data.GetParameter();
     182             :     }
     183         138 :   }
     184             : 
     185         420 :   std::unique_ptr<protocol::Runtime::RemoteObject> wrapObject(
     186             :       v8::Local<v8::Value> value) {
     187             :     InjectedScript::ContextScope scope(m_inspector, m_contextGroupId,
     188         420 :                                        m_executionContextId);
     189         420 :     Response response = scope.initialize();
     190         420 :     if (!response.isSuccess()) {
     191           0 :       m_callback->sendFailure(response);
     192             :       return nullptr;
     193             :     }
     194         420 :     std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
     195         840 :     response = scope.injectedScript()->wrapObject(
     196             :         value, m_objectGroup, m_returnByValue, m_generatePreview,
     197             :         &wrappedValue);
     198         420 :     if (!response.isSuccess()) {
     199           6 :       m_callback->sendFailure(response);
     200             :       return nullptr;
     201             :     }
     202         420 :     return wrappedValue;
     203             :   }
     204             : 
     205             :   V8InspectorImpl* m_inspector;
     206             :   int m_contextGroupId;
     207             :   int m_executionContextId;
     208             :   String16 m_objectGroup;
     209             :   bool m_returnByValue;
     210             :   bool m_generatePreview;
     211             :   std::unique_ptr<Callback> m_callback;
     212             :   v8::Global<v8::External> m_wrapper;
     213             : };
     214             : 
     215             : template <typename Callback>
     216        4751 : bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
     217             :                              v8::MaybeLocal<v8::Value> maybeResultValue,
     218             :                              const v8::TryCatch& tryCatch,
     219             :                              const String16& objectGroup, bool returnByValue,
     220             :                              bool generatePreview, Callback* callback) {
     221        4751 :   std::unique_ptr<RemoteObject> result;
     222             :   Maybe<protocol::Runtime::ExceptionDetails> exceptionDetails;
     223             : 
     224             :   Response response = injectedScript->wrapEvaluateResult(
     225             :       maybeResultValue, tryCatch, objectGroup, returnByValue, generatePreview,
     226        4751 :       &result, &exceptionDetails);
     227        4751 :   if (response.isSuccess()) {
     228       19004 :     callback->sendSuccess(std::move(result), std::move(exceptionDetails));
     229        4751 :     return true;
     230             :   }
     231           0 :   callback->sendFailure(response);
     232           0 :   return false;
     233             : }
     234             : 
     235       14985 : Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
     236             :                        Maybe<int> executionContextId, int* contextId) {
     237        5015 :   if (executionContextId.isJust()) {
     238          30 :     *contextId = executionContextId.fromJust();
     239             :   } else {
     240        4985 :     v8::HandleScope handles(inspector->isolate());
     241             :     v8::Local<v8::Context> defaultContext =
     242        4985 :         inspector->client()->ensureDefaultContextInGroup(contextGroupId);
     243        4985 :     if (defaultContext.IsEmpty())
     244           0 :       return Response::Error("Cannot find default execution context");
     245        4985 :     *contextId = InspectedContext::contextId(defaultContext);
     246             :   }
     247        5015 :   return Response::OK();
     248             : }
     249             : 
     250             : }  // namespace
     251             : 
     252        4573 : V8RuntimeAgentImpl::V8RuntimeAgentImpl(
     253        4573 :     V8InspectorSessionImpl* session, protocol::FrontendChannel* FrontendChannel,
     254             :     protocol::DictionaryValue* state)
     255             :     : m_session(session),
     256             :       m_state(state),
     257             :       m_frontend(FrontendChannel),
     258             :       m_inspector(session->inspector()),
     259       13719 :       m_enabled(false) {}
     260             : 
     261       13719 : V8RuntimeAgentImpl::~V8RuntimeAgentImpl() {}
     262             : 
     263        4745 : void V8RuntimeAgentImpl::evaluate(
     264             :     const String16& expression, Maybe<String16> objectGroup,
     265             :     Maybe<bool> includeCommandLineAPI, Maybe<bool> silent,
     266             :     Maybe<int> executionContextId, Maybe<bool> returnByValue,
     267             :     Maybe<bool> generatePreview, Maybe<bool> userGesture,
     268             :     Maybe<bool> awaitPromise, std::unique_ptr<EvaluateCallback> callback) {
     269        9490 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
     270             :                "EvaluateScript");
     271        4745 :   int contextId = 0;
     272             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     273       14583 :                                     std::move(executionContextId), &contextId);
     274        4745 :   if (!response.isSuccess()) {
     275           0 :     callback->sendFailure(response);
     276           0 :     return;
     277             :   }
     278             : 
     279             :   InjectedScript::ContextScope scope(m_inspector, m_session->contextGroupId(),
     280        9862 :                                      contextId);
     281        9490 :   response = scope.initialize();
     282        4745 :   if (!response.isSuccess()) {
     283           6 :     callback->sendFailure(response);
     284           6 :     return;
     285             :   }
     286             : 
     287        4739 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     288        4739 :   if (userGesture.fromMaybe(false)) scope.pretendUserGesture();
     289             : 
     290        4739 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     291             : 
     292        4739 :   bool evalIsDisabled = !scope.context()->IsCodeGenerationFromStringsAllowed();
     293             :   // Temporarily enable allow evals for inspector.
     294        4739 :   if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(true);
     295             : 
     296             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     297             :   v8::Local<v8::Script> script;
     298        9478 :   if (m_inspector->compileScript(scope.context(), expression, String16())
     299        9478 :           .ToLocal(&script)) {
     300             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     301        9442 :                                         v8::MicrotasksScope::kRunMicrotasks);
     302        4721 :     maybeResultValue = script->Run(scope.context());
     303             :   }
     304             : 
     305        4739 :   if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(false);
     306             : 
     307             :   // Re-initialize after running client's code, as it could have destroyed
     308             :   // context or session.
     309        9478 :   response = scope.initialize();
     310        4739 :   if (!response.isSuccess()) {
     311          12 :     callback->sendFailure(response);
     312          12 :     return;
     313             :   }
     314             : 
     315        4727 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     316             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     317             :                             scope.tryCatch(), objectGroup.fromMaybe(""),
     318             :                             returnByValue.fromMaybe(false),
     319       21775 :                             generatePreview.fromMaybe(false), callback.get());
     320        4355 :     return;
     321             :   }
     322             :   ProtocolPromiseHandler<EvaluateCallback>::add(
     323             :       m_inspector, scope.context(), maybeResultValue,
     324             :       "Result of the evaluation is not a promise", m_session->contextGroupId(),
     325             :       scope.injectedScript()->context()->contextId(), objectGroup.fromMaybe(""),
     326             :       returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
     327        3348 :       std::move(callback));
     328             : }
     329             : 
     330          36 : void V8RuntimeAgentImpl::awaitPromise(
     331             :     const String16& promiseObjectId, Maybe<bool> returnByValue,
     332             :     Maybe<bool> generatePreview,
     333             :     std::unique_ptr<AwaitPromiseCallback> callback) {
     334             :   InjectedScript::ObjectScope scope(m_inspector, m_session->contextGroupId(),
     335          72 :                                     promiseObjectId);
     336          36 :   Response response = scope.initialize();
     337          36 :   if (!response.isSuccess()) {
     338           0 :     callback->sendFailure(response);
     339          36 :     return;
     340             :   }
     341             :   ProtocolPromiseHandler<AwaitPromiseCallback>::add(
     342             :       m_inspector, scope.context(), scope.object(),
     343             :       "Could not find promise with given id", m_session->contextGroupId(),
     344             :       scope.injectedScript()->context()->contextId(), scope.objectGroupName(),
     345             :       returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
     346         252 :       std::move(callback));
     347             : }
     348             : 
     349         342 : void V8RuntimeAgentImpl::callFunctionOn(
     350             :     const String16& objectId, const String16& expression,
     351             :     Maybe<protocol::Array<protocol::Runtime::CallArgument>> optionalArguments,
     352             :     Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
     353             :     Maybe<bool> userGesture, Maybe<bool> awaitPromise,
     354             :     std::unique_ptr<CallFunctionOnCallback> callback) {
     355             :   InjectedScript::ObjectScope scope(m_inspector, m_session->contextGroupId(),
     356        1020 :                                     objectId);
     357         342 :   Response response = scope.initialize();
     358         342 :   if (!response.isSuccess()) {
     359           0 :     callback->sendFailure(response);
     360           0 :     return;
     361             :   }
     362             : 
     363             :   std::unique_ptr<v8::Local<v8::Value>[]> argv = nullptr;
     364             :   int argc = 0;
     365         342 :   if (optionalArguments.isJust()) {
     366             :     protocol::Array<protocol::Runtime::CallArgument>* arguments =
     367             :         optionalArguments.fromJust();
     368          42 :     argc = static_cast<int>(arguments->length());
     369          84 :     argv.reset(new v8::Local<v8::Value>[argc]);
     370          42 :     for (int i = 0; i < argc; ++i) {
     371             :       v8::Local<v8::Value> argumentValue;
     372         126 :       response = scope.injectedScript()->resolveCallArgument(arguments->get(i),
     373             :                                                              &argumentValue);
     374          42 :       if (!response.isSuccess()) {
     375           0 :         callback->sendFailure(response);
     376           0 :         return;
     377             :       }
     378          42 :       argv[i] = argumentValue;
     379             :     }
     380             :   }
     381             : 
     382         342 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     383         342 :   if (userGesture.fromMaybe(false)) scope.pretendUserGesture();
     384             : 
     385             :   v8::MaybeLocal<v8::Value> maybeFunctionValue;
     386             :   v8::Local<v8::Script> functionScript;
     387         342 :   if (m_inspector
     388        1710 :           ->compileScript(scope.context(), "(" + expression + ")", String16())
     389         684 :           .ToLocal(&functionScript)) {
     390             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     391         660 :                                         v8::MicrotasksScope::kRunMicrotasks);
     392         330 :     maybeFunctionValue = functionScript->Run(scope.context());
     393             :   }
     394             :   // Re-initialize after running client's code, as it could have destroyed
     395             :   // context or session.
     396         684 :   response = scope.initialize();
     397         342 :   if (!response.isSuccess()) {
     398           0 :     callback->sendFailure(response);
     399           0 :     return;
     400             :   }
     401             : 
     402         342 :   if (scope.tryCatch().HasCaught()) {
     403             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue,
     404             :                             scope.tryCatch(), scope.objectGroupName(), false,
     405          18 :                             false, callback.get());
     406          18 :     return;
     407             :   }
     408             : 
     409             :   v8::Local<v8::Value> functionValue;
     410         648 :   if (!maybeFunctionValue.ToLocal(&functionValue) ||
     411         324 :       !functionValue->IsFunction()) {
     412             :     callback->sendFailure(
     413           0 :         Response::Error("Given expression does not evaluate to a function"));
     414           0 :     return;
     415             :   }
     416             : 
     417             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     418             :   {
     419             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     420         648 :                                         v8::MicrotasksScope::kRunMicrotasks);
     421             :     maybeResultValue = functionValue.As<v8::Function>()->Call(
     422         324 :         scope.context(), scope.object(), argc, argv.get());
     423             :   }
     424             :   // Re-initialize after running client's code, as it could have destroyed
     425             :   // context or session.
     426         648 :   response = scope.initialize();
     427         324 :   if (!response.isSuccess()) {
     428           0 :     callback->sendFailure(response);
     429           0 :     return;
     430             :   }
     431             : 
     432         324 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     433             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     434             :                             scope.tryCatch(), scope.objectGroupName(),
     435             :                             returnByValue.fromMaybe(false),
     436         600 :                             generatePreview.fromMaybe(false), callback.get());
     437         300 :     return;
     438             :   }
     439             : 
     440             :   ProtocolPromiseHandler<CallFunctionOnCallback>::add(
     441             :       m_inspector, scope.context(), maybeResultValue,
     442             :       "Result of the function call is not a promise",
     443             :       m_session->contextGroupId(),
     444             :       scope.injectedScript()->context()->contextId(), scope.objectGroupName(),
     445             :       returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
     446         144 :       std::move(callback));
     447             : }
     448             : 
     449      106248 : Response V8RuntimeAgentImpl::getProperties(
     450             :     const String16& objectId, Maybe<bool> ownProperties,
     451             :     Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview,
     452             :     std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
     453             :         result,
     454             :     Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>*
     455             :         internalProperties,
     456             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     457             :   using protocol::Runtime::InternalPropertyDescriptor;
     458             : 
     459             :   InjectedScript::ObjectScope scope(m_inspector, m_session->contextGroupId(),
     460      106248 :                                     objectId);
     461      106248 :   Response response = scope.initialize();
     462      106248 :   if (!response.isSuccess()) return response;
     463             : 
     464      106248 :   scope.ignoreExceptionsAndMuteConsole();
     465      106248 :   if (!scope.object()->IsObject())
     466           0 :     return Response::Error("Value with given id is not an object");
     467             : 
     468      106248 :   v8::Local<v8::Object> object = scope.object().As<v8::Object>();
     469      424992 :   response = scope.injectedScript()->getProperties(
     470             :       object, scope.objectGroupName(), ownProperties.fromMaybe(false),
     471             :       accessorPropertiesOnly.fromMaybe(false), generatePreview.fromMaybe(false),
     472             :       result, exceptionDetails);
     473      106248 :   if (!response.isSuccess()) return response;
     474      212496 :   if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
     475           6 :     return Response::OK();
     476             :   v8::Local<v8::Array> propertiesArray;
     477      106242 :   if (!m_inspector->debugger()
     478      106242 :            ->internalProperties(scope.context(), scope.object())
     479      212484 :            .ToLocal(&propertiesArray)) {
     480           0 :     return Response::InternalError();
     481             :   }
     482             :   std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
     483             :       propertiesProtocolArray =
     484             :           protocol::Array<InternalPropertyDescriptor>::create();
     485      214460 :   for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) {
     486             :     v8::Local<v8::Value> name;
     487        2964 :     if (!propertiesArray->Get(scope.context(), i).ToLocal(&name) ||
     488             :         !name->IsString()) {
     489           0 :       return Response::InternalError();
     490             :     }
     491             :     v8::Local<v8::Value> value;
     492        1976 :     if (!propertiesArray->Get(scope.context(), i + 1).ToLocal(&value))
     493           0 :       return Response::InternalError();
     494         988 :     std::unique_ptr<RemoteObject> wrappedValue;
     495             :     protocol::Response response = scope.injectedScript()->wrapObject(
     496         988 :         value, scope.objectGroupName(), false, false, &wrappedValue);
     497         988 :     if (!response.isSuccess()) return response;
     498             :     propertiesProtocolArray->addItem(
     499             :         InternalPropertyDescriptor::create()
     500        2964 :             .setName(toProtocolString(name.As<v8::String>()))
     501             :             .setValue(std::move(wrappedValue))
     502         988 :             .build());
     503             :   }
     504      106242 :   if (propertiesProtocolArray->length())
     505             :     *internalProperties = std::move(propertiesProtocolArray);
     506      212490 :   return Response::OK();
     507             : }
     508             : 
     509           6 : Response V8RuntimeAgentImpl::releaseObject(const String16& objectId) {
     510             :   InjectedScript::ObjectScope scope(m_inspector, m_session->contextGroupId(),
     511           6 :                                     objectId);
     512           6 :   Response response = scope.initialize();
     513           6 :   if (!response.isSuccess()) return response;
     514           6 :   scope.injectedScript()->releaseObject(objectId);
     515          12 :   return Response::OK();
     516             : }
     517             : 
     518           0 : Response V8RuntimeAgentImpl::releaseObjectGroup(const String16& objectGroup) {
     519           0 :   m_session->releaseObjectGroup(objectGroup);
     520           0 :   return Response::OK();
     521             : }
     522             : 
     523           0 : Response V8RuntimeAgentImpl::runIfWaitingForDebugger() {
     524           0 :   m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId());
     525           0 :   return Response::OK();
     526             : }
     527             : 
     528           6 : Response V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(bool enabled) {
     529             :   m_state->setBoolean(V8RuntimeAgentImplState::customObjectFormatterEnabled,
     530          12 :                       enabled);
     531           6 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     532           6 :   m_session->setCustomObjectFormatterEnabled(enabled);
     533           6 :   return Response::OK();
     534             : }
     535             : 
     536           0 : Response V8RuntimeAgentImpl::discardConsoleEntries() {
     537             :   V8ConsoleMessageStorage* storage =
     538           0 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     539           0 :   storage->clear();
     540           0 :   return Response::OK();
     541             : }
     542             : 
     543         180 : Response V8RuntimeAgentImpl::compileScript(
     544             :     const String16& expression, const String16& sourceURL, bool persistScript,
     545             :     Maybe<int> executionContextId, Maybe<String16>* scriptId,
     546             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
     547         186 :   if (!m_enabled) return Response::Error("Runtime agent is not enabled");
     548             : 
     549         174 :   int contextId = 0;
     550             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     551         480 :                                     std::move(executionContextId), &contextId);
     552         174 :   if (!response.isSuccess()) return response;
     553             :   InjectedScript::ContextScope scope(m_inspector, m_session->contextGroupId(),
     554         522 :                                      contextId);
     555         348 :   response = scope.initialize();
     556         174 :   if (!response.isSuccess()) return response;
     557             : 
     558         204 :   if (!persistScript) m_inspector->debugger()->muteScriptParsedEvents();
     559             :   v8::Local<v8::Script> script;
     560         174 :   bool isOk = m_inspector->compileScript(scope.context(), expression, sourceURL)
     561         348 :                   .ToLocal(&script);
     562         204 :   if (!persistScript) m_inspector->debugger()->unmuteScriptParsedEvents();
     563         174 :   if (!isOk) {
     564          30 :     if (scope.tryCatch().HasCaught()) {
     565          90 :       response = scope.injectedScript()->createExceptionDetails(
     566             :           scope.tryCatch(), String16(), false, exceptionDetails);
     567          30 :       if (!response.isSuccess()) return response;
     568          30 :       return Response::OK();
     569             :     } else {
     570           0 :       return Response::Error("Script compilation failed");
     571             :     }
     572             :   }
     573             : 
     574         144 :   if (!persistScript) return Response::OK();
     575             : 
     576             :   String16 scriptValueId =
     577         264 :       String16::fromInteger(script->GetUnboundScript()->GetId());
     578             :   std::unique_ptr<v8::Global<v8::Script>> global(
     579         264 :       new v8::Global<v8::Script>(m_inspector->isolate(), script));
     580             :   m_compiledScripts[scriptValueId] = std::move(global);
     581         132 :   *scriptId = scriptValueId;
     582         132 :   return Response::OK();
     583             : }
     584             : 
     585         120 : void V8RuntimeAgentImpl::runScript(
     586             :     const String16& scriptId, Maybe<int> executionContextId,
     587             :     Maybe<String16> objectGroup, Maybe<bool> silent,
     588             :     Maybe<bool> includeCommandLineAPI, Maybe<bool> returnByValue,
     589             :     Maybe<bool> generatePreview, Maybe<bool> awaitPromise,
     590             :     std::unique_ptr<RunScriptCallback> callback) {
     591         120 :   if (!m_enabled) {
     592          36 :     callback->sendFailure(Response::Error("Runtime agent is not enabled"));
     593         114 :     return;
     594             :   }
     595             : 
     596             :   auto it = m_compiledScripts.find(scriptId);
     597         108 :   if (it == m_compiledScripts.end()) {
     598          36 :     callback->sendFailure(Response::Error("No script with given id"));
     599          12 :     return;
     600             :   }
     601             : 
     602          96 :   int contextId = 0;
     603             :   Response response = ensureContext(m_inspector, m_session->contextGroupId(),
     604         402 :                                     std::move(executionContextId), &contextId);
     605          96 :   if (!response.isSuccess()) {
     606           0 :     callback->sendFailure(response);
     607           0 :     return;
     608             :   }
     609             : 
     610             :   InjectedScript::ContextScope scope(m_inspector, m_session->contextGroupId(),
     611         210 :                                      contextId);
     612         192 :   response = scope.initialize();
     613          96 :   if (!response.isSuccess()) {
     614           0 :     callback->sendFailure(response);
     615          78 :     return;
     616             :   }
     617             : 
     618          96 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
     619             : 
     620             :   std::unique_ptr<v8::Global<v8::Script>> scriptWrapper = std::move(it->second);
     621             :   m_compiledScripts.erase(it);
     622          96 :   v8::Local<v8::Script> script = scriptWrapper->Get(m_inspector->isolate());
     623          96 :   if (script.IsEmpty()) {
     624           0 :     callback->sendFailure(Response::Error("Script execution failed"));
     625           0 :     return;
     626             :   }
     627             : 
     628          96 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
     629             : 
     630             :   v8::MaybeLocal<v8::Value> maybeResultValue;
     631             :   {
     632             :     v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
     633         192 :                                         v8::MicrotasksScope::kRunMicrotasks);
     634          96 :     maybeResultValue = script->Run(scope.context());
     635             :   }
     636             : 
     637             :   // Re-initialize after running client's code, as it could have destroyed
     638             :   // context or session.
     639         192 :   response = scope.initialize();
     640          96 :   if (!response.isSuccess()) {
     641           0 :     callback->sendFailure(response);
     642           0 :     return;
     643             :   }
     644             : 
     645          96 :   if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) {
     646             :     wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue,
     647             :                             scope.tryCatch(), objectGroup.fromMaybe(""),
     648             :                             returnByValue.fromMaybe(false),
     649         390 :                             generatePreview.fromMaybe(false), callback.get());
     650          78 :     return;
     651             :   }
     652             :   ProtocolPromiseHandler<RunScriptCallback>::add(
     653             :       m_inspector, scope.context(), maybeResultValue.ToLocalChecked(),
     654             :       "Result of the script execution is not a promise",
     655             :       m_session->contextGroupId(),
     656             :       scope.injectedScript()->context()->contextId(), objectGroup.fromMaybe(""),
     657             :       returnByValue.fromMaybe(false), generatePreview.fromMaybe(false),
     658         162 :       std::move(callback));
     659             : }
     660             : 
     661          36 : void V8RuntimeAgentImpl::restore() {
     662          72 :   if (!m_state->booleanProperty(V8RuntimeAgentImplState::runtimeEnabled, false))
     663          36 :     return;
     664          30 :   m_frontend.executionContextsCleared();
     665          60 :   enable();
     666          60 :   if (m_state->booleanProperty(
     667          60 :           V8RuntimeAgentImplState::customObjectFormatterEnabled, false))
     668           6 :     m_session->setCustomObjectFormatterEnabled(true);
     669             : }
     670             : 
     671         396 : Response V8RuntimeAgentImpl::enable() {
     672         396 :   if (m_enabled) return Response::OK();
     673         396 :   m_inspector->client()->beginEnsureAllContextsInGroup(
     674         792 :       m_session->contextGroupId());
     675         396 :   m_enabled = true;
     676         792 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true);
     677         396 :   m_inspector->enableStackCapturingIfNeeded();
     678         396 :   m_session->reportAllContexts(this);
     679             :   V8ConsoleMessageStorage* storage =
     680         792 :       m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
     681        6624 :   for (const auto& message : storage->messages()) {
     682        6228 :     if (!reportMessage(message.get(), false)) break;
     683             :   }
     684         396 :   return Response::OK();
     685             : }
     686             : 
     687        4765 : Response V8RuntimeAgentImpl::disable() {
     688        4765 :   if (!m_enabled) return Response::OK();
     689         396 :   m_enabled = false;
     690         792 :   m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false);
     691         792 :   m_inspector->disableStackCapturingIfNeeded();
     692         792 :   m_session->discardInjectedScripts();
     693         396 :   m_session->setCustomObjectFormatterEnabled(false);
     694         396 :   reset();
     695         396 :   m_inspector->client()->endEnsureAllContextsInGroup(
     696         792 :       m_session->contextGroupId());
     697         396 :   return Response::OK();
     698             : }
     699             : 
     700         396 : void V8RuntimeAgentImpl::reset() {
     701             :   m_compiledScripts.clear();
     702         396 :   if (m_enabled) {
     703           0 :     if (const V8InspectorImpl::ContextByIdMap* contexts =
     704           0 :             m_inspector->contextGroup(m_session->contextGroupId())) {
     705           0 :       for (auto& idContext : *contexts) idContext.second->setReported(false);
     706             :     }
     707           0 :     m_frontend.executionContextsCleared();
     708             :   }
     709         396 : }
     710             : 
     711        4945 : void V8RuntimeAgentImpl::reportExecutionContextCreated(
     712         402 :     InspectedContext* context) {
     713        9890 :   if (!m_enabled) return;
     714             :   context->setReported(true);
     715             :   std::unique_ptr<protocol::Runtime::ExecutionContextDescription> description =
     716             :       protocol::Runtime::ExecutionContextDescription::create()
     717         402 :           .setId(context->contextId())
     718         402 :           .setName(context->humanReadableName())
     719         402 :           .setOrigin(context->origin())
     720             :           .build();
     721         402 :   if (!context->auxData().isEmpty())
     722             :     description->setAuxData(protocol::DictionaryValue::cast(
     723           0 :         protocol::StringUtil::parseJSON(context->auxData())));
     724         804 :   m_frontend.executionContextCreated(std::move(description));
     725             : }
     726             : 
     727           6 : void V8RuntimeAgentImpl::reportExecutionContextDestroyed(
     728          12 :     InspectedContext* context) {
     729          12 :   if (m_enabled && context->isReported()) {
     730             :     context->setReported(false);
     731           6 :     m_frontend.executionContextDestroyed(context->contextId());
     732             :   }
     733           6 : }
     734             : 
     735          30 : void V8RuntimeAgentImpl::inspect(
     736             :     std::unique_ptr<protocol::Runtime::RemoteObject> objectToInspect,
     737             :     std::unique_ptr<protocol::DictionaryValue> hints) {
     738          30 :   if (m_enabled)
     739          90 :     m_frontend.inspectRequested(std::move(objectToInspect), std::move(hints));
     740          30 : }
     741             : 
     742        7338 : void V8RuntimeAgentImpl::messageAdded(V8ConsoleMessage* message) {
     743        7338 :   if (m_enabled) reportMessage(message, true);
     744        7338 : }
     745             : 
     746        7392 : bool V8RuntimeAgentImpl::reportMessage(V8ConsoleMessage* message,
     747             :                                        bool generatePreview) {
     748       14784 :   message->reportToFrontend(&m_frontend, m_session, generatePreview);
     749        7392 :   m_frontend.flush();
     750       14784 :   return m_inspector->hasConsoleMessageStorage(m_session->contextGroupId());
     751             : }
     752             : 
     753             : }  // namespace v8_inspector

Generated by: LCOV version 1.10