emscripten-core / emscripten-core/emscripten

Opportunities to reduce codegen size for emscripten exception handling

Open
#15,788 16 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

When using emscripten exceptions, there is a ton of code that is generated to wrap individual c++ function calls with a try-catch. This code handles saving and restoring the stack. It also re-throws JS exception, and marks c++ exceptions as thrown. This code comes from [here](https://github.com/emscripten-core/emscripten/blob/89c98c744f555dfe53220944b087367b76890bb7/tools/shared.py#L685). A lot of it ends up being very repetitive, like:
```
function invoke_iid(index,a1,a2) {
var sp = stackSave();
try {
return wasmTable.get(index)(a1,a2);
} catch(e) {
stackRestore(sp);
if (e !== e+0 && e !== 'longjmp') throw e;
_setThrew(1, 0);
}
}

function invoke_iif(index,a1,a2) {
var sp = stackSave();
try {
return wasmTable.get(index)(a1,a2);
} catch(e) {
stackRestore(sp);
if (e !== e+0 && e !== 'longjmp') throw e;
_setThrew(1, 0);
}
}
```

It seems like the signature of these functions comes from the arguments involved (i32, i64, etc). Each of these individual functions is then passed in when compiling the wasm binary, as imports.

I don't quite understand the need to generate individual functions. Is it just to handle the different parameters? Is it possible to use [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) here? It looks like the browser support for this pre-dates wasm.

You could then have one single generated function, that all c++ code uses.
```
function invoke_wrapper(index,...args) {
var sp = stackSave();
try {
return wasmTable.get(index)(...args);
} catch(e) {
stackRestore(sp);
if (e !== e+0 && e !== 'longjmp') throw e;
_setThrew(1, 0);
}
}
```

Even if the spread operator isn't appealing, I believe there are ways to support this with older JS mechanisms like [arguments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments).

```
function invoke_wrapper() {
var sp = stackSave();
try {
return wasmTable.get(arguments[0]).apply(null, arguments.slice(1));
} catch(e) {
stackRestore(sp);
if (e !== e+0 && e !== 'longjmp') throw e;
_setThrew(1, 0);
}
}
```

I understand that these invoke_* functions are also used in the llvm side [here](https://github.com/llvm/llvm-project/blob/915d1c0b74b5e9462a9ae7cd684a70d1422c7f5a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp#L134-L146). But I'm curious if this approach in theory would work? Am I missing something? @sbc100

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.