Skip to content

Commit a23058a

Browse files
authored
Add test for EM_JS and i64 arguments (#15916)
Ideally we should error out if WASM_BIGINT is not passed by I have yet to find a good place to do that. See #15871
1 parent 92c88e9 commit a23058a

File tree

7 files changed

+81
-10
lines changed

7 files changed

+81
-10
lines changed

emscripten.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,25 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile):
299299

300300
update_settings_glue(metadata)
301301

302+
if not settings.WASM_BIGINT and metadata['emJsFuncs']:
303+
module = webassembly.Module(in_wasm)
304+
types = module.get_types()
305+
import_map = {}
306+
for imp in module.get_imports():
307+
import_map[imp.field] = imp
308+
for em_js_func, raw in metadata.get('emJsFuncs', {}).items():
309+
c_sig = raw.split('<::>')[0].strip('()')
310+
if not c_sig or c_sig == 'void':
311+
c_sig = []
312+
else:
313+
c_sig = c_sig.split(',')
314+
if em_js_func in import_map:
315+
imp = import_map[em_js_func]
316+
assert(imp.kind == webassembly.ExternType.FUNC)
317+
signature = types[imp.type]
318+
if len(signature.params) != len(c_sig):
319+
diagnostics.warning('em-js-i64', 'using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `%s` (%s, %s)', em_js_func, c_sig, signature.params)
320+
302321
if settings.SIDE_MODULE:
303322
if metadata['asmConsts']:
304323
exit_with_error('EM_ASM is not supported in side modules')

tests/core/test_em_js_i64.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <stdint.h>
2+
#include <emscripten.h>
3+
4+
EM_JS(void, foo, (uint64_t a, int64_t b), {
5+
console.log(typeof a);
6+
console.log(typeof b);
7+
8+
console.log('a:' + a);
9+
console.log('b:' + b);
10+
})
11+
12+
int main() {
13+
foo(42000000000ull, -42ll);
14+
}

tests/core/test_em_js_i64.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a:42000000000
2+
b:-42

tests/test_core.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,15 @@ def test_em_js(self, args, force_c):
21422142
self.do_core_test('test_em_js.cpp', force_c=force_c)
21432143
self.assertContained("no args returning int", read_file('test_em_js.js'))
21442144

2145+
@no_wasm2js('WASM_BIGINT is not compatible with wasm2js')
2146+
def test_em_js_i64(self):
2147+
err = self.expect_fail([EMCC, '-Werror', test_file('core/test_em_js_i64.c')])
2148+
self.assertContained('emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`', err)
2149+
2150+
self.set_setting('WASM_BIGINT')
2151+
self.node_args += ['--experimental-wasm-bigint']
2152+
self.do_core_test('test_em_js_i64.c')
2153+
21452154
def test_runtime_stacksave(self):
21462155
self.do_runf(test_file('core/test_runtime_stacksave.c'), 'success')
21472156

tools/extract_metadata.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,6 @@ def extract_metadata(filename):
177177

178178
for i in imports:
179179
if i.kind == webassembly.ExternType.FUNC:
180-
if i.field.startswith('invoke_'):
181-
invoke_funcs.append(i.field)
182-
elif i.field not in em_js_funcs:
183-
declares.append(i.field)
184180
imported_funcs += 1
185181
elif i.kind == webassembly.ExternType.GLOBAL:
186182
imported_globals += 1
@@ -194,6 +190,13 @@ def extract_metadata(filename):
194190
string_address = get_global_value(globl)
195191
em_js_funcs[name] = get_string_at(module, string_address)
196192

193+
for i in imports:
194+
if i.kind == webassembly.ExternType.FUNC:
195+
if i.field.startswith('invoke_'):
196+
invoke_funcs.append(i.field)
197+
elif i.field not in em_js_funcs:
198+
declares.append(i.field)
199+
197200
export_names = [e.name for e in exports if e.kind == webassembly.ExternType.FUNC]
198201

199202
features = module.parse_features_section()

tools/shared.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
diagnostics.add_warning('pthreads-mem-growth')
7474
diagnostics.add_warning('transpile')
7575
diagnostics.add_warning('limited-postlink-optimizations')
76+
diagnostics.add_warning('em-js-i64')
7677

7778

7879
# TODO(sbc): Investigate switching to shlex.quote

tools/webassembly.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,14 @@ class InvalidWasmError(BaseException):
114114

115115
Section = namedtuple('Section', ['type', 'size', 'offset', 'name'])
116116
Limits = namedtuple('Limits', ['flags', 'initial', 'maximum'])
117-
Import = namedtuple('Import', ['kind', 'module', 'field'])
117+
Import = namedtuple('Import', ['kind', 'module', 'field', 'type'])
118118
Export = namedtuple('Export', ['name', 'kind', 'index'])
119119
Global = namedtuple('Global', ['type', 'mutable', 'init'])
120120
Dylink = namedtuple('Dylink', ['mem_size', 'mem_align', 'table_size', 'table_align', 'needed', 'export_info', 'import_info'])
121121
Table = namedtuple('Table', ['elem_type', 'limits'])
122122
FunctionBody = namedtuple('FunctionBody', ['offset', 'size'])
123123
DataSegment = namedtuple('DataSegment', ['flags', 'init', 'offset', 'size'])
124+
FuncType = namedtuple('FuncType', ['params', 'returns'])
124125

125126

126127
class Module:
@@ -210,6 +211,27 @@ def sections(self):
210211
yield Section(section_type, section_size, section_offset, name)
211212
offset = section_offset + section_size
212213

214+
def get_types(self):
215+
type_section = self.get_section(SecType.TYPE)
216+
if not type_section:
217+
return []
218+
self.seek(type_section.offset)
219+
num_types = self.readULEB()
220+
types = []
221+
for i in range(num_types):
222+
params = []
223+
returns = []
224+
type_form = self.readByte()
225+
assert type_form == 0x60
226+
num_params = self.readULEB()
227+
for j in range(num_params):
228+
params.append(self.read_type())
229+
num_returns = self.readULEB()
230+
for j in range(num_returns):
231+
returns.append(self.read_type())
232+
types.append(FuncType(params, returns))
233+
return types
234+
213235
def parse_features_section(self):
214236
features = []
215237
sec = self.get_custom_section('target_features')
@@ -315,22 +337,23 @@ def get_imports(self):
315337
mod = self.readString()
316338
field = self.readString()
317339
kind = ExternType(self.readByte())
318-
imports.append(Import(kind, mod, field))
340+
type_ = None
319341
if kind == ExternType.FUNC:
320-
self.readULEB() # sig
342+
type_ = self.readULEB()
321343
elif kind == ExternType.GLOBAL:
322-
self.readSLEB() # global type
344+
type_ = self.readSLEB()
323345
self.readByte() # mutable
324346
elif kind == ExternType.MEMORY:
325347
self.read_limits() # limits
326348
elif kind == ExternType.TABLE:
327-
self.readSLEB() # table type
349+
type_ = self.readSLEB()
328350
self.read_limits() # limits
329351
elif kind == ExternType.TAG:
330352
self.readByte() # attribute
331-
self.readULEB() # sig
353+
type_ = self.readULEB()
332354
else:
333355
assert False
356+
imports.append(Import(kind, mod, field, type_))
334357

335358
return imports
336359

0 commit comments

Comments
 (0)