Skip to content

Commit

Permalink
Add test for EM_JS and i64 arguments (#15916)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sbc100 committed May 4, 2022
1 parent 92c88e9 commit a23058a
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 10 deletions.
19 changes: 19 additions & 0 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile):

update_settings_glue(metadata)

if not settings.WASM_BIGINT and metadata['emJsFuncs']:
module = webassembly.Module(in_wasm)
types = module.get_types()
import_map = {}
for imp in module.get_imports():
import_map[imp.field] = imp
for em_js_func, raw in metadata.get('emJsFuncs', {}).items():
c_sig = raw.split('<::>')[0].strip('()')
if not c_sig or c_sig == 'void':
c_sig = []
else:
c_sig = c_sig.split(',')
if em_js_func in import_map:
imp = import_map[em_js_func]
assert(imp.kind == webassembly.ExternType.FUNC)
signature = types[imp.type]
if len(signature.params) != len(c_sig):
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)

if settings.SIDE_MODULE:
if metadata['asmConsts']:
exit_with_error('EM_ASM is not supported in side modules')
Expand Down
14 changes: 14 additions & 0 deletions tests/core/test_em_js_i64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <stdint.h>
#include <emscripten.h>

EM_JS(void, foo, (uint64_t a, int64_t b), {
console.log(typeof a);
console.log(typeof b);

console.log('a:' + a);
console.log('b:' + b);
})

int main() {
foo(42000000000ull, -42ll);
}
2 changes: 2 additions & 0 deletions tests/core/test_em_js_i64.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a:42000000000
b:-42
9 changes: 9 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,15 @@ def test_em_js(self, args, force_c):
self.do_core_test('test_em_js.cpp', force_c=force_c)
self.assertContained("no args returning int", read_file('test_em_js.js'))

@no_wasm2js('WASM_BIGINT is not compatible with wasm2js')
def test_em_js_i64(self):
err = self.expect_fail([EMCC, '-Werror', test_file('core/test_em_js_i64.c')])
self.assertContained('emcc: error: using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `foo`', err)

self.set_setting('WASM_BIGINT')
self.node_args += ['--experimental-wasm-bigint']
self.do_core_test('test_em_js_i64.c')

def test_runtime_stacksave(self):
self.do_runf(test_file('core/test_runtime_stacksave.c'), 'success')

Expand Down
11 changes: 7 additions & 4 deletions tools/extract_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,6 @@ def extract_metadata(filename):

for i in imports:
if i.kind == webassembly.ExternType.FUNC:
if i.field.startswith('invoke_'):
invoke_funcs.append(i.field)
elif i.field not in em_js_funcs:
declares.append(i.field)
imported_funcs += 1
elif i.kind == webassembly.ExternType.GLOBAL:
imported_globals += 1
Expand All @@ -194,6 +190,13 @@ def extract_metadata(filename):
string_address = get_global_value(globl)
em_js_funcs[name] = get_string_at(module, string_address)

for i in imports:
if i.kind == webassembly.ExternType.FUNC:
if i.field.startswith('invoke_'):
invoke_funcs.append(i.field)
elif i.field not in em_js_funcs:
declares.append(i.field)

export_names = [e.name for e in exports if e.kind == webassembly.ExternType.FUNC]

features = module.parse_features_section()
Expand Down
1 change: 1 addition & 0 deletions tools/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
diagnostics.add_warning('pthreads-mem-growth')
diagnostics.add_warning('transpile')
diagnostics.add_warning('limited-postlink-optimizations')
diagnostics.add_warning('em-js-i64')


# TODO(sbc): Investigate switching to shlex.quote
Expand Down
35 changes: 29 additions & 6 deletions tools/webassembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,14 @@ class InvalidWasmError(BaseException):

Section = namedtuple('Section', ['type', 'size', 'offset', 'name'])
Limits = namedtuple('Limits', ['flags', 'initial', 'maximum'])
Import = namedtuple('Import', ['kind', 'module', 'field'])
Import = namedtuple('Import', ['kind', 'module', 'field', 'type'])
Export = namedtuple('Export', ['name', 'kind', 'index'])
Global = namedtuple('Global', ['type', 'mutable', 'init'])
Dylink = namedtuple('Dylink', ['mem_size', 'mem_align', 'table_size', 'table_align', 'needed', 'export_info', 'import_info'])
Table = namedtuple('Table', ['elem_type', 'limits'])
FunctionBody = namedtuple('FunctionBody', ['offset', 'size'])
DataSegment = namedtuple('DataSegment', ['flags', 'init', 'offset', 'size'])
FuncType = namedtuple('FuncType', ['params', 'returns'])


class Module:
Expand Down Expand Up @@ -210,6 +211,27 @@ def sections(self):
yield Section(section_type, section_size, section_offset, name)
offset = section_offset + section_size

def get_types(self):
type_section = self.get_section(SecType.TYPE)
if not type_section:
return []
self.seek(type_section.offset)
num_types = self.readULEB()
types = []
for i in range(num_types):
params = []
returns = []
type_form = self.readByte()
assert type_form == 0x60
num_params = self.readULEB()
for j in range(num_params):
params.append(self.read_type())
num_returns = self.readULEB()
for j in range(num_returns):
returns.append(self.read_type())
types.append(FuncType(params, returns))
return types

def parse_features_section(self):
features = []
sec = self.get_custom_section('target_features')
Expand Down Expand Up @@ -315,22 +337,23 @@ def get_imports(self):
mod = self.readString()
field = self.readString()
kind = ExternType(self.readByte())
imports.append(Import(kind, mod, field))
type_ = None
if kind == ExternType.FUNC:
self.readULEB() # sig
type_ = self.readULEB()
elif kind == ExternType.GLOBAL:
self.readSLEB() # global type
type_ = self.readSLEB()
self.readByte() # mutable
elif kind == ExternType.MEMORY:
self.read_limits() # limits
elif kind == ExternType.TABLE:
self.readSLEB() # table type
type_ = self.readSLEB()
self.read_limits() # limits
elif kind == ExternType.TAG:
self.readByte() # attribute
self.readULEB() # sig
type_ = self.readULEB()
else:
assert False
imports.append(Import(kind, mod, field, type_))

return imports

Expand Down

0 comments on commit a23058a

Please sign in to comment.