forked from WebAssembly/wasi-libc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add setjmp/longjump support based on Wasm EH proposal. It's provided as a separate library (libsetjmp) from libc so that runtimes w/o EH support can still load libc.so. To use this setjmp/longjmp implementation, an application should be compiled with `-mllvm -wasm-enable-sjlj` and linked with `-lsetjmp`. (You need an LLVM with the change mentioned below.) Also, you need a runtime with EH support to run such an application. If you want to use the latest EH instructions, you can use `binaryen --translate-eh-old-to-new` on your application. Note: You don't need to translate libsetjmp.a/so to the new EH. While LLVM currently produces bytecode for an old version of the EH proposal, luckily for us, the bytecode used in this library (ie. the tag definition and the "throw" instruction) is compatible with the latest version of the proposal. The runtime logic is basically copy-and-paste from: https://github.com/yamt/garbage/tree/wasm-sjlj-alt2/wasm/longjmp The corresponding LLVM change: llvm/llvm-project#84137 (Note: you need this change to build setjmp/longjmp using code. otoh, you don't need this to build libsetjmp.) A similar change for emscripten: emscripten-core/emscripten#21502 An older version of this PR, which doesn't require LLVM changes: WebAssembly#467 Discussion: https://docs.google.com/document/d/1ZvTPT36K5jjiedF8MCXbEmYjULJjI723aOAks1IdLLg/edit An example to use the latest EH instructions: ``` clang -mllvm -wasm-enable-sjlj -o your_app.wasm your_app.c -lsetjmp wasm-opt --translate-eh-old-to-new -o your_app.wasm your_app.wasm toywasm --wasi your_app.wasm ``` Note: use toywasm built with `-DTOYWASM_ENABLE_WASM_EXCEPTION_HANDLING=ON`. An example to use the older EH instructions, which LLVM currently produces: ``` clang -mllvm -wasm-enable-sjlj -o your_app.wasm your_app.c -lsetjmp iwasm your_app.wasm ``` Note: use wasm-micro-runtime built with `-DWASM_ENABLE_EXCE_HANDLING=1`. Note: as of writing this, only the classic interpreter supports EH.
- Loading branch information
Showing
4 changed files
with
109 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
typedef unsigned long __jmp_buf[8]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* a runtime implementation for | ||
* https://github.com/llvm/llvm-project/pull/84137 | ||
* https://docs.google.com/document/d/1ZvTPT36K5jjiedF8MCXbEmYjULJjI723aOAks1IdLLg/edit | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <stdint.h> | ||
|
||
/* | ||
* function prototypes | ||
*/ | ||
void __wasm_setjmp(void *env, uint32_t label, void *func_invocation_id); | ||
uint32_t __wasm_setjmp_test(void *env, void *func_invocation_id); | ||
void __wasm_longjmp(void *env, int val); | ||
|
||
/* | ||
* jmp_buf should have large enough size and alignment to contain | ||
* this structure. | ||
*/ | ||
struct jmp_buf_impl { | ||
void *func_invocation_id; | ||
uint32_t label; | ||
|
||
/* | ||
* this is a temorary storage used by the communication between | ||
* __wasm_sjlj_longjmp and WebAssemblyLowerEmscriptenEHSjL-generated | ||
* logic. | ||
* ideally, this can be replaced with multivalue. | ||
*/ | ||
struct arg { | ||
void *env; | ||
int val; | ||
} arg; | ||
}; | ||
|
||
void | ||
__wasm_setjmp(void *env, uint32_t label, void *func_invocation_id) | ||
{ | ||
struct jmp_buf_impl *jb = env; | ||
if (label == 0) { /* ABI contract */ | ||
__builtin_trap(); | ||
} | ||
if (func_invocation_id == NULL) { /* sanity check */ | ||
__builtin_trap(); | ||
} | ||
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; | ||
if (jb->label == 0) { /* ABI contract */ | ||
__builtin_trap(); | ||
} | ||
if (func_invocation_id == NULL) { /* sanity check */ | ||
__builtin_trap(); | ||
} | ||
if (jb->func_invocation_id == func_invocation_id) { | ||
return jb->label; | ||
} | ||
return 0; | ||
} | ||
|
||
void | ||
__wasm_longjmp(void *env, int val) | ||
{ | ||
struct jmp_buf_impl *jb = env; | ||
struct arg *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; | ||
} | ||
arg->env = env; | ||
arg->val = val; | ||
__builtin_wasm_throw(1, arg); /* 1 == C_LONGJMP */ | ||
} |