从嵌入式 v8 调用 webassembly 而不带 JS
Call webassembly from embedded v8 without JS
我想直接从我的嵌入式 v8 使用 webassembly,而无需通过 JavaScript 绕道而行。我使用了提供的hello-world示例和来自v8.h
的WasmModuleObjectBuilderStreaming类。但是,我被困在如何提取add
函数上。帮助将不胜感激。
#include <include/v8.h>
#include <include/libplatform/libplatform.h>
#include <stdlib.h>
#include <unistd.h>
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Promise;
using v8::WasmModuleObjectBuilderStreaming;
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
HandleScope scope(isolate);
WasmModuleObjectBuilderStreaming stream(isolate);
// Use the v8 API to generate a WebAssembly module.
//
// |bytes| contains the binary format for the following module:
//
// (func (export "add") (param i32 i32) (result i32)
// get_local 0
// get_local 1
// i32.add)
//
// taken from: https://github.com/v8/v8/blob/master/samples/hello-world.cc#L66
std::vector<uint8_t> wasmbin {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
};
// write bytes and finish
stream.OnBytesReceived(wasmbin.data(), wasmbin.size());
stream.Finish();
Local<Promise> promise = stream.GetPromise();
// TODO: Get exports, extract `add` & call `add`
}
构建设置:
按照运行官方嵌入 V8 入门中的示例中的说明进行操作。将代码保存到 sample/wasm.cc 并执行以下命令:
$ g++ -I. -O2 -Iinclude samples/wasm.cc -o wasm -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17`
$ ./wasm`
溶液:
谢谢@liliscent,我相应地调整了我的例子。因为我们都喜欢,工作代码:
#include <include/v8.h>
#include <include/libplatform/libplatform.h>
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Promise;
using v8::WasmModuleObjectBuilderStreaming;
using v8::WasmCompiledModule;
using v8::Context;
using v8::Local;
using v8::Value;
using v8::String;
using v8::Object;
using v8::Function;
using v8::Int32;
using args_type = Local<Value>[];
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
HandleScope scope(isolate);
Local<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
WasmModuleObjectBuilderStreaming stream(isolate);
// Use the v8 API to generate a WebAssembly module.
//
// |bytes| contains the binary format for the following module: //
// (func (export "add") (param i32 i32) (result i32)
// get_local 0
// get_local 1
// i32.add)
//
// taken from: https://github.com/v8/v8/blob/master/samples/hello-world.cc#L66
std::vector<uint8_t> wasmbin {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
};
// same as calling:
// let module = new WebAssembly.Module(bytes);
Local<WasmCompiledModule> module = WasmCompiledModule::DeserializeOrCompile(isolate,
WasmCompiledModule::BufferReference(0, 0),
WasmCompiledModule::BufferReference(wasmbin.data(), wasmbin.size())
).ToLocalChecked();
// same as calling:
// let module_instance_exports = new WebAssembly.Instance(module).exports;
args_type instance_args{module};
Local<Object> module_instance_exports = context->Global()
->Get(context, String::NewFromUtf8(isolate, "WebAssembly"))
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "Instance"))
.ToLocalChecked().As<Object>()
->CallAsConstructor(context, 1, instance_args)
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "exports"))
.ToLocalChecked().As<Object>()
;
// same as calling:
// module_instance_exports.add(77, 88)
args_type add_args{Int32::New(isolate, 77), Int32::New(isolate, 88)};
Local<Int32> adder_res = module_instance_exports
->Get(context, String::NewFromUtf8(isolate, "add"))
.ToLocalChecked().As<Function>()
->Call(context, context->Global(), 2, add_args)
.ToLocalChecked().As<Int32>();
printf("77 + 88 = %dn", adder_res->Value());
return 0;
}
你可以通过v8::WasmCompiledModule
类直接从C++构造一个 WebAssembly 模块(在下一个版本中它将重命名为 v8::WasmModuleObject
):
Local<WasmCompiledModule> module = WasmCompiledModule::DeserializeOrCompile(isolate,
WasmCompiledModule::BufferReference(0, 0),
WasmCompiledModule::BufferReference(wasmbin.data(), wasmbin.size())
).ToLocalChecked();
但是 AFAIK,v8 不会直接公开其 webassembly api,您必须从 JS 全局上下文中获取它们。以下代码创建一个模块实例,并获取该实例的exports
:
using args_type = Local<Value>[];
Local<Object> module_instance_exports = context->Global()
->Get(context, String::NewFromUtf8(isolate, "WebAssembly"))
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "Instance"))
.ToLocalChecked().As<Object>()
->CallAsConstructor(context, 1, args_type{module})
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "exports"))
.ToLocalChecked().As<Object>()
;
然后你可以从对象中获取add
函数exports
并调用它:
Local<Int32> adder_res = module_instance_exports
->Get(context, String::NewFromUtf8(isolate, "add"))
.ToLocalChecked().As<Function>()
->Call(context, context->Global(), 2, args_type{Int32::New(isolate, 77), Int32::New(isolate, 88)})
.ToLocalChecked().As<Int32>();
std::cout << "77 + 88 = " << adder_res->Value() << "n";
您可能对 Wasm C/C++
API 提案感兴趣,该提案允许直接从 C/C++ 使用 Wasm 引擎。此 API 的设计独立于任何特定引擎,但该提案在 V8 之上包含或多或少完整的原型实现。
示例代码段(参见例如 hello.cc):
// ...
auto engine = wasm::Engine::make();
auto store = wasm::Store::make(engine.get());
auto module = wasm::Module::make(store.get(), binary);
auto instance = wasm::Instance::make(store.get(), module.get(), imports);
auto exports = instance->exports();
exports[0]->func()->call();
相关文章:
- JS相等运算符(如===)是否可以使用embind类型
- WebAssembly include OpenCV
- 在 ubuntu 上安装 node js pulsar 客户端
- 用户控制从 c++ 到 java 脚本的 Webassembly 访问调用
- 如何在 Arduino 字符串的开头添加元素.类似于 JS unshift();
- Node.js fs.open() 在尝试打开 4 个以上的命名管道 (FIFO) 后挂起
- 如何在 Cheerp/js 中迭代动态命名的对象?
- 如何与 Cheerp/js 中的 extern 变量接口?
- 如何从WebAssembly模块检测浏览器信息?
- 在C++中序列化浮点数/双精度,编译为 WebAssembly
- 没有 Emscripten,如何使用标准库编译C++到 WebAssembly
- 我可以在不使用Qt for Webassembly的情况下使用Emscripten编译Qt吗?
- 在 node.js 中将缓冲区从 C++ 转换为 UTF-8 字符串
- glfw 的基本设置会导致与 emscripten 生成的 js 文件中的事件侦听器有关的运行时错误
- 如何在C++中使用带有SFML的http reqest从节点.js服务器获取数据?
- 使用 Node.js N-API 调用 C 函数时,不会显示预期的输出
- Problems with emscripten (WebAssembly)
- 将数据从 OpenCV C++传递到 NodeJS/JS |电子
- 从嵌入式 v8 调用 webassembly 而不带 JS
- 如何从JS访问WebAssembly中的内存