看源码的时候就看 8.3.100 吧…
- 在尝试官方 example shell.cc 时发现8.0 以上版本中默认开启了 V8_COMPRESS_POINTERS 导致指针崩溃, 大概原因应该是为了节省内存占用省略了高位32位地址
- 官方讨论
- 两种解决方法:
- 编译一个关闭 pointer_compression 的 v8 版本
gn args out.gn/x64.release.sample
, 添加v8_enable_pointer_compression = false
- 编译自己的程序时添加
-DV8_COMPRESS_POINTERS
- 编译一个关闭 pointer_compression 的 v8 版本
- 如果想在调试的时候看变量, 比较简单粗暴的方法是将 V8 里的 Local value 转换成普通字符串再看
- 在全局对象上加 console 并不会覆盖 V8 自己实现的, 而且 V8 自己实现的只会在 Inspector 调试的时候才起作用.
- 解决方法: 要么注释源码, 要么写一个 ConsoleDelegate
- 编译 arm64 V8
- V8 在 6.6 版本(2018年初)才支持 Optional catch binding(省略 catch 参数)
文档
编译步骤
# https://v8.dev/docs/source-code#using-git
# https://v8.dev/docs/embed
# 安装 google depot tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=$PATH:/path/to/depot_tools
mkdir v8
cd v8
# 拉取 V8 源码
fetch v8
# 可选, 切换到一个可用的分支, lkgr = Last Known Good Revision
git checkout lkgr
# 同步依赖
gclient sync
# 配置 release 版本编译参数
tools/dev/v8gen.py x64.release.sample
# 编译, v8_monolith 表示直接将所有的动态库链接起来
ninja -C out.gn/x64.release.sample v8_monolith
# 配置和编译 debug 版本
# 可以参考 https://mem2019.github.io/jekyll/update/2019/07/18/V8-Env-Config.html
# 2020-3-19: debug 版本没编过, 有 wasm 的 unit test 错误...
tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug
# 2020-3-20
# 可以通过 gn args out.gn/x64.release.sample 后修改里面的 debug flag 实现
如果要带着 V8 编译自己的代码, 可以参照以下 CmakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(V8Demo)
# 指定 V8 的头文件地址
include_directories(
/Users/bopeng/c/tools/v8/include
)
# 指定 lib 的搜索目录
link_directories(
/Users/bopeng/c/tools/v8/out.gn/x64.release.sample/obj
)
# V8 编译的结果就是这个 .a 文件
link_libraries(v8_monolith)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -pthread")
set(SOURCE_FILES ./main.cc)
add_executable(Demo ${SOURCE_FILES})
基本概念
isolate
隔离区, 一个 isolate 对应一个 V8 实例, 一个 isolate 下可以有多个 context
handle
V8 中所有对象(context, 数据, 模板)都通过 handle(指向指针的指针) 来引用, 从而方便垃圾回收, 分为以下两种
v8::Local
: 局部的, 本地句柄, 提供对栈(stack)分配的 JS 对象的引用- HandleScope 是 Local handle 的集合栈. 有了它就可以统一管理 Local handle, 比如统一释放内存
v8::MaybeLocal
- 为了让用户注意空指针的情况出现的类型, 可以通过
ToLocalChecked()
或者ToLocal()
转换为v8::Local
-
- 为了让用户注意空指针的情况出现的类型, 可以通过
MaybeLocalv8::String str = v8::String::NewFromUtf8(isolate, “str”); // 使用 ToLocalChecked() v8::Localv8::String src = str.ToLocalChecked(); // 使用 ToLocal() v8::Localv8::String src; if (!str.ToLocal(&src)) { return; }
- [这里](https://stackoverflow.com/questions/47114090/what-does-an-empty-maybelocal-mean/47144507#47144507)有一个 V8 开发者 jmrk 的解释, idom 的[这篇文章](https://idom.me/articles/847.html)也很好的解释了
- `v8::Persistent`: 全局的, 持久化句柄, 提供对堆(heap)分配的 JS 对象的引用, 比如 Chrome 里的 DOM 节点
### context/数据/模板
- `v8::context`: 相当于全局变量, 浏览器中就是 window 对象啦
- 使用 context 可以将互相分离的 JS 脚本放在同一个 V8 的实例中运行且互不干涉, 比如浏览器中每个窗口和 iFrame 都有自己独立的 JS 环境
- `v8::Data`: 数据
- `v8::String`
- `v8::Integer`
- `v8::Template`: 模板
- `v8::FunctionTemplate`: 函数模板
- `v8::ObjectTemplate`: 对象模板
```cpp
/* 创建一个全局变量, 并在全局变量上加上 Print 方法 */
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
// do something
}
v8::Local<String> fn_name = v8::String::NewFromUtf8Literal(isolate, "print")
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
// 将 print 方法绑定到 全局对象 global
global->Set(fn_name, v8::FunctionTemplate::New(isolate, Print));
// 根据全局对象 global 创建上下文
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
// 这样就可以在 js 里执行 print() 了
// 主动执行 print 函数, 参数为 "hello"
v8::Local<Value> callback = context->Global()->Get(context, fn_name).ToLocalChecked();
v8::Local<Value> args[] = {v8::String::NewFromUtf8(isolate, "hello").ToLocalChecked()};
v8::Local<Function>::Cast(callback)->Call(context, v8::Undefined(isolate), 1, args);
node.js 的插件示例里也有类似的写法举例
Accessor(访问器)
在脚本访问特定对象属性时运行 通过 SetAccessor 方法设置
Interceptor(拦截器)
在脚本访问任何对象属性时运行
通过 SetHandler方法设置, 官方文档里说的 SetNamedPropertyHandler
方法貌似已经废弃了
基本步骤
- 初始化 V8
- 创建一个新的隔离区(Isolate), 并将这个隔离区置为当前可用
- 创建一个栈分配的句柄范围(HandleScope)来存储句柄
- 创建一个上下文(Context)
- 在上下文内编译和运行 JS 脚本
- 销毁隔离区并关掉 V8 进程
Misc
PumpMessageLoop
: 执行 Eventloop 中的 Task- Web 内存优化
- JIT: Just In Time
- D8: V8 的调试命令行工具, 便于本地执行 JS
- V8-Inspector
源码
全局: namespace i = v8::internal;
如何正确地使用v8嵌入到我们的C++应用中 by 豆米 V8 javascript engine代码阅读 by Sakura