|
5 | 5 | * found in the LICENSE file. |
6 | 6 | */ |
7 | 7 |
|
| 8 | +#include <assert.h> |
8 | 9 | #include <stdint.h> |
9 | 10 | #include <stdlib.h> |
10 | 11 | #include <setjmp.h> |
@@ -79,33 +80,59 @@ void emscripten_longjmp(uintptr_t env, int val) { |
79 | 80 | #endif |
80 | 81 |
|
81 | 82 | #ifdef __USING_WASM_SJLJ__ |
82 | | - |
83 | 83 | struct __WasmLongjmpArgs { |
84 | 84 | void *env; |
85 | 85 | int val; |
86 | 86 | }; |
87 | 87 |
|
88 | | -thread_local struct __WasmLongjmpArgs __wasm_longjmp_args; |
89 | | - |
90 | 88 | // llvm uses `1` for the __c_longjmp tag. |
91 | 89 | // See https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h |
92 | 90 | #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 | +}; |
93 | 102 |
|
| 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__ |
94 | 122 | // Wasm EH allows us to throw and catch multiple values, but that requires |
95 | 123 | // multivalue support in the toolchain, whch is not reliable at the time. |
96 | 124 | // 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. |
104 | 131 | if (val == 0) { |
105 | 132 | val = 1; |
106 | 133 | } |
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); |
109 | 137 | } |
110 | | - |
111 | 138 | #endif |
0 commit comments