在没有 JS 的情况下从嵌入式 v8 调用 webassembly [英] Call webassembly from embedded v8 without JS

查看:31
本文介绍了在没有 JS 的情况下从嵌入式 v8 调用 webassembly的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想直接从我的嵌入式 v8 中使用 webassembly,而无需通过 JavaScript 绕道而行.我使用了提供的 hello-world 示例WasmModuleObjectBuilderStreaming 类来自 v8.h.但是,我被困在如何提取 add 函数上.帮助将不胜感激.

I would like to use webassembly directly from my embedded v8 without the detour via JavaScript. I used the provided hello-world example and the WasmModuleObjectBuilderStreaming class from v8.h. However, I am stuck at how to extract the add function. Help would be appreciated.

#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 并执行以下命令:

Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:

$ g++ -I. -O2 -Iinclude samples/wasm.cc -o wasm  -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17`
$ ./wasm`

解决方案:

感谢 @liliscent,我相应地调整了我的示例.因为我们都喜欢,工作代码:

Thanks @liliscent, I adapted my example accordingly. Because we all like, working code:

#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 = %d\n", adder_res->Value());
  return 0;
}

推荐答案

您可以通过 v8::WasmCompiledModule 类直接从 C++ 构建 WebAssembly 模块(它将被重命名为 v8::WasmModuleObject 下一版本):

You can construct a WebAssembly module directly from C++ via v8::WasmCompiledModule class (it will be renamed to v8::WasmModuleObject in next version):

    Local<WasmCompiledModule> module = WasmCompiledModule::DeserializeOrCompile(isolate,
            WasmCompiledModule::BufferReference(0, 0),
            WasmCompiledModule::BufferReference(wasmbin.data(), wasmbin.size())
        ).ToLocalChecked();

但是 AFAIK,v8 不直接公开其 webassembly api,您必须从 JS 全局上下文中获取它们.以下代码创建一个模块实例,并获取该实例的exports:

But AFAIK, v8 doesn't expose its webassembly api directly, you have to get them from JS global context. The following code creates a module instance, and gets the exports of the instance:

    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>()
        ;

然后你可以从exports对象中获取add函数并调用它:

Then you can get the add function from exports object and call it:

    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";

这篇关于在没有 JS 的情况下从嵌入式 v8 调用 webassembly的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆