如何用V8给js添加一个全局对象

讲解如何为 V8 引擎新增内置全局对象 METRIC,涵盖头文件定义、API 导出、Genesis 初始化、Builtin 注册及编译验证的完整流程。

作者:npc001 · 2026-06-27T10:00:00.000000000+00:00

如何用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]