WASM not working on Android (embedded)

388 views
Skip to first unread message

Darin Dimitrov

unread,
Jan 15, 2020, 3:15:49 AM1/15/20
to v8-users
I have embedded V8 (7.8.279.19) inside my Android application and tried executing a script that compiles a WebAssembly module.

Unfortunately the promise returned by the "WebAssembly.compile" method is never completed (neither the "then" or the "catch" methods are invoked). The same happens with the "WebAssembly.instantiate" method:

std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8
::V8::InitializePlatform(platform.get());
v8
::V8::Initialize();

v8
::Isolate::CreateParams create_params;
create_params
.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8
::Isolate* isolate = v8::Isolate::New(create_params);
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::NewStringType::kNormal).ToLocalChecked(), v8::FunctionTemplate::New(isolate, [](const v8::FunctionCallbackInfo<v8::Value>& info) {
    v8
::Isolate* isolate = info.GetIsolate();
    v8
::String::Utf8Value utf(isolate, info[0].As<v8::String>());
    __android_log_print
(ANDROID_LOG_DEBUG, "V8Native", "%s",*utf);
}));

v8
::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global_template);
v8
::Context::Scope context_scope(context);
const char* csource = R"(
    let bytes = 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
    ]);
    log('before the call');
    WebAssembly
        .instantiate(bytes)
        .then(obj => log('success'))
        .catch(err => log('log'));
    )"
;
v8
::Local<v8::String> source = v8::String::NewFromUtf8(isolate, csource, v8::NewStringType::kNormal).ToLocalChecked();
v8
::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8
::Local<v8::Value> result;
script
->Run(context).ToLocal(&result);


Do you have any idea what I might be missing here? The same javascript code works fine in the desktop browser.

Clemens Backes

unread,
Jan 15, 2020, 10:12:39 AM1/15/20
to v8-u...@googlegroups.com
Hi Darin,

WebAssembly.instantiate works asynchronously, so you have to keep your program running for a while to wait for the asynchronous result, and keep pumping the message loop and running microtasks to actually execute the compilation tasks and promise resolution tasks that get added from the background.

This is probably not the most elegant solution, but it works:
  [...]
  script->Run(context).ToLocal(&result);
  // Keep running for 10 seconds, pumping the message loop and running
  // microtasks.
  auto start = std::chrono::system_clock::now();
  do {
    v8::platform::PumpMessageLoop(platform.get(), isolate);
    isolate->RunMicrotasks();
  } while (std::chrono::duration_cast<std::chrono::seconds>(
               std::chrono::system_clock::now() - start)
               .count() < 10);

Hope that helps,
Clemens


--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-users/4c766e82-892c-45f5-984a-aa9dd87f8138%40googlegroups.com.


--

Clemens Backes

Software Engineer

clem...@google.com


Google Germany GmbH

Erika-Mann-Straße 33

80636 München


Geschäftsführer: Paul Manicle, Halimah DeLaine Prado

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg


Diese E-Mail ist vertraulich. Falls sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde.


This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.

Darin Dimitrov

unread,
Jan 15, 2020, 10:13:17 AM1/15/20
to v8-users
It appears that the WebAssembly compilation is happening on of the v8::Platform's background threads and a task will be posted to the foreground loop to resolve the compilation promise.

So I need to pump the message loop:

while (v8::platform::PumpMessageLoop(Runtime::platform, isolate, v8::platform::MessageLoopBehavior::kDoNotWait)) {
    isolate
->RunMicrotasks();
}

Now the question is what would be the best approach to implement such message loop inside an Android application. I initialize the v8::Isolate on the main thread and I cannot block it to wait for such events. I was able to achieve this by using a timer which executes this pumping from time to time but I suppose that this is not the best solution. I was wondering if there's some mechanism I which would notify me that there are some tasks accumulated on the message loop, or maybe somehow consolidate v8 platform's loop with Android's message loop.

Darin Dimitrov

unread,
Jan 16, 2020, 8:23:31 AM1/16/20
to v8-users
Thanks Clemens. 

This works fine but it blocks the main thread. What would be the best approach to handle this in an Android app? Would writing a custom platform help in this case?


On Wednesday, January 15, 2020 at 5:12:39 PM UTC+2, Clemens Hammacher wrote:
Hi Darin,

WebAssembly.instantiate works asynchronously, so you have to keep your program running for a while to wait for the asynchronous result, and keep pumping the message loop and running microtasks to actually execute the compilation tasks and promise resolution tasks that get added from the background.


This is probably not the most elegant solution, but it works:
  [...]
  script->Run(context).ToLocal(&result);
  // Keep running for 10 seconds, pumping the message loop and running
  // microtasks.
  auto start = std::chrono::system_clock::now();
  do {
    v8::platform::PumpMessageLoop(platform.get(), isolate);
    isolate->RunMicrotasks();
  } while (std::chrono::duration_cast<std::chrono::seconds>(
               std::chrono::system_clock::now() - start)
               .count() < 10);

Hope that helps,
Clemens


To unsubscribe from this group and stop receiving emails from it, send an email to v8-u...@googlegroups.com.

Clemens Backes

unread,
Jan 16, 2020, 8:41:22 AM1/16/20
to v8-u...@googlegroups.com
On Thu, Jan 16, 2020 at 2:23 PM Darin Dimitrov <darin.d...@gmail.com> wrote:
Thanks Clemens. 

This works fine but it blocks the main thread. What would be the best approach to handle this in an Android app? Would writing a custom platform help in this case?

I don't know about Android development, and I am not a platform expert, so maybe others can chime in.
I guess that your own platform implementation would help because you would get notified of new tasks that get scheduled.

To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-users/94c52b07-5b54-4e61-9fc2-4f2afecf2096%40googlegroups.com.

Darin Dimitrov

unread,
Jan 17, 2020, 10:29:12 AM1/17/20
to v8-users
Thanks Clemens. I would be very happy if someone more familiar could provide some insight.

Any pointers in the Google Chrome source code for Android would also be helpful. I suppose they have already faced this problem and implemented it properly.


On Thursday, January 16, 2020 at 3:41:22 PM UTC+2, Clemens Backes wrote:

ibon

unread,
Jan 18, 2020, 5:40:23 PM1/18/20
to v8-users
Hi Darin,

I do embed v8 on android on a regular basis.
Unlike you, I run v8 bound to gl thread, and as a rule of thumb for performance reasons always on a different than the main thread. 
I need to, at least, run `v8::platform::PumpMessageLoop(&platform, isolate_);` to have promises executed. 
In my case, this is executed consistently once every gl thread tick, 60 times a sec.

Your webassembly example, throws this btw: "TypeError: WebAssembly.instantiate(): Imports argument must be present and must be an object"

Hope that helps.

kosit la-orngsri

unread,
Jan 18, 2020, 6:26:11 PM1/18/20
to v8-users


เมื่อ วันพุธที่ 15 มกราคม ค.ศ. 2020 15 นาฬิกา 15 นาที 49 วินาที UTC+7, Darin Dimitrov เขียนว่า:

Darin Dimitrov

unread,
Feb 21, 2020, 6:10:49 AM2/21/20
to v8-users
I managed to resolve this by replacing the global.WebAssembly object with a Proxy which intercepts the "compile" and "instantiate" methods. When one of those methods is called I start a background thread which is polling the main looper at regular intervals, pumps the message loop and executes any pending microtasks. When the method completes, the background thread is destroyed.
Reply all
Reply to author
Forward
Message has been deleted
0 new messages