LCOV - code coverage report
Current view: top level - src/inspector - v8-console.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 343 371 92.5 %
Date: 2017-04-26 Functions: 55 59 93.2 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/inspector/v8-console.h"
       6             : 
       7             : #include "src/base/macros.h"
       8             : #include "src/inspector/injected-script.h"
       9             : #include "src/inspector/inspected-context.h"
      10             : #include "src/inspector/string-util.h"
      11             : #include "src/inspector/v8-console-message.h"
      12             : #include "src/inspector/v8-debugger-agent-impl.h"
      13             : #include "src/inspector/v8-inspector-impl.h"
      14             : #include "src/inspector/v8-inspector-session-impl.h"
      15             : #include "src/inspector/v8-profiler-agent-impl.h"
      16             : #include "src/inspector/v8-runtime-agent-impl.h"
      17             : #include "src/inspector/v8-stack-trace-impl.h"
      18             : #include "src/inspector/v8-value-copier.h"
      19             : 
      20             : #include "include/v8-inspector.h"
      21             : 
      22             : namespace v8_inspector {
      23             : 
      24             : namespace {
      25             : 
      26             : class ConsoleHelper {
      27             :  public:
      28        7640 :   ConsoleHelper(const v8::debug::ConsoleCallArguments& info,
      29        7640 :                 V8InspectorImpl* inspector)
      30             :       : m_info(info),
      31             :         m_isolate(inspector->isolate()),
      32             :         m_context(m_isolate->GetCurrentContext()),
      33             :         m_inspector(inspector),
      34        7640 :         m_contextId(InspectedContext::contextId(m_context)),
      35       22920 :         m_groupId(m_inspector->contextGroupId(m_contextId)) {}
      36             : 
      37             :   int contextId() const { return m_contextId; }
      38             :   int groupId() const { return m_groupId; }
      39             : 
      40             :   InjectedScript* injectedScript() {
      41          96 :     InspectedContext* context = m_inspector->getContext(m_groupId, m_contextId);
      42          96 :     if (!context) return nullptr;
      43             :     return context->getInjectedScript();
      44             :   }
      45             : 
      46             :   V8ConsoleMessageStorage* consoleMessageStorage() {
      47        7440 :     return m_inspector->ensureConsoleMessageStorage(m_groupId);
      48             :   }
      49             : 
      50        6642 :   void reportCall(ConsoleAPIType type) {
      51       13284 :     if (!m_info.Length()) return;
      52             :     std::vector<v8::Local<v8::Value>> arguments;
      53       33210 :     for (int i = 0; i < m_info.Length(); ++i) arguments.push_back(m_info[i]);
      54        6642 :     reportCall(type, arguments);
      55             :   }
      56             : 
      57         462 :   void reportCallWithDefaultArgument(ConsoleAPIType type,
      58             :                                      const String16& message) {
      59             :     std::vector<v8::Local<v8::Value>> arguments;
      60        2184 :     for (int i = 0; i < m_info.Length(); ++i) arguments.push_back(m_info[i]);
      61         504 :     if (!m_info.Length()) arguments.push_back(toV8String(m_isolate, message));
      62         462 :     reportCall(type, arguments);
      63         462 :   }
      64             : 
      65          84 :   void reportCallWithArgument(ConsoleAPIType type, const String16& message) {
      66             :     std::vector<v8::Local<v8::Value>> arguments(1,
      67         168 :                                                 toV8String(m_isolate, message));
      68          84 :     reportCall(type, arguments);
      69          84 :   }
      70             : 
      71        7254 :   void reportCall(ConsoleAPIType type,
      72        7254 :                   const std::vector<v8::Local<v8::Value>>& arguments) {
      73        7254 :     if (!m_groupId) return;
      74             :     std::unique_ptr<V8ConsoleMessage> message =
      75             :         V8ConsoleMessage::createForConsoleAPI(
      76             :             m_context, m_contextId, m_groupId, m_inspector,
      77       14508 :             m_inspector->client()->currentTimeMS(), type, arguments,
      78       36270 :             m_inspector->debugger()->captureStackTrace(false));
      79       14508 :     consoleMessageStorage()->addMessage(std::move(message));
      80             :   }
      81             : 
      82          60 :   void reportDeprecatedCall(const char* id, const String16& message) {
      83          30 :     if (!consoleMessageStorage()->shouldReportDeprecationMessage(m_contextId,
      84          90 :                                                                  id)) {
      85          12 :       return;
      86             :     }
      87             :     std::vector<v8::Local<v8::Value>> arguments(1,
      88          36 :                                                 toV8String(m_isolate, message));
      89          18 :     reportCall(ConsoleAPIType::kWarning, arguments);
      90             :   }
      91             : 
      92             :   bool firstArgToBoolean(bool defaultValue) {
      93             :     if (m_info.Length() < 1) return defaultValue;
      94             :     if (m_info[0]->IsBoolean()) return m_info[0].As<v8::Boolean>()->Value();
      95             :     return m_info[0]->BooleanValue(m_context).FromMaybe(defaultValue);
      96             :   }
      97             : 
      98         218 :   String16 firstArgToString(const String16& defaultValue) {
      99         436 :     if (m_info.Length() < 1) return defaultValue;
     100             :     v8::Local<v8::String> titleValue;
     101         191 :     if (m_info[0]->IsObject()) {
     102           0 :       if (!m_info[0].As<v8::Object>()->ObjectProtoToString(m_context).ToLocal(
     103           0 :               &titleValue))
     104             :         return defaultValue;
     105             :     } else {
     106         573 :       if (!m_info[0]->ToString(m_context).ToLocal(&titleValue))
     107             :         return defaultValue;
     108             :     }
     109         191 :     return toProtocolString(titleValue);
     110             :   }
     111             : 
     112          12 :   v8::MaybeLocal<v8::Object> firstArgAsObject() {
     113          36 :     if (m_info.Length() < 1 || !m_info[0]->IsObject())
     114           0 :       return v8::MaybeLocal<v8::Object>();
     115          24 :     return m_info[0].As<v8::Object>();
     116             :   }
     117             : 
     118         126 :   v8::MaybeLocal<v8::Function> firstArgAsFunction() {
     119         378 :     if (m_info.Length() < 1 || !m_info[0]->IsFunction())
     120           0 :       return v8::MaybeLocal<v8::Function>();
     121         126 :     v8::Local<v8::Function> func = m_info[0].As<v8::Function>();
     122         360 :     while (func->GetBoundFunction()->IsFunction())
     123          54 :       func = func->GetBoundFunction().As<v8::Function>();
     124         126 :     return func;
     125             :   }
     126             : 
     127          56 :   V8ProfilerAgentImpl* profilerAgent() {
     128          56 :     if (V8InspectorSessionImpl* session = currentSession()) {
     129         112 :       if (session && session->profilerAgent()->enabled())
     130          56 :         return session->profilerAgent();
     131             :     }
     132             :     return nullptr;
     133             :   }
     134             : 
     135         174 :   V8DebuggerAgentImpl* debuggerAgent() {
     136         174 :     if (V8InspectorSessionImpl* session = currentSession()) {
     137         348 :       if (session && session->debuggerAgent()->enabled())
     138         150 :         return session->debuggerAgent();
     139             :     }
     140             :     return nullptr;
     141             :   }
     142             : 
     143             :   V8InspectorSessionImpl* currentSession() {
     144         266 :     return m_inspector->sessionForContextGroup(m_groupId);
     145             :   }
     146             : 
     147             :  private:
     148             :   const v8::debug::ConsoleCallArguments& m_info;
     149             :   v8::Isolate* m_isolate;
     150             :   v8::Local<v8::Context> m_context;
     151             :   V8InspectorImpl* m_inspector = nullptr;
     152             :   int m_contextId;
     153             :   int m_groupId;
     154             : 
     155             :   DISALLOW_COPY_AND_ASSIGN(ConsoleHelper);
     156             : };
     157             : 
     158         672 : void returnDataCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     159             :   info.GetReturnValue().Set(info.Data());
     160         672 : }
     161             : 
     162        1080 : void createBoundFunctionProperty(v8::Local<v8::Context> context,
     163             :                                  v8::Local<v8::Object> console,
     164             :                                  v8::Local<v8::Value> data, const char* name,
     165             :                                  v8::FunctionCallback callback,
     166             :                                  const char* description = nullptr) {
     167             :   v8::Local<v8::String> funcName =
     168        1080 :       toV8StringInternalized(context->GetIsolate(), name);
     169             :   v8::Local<v8::Function> func;
     170        1080 :   if (!v8::Function::New(context, callback, data, 0,
     171             :                          v8::ConstructorBehavior::kThrow)
     172        2160 :            .ToLocal(&func))
     173           0 :     return;
     174        1080 :   func->SetName(funcName);
     175        1080 :   if (description) {
     176             :     v8::Local<v8::String> returnValue =
     177        1512 :         toV8String(context->GetIsolate(), description);
     178             :     v8::Local<v8::Function> toStringFunction;
     179         756 :     if (v8::Function::New(context, returnDataCallback, returnValue, 0,
     180         756 :                           v8::ConstructorBehavior::kThrow)
     181        1512 :             .ToLocal(&toStringFunction))
     182             :       createDataProperty(context, func, toV8StringInternalized(
     183             :                                             context->GetIsolate(), "toString"),
     184        1512 :                          toStringFunction);
     185             :   }
     186        1080 :   createDataProperty(context, console, funcName, func);
     187             : }
     188             : 
     189             : }  // namespace
     190             : 
     191        9086 : V8Console::V8Console(V8InspectorImpl* inspector) : m_inspector(inspector) {}
     192             : 
     193           6 : void V8Console::Debug(const v8::debug::ConsoleCallArguments& info) {
     194           6 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kDebug);
     195           6 : }
     196             : 
     197          12 : void V8Console::Error(const v8::debug::ConsoleCallArguments& info) {
     198          12 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kError);
     199          12 : }
     200             : 
     201           6 : void V8Console::Info(const v8::debug::ConsoleCallArguments& info) {
     202           6 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kInfo);
     203           6 : }
     204             : 
     205        6450 : void V8Console::Log(const v8::debug::ConsoleCallArguments& info) {
     206        6450 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kLog);
     207        6450 : }
     208             : 
     209           6 : void V8Console::Warn(const v8::debug::ConsoleCallArguments& info) {
     210           6 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kWarning);
     211           6 : }
     212             : 
     213          24 : void V8Console::Dir(const v8::debug::ConsoleCallArguments& info) {
     214          24 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kDir);
     215          24 : }
     216             : 
     217          18 : void V8Console::DirXml(const v8::debug::ConsoleCallArguments& info) {
     218          18 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kDirXML);
     219          18 : }
     220             : 
     221         120 : void V8Console::Table(const v8::debug::ConsoleCallArguments& info) {
     222         120 :   ConsoleHelper(info, m_inspector).reportCall(ConsoleAPIType::kTable);
     223         120 : }
     224             : 
     225         420 : void V8Console::Trace(const v8::debug::ConsoleCallArguments& info) {
     226             :   ConsoleHelper(info, m_inspector)
     227             :       .reportCallWithDefaultArgument(ConsoleAPIType::kTrace,
     228         840 :                                      String16("console.trace"));
     229         420 : }
     230             : 
     231           6 : void V8Console::Group(const v8::debug::ConsoleCallArguments& info) {
     232             :   ConsoleHelper(info, m_inspector)
     233             :       .reportCallWithDefaultArgument(ConsoleAPIType::kStartGroup,
     234          12 :                                      String16("console.group"));
     235           6 : }
     236             : 
     237           6 : void V8Console::GroupCollapsed(const v8::debug::ConsoleCallArguments& info) {
     238             :   ConsoleHelper(info, m_inspector)
     239             :       .reportCallWithDefaultArgument(ConsoleAPIType::kStartGroupCollapsed,
     240          12 :                                      String16("console.groupCollapsed"));
     241           6 : }
     242             : 
     243           6 : void V8Console::GroupEnd(const v8::debug::ConsoleCallArguments& info) {
     244             :   ConsoleHelper(info, m_inspector)
     245             :       .reportCallWithDefaultArgument(ConsoleAPIType::kEndGroup,
     246          12 :                                      String16("console.groupEnd"));
     247           6 : }
     248             : 
     249          24 : void V8Console::Clear(const v8::debug::ConsoleCallArguments& info) {
     250          48 :   ConsoleHelper helper(info, m_inspector);
     251          24 :   if (!helper.groupId()) return;
     252          48 :   m_inspector->client()->consoleClear(helper.groupId());
     253             :   helper.reportCallWithDefaultArgument(ConsoleAPIType::kClear,
     254          48 :                                        String16("console.clear"));
     255             : }
     256             : 
     257          24 : void V8Console::Count(const v8::debug::ConsoleCallArguments& info) {
     258          24 :   ConsoleHelper helper(info, m_inspector);
     259          48 :   String16 title = helper.firstArgToString(String16());
     260             :   String16 identifier;
     261          24 :   if (title.isEmpty()) {
     262             :     std::unique_ptr<V8StackTraceImpl> stackTrace =
     263          36 :         V8StackTraceImpl::capture(m_inspector->debugger(), helper.groupId(), 1);
     264          18 :     if (stackTrace && !stackTrace->isEmpty()) {
     265          84 :       identifier = toString16(stackTrace->topSourceURL()) + ":" +
     266          12 :                    String16::fromInteger(stackTrace->topLineNumber());
     267             :     }
     268             :   } else {
     269          18 :     identifier = title + "@";
     270             :   }
     271             : 
     272             :   int count =
     273          48 :       helper.consoleMessageStorage()->count(helper.contextId(), identifier);
     274          24 :   String16 countString = String16::fromInteger(count);
     275             :   helper.reportCallWithArgument(
     276             :       ConsoleAPIType::kCount,
     277          66 :       title.isEmpty() ? countString : (title + ": " + countString));
     278          24 : }
     279             : 
     280          48 : void V8Console::Assert(const v8::debug::ConsoleCallArguments& info) {
     281          84 :   ConsoleHelper helper(info, m_inspector);
     282             :   DCHECK(!helper.firstArgToBoolean(false));
     283             : 
     284             :   std::vector<v8::Local<v8::Value>> arguments;
     285         150 :   for (int i = 1; i < info.Length(); ++i) arguments.push_back(info[i]);
     286          48 :   if (info.Length() < 2)
     287             :     arguments.push_back(
     288         144 :         toV8String(m_inspector->isolate(), String16("console.assert")));
     289          48 :   helper.reportCall(ConsoleAPIType::kAssert, arguments);
     290             : 
     291          48 :   if (V8DebuggerAgentImpl* debuggerAgent = helper.debuggerAgent())
     292             :     debuggerAgent->breakProgramOnException(
     293          72 :         protocol::Debugger::Paused::ReasonEnum::Assert, nullptr);
     294          48 : }
     295             : 
     296           6 : void V8Console::MarkTimeline(const v8::debug::ConsoleCallArguments& info) {
     297             :   ConsoleHelper(info, m_inspector)
     298             :       .reportDeprecatedCall("V8Console#markTimelineDeprecated",
     299             :                             "'console.markTimeline' is "
     300             :                             "deprecated. Please use "
     301          12 :                             "'console.timeStamp' instead.");
     302           6 :   TimeStamp(info);
     303           6 : }
     304             : 
     305          28 : void V8Console::Profile(const v8::debug::ConsoleCallArguments& info) {
     306          28 :   ConsoleHelper helper(info, m_inspector);
     307          28 :   if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
     308          84 :     profilerAgent->consoleProfile(helper.firstArgToString(String16()));
     309          28 : }
     310             : 
     311          28 : void V8Console::ProfileEnd(const v8::debug::ConsoleCallArguments& info) {
     312          28 :   ConsoleHelper helper(info, m_inspector);
     313          28 :   if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
     314          84 :     profilerAgent->consoleProfileEnd(helper.firstArgToString(String16()));
     315          28 : }
     316             : 
     317          72 : static void timeFunction(const v8::debug::ConsoleCallArguments& info,
     318          72 :                          bool timelinePrefix, V8InspectorImpl* inspector) {
     319          72 :   ConsoleHelper helper(info, inspector);
     320         144 :   String16 protocolTitle = helper.firstArgToString("default");
     321         126 :   if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'";
     322          72 :   inspector->client()->consoleTime(toStringView(protocolTitle));
     323         144 :   helper.consoleMessageStorage()->time(helper.contextId(), protocolTitle);
     324          72 : }
     325             : 
     326          60 : static void timeEndFunction(const v8::debug::ConsoleCallArguments& info,
     327          60 :                             bool timelinePrefix, V8InspectorImpl* inspector) {
     328          60 :   ConsoleHelper helper(info, inspector);
     329         120 :   String16 protocolTitle = helper.firstArgToString("default");
     330          78 :   if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'";
     331          60 :   inspector->client()->consoleTimeEnd(toStringView(protocolTitle));
     332             :   double elapsed = helper.consoleMessageStorage()->timeEnd(helper.contextId(),
     333         120 :                                                            protocolTitle);
     334             :   String16 message =
     335         360 :       protocolTitle + ": " + String16::fromDouble(elapsed) + "ms";
     336          60 :   helper.reportCallWithArgument(ConsoleAPIType::kTimeEnd, message);
     337          60 : }
     338             : 
     339          18 : void V8Console::Timeline(const v8::debug::ConsoleCallArguments& info) {
     340             :   ConsoleHelper(info, m_inspector)
     341             :       .reportDeprecatedCall("V8Console#timeline",
     342             :                             "'console.timeline' is deprecated. Please use "
     343          36 :                             "'console.time' instead.");
     344          18 :   timeFunction(info, true, m_inspector);
     345          18 : }
     346             : 
     347           6 : void V8Console::TimelineEnd(const v8::debug::ConsoleCallArguments& info) {
     348             :   ConsoleHelper(info, m_inspector)
     349             :       .reportDeprecatedCall("V8Console#timelineEnd",
     350             :                             "'console.timelineEnd' is "
     351             :                             "deprecated. Please use "
     352          12 :                             "'console.timeEnd' instead.");
     353           6 :   timeEndFunction(info, true, m_inspector);
     354           6 : }
     355             : 
     356          54 : void V8Console::Time(const v8::debug::ConsoleCallArguments& info) {
     357          54 :   timeFunction(info, false, m_inspector);
     358          54 : }
     359             : 
     360          54 : void V8Console::TimeEnd(const v8::debug::ConsoleCallArguments& info) {
     361          54 :   timeEndFunction(info, false, m_inspector);
     362          54 : }
     363             : 
     364           6 : void V8Console::TimeStamp(const v8::debug::ConsoleCallArguments& info) {
     365          12 :   ConsoleHelper helper(info, m_inspector);
     366          12 :   String16 title = helper.firstArgToString(String16());
     367          12 :   m_inspector->client()->consoleTimeStamp(toStringView(title));
     368           6 : }
     369             : 
     370          24 : void V8Console::memoryGetterCallback(
     371          60 :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     372             :   v8::Local<v8::Value> memoryValue;
     373          48 :   if (!m_inspector->client()
     374             :            ->memoryInfo(info.GetIsolate(),
     375          48 :                         info.GetIsolate()->GetCurrentContext())
     376          48 :            .ToLocal(&memoryValue))
     377          24 :     return;
     378             :   info.GetReturnValue().Set(memoryValue);
     379             : }
     380             : 
     381           0 : void V8Console::memorySetterCallback(
     382             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     383             :   // We can't make the attribute readonly as it breaks existing code that relies
     384             :   // on being able to assign to console.memory in strict mode. Instead, the
     385             :   // setter just ignores the passed value.  http://crbug.com/468611
     386           0 : }
     387             : 
     388          36 : void V8Console::keysCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     389             :   v8::Isolate* isolate = info.GetIsolate();
     390          12 :   info.GetReturnValue().Set(v8::Array::New(isolate));
     391             : 
     392          12 :   v8::debug::ConsoleCallArguments args(info);
     393          12 :   ConsoleHelper helper(args, m_inspector);
     394             :   v8::Local<v8::Object> obj;
     395          24 :   if (!helper.firstArgAsObject().ToLocal(&obj)) return;
     396             :   v8::Local<v8::Array> names;
     397          24 :   if (!obj->GetOwnPropertyNames(isolate->GetCurrentContext()).ToLocal(&names))
     398             :     return;
     399             :   info.GetReturnValue().Set(names);
     400             : }
     401             : 
     402           0 : void V8Console::valuesCallback(
     403           0 :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     404             :   v8::Isolate* isolate = info.GetIsolate();
     405           0 :   info.GetReturnValue().Set(v8::Array::New(isolate));
     406             : 
     407           0 :   v8::debug::ConsoleCallArguments args(info);
     408           0 :   ConsoleHelper helper(args, m_inspector);
     409             :   v8::Local<v8::Object> obj;
     410           0 :   if (!helper.firstArgAsObject().ToLocal(&obj)) return;
     411             :   v8::Local<v8::Array> names;
     412           0 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     413           0 :   if (!obj->GetOwnPropertyNames(context).ToLocal(&names)) return;
     414           0 :   v8::Local<v8::Array> values = v8::Array::New(isolate, names->Length());
     415           0 :   for (uint32_t i = 0; i < names->Length(); ++i) {
     416             :     v8::Local<v8::Value> key;
     417           0 :     if (!names->Get(context, i).ToLocal(&key)) continue;
     418             :     v8::Local<v8::Value> value;
     419           0 :     if (!obj->Get(context, key).ToLocal(&value)) continue;
     420           0 :     createDataProperty(context, values, i, value);
     421             :   }
     422             :   info.GetReturnValue().Set(values);
     423             : }
     424             : 
     425         126 : static void setFunctionBreakpoint(ConsoleHelper& helper,
     426             :                                   v8::Local<v8::Function> function,
     427             :                                   V8DebuggerAgentImpl::BreakpointSource source,
     428             :                                   const String16& condition, bool enable) {
     429         126 :   V8DebuggerAgentImpl* debuggerAgent = helper.debuggerAgent();
     430         126 :   if (!debuggerAgent) return;
     431         126 :   String16 scriptId = String16::fromInteger(function->ScriptId());
     432         126 :   int lineNumber = function->GetScriptLineNumber();
     433         126 :   int columnNumber = function->GetScriptColumnNumber();
     434         126 :   if (lineNumber == v8::Function::kLineOffsetNotFound ||
     435             :       columnNumber == v8::Function::kLineOffsetNotFound)
     436             :     return;
     437         126 :   if (enable)
     438             :     debuggerAgent->setBreakpointAt(scriptId, lineNumber, columnNumber, source,
     439          66 :                                    condition);
     440             :   else
     441             :     debuggerAgent->removeBreakpointAt(scriptId, lineNumber, columnNumber,
     442          60 :                                       source);
     443             : }
     444             : 
     445          36 : void V8Console::debugFunctionCallback(
     446             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     447          36 :   v8::debug::ConsoleCallArguments args(info);
     448          36 :   ConsoleHelper helper(args, m_inspector);
     449             :   v8::Local<v8::Function> function;
     450          72 :   if (!helper.firstArgAsFunction().ToLocal(&function)) return;
     451             :   setFunctionBreakpoint(helper, function,
     452             :                         V8DebuggerAgentImpl::DebugCommandBreakpointSource,
     453          72 :                         String16(), true);
     454             : }
     455             : 
     456          30 : void V8Console::undebugFunctionCallback(
     457             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     458          30 :   v8::debug::ConsoleCallArguments args(info);
     459          30 :   ConsoleHelper helper(args, m_inspector);
     460             :   v8::Local<v8::Function> function;
     461          60 :   if (!helper.firstArgAsFunction().ToLocal(&function)) return;
     462             :   setFunctionBreakpoint(helper, function,
     463             :                         V8DebuggerAgentImpl::DebugCommandBreakpointSource,
     464          60 :                         String16(), false);
     465             : }
     466             : 
     467          30 : void V8Console::monitorFunctionCallback(
     468             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     469          30 :   v8::debug::ConsoleCallArguments args(info);
     470          30 :   ConsoleHelper helper(args, m_inspector);
     471             :   v8::Local<v8::Function> function;
     472          60 :   if (!helper.firstArgAsFunction().ToLocal(&function)) return;
     473          30 :   v8::Local<v8::Value> name = function->GetName();
     474          30 :   if (!name->IsString() || !v8::Local<v8::String>::Cast(name)->Length())
     475           0 :     name = function->GetInferredName();
     476          30 :   String16 functionName = toProtocolStringWithTypeCheck(name);
     477          30 :   String16Builder builder;
     478          60 :   builder.append("console.log(\"function ");
     479          30 :   if (functionName.isEmpty())
     480           0 :     builder.append("(anonymous function)");
     481             :   else
     482          30 :     builder.append(functionName);
     483             :   builder.append(
     484             :       " called\" + (arguments.length > 0 ? \" with arguments: \" + "
     485          60 :       "Array.prototype.join.call(arguments, \", \") : \"\")) && false");
     486             :   setFunctionBreakpoint(helper, function,
     487             :                         V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
     488          60 :                         builder.toString(), true);
     489             : }
     490             : 
     491          30 : void V8Console::unmonitorFunctionCallback(
     492             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     493          30 :   v8::debug::ConsoleCallArguments args(info);
     494          30 :   ConsoleHelper helper(args, m_inspector);
     495             :   v8::Local<v8::Function> function;
     496          60 :   if (!helper.firstArgAsFunction().ToLocal(&function)) return;
     497             :   setFunctionBreakpoint(helper, function,
     498             :                         V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
     499          60 :                         String16(), false);
     500             : }
     501             : 
     502          66 : void V8Console::lastEvaluationResultCallback(
     503          66 :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     504          66 :   v8::debug::ConsoleCallArguments args(info);
     505          66 :   ConsoleHelper helper(args, m_inspector);
     506          66 :   InjectedScript* injectedScript = helper.injectedScript();
     507          66 :   if (!injectedScript) return;
     508          66 :   info.GetReturnValue().Set(injectedScript->lastEvaluationResult());
     509             : }
     510             : 
     511          54 : static void inspectImpl(const v8::FunctionCallbackInfo<v8::Value>& info,
     512             :                         bool copyToClipboard, V8InspectorImpl* inspector) {
     513          30 :   if (info.Length() < 1) return;
     514          30 :   if (!copyToClipboard) info.GetReturnValue().Set(info[0]);
     515             : 
     516          30 :   v8::debug::ConsoleCallArguments args(info);
     517          30 :   ConsoleHelper helper(args, inspector);
     518          30 :   InjectedScript* injectedScript = helper.injectedScript();
     519          30 :   if (!injectedScript) return;
     520          30 :   std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject;
     521             :   protocol::Response response =
     522             :       injectedScript->wrapObject(info[0], "", false /** forceValueType */,
     523          90 :                                  false /** generatePreview */, &wrappedObject);
     524          30 :   if (!response.isSuccess()) return;
     525             : 
     526             :   std::unique_ptr<protocol::DictionaryValue> hints =
     527          30 :       protocol::DictionaryValue::create();
     528          42 :   if (copyToClipboard) hints->setBoolean("copyToClipboard", true);
     529          60 :   if (V8InspectorSessionImpl* session = helper.currentSession()) {
     530             :     session->runtimeAgent()->inspect(std::move(wrappedObject),
     531          90 :                                      std::move(hints));
     532             :   }
     533             : }
     534             : 
     535           0 : void V8Console::inspectCallback(
     536             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
     537          24 :   inspectImpl(info, false, m_inspector);
     538           0 : }
     539             : 
     540           0 : void V8Console::copyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     541           6 :   inspectImpl(info, true, m_inspector);
     542           0 : }
     543             : 
     544          12 : void V8Console::inspectedObject(const v8::FunctionCallbackInfo<v8::Value>& info,
     545             :                                 unsigned num) {
     546             :   DCHECK(num < V8InspectorSessionImpl::kInspectedObjectBufferSize);
     547           6 :   v8::debug::ConsoleCallArguments args(info);
     548           6 :   ConsoleHelper helper(args, m_inspector);
     549          12 :   if (V8InspectorSessionImpl* session = helper.currentSession()) {
     550           6 :     V8InspectorSession::Inspectable* object = session->inspectedObject(num);
     551             :     v8::Isolate* isolate = info.GetIsolate();
     552           6 :     if (object)
     553           0 :       info.GetReturnValue().Set(object->get(isolate->GetCurrentContext()));
     554             :     else
     555             :       info.GetReturnValue().Set(v8::Undefined(isolate));
     556             :   }
     557           6 : }
     558             : 
     559         753 : void V8Console::installMemoryGetter(v8::Local<v8::Context> context,
     560             :                                     v8::Local<v8::Object> console) {
     561         753 :   v8::Isolate* isolate = context->GetIsolate();
     562         753 :   v8::Local<v8::External> data = v8::External::New(isolate, this);
     563             :   console->SetAccessorProperty(
     564             :       toV8StringInternalized(isolate, "memory"),
     565             :       v8::Function::New(context,
     566             :                         &V8Console::call<&V8Console::memoryGetterCallback>,
     567         753 :                         data, 0, v8::ConstructorBehavior::kThrow)
     568             :           .ToLocalChecked(),
     569             :       v8::Function::New(context,
     570             :                         &V8Console::call<&V8Console::memorySetterCallback>,
     571         753 :                         data, 0, v8::ConstructorBehavior::kThrow)
     572             :           .ToLocalChecked(),
     573        3012 :       static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT);
     574         753 : }
     575             : 
     576          54 : v8::Local<v8::Object> V8Console::createCommandLineAPI(
     577             :     v8::Local<v8::Context> context) {
     578          54 :   v8::Isolate* isolate = context->GetIsolate();
     579             :   v8::MicrotasksScope microtasksScope(isolate,
     580          54 :                                       v8::MicrotasksScope::kDoNotRunMicrotasks);
     581             : 
     582          54 :   v8::Local<v8::Object> commandLineAPI = v8::Object::New(isolate);
     583             :   bool success =
     584          54 :       commandLineAPI->SetPrototype(context, v8::Null(isolate)).FromMaybe(false);
     585             :   DCHECK(success);
     586             :   USE(success);
     587             : 
     588          54 :   v8::Local<v8::External> data = v8::External::New(isolate, this);
     589             :   createBoundFunctionProperty(context, commandLineAPI, data, "dir",
     590             :                               &V8Console::call<&V8Console::Dir>,
     591          54 :                               "function dir(value) { [Command Line API] }");
     592             :   createBoundFunctionProperty(context, commandLineAPI, data, "dirxml",
     593             :                               &V8Console::call<&V8Console::DirXml>,
     594          54 :                               "function dirxml(value) { [Command Line API] }");
     595             :   createBoundFunctionProperty(context, commandLineAPI, data, "profile",
     596             :                               &V8Console::call<&V8Console::Profile>,
     597          54 :                               "function profile(title) { [Command Line API] }");
     598             :   createBoundFunctionProperty(
     599             :       context, commandLineAPI, data, "profileEnd",
     600             :       &V8Console::call<&V8Console::ProfileEnd>,
     601          54 :       "function profileEnd(title) { [Command Line API] }");
     602             :   createBoundFunctionProperty(context, commandLineAPI, data, "clear",
     603             :                               &V8Console::call<&V8Console::Clear>,
     604          54 :                               "function clear() { [Command Line API] }");
     605             :   createBoundFunctionProperty(
     606             :       context, commandLineAPI, data, "table",
     607             :       &V8Console::call<&V8Console::Table>,
     608          54 :       "function table(data, [columns]) { [Command Line API] }");
     609             : 
     610             :   createBoundFunctionProperty(context, commandLineAPI, data, "keys",
     611             :                               &V8Console::call<&V8Console::keysCallback>,
     612          54 :                               "function keys(object) { [Command Line API] }");
     613             :   createBoundFunctionProperty(context, commandLineAPI, data, "values",
     614             :                               &V8Console::call<&V8Console::valuesCallback>,
     615          54 :                               "function values(object) { [Command Line API] }");
     616             :   createBoundFunctionProperty(
     617             :       context, commandLineAPI, data, "debug",
     618             :       &V8Console::call<&V8Console::debugFunctionCallback>,
     619          54 :       "function debug(function) { [Command Line API] }");
     620             :   createBoundFunctionProperty(
     621             :       context, commandLineAPI, data, "undebug",
     622             :       &V8Console::call<&V8Console::undebugFunctionCallback>,
     623          54 :       "function undebug(function) { [Command Line API] }");
     624             :   createBoundFunctionProperty(
     625             :       context, commandLineAPI, data, "monitor",
     626             :       &V8Console::call<&V8Console::monitorFunctionCallback>,
     627          54 :       "function monitor(function) { [Command Line API] }");
     628             :   createBoundFunctionProperty(
     629             :       context, commandLineAPI, data, "unmonitor",
     630             :       &V8Console::call<&V8Console::unmonitorFunctionCallback>,
     631          54 :       "function unmonitor(function) { [Command Line API] }");
     632             :   createBoundFunctionProperty(
     633             :       context, commandLineAPI, data, "inspect",
     634             :       &V8Console::call<&V8Console::inspectCallback>,
     635          54 :       "function inspect(object) { [Command Line API] }");
     636             :   createBoundFunctionProperty(context, commandLineAPI, data, "copy",
     637             :                               &V8Console::call<&V8Console::copyCallback>,
     638          54 :                               "function copy(value) { [Command Line API] }");
     639             :   createBoundFunctionProperty(
     640             :       context, commandLineAPI, data, "$_",
     641          54 :       &V8Console::call<&V8Console::lastEvaluationResultCallback>);
     642             :   createBoundFunctionProperty(context, commandLineAPI, data, "$0",
     643          54 :                               &V8Console::call<&V8Console::inspectedObject0>);
     644             :   createBoundFunctionProperty(context, commandLineAPI, data, "$1",
     645          54 :                               &V8Console::call<&V8Console::inspectedObject1>);
     646             :   createBoundFunctionProperty(context, commandLineAPI, data, "$2",
     647          54 :                               &V8Console::call<&V8Console::inspectedObject2>);
     648             :   createBoundFunctionProperty(context, commandLineAPI, data, "$3",
     649          54 :                               &V8Console::call<&V8Console::inspectedObject3>);
     650             :   createBoundFunctionProperty(context, commandLineAPI, data, "$4",
     651          54 :                               &V8Console::call<&V8Console::inspectedObject4>);
     652             : 
     653          54 :   m_inspector->client()->installAdditionalCommandLineAPI(context,
     654          54 :                                                          commandLineAPI);
     655          54 :   return commandLineAPI;
     656             : }
     657             : 
     658             : static bool isCommandLineAPIGetter(const String16& name) {
     659        1896 :   if (name.length() != 2) return false;
     660             :   // $0 ... $4, $_
     661         144 :   return name[0] == '$' &&
     662          72 :          ((name[1] >= '0' && name[1] <= '4') || name[1] == '_');
     663             : }
     664             : 
     665        8778 : void V8Console::CommandLineAPIScope::accessorGetterCallback(
     666             :     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     667             :   CommandLineAPIScope* scope = static_cast<CommandLineAPIScope*>(
     668        8778 :       info.Data().As<v8::External>()->Value());
     669             :   DCHECK(scope);
     670             : 
     671        8778 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
     672        8778 :   if (scope->m_cleanup) {
     673        6882 :     bool removed = info.Holder()->Delete(context, name).FromMaybe(false);
     674             :     DCHECK(removed);
     675             :     USE(removed);
     676        6882 :     return;
     677             :   }
     678        1896 :   v8::Local<v8::Object> commandLineAPI = scope->m_commandLineAPI;
     679             : 
     680             :   v8::Local<v8::Value> value;
     681        3792 :   if (!commandLineAPI->Get(context, name).ToLocal(&value)) return;
     682        3792 :   if (isCommandLineAPIGetter(toProtocolStringWithTypeCheck(name))) {
     683             :     DCHECK(value->IsFunction());
     684             :     v8::MicrotasksScope microtasks(info.GetIsolate(),
     685          72 :                                    v8::MicrotasksScope::kDoNotRunMicrotasks);
     686          72 :     if (value.As<v8::Function>()
     687          72 :             ->Call(context, commandLineAPI, 0, nullptr)
     688         144 :             .ToLocal(&value))
     689          72 :       info.GetReturnValue().Set(value);
     690             :   } else {
     691             :     info.GetReturnValue().Set(value);
     692             :   }
     693             : }
     694             : 
     695          66 : void V8Console::CommandLineAPIScope::accessorSetterCallback(
     696             :     v8::Local<v8::Name> name, v8::Local<v8::Value> value,
     697             :     const v8::PropertyCallbackInfo<void>& info) {
     698             :   CommandLineAPIScope* scope = static_cast<CommandLineAPIScope*>(
     699          66 :       info.Data().As<v8::External>()->Value());
     700          66 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
     701         132 :   if (!info.Holder()->Delete(context, name).FromMaybe(false)) return;
     702         132 :   if (!info.Holder()->CreateDataProperty(context, name, value).FromMaybe(false))
     703             :     return;
     704             :   bool removed =
     705          66 :       scope->m_installedMethods->Delete(context, name).FromMaybe(false);
     706             :   DCHECK(removed);
     707             :   USE(removed);
     708             : }
     709             : 
     710         408 : V8Console::CommandLineAPIScope::CommandLineAPIScope(
     711             :     v8::Local<v8::Context> context, v8::Local<v8::Object> commandLineAPI,
     712             :     v8::Local<v8::Object> global)
     713             :     : m_context(context),
     714             :       m_commandLineAPI(commandLineAPI),
     715             :       m_global(global),
     716         408 :       m_installedMethods(v8::Set::New(context->GetIsolate())),
     717         816 :       m_cleanup(false) {
     718             :   v8::Local<v8::Array> names;
     719         816 :   if (!m_commandLineAPI->GetOwnPropertyNames(context).ToLocal(&names)) return;
     720             :   v8::Local<v8::External> externalThis =
     721         408 :       v8::External::New(context->GetIsolate(), this);
     722        8568 :   for (uint32_t i = 0; i < names->Length(); ++i) {
     723             :     v8::Local<v8::Value> name;
     724       16320 :     if (!names->Get(context, i).ToLocal(&name) || !name->IsName()) continue;
     725       16320 :     if (m_global->Has(context, name).FromMaybe(true)) continue;
     726       13896 :     if (!m_installedMethods->Add(context, name).ToLocal(&m_installedMethods))
     727             :       continue;
     728        6948 :     if (!m_global
     729             :              ->SetAccessor(context, v8::Local<v8::Name>::Cast(name),
     730             :                            CommandLineAPIScope::accessorGetterCallback,
     731             :                            CommandLineAPIScope::accessorSetterCallback,
     732        6948 :                            externalThis, v8::DEFAULT, v8::DontEnum)
     733       13896 :              .FromMaybe(false)) {
     734           0 :       bool removed = m_installedMethods->Delete(context, name).FromMaybe(false);
     735             :       DCHECK(removed);
     736             :       USE(removed);
     737             :       continue;
     738             :     }
     739             :   }
     740             : }
     741             : 
     742         408 : V8Console::CommandLineAPIScope::~CommandLineAPIScope() {
     743         408 :   m_cleanup = true;
     744         408 :   v8::Local<v8::Array> names = m_installedMethods->AsArray();
     745        7290 :   for (uint32_t i = 0; i < names->Length(); ++i) {
     746             :     v8::Local<v8::Value> name;
     747       13764 :     if (!names->Get(m_context, i).ToLocal(&name) || !name->IsName()) continue;
     748        6882 :     if (name->IsString()) {
     749             :       v8::Local<v8::Value> descriptor;
     750             :       bool success = m_global
     751             :                          ->GetOwnPropertyDescriptor(
     752             :                              m_context, v8::Local<v8::String>::Cast(name))
     753        6882 :                          .ToLocal(&descriptor);
     754             :       DCHECK(success);
     755             :       USE(success);
     756             :     }
     757             :   }
     758         408 : }
     759             : 
     760             : }  // namespace v8_inspector

Generated by: LCOV version 1.10