Skip to content

Commit

Permalink
Add a setjmp/longjmp runtime for a new sjlj translation proposed in L…
Browse files Browse the repository at this point in the history
  • Loading branch information
yamt authored Mar 21, 2024
1 parent 0481f78 commit 618ed94
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 13 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -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]>
53 changes: 40 additions & 13 deletions system/lib/compiler-rt/emscripten_setjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* found in the LICENSE file.
*/

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <setjmp.h>
Expand Down Expand Up @@ -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

0 comments on commit 618ed94

Please sign in to comment.