Chromium 中JavaScript Console API接口c++代码实现

Console API - Web API | MDN (mozilla.org)

Console API

Console API 提供了允许开发人员执行调试任务的功能,例如在代码中的某个位置记录消息或变量值,或者计算任务完成所需的时间。

概念和用法

Console API 最初是一个专有的 API,不同的浏览器以自己的实现方式来实现它。Console API 规范统一了这个 API 的行为,并且所有现代浏览器最终都决定实现这种行为 — 尽管一些实现仍然有自己的附加专有功能。了解这些请查看:

用法非常简单 — console 对象 — 可以通过window.console获取到,在 workers 里面使用WorkerGlobalScope.console获取,console — 包含许多方法,你可以调用它们来执行基本的调试任务,通常专注于将各种值记录到浏览器中 WEB 控制台.

到目前为止,最常用的方法是 console.log,它用于记录特定变量中包含的当前值。

接口

console

提供基本的调试功能,包括日志记录,堆栈跟踪,计时器和计数器。

示例

jsCopy to Clipboard

let myString = "Hello world";

// Output "Hello world" to the console
console.log(myString);

那么前端中  console.Debug()
  console.Error()
  console.Info(()
  console.Log()
  console.Warn()
  console.Dir() 
  console.DirXml()
  console.Table()
  console.Trace()
  console.Group()
  console.GroupCollapsed()
  console.GroupEnd()
  console.Clear()
  console.Count()             
  console.CountReset()
  console.Assert()
  console.Profile()
  console.ProfileEnd()
  console.Time(
  console.TimeLog()
  console.TimeEnd()
  console.TimeStamp()这些方法在c++代码中如何实现的呢?

一、启动浏览器 打开一个页面 按F12打开开发者工具初始化过程

  1、初始化 InspectedContext src\v8\src\inspector\v8-inspector-impl.cc

        auto* context = new InspectedContext(this, info, contextId);

void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
  int contextId = ++m_lastContextId;
  auto* context = new InspectedContext(this, info, contextId);
  m_contextIdToGroupIdMap[contextId] = info.contextGroupId;

  DCHECK(m_uniqueIdToContextId.find(context->uniqueId().pair()) ==
         m_uniqueIdToContextId.end());
  m_uniqueIdToContextId.insert(
      std::make_pair(context->uniqueId().pair(), contextId));

  auto contextIt = m_contexts.find(info.contextGroupId);
  if (contextIt == m_contexts.end())
    contextIt = m_contexts
                    .insert(std::make_pair(
                        info.contextGroupId,
                        std::unique_ptr<ContextByIdMap>(new ContextByIdMap())))
                    .first;
  const auto& contextById = contextIt->second;

  DCHECK(contextById->find(contextId) == contextById->cend());
  (*contextById)[contextId].reset(context);
  forEachSession(
      info.contextGroupId, [&context](V8InspectorSessionImpl* session) {
        session->runtimeAgent()->addBindings(context);
        session->runtimeAgent()->reportExecutionContextCreated(context);
      });
}

   2、在InspectedContext  中调用(src\v8\src\inspector\inspected-context.cc

        m_inspector->console()->installAsyncStackTaggingAPI

          初始化 console对象。

       

InspectedContext::InspectedContext(V8InspectorImpl* inspector,
                                   const V8ContextInfo& info, int contextId)
    : m_inspector(inspector),
      m_context(info.context->GetIsolate(), info.context),
      m_contextId(contextId),
      m_contextGroupId(info.contextGroupId),
      m_origin(toString16(info.origin)),
      m_humanReadableName(toString16(info.humanReadableName)),
      m_auxData(toString16(info.auxData)),
      m_uniqueId(internal::V8DebuggerId::generate(inspector)) {
  v8::debug::SetContextId(info.context, contextId);
  m_weakCallbackData =
      new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);
  m_context.SetWeak(m_weakCallbackData,
                    &InspectedContext::WeakCallbackData::resetContext,
                    v8::WeakCallbackType::kParameter);

  v8::Context::Scope contextScope(info.context);
  v8::HandleScope handleScope(info.context->GetIsolate());
  v8::Local<v8::Object> global = info.context->Global();
  v8::Local<v8::Value> console;
  if (!global
           ->Get(info.context,
                 toV8String(info.context->GetIsolate(), "console"))
           .ToLocal(&console) ||
      !console->IsObject()) {
    return;
  }
  
  //初始化前端调用API 
  m_inspector->console()->installAsyncStackTaggingAPI(info.context,
                                                      console.As<v8::Object>());

  if (info.hasMemoryOnConsole) {
    m_inspector->console()->installMemoryGetter(info.context,
                                                console.As<v8::Object>());
  }
}

3、初始化 console对象。src\v8\src\inspector\v8-inspector-impl.cc

     

V8Console* V8InspectorImpl::console() {
  if (!m_console) m_console.reset(new V8Console(this));
  return m_console.get();
}

4、console对象实现代码

    v8\src\inspector\v8-console.cc

    v8\src\inspector\v8-console.h

  在v8-console.h 中有log info 等代码声明

// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_INSPECTOR_V8_CONSOLE_H_
#define V8_INSPECTOR_V8_CONSOLE_H_

#include <map>

#include "include/v8-array-buffer.h"
#include "include/v8-external.h"
#include "include/v8-local-handle.h"
#include "src/base/macros.h"
#include "src/debug/interface-types.h"

namespace v8 {
class ObjectTemplate;
class Set;
}  // namespace v8

namespace v8_inspector {

class InspectedContext;
class TaskInfo;
class V8InspectorImpl;

// Console API
// https://console.spec.whatwg.org/#console-namespace
class V8Console : public v8::debug::ConsoleDelegate {
 public:
  v8::Local<v8::Object> createCommandLineAPI(v8::Local<v8::Context> context,
                                             int sessionId);
  void installMemoryGetter(v8::Local<v8::Context> context,
                           v8::Local<v8::Object> console);
  void installAsyncStackTaggingAPI(v8::Local<v8::Context> context,
                                   v8::Local<v8::Object> console);
  void cancelConsoleTask(TaskInfo* taskInfo);

  std::map<void*, std::unique_ptr<TaskInfo>>& AllConsoleTasksForTest() {
    return m_tasks;
  }

  class V8_NODISCARD CommandLineAPIScope {
   public:
    CommandLineAPIScope(v8::Local<v8::Context>,
                        v8::Local<v8::Object> commandLineAPI,
                        v8::Local<v8::Object> global);
    ~CommandLineAPIScope();
    CommandLineAPIScope(const CommandLineAPIScope&) = delete;
    CommandLineAPIScope& operator=(const CommandLineAPIScope&) = delete;

   private:
    static void accessorGetterCallback(
        v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&);
    static void accessorSetterCallback(v8::Local<v8::Name>,
                                       v8::Local<v8::Value>,
                                       const v8::PropertyCallbackInfo<void>&);

    v8::Local<v8::Context> context() const { return m_context.Get(m_isolate); }
    v8::Local<v8::Object> commandLineAPI() const {
      return m_commandLineAPI.Get(m_isolate);
    }
    v8::Local<v8::Object> global() const { return m_global.Get(m_isolate); }
    v8::Local<v8::Set> installedMethods() const {
      return m_installedMethods.Get(m_isolate);
    }
    v8::Local<v8::ArrayBuffer> thisReference() const {
      return m_thisReference.Get(m_isolate);
    }

    v8::Isolate* m_isolate;
    v8::Global<v8::Context> m_context;
    v8::Global<v8::Object> m_commandLineAPI;
    v8::Global<v8::Object> m_global;
    v8::Global<v8::Set> m_installedMethods;
    v8::Global<v8::ArrayBuffer> m_thisReference;
  };

  explicit V8Console(V8InspectorImpl* inspector);

 private:
  friend class TaskInfo;

  void Debug(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void Error(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void Info(const v8::debug::ConsoleCallArguments&,
            const v8::debug::ConsoleContext& consoleContext) override;
  void Log(const v8::debug::ConsoleCallArguments&,
           const v8::debug::ConsoleContext& consoleContext) override;
  void Warn(const v8::debug::ConsoleCallArguments&,
            const v8::debug::ConsoleContext& consoleContext) override;
  void Dir(const v8::debug::ConsoleCallArguments&,
           const v8::debug::ConsoleContext& consoleContext) override;
  void DirXml(const v8::debug::ConsoleCallArguments&,
              const v8::debug::ConsoleContext& consoleContext) override;
  void Table(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void Trace(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void Group(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void GroupCollapsed(const v8::debug::ConsoleCallArguments&,
                      const v8::debug::ConsoleContext& consoleContext) override;
  void GroupEnd(const v8::debug::ConsoleCallArguments&,
                const v8::debug::ConsoleContext& consoleContext) override;
  void Clear(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void Count(const v8::debug::ConsoleCallArguments&,
             const v8::debug::ConsoleContext& consoleContext) override;
  void CountReset(const v8::debug::ConsoleCallArguments&,
                  const v8::debug::ConsoleContext& consoleContext) override;
  void Assert(const v8::debug::ConsoleCallArguments&,
              const v8::debug::ConsoleContext& consoleContext) override;
  void Profile(const v8::debug::ConsoleCallArguments&,
               const v8::debug::ConsoleContext& consoleContext) override;
  void ProfileEnd(const v8::debug::ConsoleCallArguments&,
                  const v8::debug::ConsoleContext& consoleContext) override;
  void Time(const v8::debug::ConsoleCallArguments&,
            const v8::debug::ConsoleContext& consoleContext) override;
  void TimeLog(const v8::debug::ConsoleCallArguments&,
               const v8::debug::ConsoleContext& consoleContext) override;
  void TimeEnd(const v8::debug::ConsoleCallArguments&,
               const v8::debug::ConsoleContext& consoleContext) override;
  void TimeStamp(const v8::debug::ConsoleCallArguments&,
                 const v8::debug::ConsoleContext& consoleContext) override;

  template <void (V8Console::*func)(const v8::FunctionCallbackInfo<v8::Value>&)>
  static void call(const v8::FunctionCallbackInfo<v8::Value>& info) {
    V8Console* console =
        static_cast<V8Console*>(info.Data().As<v8::External>()->Value());
    (console->*func)(info);
  }
  using CommandLineAPIData = std::pair<V8Console*, int>;
  template <void (V8Console::*func)(const v8::FunctionCallbackInfo<v8::Value>&,
                                    int)>
  static void call(const v8::FunctionCallbackInfo<v8::Value>& info) {
    CommandLineAPIData* data = static_cast<CommandLineAPIData*>(
        info.Data().As<v8::ArrayBuffer>()->GetBackingStore()->Data());
    (data->first->*func)(info, data->second);
  }
  template <void (V8Console::*func)(const v8::debug::ConsoleCallArguments&,
                                    const v8::debug::ConsoleContext&)>
  static void call(const v8::FunctionCallbackInfo<v8::Value>& info) {
    CommandLineAPIData* data = static_cast<CommandLineAPIData*>(
        info.Data().As<v8::ArrayBuffer>()->GetBackingStore()->Data());
    v8::debug::ConsoleCallArguments args(info);
    (data->first->*func)(args, v8::debug::ConsoleContext());
  }

  // TODO(foolip): There is no spec for the Memory Info API, see blink-dev:
  // https://groups.google.com/a/chromium.org/d/msg/blink-dev/g5YRCGpC9vs/b4OJz71NmPwJ
  void memoryGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
  void memorySetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);

  void createTask(const v8::FunctionCallbackInfo<v8::Value>&);
  void runTask(const v8::FunctionCallbackInfo<v8::Value>&);

  // CommandLineAPI
  void keysCallback(const v8::FunctionCallbackInfo<v8::Value>&, int sessionId);
  void valuesCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                      int sessionId);
  void debugFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                             int sessionId);
  void undebugFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                               int sessionId);
  void monitorFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                               int sessionId);
  void unmonitorFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                                 int sessionId);
  void lastEvaluationResultCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                                    int sessionId);
  void inspectCallback(const v8::FunctionCallbackInfo<v8::Value>&,
                       int sessionId);
  void copyCallback(const v8::FunctionCallbackInfo<v8::Value>&, int sessionId);
  void inspectedObject(const v8::FunctionCallbackInfo<v8::Value>&,
                       int sessionId, unsigned num);
  void inspectedObject0(const v8::FunctionCallbackInfo<v8::Value>& info,
                        int sessionId) {
    inspectedObject(info, sessionId, 0);
  }
  void inspectedObject1(const v8::FunctionCallbackInfo<v8::Value>& info,
                        int sessionId) {
    inspectedObject(info, sessionId, 1);
  }
  void inspectedObject2(const v8::FunctionCallbackInfo<v8::Value>& info,
                        int sessionId) {
    inspectedObject(info, sessionId, 2);
  }
  void inspectedObject3(const v8::FunctionCallbackInfo<v8::Value>& info,
                        int sessionId) {
    inspectedObject(info, sessionId, 3);
  }
  void inspectedObject4(const v8::FunctionCallbackInfo<v8::Value>& info,
                        int sessionId) {
    inspectedObject(info, sessionId, 4);
  }
  void queryObjectsCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
                            int sessionId);

  // Lazily creates m_taskInfoKey and returns a local handle to it. We can't
  // initialize m_taskInfoKey in the constructor as it would be part of
  // Chromium's context snapshot.
  v8::Local<v8::Private> taskInfoKey();

  // Lazily creates m_taskTemplate and returns a local handle to it.
  // Similarly to m_taskInfoKey, we can't create the template upfront as to not
  // be part of Chromium's context snapshot.
  v8::Local<v8::ObjectTemplate> taskTemplate();

  V8InspectorImpl* m_inspector;

  // All currently alive tasks. We mark tasks immediately as weak when created
  // but we need the finalizer to cancel the task when GC cleans them up.
  std::map<void*, std::unique_ptr<TaskInfo>> m_tasks;

  // We use a private symbol to stash the `TaskInfo` as an v8::External on the
  // JS task objects created by `console.createTask`.
  v8::Global<v8::Private> m_taskInfoKey;

  // We cache the task template for the async stack tagging API for faster
  // instantiation. Use `taskTemplate()` to retrieve the lazily created
  // template.
  v8::Global<v8::ObjectTemplate> m_taskTemplate;
};

/**
 * Each JS task object created via `console.createTask` has a corresponding
 * `TaskInfo` object on the C++ side (in a 1:1 relationship).
 *
 * The `TaskInfo` holds on weakly to the JS task object.
 * The JS task objects uses a private symbol to store a pointer to the
 * `TaskInfo` object (via v8::External).
 *
 * The `TaskInfo` objects holds all the necessary information we need to
 * properly cancel the corresponding async task then the JS task object
 * gets GC'ed.
 */
class TaskInfo {
 public:
  TaskInfo(v8::Isolate* isolate, V8Console* console,
           v8::Local<v8::Object> task);

  // For these task IDs we duplicate the ID logic from blink and use even
  // pointers compared to the odd IDs we use for promises. This guarantees that
  // we don't have any conflicts between task IDs.
  void* Id() const {
    return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(this) << 1);
  }

  // After calling `Cancel` the `TaskInfo` instance is destroyed.
  void Cancel() { m_console->cancelConsoleTask(this); }

 private:
  v8::Global<v8::Object> m_task;
  V8Console* m_console = nullptr;
};

}  // namespace v8_inspector

#endif  // V8_INSPECTOR_V8_CONSOLE_H_

  5、看下堆栈图:

  

至此初始化完毕,接下来看调用过程堆栈。

二、浏览器console调用过程

console.log("hello world");

2、按回车看下堆栈:

v8.dll!v8_inspector::`anonymous namespace'::ConsoleHelper::reportCall(v8_inspector::ConsoleAPIType type, v8::MemorySpan<const v8::Local<v8::Value>> arguments) 行 111
v8.dll!v8_inspector::`anonymous namespace'::ConsoleHelper::reportCall(v8_inspector::ConsoleAPIType type) 行 77	
v8.dll!v8_inspector::V8Console::Log(const v8::debug::ConsoleCallArguments & info, const v8::debug::ConsoleContext & consoleContext) 行 217	
v8.dll!v8::internal::`anonymous namespace'::ConsoleCall(v8::internal::Isolate * isolate, const v8::internal::BuiltinArguments & args, void(v8::debug::ConsoleDelegate::*)(const v8::debug::ConsoleCallArguments &, const v8::debug::ConsoleContext &) func) 行 165	
v8.dll!v8::internal::Builtin_Impl_ConsoleLog(v8::internal::BuiltinArguments args, v8::internal::Isolate * isolate) 行 201	
v8.dll!v8::internal::Builtin_ConsoleLog(int args_length, unsigned __int64 * args_object, v8::internal::Isolate * isolate) 行 201	

 可以看到在src\v8\src\builtins\builtins-console.cc

// 2.2 Formatter(args) [https://console.spec.whatwg.org/#formatter]
//
// This implements the formatter operation defined in the Console
// specification to the degree that it makes sense for V8.  That
// means we primarily deal with %s, %i, %f, and %d, and any side
// effects caused by the type conversions, and we preserve the %o,
// %c, and %O specifiers and their parameters unchanged, and instead
// leave it to the debugger front-end to make sense of those.
//
// Chrome also supports the non-standard bypass format specifier %_
// which just skips over the parameter.
//
// This implementation updates the |args| in-place with the results
// from the conversion.
//
// The |index| describes the position of the format string within,
// |args| (starting with 1, since |args| also includes the receiver),
// which is different for example in case of `console.log` where it
// is 1 compared to `console.assert` where it is 2.
bool Formatter(Isolate* isolate, BuiltinArguments& args, int index) {
  if (args.length() < index + 2 || !IsString(args[index])) {
    return true;
  }
  struct State {
    Handle<String> str;
    int off;
  };
  std::stack<State> states;
  HandleScope scope(isolate);
  auto percent = isolate->factory()->LookupSingleCharacterStringFromCode('%');
  states.push({args.at<String>(index++), 0});
  while (!states.empty() && index < args.length()) {
    State& state = states.top();
    state.off = String::IndexOf(isolate, state.str, percent, state.off);
    if (state.off < 0 || state.off == state.str->length() - 1) {
      states.pop();
      continue;
    }
    Handle<Object> current = args.at(index);
    uint16_t specifier = state.str->Get(state.off + 1, isolate);
    if (specifier == 'd' || specifier == 'f' || specifier == 'i') {
      if (IsSymbol(*current)) {
        current = isolate->factory()->nan_value();
      } else {
        Handle<Object> params[] = {current,
                                   isolate->factory()->NewNumberFromInt(10)};
        auto builtin = specifier == 'f' ? isolate->global_parse_float_fun()
                                        : isolate->global_parse_int_fun();
        if (!Execution::CallBuiltin(isolate, builtin,
                                    isolate->factory()->undefined_value(),
                                    arraysize(params), params)
                 .ToHandle(&current)) {
          return false;
        }
      }
    } else if (specifier == 's') {
      Handle<Object> params[] = {current};
      if (!Execution::CallBuiltin(isolate, isolate->string_function(),
                                  isolate->factory()->undefined_value(),
                                  arraysize(params), params)
               .ToHandle(&current)) {
        return false;
      }

      // Recurse into string results from type conversions, as they
      // can themselves contain formatting specifiers.
      states.push({Handle<String>::cast(current), 0});
    } else if (specifier == 'c' || specifier == 'o' || specifier == 'O' ||
               specifier == '_') {
      // We leave the interpretation of %c (CSS), %o (optimally useful
      // formatting), and %O (generic JavaScript object formatting) as
      // well as the non-standard %_ (bypass formatter in Chrome) to
      // the debugger front-end, and preserve these specifiers as well
      // as their arguments verbatim.
      index++;
      state.off += 2;
      continue;
    } else if (specifier == '%') {
      // Chrome also supports %% as a way to generate a single % in the
      // output.
      state.off += 2;
      continue;
    } else {
      state.off++;
      continue;
    }

    // Replace the |specifier| (including the '%' character) in |target|
    // with the |current| value. We perform the replacement only morally
    // by updating the argument to the conversion result, but leave it to
    // the debugger front-end to perform the actual substitution.
    args.set_at(index++, *current);
    state.off += 2;
  }
  return true;
}

void ConsoleCall(
    Isolate* isolate, const internal::BuiltinArguments& args,
    void (debug::ConsoleDelegate::*func)(const v8::debug::ConsoleCallArguments&,
                                         const v8::debug::ConsoleContext&)) {
  if (isolate->is_execution_terminating()) return;
  CHECK(!isolate->has_exception());
  if (!isolate->console_delegate()) return;
  HandleScope scope(isolate);
  debug::ConsoleCallArguments wrapper(isolate, args);
  Handle<Object> context_id_obj = JSObject::GetDataProperty(
      isolate, args.target(), isolate->factory()->console_context_id_symbol());
  int context_id =
      IsSmi(*context_id_obj) ? Smi::cast(*context_id_obj).value() : 0;
  Handle<Object> context_name_obj = JSObject::GetDataProperty(
      isolate, args.target(),
      isolate->factory()->console_context_name_symbol());
  Handle<String> context_name = IsString(*context_name_obj)
                                    ? Handle<String>::cast(context_name_obj)
                                    : isolate->factory()->anonymous_string();
  (isolate->console_delegate()->*func)(
      wrapper,
      v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
}

#define CONSOLE_BUILTIN_IMPLEMENTATION(call, name, index)      \
  BUILTIN(Console##call) {                                     \
    if (!Formatter(isolate, args, index)) {                    \
      return ReadOnlyRoots(isolate).exception();               \
    }                                                          \
    ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \
    RETURN_FAILURE_IF_EXCEPTION(isolate);                      \
    return ReadOnlyRoots(isolate).undefined_value();           \
  }
CONSOLE_METHOD_WITH_FORMATTER_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
#undef CONSOLE_BUILTIN_IMPLEMENTATION

调用顺序 Formatter-》ConsoleCall-》V8Console::Log-》ConsoleHelper::reportCall

最终调用到 src\v8\src\inspector\v8-console.cc中的reportCall函数
 

void V8Console::Log(const v8::debug::ConsoleCallArguments& info,
                    const v8::debug::ConsoleContext& consoleContext) {
  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::Log");
  ConsoleHelper(info, consoleContext, m_inspector)
      .reportCall(ConsoleAPIType::kLog);
}


void reportCall(ConsoleAPIType type,
                  v8::MemorySpan<const v8::Local<v8::Value>> arguments) {
    if (!m_groupId) return;
    std::unique_ptr<V8ConsoleMessage> message =
        V8ConsoleMessage::createForConsoleAPI(
            m_context, m_contextId, m_groupId, m_inspector,
            m_inspector->client()->currentTimeMS(), type, arguments,
            consoleContextToString(m_isolate, m_consoleContext),
            m_inspector->debugger()->captureStackTrace(false));
    consoleMessageStorage()->addMessage(std::move(message));
  }

而且前端的内容存储在message.value()->m_message.m_impl  如图:

总结下调用顺序 Formatter-》ConsoleCall-》V8Console::Log-》ConsoleHelper::reportCall

内容存储在V8ConsoleMessage(v8\src\inspector\v8-console-message.h)结构中。

结论:至于前端中其他的console方法c++实现参考 src\v8\src\inspector\v8-console.h|v8\src\debug\interface-types.h声明。

主要涉及文件:

src\v8\src\inspector\v8-console.cc

src\v8\src\inspector\v8-console.h

src\v8\src\builtins\builtins-console.cc

src\v8\src\inspector\v8-inspector-impl.cc

src\v8\src\inspector\v8-inspector-impl.h

v8\src\inspector\v8-console-message.h

v8\src\inspector\v8-console-message.cc

附:v8\src\inspector\v8-console-message.h

// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_INSPECTOR_V8_CONSOLE_MESSAGE_H_
#define V8_INSPECTOR_V8_CONSOLE_MESSAGE_H_

#include <deque>
#include <map>
#include <memory>
#include <set>

#include "include/v8-local-handle.h"
#include "include/v8-persistent-handle.h"
#include "src/inspector/protocol/Console.h"
#include "src/inspector/protocol/Forward.h"
#include "src/inspector/protocol/Runtime.h"

namespace v8_inspector {

class InspectedContext;
class V8InspectorImpl;
class V8InspectorSessionImpl;
class V8StackTraceImpl;

enum class V8MessageOrigin { kConsole, kException, kRevokedException };

enum class ConsoleAPIType {
  kLog,
  kDebug,
  kInfo,
  kError,
  kWarning,
  kDir,
  kDirXML,
  kTable,
  kTrace,
  kStartGroup,
  kStartGroupCollapsed,
  kEndGroup,
  kClear,
  kAssert,
  kTimeEnd,
  kCount
};

class V8ConsoleMessage {
 public:
  ~V8ConsoleMessage();

  static std::unique_ptr<V8ConsoleMessage> createForConsoleAPI(
      v8::Local<v8::Context> v8Context, int contextId, int groupId,
      V8InspectorImpl* inspector, double timestamp, ConsoleAPIType,
      v8::MemorySpan<const v8::Local<v8::Value>> arguments,
      const String16& consoleContext, std::unique_ptr<V8StackTraceImpl>);

  static std::unique_ptr<V8ConsoleMessage> createForException(
      double timestamp, const String16& detailedMessage, const String16& url,
      unsigned lineNumber, unsigned columnNumber,
      std::unique_ptr<V8StackTraceImpl>, int scriptId, v8::Isolate*,
      const String16& message, int contextId, v8::Local<v8::Value> exception,
      unsigned exceptionId);

  static std::unique_ptr<V8ConsoleMessage> createForRevokedException(
      double timestamp, const String16& message, unsigned revokedExceptionId);

  V8MessageOrigin origin() const;
  void reportToFrontend(protocol::Console::Frontend*) const;
  void reportToFrontend(protocol::Runtime::Frontend*, V8InspectorSessionImpl*,
                        bool generatePreview) const;
  ConsoleAPIType type() const;
  void contextDestroyed(int contextId);

  int estimatedSize() const {
    return m_v8Size + static_cast<int>(m_message.length() * sizeof(UChar));
  }

 private:
  V8ConsoleMessage(V8MessageOrigin, double timestamp, const String16& message);

  using Arguments = std::vector<std::unique_ptr<v8::Global<v8::Value>>>;
  std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>>
  wrapArguments(V8InspectorSessionImpl*, bool generatePreview) const;
  std::unique_ptr<protocol::Runtime::RemoteObject> wrapException(
      V8InspectorSessionImpl*, bool generatePreview) const;
  void setLocation(const String16& url, unsigned lineNumber,
                   unsigned columnNumber, std::unique_ptr<V8StackTraceImpl>,
                   int scriptId);
  std::unique_ptr<protocol::DictionaryValue> getAssociatedExceptionData(
      V8InspectorImpl* inspector, V8InspectorSessionImpl* session) const;

  V8MessageOrigin m_origin;
  double m_timestamp;
  String16 m_message;
  String16 m_url;
  unsigned m_lineNumber;
  unsigned m_columnNumber;
  std::unique_ptr<V8StackTraceImpl> m_stackTrace;
  int m_scriptId;
  int m_contextId;
  ConsoleAPIType m_type;
  unsigned m_exceptionId;
  unsigned m_revokedExceptionId;
  int m_v8Size = 0;
  Arguments m_arguments;
  String16 m_detailedMessage;
  String16 m_consoleContext;
};

class V8ConsoleMessageStorage {
 public:
  V8ConsoleMessageStorage(V8InspectorImpl*, int contextGroupId);
  ~V8ConsoleMessageStorage();

  int contextGroupId() { return m_contextGroupId; }
  const std::deque<std::unique_ptr<V8ConsoleMessage>>& messages() const {
    return m_messages;
  }

  void addMessage(std::unique_ptr<V8ConsoleMessage>);
  void contextDestroyed(int contextId);
  void clear();

  bool shouldReportDeprecationMessage(int contextId, const String16& method);
  int count(int contextId, const String16& id);
  bool countReset(int contextId, const String16& id);
  void time(int contextId, const String16& id);
  double timeLog(int contextId, const String16& id);
  double timeEnd(int contextId, const String16& id);
  bool hasTimer(int contextId, const String16& id);

 private:
  V8InspectorImpl* m_inspector;
  int m_contextGroupId;
  int m_estimatedSize = 0;
  std::deque<std::unique_ptr<V8ConsoleMessage>> m_messages;

  struct PerContextData {
    std::set<String16> m_reportedDeprecationMessages;
    // Corresponds to https://console.spec.whatwg.org/#count-map
    std::map<String16, int> m_count;
    // Corresponds to https://console.spec.whatwg.org/#timer-table
    std::map<String16, double> m_time;
  };
  std::map<int, PerContextData> m_data;
};

}  // namespace v8_inspector

#endif  // V8_INSPECTOR_V8_CONSOLE_MESSAGE_H_

v8\src\debug\interface-types.h

// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_DEBUG_INTERFACE_TYPES_H_
#define V8_DEBUG_INTERFACE_TYPES_H_

#include <cstdint>

#include "include/v8-function-callback.h"
#include "include/v8-local-handle.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "v8-isolate.h"

namespace v8 {

class String;

namespace internal {
class BuiltinArguments;
}  // namespace internal

namespace debug {

/**
 * Defines location inside script.
 * Lines and columns are 0-based.
 */
class V8_EXPORT_PRIVATE Location {
 public:
  Location(int line_number, int column_number);
  /**
   * Create empty location.
   */
  Location();

  int GetLineNumber() const;
  int GetColumnNumber() const;
  bool IsEmpty() const;

 private:
  int line_number_;
  int column_number_;
  bool is_empty_;
};

enum DebugAsyncActionType {
  kDebugAwait,
  kDebugPromiseThen,
  kDebugPromiseCatch,
  kDebugPromiseFinally,
  kDebugWillHandle,
  kDebugDidHandle
};

enum BreakLocationType {
  kCallBreakLocation,
  kReturnBreakLocation,
  kDebuggerStatementBreakLocation,
  kCommonBreakLocation
};

enum class CoverageMode {
  // Make use of existing information in feedback vectors on the heap.
  // Only return a yes/no result. Optimization and GC are not affected.
  // Collecting best effort coverage does not reset counters.
  kBestEffort,
  // Disable optimization and prevent feedback vectors from being garbage
  // collected in order to preserve precise invocation counts. Collecting
  // precise count coverage resets counters to get incremental updates.
  kPreciseCount,
  // We are only interested in a yes/no result for the function. Optimization
  // and GC can be allowed once a function has been invoked. Collecting
  // precise binary coverage resets counters for incremental updates.
  kPreciseBinary,
  // Similar to the precise coverage modes but provides coverage at a
  // lower granularity. Design doc: goo.gl/lA2swZ.
  kBlockCount,
  kBlockBinary,
};

class V8_EXPORT_PRIVATE BreakLocation : public Location {
 public:
  BreakLocation(int line_number, int column_number, BreakLocationType type)
      : Location(line_number, column_number), type_(type) {}

  BreakLocationType type() const { return type_; }

 private:
  BreakLocationType type_;
};

class ConsoleCallArguments {
 public:
  int Length() const { return length_; }
  /**
   * Accessor for the available arguments. Returns `undefined` if the index
   * is out of bounds.
   */
  V8_INLINE v8::Local<v8::Value> operator[](int i) const {
    // values_ points to the first argument.
    if (i < 0 || length_ <= i) return Undefined(GetIsolate());
    DCHECK_NOT_NULL(values_);
    return Local<Value>::FromSlot(values_ + i);
  }

  V8_INLINE v8::Isolate* GetIsolate() const { return isolate_; }

  explicit ConsoleCallArguments(const v8::FunctionCallbackInfo<v8::Value>&);
  explicit ConsoleCallArguments(internal::Isolate* isolate,
                                const internal::BuiltinArguments&);

 private:
  v8::Isolate* isolate_;
  internal::Address* values_;
  int length_;
};

class ConsoleContext {
 public:
  ConsoleContext(int id, v8::Local<v8::String> name) : id_(id), name_(name) {}
  ConsoleContext() : id_(0) {}

  int id() const { return id_; }
  v8::Local<v8::String> name() const { return name_; }

 private:
  int id_;
  v8::Local<v8::String> name_;
};

class ConsoleDelegate {
 public:
  virtual void Debug(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void Error(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void Info(const ConsoleCallArguments& args,
                    const ConsoleContext& context) {}
  virtual void Log(const ConsoleCallArguments& args,
                   const ConsoleContext& context) {}
  virtual void Warn(const ConsoleCallArguments& args,
                    const ConsoleContext& context) {}
  virtual void Dir(const ConsoleCallArguments& args,
                   const ConsoleContext& context) {}
  virtual void DirXml(const ConsoleCallArguments& args,
                      const ConsoleContext& context) {}
  virtual void Table(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void Trace(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void Group(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void GroupCollapsed(const ConsoleCallArguments& args,
                              const ConsoleContext& context) {}
  virtual void GroupEnd(const ConsoleCallArguments& args,
                        const ConsoleContext& context) {}
  virtual void Clear(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void Count(const ConsoleCallArguments& args,
                     const ConsoleContext& context) {}
  virtual void CountReset(const ConsoleCallArguments& args,
                          const ConsoleContext& context) {}
  virtual void Assert(const ConsoleCallArguments& args,
                      const ConsoleContext& context) {}
  virtual void Profile(const ConsoleCallArguments& args,
                       const ConsoleContext& context) {}
  virtual void ProfileEnd(const ConsoleCallArguments& args,
                          const ConsoleContext& context) {}
  virtual void Time(const ConsoleCallArguments& args,
                    const ConsoleContext& context) {}
  virtual void TimeLog(const ConsoleCallArguments& args,
                       const ConsoleContext& context) {}
  virtual void TimeEnd(const ConsoleCallArguments& args,
                       const ConsoleContext& context) {}
  virtual void TimeStamp(const ConsoleCallArguments& args,
                         const ConsoleContext& context) {}
  virtual ~ConsoleDelegate() = default;
};

using BreakpointId = int;

}  // namespace debug
}  // namespace v8

#endif  // V8_DEBUG_INTERFACE_TYPES_H_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值