1/*
 2 * a runtime implementation for
 3 * https://github.com/llvm/llvm-project/pull/84137
 4 * https://docs.google.com/document/d/1ZvTPT36K5jjiedF8MCXbEmYjULJjI723aOAks1IdLLg/edit
 5 */
 6
 7#include <stddef.h>
 8#include <stdint.h>
 9
10/*
11 * function prototypes
12 */
13void __wasm_setjmp(void *env, uint32_t label, void *func_invocation_id);
14uint32_t __wasm_setjmp_test(void *env, void *func_invocation_id);
15void __wasm_longjmp(void *env, int val);
16
17/*
18 * jmp_buf should have large enough size and alignment to contain
19 * this structure.
20 */
21struct jmp_buf_impl {
22        void *func_invocation_id;
23        uint32_t label;
24
25        /*
26         * this is a temorary storage used by the communication between
27         * __wasm_sjlj_longjmp and WebAssemblyLowerEmscriptenEHSjL-generated
28         * logic.
29         * ideally, this can be replaced with multivalue.
30         */
31        struct arg {
32                void *env;
33                int val;
34        } arg;
35};
36
37void
38__wasm_setjmp(void *env, uint32_t label, void *func_invocation_id)
39{
40        struct jmp_buf_impl *jb = env;
41        if (label == 0) { /* ABI contract */
42                __builtin_trap();
43        }
44        if (func_invocation_id == NULL) { /* sanity check */
45                __builtin_trap();
46        }
47        jb->func_invocation_id = func_invocation_id;
48        jb->label = label;
49}
50
51uint32_t
52__wasm_setjmp_test(void *env, void *func_invocation_id)
53{
54        struct jmp_buf_impl *jb = env;
55        if (jb->label == 0) { /* ABI contract */
56                __builtin_trap();
57        }
58        if (func_invocation_id == NULL) { /* sanity check */
59                __builtin_trap();
60        }
61        if (jb->func_invocation_id == func_invocation_id) {
62                return jb->label;
63        }
64        return 0;
65}
66
67void
68__wasm_longjmp(void *env, int val)
69{
70        struct jmp_buf_impl *jb = env;
71        struct arg *arg = &jb->arg;
72        /*
73         * C standard says:
74         * The longjmp function cannot cause the setjmp macro to return
75         * the value 0; if val is 0, the setjmp macro returns the value 1.
76         */
77        if (val == 0) {
78                val = 1;
79        }
80        arg->env = env;
81        arg->val = val;
82        __builtin_wasm_throw(1, arg); /* 1 == C_LONGJMP */
83}