LCOV - code coverage report
Current view: top level - src/inspector - v8-console.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 377 400 94.2 %
Date: 2017-10-20 Functions: 61 63 96.8 %

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

Generated by: LCOV version 1.10