如何用V8给js添加一个全局对象
讲解如何为 V8 引擎新增内置全局对象 METRIC,涵盖头文件定义、API 导出、Genesis 初始化、Builtin 注册及编译验证的完整流程。
如何用V8给js添加一个全局对象
新增javascript一个内置的全局对象,来获取该系统的指标信息
i) 新增头文件信息
需要保证的namespace在v8::internal
namespace v8 {
namespace internal {
V8_WARN_UNUSED_RESULT MaybeHandle<Object> CpuInfo(Isolate* isolate,
Handle<Object> object,
Handle<Object> replacer,
Handle<Object> gap);
} // namespace internal
} // namespace v8
源文件中构造函数需要初始化成员变量Isolate(可以理解认为是一个上下文的context)。对外暴露一个CpuInfo函数(未实现)
MetricHost::MetricHost(Isolate* isolate)
: isolate_(isolate){
}
MetricHost::~MetricHost() {
std::cout << " destory" << std::endl;
}
MaybeHandle<Object> CpuInfo(Isolate* isolate, Handle<Object> object,
Handle<Object> replacer, Handle<Object> gap) {
MetricHost metricHost(isolate);
std::cout << " before cpuinfo " << std::endl;
if (!gap->IsUndefined(isolate)) {
return MaybeHandle<Object>();
}
Handle<JSObject> holder =
isolate->factory()->NewJSObject(isolate->object_function());
Handle<String> name = isolate->factory()->empty_string();
JSObject::AddProperty(isolate, holder, name, object, NONE);
std::cout << " after cpuinfo " << std::endl;
return holder;
}
ii)将函数(CpuInfo)符号导出同时在api.cc中发布
class V8_EXPORT Metric {
public:
static V8_WARN_UNUSED_RESULT MaybeLocal<String> CpuInfo(
Local<Context> context, Local<Value> json_object,
Local<String> gap = Local<String>());
};
} // namespace v8
iii) 作为内嵌对象发布
全局变量的初始化Genesis::InitializeGlobal(src/init/bootstrapper.cc) 加入metric的初始化
{ // -- metric cupinfo
Handle<JSObject> json_object =
factory->NewJSObject(isolate_->object_function(), AllocationType::kOld);
JSObject::AddProperty(isolate_, global, "METRIC", json_object, DONT_ENUM);
SimpleInstallFunction(isolate_, json_object, "cupInfo",
Builtin::kCupInfo, 3, true);
InstallToStringTag(isolate_, json_object, "METRIC");
}
增加一个METRIC全局对象同时为该全局对象增加函数 创建Builtin::kCupInfo 在头文件(src/builtins/builtins-definitions.h)添加对应的宏展开
CPP(CupInfo)
在对应的位置创建源文件
namespace v8 {
namespace internal {
// METRIC.cupInfo.
BUILTIN(CupInfo) {
HandleScope scope(isolate);
Handle<Object> object = args.atOrUndefined(isolate, 1);
Handle<Object> replacer = args.atOrUndefined(isolate, 2);
Handle<Object> indent = args.atOrUndefined(isolate, 3);
RETURN_RESULT_OR_FAILURE(isolate,
CpuInfo(isolate, object, replacer, indent));
}
} // namespace internal
} // namespace v8
iV) 添加依赖
BUILD.gn BUILD.bazel
v) 编译
如果使用d8来测试需要在编译后面的参数加上(假设gn 生成在out/foo目录下) ninja -C out/foo d8 (在gn生成的时候third_party/jinja2在python3.10会导致失败可以做如下调整
from collections import Mapping
=>
from collections.abc import Mapping
) link
vi)验证
console.log("hello world")
METRIC.cupInfo("hello")
console.log(METRIC)
console.log(console)
输出如下
PS D:\code\v8\v8\out\foo> .\d8.exe .\foo.js
hello world
before cpuinfo
after cpuinfo
destory
[object METRIC]
[object Object]