从没有JS的嵌入式v8调用Webassembly

时间:2018-12-25 22:19:09

标签: c++ v8 webassembly

我想直接从嵌入式v8使用webassembly,而不会通过JavaScript绕行。我使用了private func setupAudioContent() { let urlString = "https://s3.amazonaws.com/kargopolov/kukushka.mp3" if let url = NSURL(string: urlString) { audioPlayer = AVPlayer(url: url as URL) let playerLayer = AVPlayerLayer(player: audioPlayer) self.layer.addSublayer(playerLayer) playerLayer.frame = self.frame audioPlayer?.play() audioPlayer?.volume = 1.0 audioPlayer?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil) let interval = CMTime(value: 1, timescale: 2) audioPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in let currentTime = CMTimeGetSeconds(progressTime) let currentTimeSecondsString = String(format: "%02d", Int(currentTime.truncatingRemainder(dividingBy: 60))) let currentTimeMinutesString = String(format: "%02d", Int(currentTime / 60)) self.currentTimeLabel.text = "\(currentTimeMinutesString):\(currentTimeSecondsString)" if let duration = self.audioPlayer?.currentItem?.duration { let durationsSeconds = CMTimeGetSeconds(duration) self.audioSlider.value = Float(currentTime / durationsSeconds) } }) } } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "currentItem.loadedTimeRanges" { isAudioPlaying = true if let duration = audioPlayer?.currentItem?.duration { let seconds = CMTimeGetSeconds(duration) let secondsText = Int(seconds) % 60 let minutesText = String(format: "%02d", Int(seconds) / 60) audioLengthLabel.text = "\(minutesText):\(secondsText)" } } } @objc func handleSliderChange() { if let duration = audioPlayer?.currentItem?.duration { let totalSeconds = CMTimeGetSeconds(duration) let value = Float64(audioSlider.value) * totalSeconds let seekTime = CMTime(value: Int64(value), timescale: 1) audioPlayer?.seek(to: seekTime, completionHandler: { (completedSeek) in }) } } 中提供的hello-world exampleWasmModuleObjectBuilderStreaming类。但是,我坚持如何提取v8.h函数。帮助将不胜感激。

add

构建设置:

按照官方Getting started with embedding V8运行示例中的说明进行操作。将代码保存到 sample / wasm.cc 并执行以下命令:

#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`
}

解决方案:

感谢@liliscent,我相应地修改了我的示例。因为我们都喜欢,所以工作代码:

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

2 个答案:

答案 0 :(得分:1)

您可以通过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";

答案 1 :(得分:0)

您可能对Wasm C/C++ API proposal感兴趣,它允许直接从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();