Skip to content

Commit 618ed94

Browse files
authored
Add a setjmp/longjmp runtime for a new sjlj translation proposed in LLVM (#21502)
the new runtime code is basically a copy from: https://github.com/yamt/garbage/blob/wasm-sjlj-alt2/wasm/longjmp/rt.c. The corresponding LLVM change: llvm/llvm-project#84137 Discussion: https://docs.google.com/document/d/1ZvTPT36K5jjiedF8MCXbEmYjULJjI723aOAks1IdLLg/edit
1 parent 0481f78 commit 618ed94

File tree

2 files changed

+41
-13
lines changed

2 files changed

+41
-13
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,4 @@ a license to everyone to use it as detailed in LICENSE.)
597597
* James Hu <[email protected]>
598598
* Jerry Zhuang <[email protected]>
599599
* Taisei Kon <[email protected]>
600+
* YAMAMOTO Takashi <[email protected]>

system/lib/compiler-rt/emscripten_setjmp.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* found in the LICENSE file.
66
*/
77

8+
#include <assert.h>
89
#include <stdint.h>
910
#include <stdlib.h>
1011
#include <setjmp.h>
@@ -79,33 +80,59 @@ void emscripten_longjmp(uintptr_t env, int val) {
7980
#endif
8081

8182
#ifdef __USING_WASM_SJLJ__
82-
8383
struct __WasmLongjmpArgs {
8484
void *env;
8585
int val;
8686
};
8787

88-
thread_local struct __WasmLongjmpArgs __wasm_longjmp_args;
89-
9088
// llvm uses `1` for the __c_longjmp tag.
9189
// See https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h
9290
#define C_LONGJMP 1
91+
#endif
92+
93+
// jmp_buf should have large enough size and alignment to contain
94+
// this structure.
95+
struct jmp_buf_impl {
96+
void* func_invocation_id;
97+
uint32_t label;
98+
#ifdef __USING_WASM_SJLJ__
99+
struct __WasmLongjmpArgs arg;
100+
#endif
101+
};
93102

103+
void __wasm_setjmp(void* env, uint32_t label, void* func_invocation_id) {
104+
struct jmp_buf_impl* jb = env;
105+
assert(label != 0); // ABI contract
106+
assert(func_invocation_id != NULL); // sanity check
107+
jb->func_invocation_id = func_invocation_id;
108+
jb->label = label;
109+
}
110+
111+
uint32_t __wasm_setjmp_test(void* env, void* func_invocation_id) {
112+
struct jmp_buf_impl* jb = env;
113+
assert(jb->label != 0); // ABI contract
114+
assert(func_invocation_id != NULL); // sanity check
115+
if (jb->func_invocation_id == func_invocation_id) {
116+
return jb->label;
117+
}
118+
return 0;
119+
}
120+
121+
#ifdef __USING_WASM_SJLJ__
94122
// Wasm EH allows us to throw and catch multiple values, but that requires
95123
// multivalue support in the toolchain, whch is not reliable at the time.
96124
// TODO Consider switching to throwing two values at the same time later.
97-
void __wasm_longjmp(void *env, int val) {
98-
__wasm_longjmp_args.env = env;
99-
/*
100-
 * C standard:
101-
 * The longjmp function cannot cause the setjmp macro to return
102-
 * the value 0; if val is 0, the setjmp macro returns the value 1.
103-
 */
125+
void __wasm_longjmp(void* env, int val) {
126+
struct jmp_buf_impl* jb = env;
127+
struct __WasmLongjmpArgs* arg = &jb->arg;
128+
// C standard says:
129+
// The longjmp function cannot cause the setjmp macro to return
130+
// the value 0; if val is 0, the setjmp macro returns the value 1.
104131
if (val == 0) {
105132
val = 1;
106133
}
107-
__wasm_longjmp_args.val = val;
108-
__builtin_wasm_throw(C_LONGJMP, &__wasm_longjmp_args);
134+
arg->env = env;
135+
arg->val = val;
136+
__builtin_wasm_throw(C_LONGJMP, arg);
109137
}
110-
111138
#endif

0 commit comments

Comments
 (0)