|
9 | 9 | from tools.shared import Settings, path_from_root, unsuffixed, NODE_JS, check_call, exit_with_error
|
10 | 10 |
|
11 | 11 |
|
| 12 | +# map an emscripten-style signature letter to a wasm2c C type |
| 13 | +def s_to_c(s): |
| 14 | + if s == 'v': |
| 15 | + return 'void' |
| 16 | + elif s == 'i': |
| 17 | + return 'u32' |
| 18 | + elif s == 'j': |
| 19 | + return 'u64' |
| 20 | + elif s == 'f': |
| 21 | + return 'f32' |
| 22 | + elif s == 'd': |
| 23 | + return 'f64' |
| 24 | + else: |
| 25 | + exit_with_error('invalid sig element:' + str(s)) |
| 26 | + |
| 27 | + |
| 28 | +# map a wasm2c C type to an emscripten-style signature letter |
| 29 | +def c_to_s(c): |
| 30 | + if c == 'WASM_RT_I32': |
| 31 | + return 'i' |
| 32 | + elif c == 'WASM_RT_I64': |
| 33 | + return 'j' |
| 34 | + elif c == 'WASM_RT_F32': |
| 35 | + return 'f' |
| 36 | + elif c == 'WASM_RT_F64': |
| 37 | + return 'd' |
| 38 | + else: |
| 39 | + exit_with_error('invalid wasm2c type element:' + str(c)) |
| 40 | + |
| 41 | + |
| 42 | +def get_func_types(code): |
| 43 | + ''' |
| 44 | + We look for this pattern: |
| 45 | +
|
| 46 | + static void init_func_types(void) { |
| 47 | + func_types[0] = wasm_rt_register_func_type(3, 1, WASM_RT_I32, WASM_RT_I32, WASM_RT_I32, WASM_RT_I32); |
| 48 | + func_types[1] = wasm_rt_register_func_type(1, 1, WASM_RT_I32, WASM_RT_I32); |
| 49 | + func_types[2] = wasm_rt_register_func_type(0, 0); |
| 50 | + } |
| 51 | +
|
| 52 | + We return a map of signatures names to their index. |
| 53 | + ''' |
| 54 | + init_func_types = re.search(r'static void init_func_types\(void\) {([^}]*)}', code) |
| 55 | + if not init_func_types: |
| 56 | + return {} |
| 57 | + ret = {} |
| 58 | + for entry in re.findall(r'func_types\[(\d+)\] = wasm_rt_register_func_type\((\d+), (\d+),? ?([^)]+)?\);', init_func_types[0]): |
| 59 | + index, params, results, types = entry |
| 60 | + index = int(index) |
| 61 | + params = int(params) |
| 62 | + results = int(results) |
| 63 | + types = types.split(', ') |
| 64 | + sig = '' |
| 65 | + for i in range(params): |
| 66 | + sig += c_to_s(types[i]) |
| 67 | + if results == 0: |
| 68 | + sig = 'v' + sig |
| 69 | + else: |
| 70 | + assert results == 1, 'no multivalue support' |
| 71 | + sig = c_to_s(types[-1]) + sig |
| 72 | + ret[sig] = index |
| 73 | + return ret |
| 74 | + |
| 75 | + |
12 | 76 | def do_wasm2c(infile):
|
13 | 77 | assert Settings.STANDALONE_WASM
|
14 | 78 | WASM2C = NODE_JS + [path_from_root('node_modules', 'wasm2c', 'wasm2c.js')]
|
@@ -72,39 +136,55 @@ def bundle_file(total, filename):
|
72 | 136 | # generate the necessary invokes
|
73 | 137 | invokes = []
|
74 | 138 | for sig in re.findall(r"\/\* import\: 'env' 'invoke_(\w+)' \*\/", total):
|
75 |
| - def s_to_c(s): |
76 |
| - if s == 'v': |
77 |
| - return 'void' |
78 |
| - elif s == 'i': |
79 |
| - return 'u32' |
80 |
| - elif s == 'j': |
81 |
| - return 'u64' |
82 |
| - elif s == 'f': |
83 |
| - return 'f32' |
84 |
| - elif s == 'd': |
85 |
| - return 'f64' |
86 |
| - else: |
87 |
| - exit_with_error('invalid sig element:' + str(s)) |
| 139 | + all_func_types = get_func_types(total) |
88 | 140 |
|
89 | 141 | def name(i):
|
90 | 142 | return 'a' + str(i)
|
91 | 143 |
|
92 | 144 | wabt_sig = sig[0] + 'i' + sig[1:]
|
93 |
| - typed_args = ['u32 fptr'] + [s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))] |
94 |
| - types = ['u32'] + [s_to_c(sig[i]) for i in range(1, len(sig))] |
95 |
| - args = ['fptr'] + [name(i) for i in range(1, len(sig))] |
96 |
| - invokes.append( |
97 |
| - '%s_INVOKE_IMPL(%sZ_envZ_invoke_%sZ_%s, (%s), (%s), (%s), Z_dynCall_%sZ_%s);' % ( |
98 |
| - 'VOID' if sig[0] == 'v' else 'RETURNING', |
99 |
| - (s_to_c(sig[0]) + ', ') if sig[0] != 'v' else '', |
100 |
| - sig, |
101 |
| - wabt_sig, |
102 |
| - ', '.join(typed_args), |
103 |
| - ', '.join(types), |
104 |
| - ', '.join(args), |
105 |
| - sig, |
106 |
| - wabt_sig |
107 |
| - )) |
| 145 | + typed_args = [s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))] |
| 146 | + full_typed_args = ['u32 fptr'] + typed_args |
| 147 | + types = [s_to_c(sig[i]) for i in range(1, len(sig))] |
| 148 | + args = [name(i) for i in range(1, len(sig))] |
| 149 | + c_func_type = s_to_c(sig[0]) + ' (*)(' + (', '.join(types) if types else 'void') + ')' |
| 150 | + if sig not in all_func_types: |
| 151 | + exit_with_error('could not find signature ' + sig + ' in function types ' + str(all_func_types)) |
| 152 | + type_index = all_func_types[sig] |
| 153 | + |
| 154 | + invokes.append(r''' |
| 155 | +IMPORT_IMPL(%(return_type)s, Z_envZ_invoke_%(sig)sZ_%(wabt_sig)s, (%(full_typed_args)s), { |
| 156 | + VERBOSE_LOG("invoke\n"); // waka |
| 157 | + u32 sp = Z_stackSaveZ_iv(); |
| 158 | + if (next_setjmp >= MAX_SETJMP_STACK) { |
| 159 | + abort_with_message("too many nested setjmps"); |
| 160 | + } |
| 161 | + u32 id = next_setjmp++; |
| 162 | + int result = setjmp(setjmp_stack[id]); |
| 163 | + %(declare_return)s |
| 164 | + if (result == 0) { |
| 165 | + %(receive)sCALL_INDIRECT(w2c___indirect_function_table, %(c_func_type)s, %(type_index)s, fptr %(args)s); |
| 166 | + /* if we got here, no longjmp or exception happened, we returned normally */ |
| 167 | + } else { |
| 168 | + /* A longjmp or an exception took us here. */ |
| 169 | + Z_stackRestoreZ_vi(sp); |
| 170 | + Z_setThrewZ_vii(1, 0); |
| 171 | + } |
| 172 | + next_setjmp--; |
| 173 | + %(return)s |
| 174 | +}); |
| 175 | +''' % { |
| 176 | + 'return_type': s_to_c(sig[0]) if sig[0] != 'v' else 'void', |
| 177 | + 'sig': sig, |
| 178 | + 'wabt_sig': wabt_sig, |
| 179 | + 'full_typed_args': ', '.join(full_typed_args), |
| 180 | + 'type_index': type_index, |
| 181 | + 'c_func_type': c_func_type, |
| 182 | + 'args': (', ' + ', '.join(args)) if args else '', |
| 183 | + 'declare_return': (s_to_c(sig[0]) + ' returned_value = 0;') if sig[0] != 'v' else '', |
| 184 | + 'receive': 'returned_value = ' if sig[0] != 'v' else '', |
| 185 | + 'return': 'return returned_value;' if sig[0] != 'v' else '' |
| 186 | + }) |
| 187 | + |
108 | 188 | total += '\n'.join(invokes)
|
109 | 189 | # write out the final file
|
110 | 190 | with open(c_file, 'w') as out:
|
|
0 commit comments