|
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