Skip to content

Remove assert for __get_temp_ret() and __set_temp_ret() after Binaryen JS FFI legalizer pass - #26791

Closed
juj wants to merge 1 commit into
emscripten-core:mainfrom
juj:fix_wasm2js0_test_autodebug_wasm
Closed

Remove assert for __get_temp_ret() and __set_temp_ret() after Binaryen JS FFI legalizer pass#26791
juj wants to merge 1 commit into
emscripten-core:mainfrom
juj:fix_wasm2js0_test_autodebug_wasm

Conversation

@juj

@juj juj commented Apr 26, 2026

Copy link
Copy Markdown
Collaborator

Binaryen JS FFI legalizer pass seems to be dropping __get_temp_ret() and __set_temp_ret() if they are unused, so do not emit assert() for their existence. Fixes #25549.

I am not 100% sure about this, but this did fix the test wasm2js0.test_autodebug_wasm to pass.

@juj
juj force-pushed the fix_wasm2js0_test_autodebug_wasm branch from da647ad to 9fd8bab Compare April 26, 2026 13:20
@sbc100

sbc100 commented Apr 26, 2026

Copy link
Copy Markdown
Collaborator

Can you add wasm2js0.test_autodebug_wasm to the core3+extras list in .circleci/config.yml?

We run all the tests in wasm2js1 mode in CI.. i wonder why opt level zero would mean these exports don't exist but they do exist at opt level 1 and above? I would imagine it would be other way around.

Comment thread tools/building.py
flags += ['--pass-arg=legalize-js-interface-exported-helpers']
# Ensure that the legalizer pass does not erase debug info
if settings.DEBUG_LEVEL:
flags += ['-g']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the run_binaryen_command wrapper is supposed to take are of adding this (or not) at the appropriate times.

@juj juj Apr 26, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is/was not happening at least for this FFI JS run pass. Adding -g manually here does help the output retain debug info.

…and __set_temp_ret() if they are unused, so do not emit assert() for their existence. Fixes emscripten-core#25549.
@juj

juj commented Apr 26, 2026

Copy link
Copy Markdown
Collaborator Author

Can you add wasm2js0.test_autodebug_wasm to the core3+extras list in .circleci/config.yml?

Check.

i wonder why opt level zero would mean these exports don't exist but they do exist at opt level 1 and above? I would imagine it would be other way around.

I don't think they exist in any wasm2js* level after the JS FFI legalization wasm-opt pass runs (they exist in the output before the legalization wasm-opt run, but not after). But wasm2js0 is the only build that has assert()s that the exports would exist. Which is why it only trips up in debug builds.

@juj
juj force-pushed the fix_wasm2js0_test_autodebug_wasm branch from 9fd8bab to d9eb90c Compare April 26, 2026 18:21
Comment thread tools/emscripten.py
# are created by binaryen will be missing.
continue
if settings.LEGALIZE_JS_FFI and sym in {'__get_temp_ret', '__set_temp_ret'}:
# The Binaryen legalizer pass will drop exports of __get_temp_ret() and __set_temp_ret()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this code elsewhere:

  if settings.LEGALIZE_JS_FFI:                                                                            
    settings.REQUIRED_EXPORTS += ['__get_temp_ret', '__set_temp_ret']  

Which means wasm-ld will always export them when LEGALIZE_JS_FFI.

If they are then removed at some point (for example by DCE) then that should be not different any other removed exports. i.e. the list of exports here should already take into account any DCE.

@juj juj Apr 27, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then that should be not different any other removed exports

They still go to the list of exports to generate assert()s for, which is why the test case fails. I don't know why they aren't removed there, except to hypothesize that is because they are removed by a separate FFI JS wasm-opt execution, rather than the general wasm-opt code optimization pass.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, but I think we should understand why we need a special case for them here, since we have many other symbols that get added to settings.REQUIRED_EXPORTS but that are potentially unused and get DCE'd.

I'd rather not make special case here just for these symbols if it can be avoided.

@juj juj Apr 27, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason is that it is the later phase_binaryen JS FFI legalizer call pass that optimizes those out, rather than the wasm finalizer metadce optimizer in phase_emscript that generally DCEs imports/exports.

That is:

In the emscript phase:

When finalize_wasm wasm-opt pass is called here, the output Wasm module still exports __get_temp_ret, which is correctly recorded out in metadata, and accurate in the .wasm file.. it has that export.

The next phase after the emscript phase is the binaryen phase. That phase is what calls to wasm-opt:

'C:/emsdk/binaryen/main_vs2022_64bit_binaryen\bin\wasm-opt' --instrument-locals --log-execution --instrument-memory --legalize-js-interface --pass-arg=legalize-js-interface-exported-helpers 'C:\Users\clb\AppData\Local\Temp\emscripten_temp\test_autodebug.wasm' -o 'C:\Users\clb\AppData\Local\Temp\emscripten_temp\test_autodebug.wasm' --mvp-features --enable-bulk-memory --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-multivalue --enable-mutable-globals --enable-nontrapping-float-to-int --enable-reference-types --enable-sign-ext

and legalizes the JS FFI interface.

This phase deletes the __get_temp_ret Wasm export in the test.

But the metadata is still from the earlier emscript phase, which has the __get_temp_ret Wasm export. So the later JS emit phase will incorrectly emit an assert for it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like where we should fix it then. I don't think the legalize phase should be going around deleting exports, unless we tell it to.

Free free to disable tests until we can address this in binaryen.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we remove the assert the resulting JS still thinks that these exports exist:

For example, I see the following in the generated code:

___get_temp_ret = createExportWrapper('__get_temp_ret', 0);                    
___set_temp_ret = createExportWrapper('__set_temp_ret', 1);   

Either we should remove them completely after wasm-opt removes them or better still, wasm-opt should probably leave them alone and let DCE processes handle removing then just like any other unused exports.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so here is the code in binaryen that deletes the exports:

https://github.com/WebAssembly/binaryen/blob/1e36622832c32ad335403065c322781982f1b55c/src/passes/LegalizeJSInterface.cpp#L165-L166

And we even mention that here:

# These aliases exist for LegalizeJSInterface pass in binaryen
# They get exported by emcc and the exports are then removed by the
# binaryen pass

However, I think maybe the right solution is to leave those exports alone and have DCE delete.

If that seems like too much work I think we should just these elements from function_exports when we create it in the emscript function.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll drop this for now, and skip the test. #26793

juj added a commit that referenced this pull request Apr 27, 2026
Disable failing test wasm2js0.test_autodebug_wasm.
#25549

Supercedes #26791.
@juj

juj commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator Author

Not needed anymore.

@juj juj closed this Apr 30, 2026
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

Successfully merging this pull request may close these issues.

wasm2js0.test_autodebug_wasm regression

2 participants