【问题标题】:Can V8 perform build-time precompilation of JS code?V8 可以执行 JS 代码的构建时预编译吗?
【发布时间】:2021-04-22 16:13:28
【问题描述】:
我们正在尝试优化 JS 代码在移动设备上的启动时间并寻找机会。我发现 Facebook Hermes JS engine 是为类似目的而创建的,但我们目前严重依赖 V8。
是否可以使用 V8 完成构建时预编译,这意味着解析和代码优化将在编译时完成并在运行时节省一些时间?从源代码生成 LLVM 位码并在运行时执行位码似乎非常接近我的想象。 WASM 似乎不是一种选择(至少对于移动设备而言)。
如果可以的话,能否提供一个简单的用 V8 优化的 JS 代码的简单示例?
附言。可能它也有助于减少内存消耗,这可能是次要目标。
【问题讨论】:
标签:
javascript
android
v8
escape-analysis
ahead-of-time-compile
【解决方案1】:
V8 为此目的支持heap snapshots。例如,used by the Atom editor 用于缩短启动时间。与其说是预编译,不如说是关于预构建全局环境和实例化函数(可能还没有编译,只是转换为Ignition 的字节码,这就足够了)。如果您使用的是 Electron,mksnapshot npm package 可能会很有用。 (如果没有,看看它是如何工作的可能仍然有用。)
我没有做过任何 V8 黑客攻击,但他们从 blog post above 链接的 example 如下:
TEST(PerIsolateSnapshotBlobs) {
DisableTurbofan();
const char* source1 = "function f() { return 42; }";
const char* source2 =
"function f() { return g() * 2; }"
"function g() { return 43; }"
"/./.test('a')";
v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1);
v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2);
v8::Isolate::CreateParams params1;
params1.snapshot_blob = &data1;
params1.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate1 = v8::Isolate::New(params1);
{
v8::Isolate::Scope i_scope(isolate1);
v8::HandleScope h_scope(isolate1);
v8::Local<v8::Context> context = v8::Context::New(isolate1);
delete[] data1.data; // We can dispose of the snapshot blob now.
v8::Context::Scope c_scope(context);
CHECK_EQ(42, CompileRun("f()")->ToInt32(isolate1)->Int32Value());
CHECK(CompileRun("this.g")->IsUndefined());
}
isolate1->Dispose();
v8::Isolate::CreateParams params2;
params2.snapshot_blob = &data2;
params2.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate2 = v8::Isolate::New(params2);
{
v8::Isolate::Scope i_scope(isolate2);
v8::HandleScope h_scope(isolate2);
v8::Local<v8::Context> context = v8::Context::New(isolate2);
delete[] data2.data; // We can dispose of the snapshot blob now.
v8::Context::Scope c_scope(context);
CHECK_EQ(86, CompileRun("f()")->ToInt32(isolate2)->Int32Value());
CHECK_EQ(43, CompileRun("g()")->ToInt32(isolate2)->Int32Value());
}
isolate2->Dispose();
}
那篇博文(以及相关的例子?)是 2015 年的,所以从那以后事情可能已经发生了变化。