Chromium 中JavaScript Console API接口c++代码实现
Console API - Web API | MDN (mozilla.org)
Console API
Console API 提供了允许开发人员执行调试任务的功能,例如在代码中的某个位置记录消息或变量值,或者计算任务完成所需的时间。
概念和用法
Console API 最初是一个专有的 API,不同的浏览器以自己的实现方式来实现它。Console API 规范统一了这个 API 的行为,并且所有现代浏览器最终都决定实现这种行为 — 尽管一些实现仍然有自己的附加专有功能。了解这些请查看:
- Google Chrome DevTools implementation
- Safari DevTools implementation
用法非常简单 — 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(¤t)) {
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(¤t)) {
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_