-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Add a setjmp/longjmp runtime for a new sjlj translation proposed in LLVM #21502
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -597,3 +597,4 @@ a license to everyone to use it as detailed in LICENSE.) | |
* James Hu <[email protected]> | ||
* Jerry Zhuang <[email protected]> | ||
* Taisei Kon <[email protected]> | ||
* YAMAMOTO Takashi <[email protected]> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
* found in the LICENSE file. | ||
*/ | ||
|
||
#include <assert.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <setjmp.h> | ||
|
@@ -73,33 +74,59 @@ void emscripten_longjmp(uintptr_t env, int val) { | |
#endif | ||
|
||
#ifdef __USING_WASM_SJLJ__ | ||
|
||
struct __WasmLongjmpArgs { | ||
void *env; | ||
int val; | ||
}; | ||
|
||
thread_local struct __WasmLongjmpArgs __wasm_longjmp_args; | ||
|
||
// llvm uses `1` for the __c_longjmp tag. | ||
// See https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h | ||
#define C_LONGJMP 1 | ||
#endif | ||
|
||
// jmp_buf should have large enough size and alignment to contain | ||
// this structure. | ||
struct jmp_buf_impl { | ||
void* func_invocation_id; | ||
uint32_t label; | ||
#ifdef __USING_WASM_SJLJ__ | ||
struct __WasmLongjmpArgs arg; | ||
#endif | ||
}; | ||
|
||
void __wasm_setjmp(void* env, uint32_t label, void* func_invocation_id) { | ||
struct jmp_buf_impl* jb = env; | ||
assert(label != 0); // ABI contract | ||
assert(func_invocation_id != NULL); // sanity check | ||
jb->func_invocation_id = func_invocation_id; | ||
jb->label = label; | ||
} | ||
|
||
uint32_t __wasm_setjmp_test(void* env, void* func_invocation_id) { | ||
struct jmp_buf_impl* jb = env; | ||
assert(jb->label != 0); // ABI contract | ||
assert(func_invocation_id != NULL); // sanity check | ||
if (jb->func_invocation_id == func_invocation_id) { | ||
return jb->label; | ||
} | ||
return 0; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the corresponding LLVM change not also change the ABI for emscripten exceptions too? i.e. not just when USING_WASM_SJLJ? (i.e. should all this new code live outside the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1. These There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
currently, no. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
maybe. i haven't looked at the emscrpiten sjlj closely. do you think it's enough to apply the same change mechanically? |
||
|
||
#ifdef __USING_WASM_SJLJ__ | ||
// Wasm EH allows us to throw and catch multiple values, but that requires | ||
// multivalue support in the toolchain, whch is not reliable at the time. | ||
// TODO Consider switching to throwing two values at the same time later. | ||
void __wasm_longjmp(void *env, int val) { | ||
__wasm_longjmp_args.env = env; | ||
/* | ||
 * C standard: | ||
 * The longjmp function cannot cause the setjmp macro to return | ||
 * the value 0; if val is 0, the setjmp macro returns the value 1. | ||
 */ | ||
void __wasm_longjmp(void* env, int val) { | ||
struct jmp_buf_impl* jb = env; | ||
struct __WasmLongjmpArgs* arg = &jb->arg; | ||
// C standard says: | ||
// The longjmp function cannot cause the setjmp macro to return | ||
// the value 0; if val is 0, the setjmp macro returns the value 1. | ||
if (val == 0) { | ||
val = 1; | ||
} | ||
Comment on lines
+122
to
127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need this for |
||
__wasm_longjmp_args.val = val; | ||
__builtin_wasm_throw(C_LONGJMP, &__wasm_longjmp_args); | ||
arg->env = env; | ||
arg->val = val; | ||
__builtin_wasm_throw(C_LONGJMP, arg); | ||
} | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That we don't need this
thread_local struct
is nice!