diff --git a/AUTHORS b/AUTHORS index 312de41a8d90d..6f3f0da89aaeb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -597,3 +597,4 @@ a license to everyone to use it as detailed in LICENSE.) * James Hu * Jerry Zhuang * Taisei Kon +* YAMAMOTO Takashi diff --git a/system/lib/compiler-rt/emscripten_setjmp.c b/system/lib/compiler-rt/emscripten_setjmp.c index fb8a287391ad0..b43df61b9154e 100644 --- a/system/lib/compiler-rt/emscripten_setjmp.c +++ b/system/lib/compiler-rt/emscripten_setjmp.c @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include #include #include #include @@ -79,33 +80,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; +} + +#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; } - __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