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

"Unexpected arg0 type (select)" for EM_ASM call #11539

Open
hostilefork opened this issue Jul 4, 2020 · 10 comments
Open

"Unexpected arg0 type (select)" for EM_ASM call #11539

hostilefork opened this issue Jul 4, 2020 · 10 comments
Labels

Comments

@hostilefork
Copy link
Contributor

hostilefork commented Jul 4, 2020

I have previously compiling code not working after git pull and activating the latest emsdk (1.39.18). The error is:

"Fatal: Unexpected arg0 type (select) in call to: emscripten_asm_const_int_sync_on_main_thread"

There are several EM_ASM calls, some returning an int and not. Commenting them out one by one revealed the call it was complaining about was this one (where utf8 is a const char *):

MAIN_THREAD_EM_ASM(
    { (1,eval)(UTF8ToString($0)) },
    utf8
);

Changing this to simply { eval(UTF8ToString($0)) } gets it to compile. However, that doesn't achieve the purpose... which was to achieve an "indirect eval call".

Changing it to a plain EM_ASM (no MAIN_THREAD) also seems to work, but also does not accomplish the intent.

Command line

emcc -shared -o libr3.js -static-libgcc -Os -s ENVIRONMENT='web,worker' -s ASSERTIONS=1 --closure 0 --minify 0 --post-js prep/include/reb-lib.js -s DISABLE_EXCEPTION_CATCHING=1 -s DEMANGLE_SUPPORT=0 -s EXPORTED_FUNCTIONS=@prep/include/libr3.exports.json -s "EXTRA_EXPORTED_RUNTIME_METHODS=['allocateUTF8']" -s WASM=1 -s SAFE_HEAP=0 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=1 (...bunch of obj files...)

@hostilefork
Copy link
Contributor Author

hostilefork commented Jul 6, 2020

Further intrigue on this. The broader context is that the code looks like:

if (not flag1) {
    if (flag2)
        MAIN_THREAD_EM_ASM(
            { eval(UTF8ToString($0)) },
            utf8
        );
    else 
        MAIN_THREAD_EM_ASM(
            { (1,eval)(UTF8ToString($0)) },  // !!! This is the one causing the error
            utf8
        );
    /* ... */
}

As mentioned, I can change that second from (1,eval) to just eval and not get the error, or change it away form MAIN_THREAD_EM_ASM to plain EM_ASM.

Strangely, rewriting it to not use an else also seems to get past the error, by using two if with one negated. :-/

if (not flag1) {
    if (flag2)
        MAIN_THREAD_EM_ASM(
            { eval(UTF8ToString($0)) },
            utf8
        );
    if (not flag2) {
        MAIN_THREAD_EM_ASM(
            { (1,eval)(UTF8ToString($0)) },
            utf8
        );
    }
    /* ... */
}

I'll point out that strange compiler errors arose in similarly-patterned code before from the same routine:

#8731

I tried using latest-upstream and it didn't help; same error unless it's broken into two ifs.

@sbc100
Copy link
Collaborator

sbc100 commented Jul 6, 2020

This looks like a bug/limitation in binaryen: https://github.com/WebAssembly/binaryen/blob/cd0cc95e2794375c463a69833b1ccc9cc96d597c/src/wasm/wasm-emscripten.cpp#L774

I imagine what happens is that llvm is performing optimizations and then binaryen tries to essentially decompile to find the pointer to the JS code which you embed.

Perhaps the quickest and most robust solution would be to switch to EM_JS which puts each JS function on its own C function and I don't think suffers from this problem.

@hostilefork
Copy link
Contributor Author

hostilefork commented Jul 6, 2020

I imagine what happens is that llvm is performing optimizations and then binaryen tries to essentially decompile to find the pointer to the JS code which you embed.

I wonder what the difference would be between EM_ASM and EM_ASM_MAIN_THREAD, from an optimization point of view...as the definitions look very similar:

#define EM_ASM(code, ...) ((void)emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)))

#define MAIN_THREAD_EM_ASM(code, ...) ((void)emscripten_asm_const_int_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)))

If the functions aren't inlined, why would one of these trigger the problem and the other not? Might there be some accommodation in a process that is looking for emscripten_asm_const_int but it was overlooked to add that same accommodation for emscripten_asm_const_int_sync_on_main_thread?

@sbc100
Copy link
Collaborator

sbc100 commented Jul 6, 2020

To debug the issue fully you would need to look a the compiled code by decompiling the resulting wasm object file, then look at the code in binaryen(in wasm-emscripten.cpp) to figure out why failing to find what it needs.

Switching to EM_JS seems like it might be an easier option.

@hostilefork
Copy link
Contributor Author

Switching to EM_JS seems like it might be an easier option.

I need to synchronously run on the main thread, and there doesn't seem to be a MAIN_THREAD_EM_JS:

https://github.com/emscripten-core/emscripten/blob/b43474f55aeb49083b9df74fdd0e52ec8decf788/system/include/emscripten/em_js.h

For now I'll go with the workaround of if (flag)...if (not flag) instead of using the else. Maybe someone can come up with a simpler repro case than I have.

@sbc100
Copy link
Collaborator

sbc100 commented Jul 6, 2020

Ah yes I guess maybe EM_JS has no support for threading yet? @jgravelle-google ?

@mlomb
Copy link

mlomb commented Dec 13, 2020

I came across the same error, fortunately I was prototyping and didn't have much code, so I reduced it to a minimal example showing this error.
My exact setup:

  • Windows 10.0.19042
  • CMake 3.18.3
  • Emscripten 2.0.9
cmake_minimum_required(VERSION 2.8)
add_executable(test main.cpp)
#include <cstdlib> // rand
#include <emscripten/emscripten.h>

int main() {
    int test = rand() % 2;

    if (test == 0) {
        EM_ASM(alert('a'));
    } else {
        EM_ASM(alert('b'));
    }

    return 0;
}
cmake -GNinja -DCMAKE_TOOLCHAIN_FILE="(...)/cmake/Modules/Platform/Emscripten.cmake"
ninja

Note that compiling

if (test == 0) {
    //EM_ASM(alert('a'));
} else {
    EM_ASM(alert('b'));
}

or

if (test == 0) {
    EM_ASM(alert('a'));
} else {
    //EM_ASM(alert('b'));
}

both works and compile fine.
But compiling

if (test == 0) {
    EM_ASM(alert('a'));
} else {
    EM_ASM(alert('b'));
}

results in:

Fatal: Unexpected arg0 type (select) in call to: emscripten_asm_const_int

@kripken
Copy link
Member

kripken commented Dec 14, 2020

Thanks for the testcase @mlomb !

Looks like the issue is that binaryen wants to see a constant there, so we can tell the ID for each EM_ASM statically (we use that to find the text of the EM_ASM JS code). But LLVM optimizes here and passes a dynamic value (here, a select of two constant values).

It may be interesting to look into handling such a select, but in more complicated cases the instruction could be much more complex. So it may be better to look into emitting a better error message + suggestion for how to work around this. In general the workaround would be to avoid almost-identical EM_ASMs in the same function.

Alternatively, if we can implement EM_ASM not using a pointer to JS as text in the data section, this problem could go away.

@mmore500
Copy link
Contributor

mmore500 commented Jan 28, 2021

I couldn't track down precisely which MAIN_THREAD_EM_ASM call this issue is arising from in my codebase, so here's what I'm using as a workaround for the time being in case it's useful to anyone else.

#define QUICKFIX_MAIN_THREAD_EM_ASM(...) [&](){ \
  [[maybe_unused]] volatile int no_optimize{}; \
  MAIN_THREAD_EM_ASM(__VA_ARGS__); \
}()

@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

@stale stale bot added the wontfix label Apr 16, 2022
hostilefork added a commit to metaeducation/ren-c that referenced this issue Jun 26, 2022
This may (?) still be a problem when using PTHREAD features:

emscripten-core/emscripten#11539

But the pthreads build is unlikely to be relevant again in this
particular lifetime.  It does not seem to be a problem with
the stackless build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants