Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASYNCIFY_IGNORE_INDIRECT Javascript callback #10941

Closed
JesseFarebro opened this issue Apr 16, 2020 · 2 comments
Closed

ASYNCIFY_IGNORE_INDIRECT Javascript callback #10941

JesseFarebro opened this issue Apr 16, 2020 · 2 comments

Comments

@JesseFarebro
Copy link

JesseFarebro commented Apr 16, 2020

I've noticed an issue when using Javascript callbacks and ASYNCIFY_IGNORE_INDIRECT. If wakeUp is called in a nested callback it will raise function signature mismatch with -O3 and unreachable otherwise. With -O3 the function call still works as expected, emscripten is woken up and parameters are passed correctly, it just raises the runtime error.
Is this the desired behaviour? From what I understand the indirect call only refers to a C++ indirect call?

Here is a minimal reproduction:

#include <emscripten.h>

EM_JS(void, callback, (), {
  Asyncify.handleSleep((wakeUp) => {
    Module.callback(wakeUp);
  })
})

void loop() {
  callback();
}

int main() {
  emscripten_set_main_loop(loop, 0, 0);
}
emcc main.cpp -O3 \ 
        -s ASYNCIFY=1 \
        -s ASYNCIFY_IGNORE_INDIRECT \
        -s ASYNCIFY_IMPORTS=['callback'] \
        -s MODULARIZE
<html>
  <head>
    <script type="text/javascript" src="a.out.js"></script>
    <script type="text/javascript">
      Module({
        // First callback, raises an error when wakeUp is called
        callback: (wakeUp) => {
          setTimeout(() => {
            console.log("First callback")
            wakeUp();
          }, 0);
        }
      }).then((module) => {
        console.log(module)
        window.MODULE = module
      })

      // Second callback, works without raising an error
      setTimeout(() => {
        window.MODULE.callback = (wakeUp) => {
          console.log("Second callback")
          wakeUp();
        }
      }, 1000)
    </script>
  </head>
  <body>
  </body>
</html>

This following common pattern also doesn't work, i.e., chaining wakeUp on a promise returned from the callback.

EM_JS(void, callback, (), {
  return Asyncify.handleSleep((wakeUp) => {
    Module.callback().then(wakeUp);
  })
})

Thanks for taking a look!

@kripken
Copy link
Member

kripken commented Apr 21, 2020

The full stack trace, when building with function names (-g or --profiling) is

a.out.js:2090 exception thrown: RuntimeError: unreachable,RuntimeError: unreachable
    at dynCall_v (wasm-function[27]:0x6820)
    at ret.<computed> (http://localhost:8000/a.out.js:2893:35)
    at Object.Module.dynCall_v (http://localhost:8000/a.out.js:3151:37)
    at browserIterationFunc (http://localhost:8000/a.out.js:2759:30)
    at Object.runIter (http://localhost:8000/a.out.js:2085:13)
    at Browser_mainLoop_runner (http://localhost:8000/a.out.js:2815:26)

That dynCall_v is doing an indirect call, which is why ASYNCIFY_IGNORE_INDIRECT breaks things. It's because of how the main loop works: it gets a function pointer, then does an indirect call to that. So you can't ignore indirect calls in this case.

@JesseFarebro
Copy link
Author

Thanks for looking into this @kripken, that makes sense. I was overthinking my main loop, making the proper design decisions was the proper way to go about my issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants