WebAssembly.instantiate 没有调用 then 也没有在 v8 embedded 中捕获

WebAssembly.instantiate didn't call then nor catch in v8 embedded

我试图在 v8 7.2 中为我的 Android 项目发布 WebAssembly 功能。我已成功将 v8 作为静态库导入。但是我遇到了一个问题,即 WebAssembly 既没有调用 then 也没有调用 catch 回调。 下面是我的代码:

std::unique_ptr<v8::Platform> platform;
v8::Isolate *isolate;
v8::Persistent<v8::Context> persistentContext;
void runMain();
void runScript();
void _log(const v8::FunctionCallbackInfo<v8::Value>& info) {
  v8::String::Utf8Value utf(isolate, info[0].As<v8::String>());
  __android_log_print(ANDROID_LOG_DEBUG, "V8Native", "%s",*utf);
}

void JNICALL
Java_com_hustunique_v8demoapplication_MainActivity_initV8(JNIEnv *env, jobject /* this */) {
  // Initialize V8.
  v8::V8::InitializeICU();
  platform = v8::platform::NewDefaultPlatform();
  v8::V8::InitializePlatform(&(*platform.get()));
  v8::V8::Initialize();
  runMain();
}

void runMain() {
  // Create a new Isolate and make it the current one.

  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
  isolate = v8::Isolate::New(create_params);
//  isolate->Enter();
  v8::Isolate::Scope isolate_scope(isolate);
  v8::HandleScope scope(isolate);


  auto global_template = v8::ObjectTemplate::New(isolate);
  global_template->Set(v8::String::NewFromUtf8(isolate, "log"), v8::FunctionTemplate::New(isolate, _log));   // set log function here, as it is used in my sample javascript code
  // Enter the context for compiling and running the sample script.
  v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global_template);
  persistentContext.Reset(isolate, context);

  // Run the script to get the result.
  runScript();

}

void runScript() {
  // sample wasm javascript code here.
  const char *csource = R"(
    WebAssembly.instantiate(new Uint8Array([0,97,115,109,1,0,0,0,1,8,2,96,1,127,0,96,0,0,2,8,1,2,106,
      115,1,95,0,0,3,2,1,1,8,1,1,10,9,1,7,0,65,185,10,16,0,11]),
      {js:{_:console.log('Called from WebAssembly Hello world')}}).then(function(obj) {
        log('Called with instance ' + obj);
      }).catch(function(err) {
        log('Called with error ' + err);
      });
  )"; // should call my Hello World log and trigger the error or return the instance successfully

  v8::HandleScope handle_scope(isolate);
  auto ctx = persistentContext.Get(isolate);
  v8::Context::Scope context_scope(ctx);
  v8::TryCatch try_catch(isolate);
  v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, csource,
                                                         v8::NewStringType::kNormal).ToLocalChecked();

  v8::Local<v8::Script> script =
      v8::Script::Compile(ctx, source).ToLocalChecked();
  v8::Local<v8::Value> result;
  if (!script->Run(ctx).ToLocal(&result)) {
    ReportException(isolate, &try_catch); // report exception, ignore the implementation here
    return;
  }
  // Convert the result to an UTF8 string and print it.
  v8::String::Utf8Value utf8(isolate, result);
  __android_log_print(ANDROID_LOG_INFO, "V8Native", "%s\n", *utf8);

}

在上面的演示中,我得到了 Called from WebAssembly Hello world 作为例外的输出,但我无法获得错误消息和实例信息。

我在website上做了一个简单的例子,与我上面的演示相比,这是网站上的输出,我认为可以轻松复制:

Called from WebAssembly Hello world
Called with error LinkError: WebAssembly.instantiate(): Import #0 module="js" function="_" error: function import requires a callable

似乎在我的演示中,resolvereject 都不是从 WebAssembly 的返回承诺中调用的。在检查runScript方法中v8::Local<v8::Value> result的类型后,v8运行time确认它是一个promise对象。

我在这里尝试了几种方法,但其中 none 有效:

  1. 调用 v8::Isolate::RunMicroTasks()。什么都没发生
  2. runScript 方法的末尾将 result 转换为 v8::Local<v8::Promise>,然后 运行 使用:
auto resolver = v8::Resolver::New(context)->toLocalChecked();
while (promise->State() == v8::PromiseState::kPending) {
    isolate->RunMicroTasks();
}
if (promise->State() == v8::PromiseState::kFullfilled) {
    resolver->Resolve(context, promise->Result());
}
if (promise->State() == v8::PromiseState::kRejected) {
    resolver->Reject(context, promise->Result());
}

此代码段也不起作用,此外,它停留在 kPending 状态。

我搜索了类似 flush the promise queue 的内容,但没有找到任何解决方案。我在这里错过了什么?

WebAssembly 的异步编译 API 在 v8::Platform 的后台线程之一上注册正在进行的工作,最终在未来,一个任务将被发布到前台线程以解决承诺用于编译。

为了解决此承诺,您需要启动消息循环和 运行 任何待处理的微任务:

v8::platform::PumpMessageLoop(platform.get(), isolate);
isolate->RunMicrotasks();

根据完成编译所需的时间,可能需要执行此泵送更长时间。