diff --git a/src/runtime.js b/src/runtime.js index 78472acbfed2a..9ba46fed78dac 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -21,6 +21,10 @@ var Compiletime = { // code used both at compile time and runtime is defined here, then put on // the Runtime object for compile time and support.js for the generated code +function getPointerSize() { + return MEMORY64 ? 8 : 4; +} + function getNativeTypeSize(type) { switch (type) { case 'i1': case 'i8': return 1; @@ -31,7 +35,7 @@ function getNativeTypeSize(type) { case 'double': return 8; default: { if (type[type.length-1] === '*') { - return 4; // A pointer + return getPointerSize(); } else if (type[0] === 'i') { var bits = Number(type.substr(1)); assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); @@ -53,6 +57,6 @@ var Runtime = { return Math.max(getNativeTypeSize(type), Runtime.QUANTUM_SIZE); }, - POINTER_SIZE: 4, - QUANTUM_SIZE: 4, + POINTER_SIZE: getPointerSize(), + QUANTUM_SIZE: getPointerSize(), }; diff --git a/src/support.js b/src/support.js index 6edfef322ab54..84437cb8b3dc2 100644 --- a/src/support.js +++ b/src/support.js @@ -6,6 +6,10 @@ var STACK_ALIGN = {{{ STACK_ALIGN }}}; +function getPointerSize() { + return {{{ MEMORY64 ? 8 : 4 }}}; +} + {{{ getNativeTypeSize }}} function warnOnce(text) { diff --git a/tests/core/test_typeid.cpp b/tests/core/test_typeid.cpp index f832faa510fd7..fc2817ee279fd 100644 --- a/tests/core/test_typeid.cpp +++ b/tests/core/test_typeid.cpp @@ -8,17 +8,18 @@ #include #include #include +#include int main() { printf("*\n"); #define MAX 100 - int ptrs[MAX]; + long ptrs[MAX]; int groups[MAX]; - memset(ptrs, 0, MAX * sizeof(int)); + memset(ptrs, 0, MAX * sizeof(long)); memset(groups, 0, MAX * sizeof(int)); int next_group = 1; #define TEST(X) \ { \ - int ptr = (int)&typeid(X); \ + intptr_t ptr = (intptr_t)&typeid(X); \ int group = 0; \ int i; \ for (i = 0; i < MAX; i++) { \ diff --git a/tests/runner.py b/tests/runner.py index b9187d9bc88ce..00aeb6486cc85 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -60,6 +60,7 @@ 'wasm2js3', 'wasm2jss', 'wasm2jsz', + 'wasm64' ] # The default core test mode, used when none is specified @@ -312,6 +313,8 @@ def parse_args(args): parser.add_argument('tests', nargs='*') parser.add_argument('--failfast', dest='failfast', action='store_const', const=True, default=False) + parser.add_argument('--force64', dest='force64', action='store_const', + const=True, default=False) return parser.parse_args() @@ -324,6 +327,8 @@ def configure(): common.EMTEST_LACKS_NATIVE_CLANG = int(os.getenv('EMTEST_LACKS_NATIVE_CLANG', '0')) common.EMTEST_REBASELINE = int(os.getenv('EMTEST_REBASELINE', '0')) common.EMTEST_VERBOSE = int(os.getenv('EMTEST_VERBOSE', '0')) or shared.DEBUG + global FORCE64 + FORCE64 = int(os.getenv('EMTEST_FORCE64', '0')) if common.EMTEST_VERBOSE: logging.root.setLevel(logging.DEBUG) @@ -361,6 +366,7 @@ def set_env(name, option_value): set_env('EMTEST_REBASELINE', options.rebaseline) set_env('EMTEST_VERBOSE', options.verbose) set_env('EMTEST_CORES', options.cores) + set_env('EMTEST_FORCE64', options.force64) configure() diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 2176d1f96bab9..4cb91e8578e07 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -51,6 +51,8 @@ LLVM_FEATURE_FLAGS = ['-mnontrapping-fptoint'] +FORCE64 = 0 + class Benchmarker(): # called when we init the object, which is during startup, even if we are @@ -205,12 +207,14 @@ def build(self, parent, filename, args, shared_args, emcc_args, native_args, nat OPTIMIZATIONS, '-s', 'INITIAL_MEMORY=256MB', '-s', 'FILESYSTEM=0', - '--closure=1', - '-s', 'MINIMAL_RUNTIME', '-s', 'ENVIRONMENT=node,shell', '-s', 'BENCHMARK=%d' % (1 if IGNORE_COMPILATION and not has_output_parser else 0), '-o', final ] + shared_args + emcc_args + LLVM_FEATURE_FLAGS + self.extra_args + if FORCE64: + cmd += ['--profiling'] + else: + cmd += ['--closure=1', '-sMINIMAL_RUNTIME'] if 'FORCE_FILESYSTEM' in cmd: cmd = [arg if arg != 'FILESYSTEM=0' else 'FILESYSTEM=1' for arg in cmd] if PROFILING: @@ -353,10 +357,13 @@ def cleanup(self): # Benchmarkers -benchmarkers = [ - NativeBenchmarker('clang', [CLANG_CC], [CLANG_CXX]), - # NativeBenchmarker('gcc', ['gcc', '-no-pie'], ['g++', '-no-pie']) -] +benchmarkers = [] + +if not FORCE64: + benchmarkers += [ + NativeBenchmarker('clang', [CLANG_CC], [CLANG_CXX]), + # NativeBenchmarker('gcc', ['gcc', '-no-pie'], ['g++', '-no-pie']) + ] if config.V8_ENGINE and config.V8_ENGINE in config.JS_ENGINES: # avoid the baseline compiler running, because it adds a lot of noise @@ -364,11 +371,16 @@ def cleanup(self): # mattering as much as the actual benchmark) aot_v8 = config.V8_ENGINE + ['--no-liftoff'] default_v8_name = os.environ.get('EMBENCH_NAME') or 'v8' - benchmarkers += [ - EmscriptenBenchmarker(default_v8_name, aot_v8), - EmscriptenBenchmarker(default_v8_name + '-lto', aot_v8, ['-flto']), - # EmscriptenWasm2CBenchmarker('wasm2c') - ] + if FORCE64: + benchmarkers += [ + EmscriptenBenchmarker(default_v8_name, aot_v8, ['-sMEMORY64=2']), + ] + else: + benchmarkers += [ + EmscriptenBenchmarker(default_v8_name, aot_v8), + EmscriptenBenchmarker(default_v8_name + '-lto', aot_v8, ['-flto']), + # EmscriptenWasm2CBenchmarker('wasm2c') + ] if os.path.exists(CHEERP_BIN): benchmarkers += [ # CheerpBenchmarker('cheerp-v8-wasm', aot_v8), @@ -385,9 +397,14 @@ def cleanup(self): ] if config.NODE_JS and config.NODE_JS in config.JS_ENGINES: - benchmarkers += [ - # EmscriptenBenchmarker('Node.js', config.NODE_JS), - ] + if FORCE64: + benchmarkers += [ + EmscriptenBenchmarker('Node.js', config.NODE_JS, ['-sMEMORY64=2']), + ] + else: + benchmarkers += [ + # EmscriptenBenchmarker('Node.js', config.NODE_JS), + ] class benchmark(common.RunnerCore): diff --git a/tests/test_core.py b/tests/test_core.py index 059137e6b7417..932943323f42e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -245,6 +245,21 @@ def decorated(self, *args, **kwargs): return decorator +def no_memory64(note): + assert not callable(note) + + def decorator(f): + assert callable(f) + + @wraps(f) + def decorated(self, *args, **kwargs): + if self.get_setting('MEMORY64'): + self.skipTest(note) + f(self, *args, **kwargs) + return decorated + return decorator + + def make_no_decorator_for_setting(name): def outer_decorator(note): assert not callable(note) @@ -467,6 +482,7 @@ def test_bswap64(self): def test_sha1(self): self.do_runf(test_file('sha1.c'), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6') + @no_memory64('tests 32-bit specific sizes') def test_wasm32_unknown_emscripten(self): # No other configuration is supported, so always run this. self.do_runf(test_file('wasm32-unknown-emscripten.c'), '') @@ -509,8 +525,8 @@ def test_unaligned(self): s[1] = s0[1]; s[2] = s0[2]; - printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8, - ((unsigned int)&s[1]) - ((unsigned int)&s[0])); + printf("*%d : %d : %d\n", sizeof(S), ((unsigned long)&s[0]) % 8 != ((unsigned long)&s[1]) % 8, + ((unsigned long)&s[1]) - ((unsigned long)&s[0])); s[0].x++; s[0].y++; s[1].x++; @@ -2036,6 +2052,7 @@ def test_memorygrowth_3_force_fail_reallocBuffer(self): 'grow': (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],) }) @no_asan('requires more memory when growing') + @no_memory64('does not fail under wasm64') def test_aborting_new(self, args): # test that C++ new properly errors if we fail to malloc when growth is # enabled, with or without growth @@ -6585,6 +6602,7 @@ def test_large_exported_response(self): self.do_run(src, 'waka 4999!') self.assertContained('_exported_func_from_response_file_1', read_file('src.js')) + @no_memory64('gives: TypeError: WebAssembly.Table.set(): Argument 1 must be null or a WebAssembly function') def test_add_function(self): self.set_setting('INVOKE_RUN', 0) self.set_setting('WASM_ASYNC_COMPILATION', 0) @@ -7418,6 +7436,7 @@ def test_vswprintf_utf8(self): # needs setTimeout which only node has @require_node + @no_memory64('TODO: asyncify for wasm64') def test_async_hello(self): # needs to flush stdio streams self.set_setting('EXIT_RUNTIME') @@ -7443,6 +7462,7 @@ def test_async_hello(self): self.do_runf('main.c', 'HelloWorld!99') @require_node + @no_memory64('TODO: asyncify for wasm64') def test_async_ccall_bad(self): # check bad ccall use # needs to flush stdio streams @@ -7474,6 +7494,7 @@ def test_async_ccall_bad(self): self.do_runf('main.c', 'The call to main is running asynchronously.') @require_node + @no_memory64('TODO: asyncify for wasm64') def test_async_ccall_good(self): # check reasonable ccall use # needs to flush stdio streams @@ -7502,6 +7523,7 @@ def test_async_ccall_good(self): '': (False,), 'exit_runtime': (True,), }) + @no_memory64('TODO: asyncify for wasm64') def test_async_ccall_promise(self, exit_runtime): self.set_setting('ASYNCIFY') self.set_setting('EXIT_RUNTIME') @@ -7540,6 +7562,7 @@ def test_async_ccall_promise(self, exit_runtime): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'stringf: first\nsecond\n6.4') + @no_memory64('TODO: asyncify for wasm64') def test_fibers_asyncify(self): self.set_setting('ASYNCIFY') self.maybe_closure() @@ -7562,6 +7585,7 @@ def test_asyncify_unused(self): 'onlylist_b_response': ([], True, '["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()"]'), 'onlylist_c_response': ([], False, '["main","__original_main","foo(int, double)","baz()","c_baz"]'), }) + @no_memory64('TODO: asyncify for wasm64') def test_asyncify_lists(self, args, should_pass, response=None, no_san=False): if no_san and is_sanitizing(self.emcc_args): self.skipTest('remaining asyncify+sanitizer TODO') @@ -7594,6 +7618,7 @@ def test_asyncify_lists(self, args, should_pass, response=None, no_san=False): 'ignoreindirect': (['-s', 'ASYNCIFY_IGNORE_INDIRECT'], False), 'add': (['-s', 'ASYNCIFY_IGNORE_INDIRECT', '-s', 'ASYNCIFY_ADD=["__original_main","main","virt()"]'], True), }) + @no_memory64('TODO: asyncify for wasm64') def test_asyncify_indirect_lists(self, args, should_pass): self.set_setting('ASYNCIFY') self.emcc_args += args @@ -7607,10 +7632,12 @@ def test_asyncify_indirect_lists(self, args, should_pass): raise @no_asan('asyncify stack operations confuse asan') + @no_memory64('TODO: asyncify for wasm64') def test_emscripten_scan_registers(self): self.set_setting('ASYNCIFY') self.do_core_test('test_emscripten_scan_registers.cpp') + @no_memory64('TODO: asyncify for wasm64') def test_asyncify_assertions(self): self.set_setting('ASYNCIFY') self.set_setting('ASYNCIFY_IMPORTS', ['suspend']) @@ -7619,6 +7646,7 @@ def test_asyncify_assertions(self): @no_lsan('leaks asyncify stack during exit') @no_asan('leaks asyncify stack during exit') + @no_memory64('TODO: asyncify for wasm64') def test_asyncify_during_exit(self): self.set_setting('ASYNCIFY') self.set_setting('ASSERTIONS') @@ -7635,6 +7663,7 @@ def test_asyncify_main_module(self): self.do_core_test('test_hello_world.c') @no_asan('asyncify stack operations confuse asan') + @no_memory64('TODO: asyncify for wasm64') @no_wasm2js('TODO: lazy loading in wasm2js') @parameterized({ 'conditional': (True,), @@ -8173,6 +8202,7 @@ def test_template_class_deduction(self): @no_wasm2js('TODO: ASAN in wasm2js') @no_safe_heap('asan does not work with SAFE_HEAP') + @no_memory64('TODO: ASAN in memory64') @parameterized({ 'c': ['test_asan_no_error.c'], 'cpp': ['test_asan_no_error.cpp'], @@ -8188,6 +8218,7 @@ def test_asan_no_error(self, name): # stores, and then the stores identified as dead, which leaves nothing for # asan to test. here we want to test asan itself, so we work around that. @no_safe_heap('asan does not work with SAFE_HEAP') + @no_memory64('TODO: ASAN in memory64') @parameterized({ 'use_after_free_c': ('test_asan_use_after_free.c', [ 'AddressSanitizer: heap-use-after-free on address', @@ -8259,6 +8290,7 @@ def test_asan(self, name, expected_output, cflags=None): @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm2js('TODO: ASAN in wasm2js') + @no_memory64('TODO: ASAN in memory64') def test_asan_js_stack_op(self): self.emcc_args.append('-fsanitize=address') self.set_setting('ALLOW_MEMORY_GROWTH') @@ -8268,6 +8300,7 @@ def test_asan_js_stack_op(self): @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm2js('TODO: ASAN in wasm2js') + @no_memory64('TODO: ASAN in memory64') def test_asan_api(self): self.emcc_args.append('-fsanitize=address') self.set_setting('INITIAL_MEMORY', '300mb') @@ -8275,6 +8308,7 @@ def test_asan_api(self): @no_safe_heap('asan does not work with SAFE_HEAP') @no_wasm2js('TODO: ASAN in wasm2js') + @no_memory64('TODO: ASAN in memory64') def test_asan_modularized_with_closure(self): # the bug is that createModule() returns undefined, instead of the # proper Promise object. @@ -8616,11 +8650,6 @@ def test_export_start(self): self.set_setting('EXPORTED_FUNCTIONS', ['__start']) self.do_core_test('test_hello_world.c') - @unittest.skip("memory64 functionality only partially working") - def test_memory64_hello_world(self): - self.set_setting('MEMORY64', 2) - self.do_core_test('test_hello_world.c') - # Tests the operation of API found in #include def test_emscripten_math(self): self.do_core_test('test_emscripten_math.c') @@ -8641,6 +8670,7 @@ def test_emscripten_stack(self): self.do_core_test('test_stack_get_free.c') # Tests settings.ABORT_ON_WASM_EXCEPTIONS + @no_memory64('missing "crashing"') def test_abort_on_exceptions(self): # Explictly disable EXIT_RUNTIME, since otherwise addOnPostRun does not work. # https://github.com/emscripten-core/emscripten/issues/15080 @@ -8706,7 +8736,7 @@ def test_em_async_js(self): # Generate tests for everything -def make_run(name, emcc_args, settings=None, env=None): +def make_run(name, emcc_args, settings=None, env=None, node_args=None): if env is None: env = {} if settings is None: @@ -8725,6 +8755,9 @@ def tearDown(self): for k, v in self.env.items(): del os.environ[k] + if node_args: + self.node_args = TT.original + TT.tearDown = tearDown def setUp(self): @@ -8740,6 +8773,10 @@ def setUp(self): self.emcc_args += emcc_args + if node_args: + TT.original = self.node_args + self.node_args.append(node_args) + TT.setUp = setUp return TT @@ -8754,6 +8791,8 @@ def setUp(self): wasm3 = make_run('wasm3', emcc_args=['-O3']) wasms = make_run('wasms', emcc_args=['-Os']) wasmz = make_run('wasmz', emcc_args=['-Oz']) +wasm64 = make_run('wasm64', emcc_args=['-O0', '-g3'], + settings={'MEMORY64': 2}, env=None, node_args='--experimental-wasm-bigint') wasmlto0 = make_run('wasmlto0', emcc_args=['-flto', '-O0']) wasmlto1 = make_run('wasmlto1', emcc_args=['-flto', '-O1']) diff --git a/tools/gen_struct_info.py b/tools/gen_struct_info.py index a1b75a0e73834..1c17554509ccc 100755 --- a/tools/gen_struct_info.py +++ b/tools/gen_struct_info.py @@ -266,6 +266,13 @@ def inspect_headers(headers, cflags): '-Wno-format', '-nostdlib', compiler_rt, + # FIXME: this setting here won't work, since this is only + # ran once on first use. If there are differences here then + # we would need a second set of json file and have them stored + # separately in the cache. + # Whereever generated_struct_info.json is generated, there now + # needs to be a generated_struct_info64.json for MEMORY64 mode. + # '-s', 'MEMORY64=' + str(settings.MEMORY64), '-s', 'BOOTSTRAPPING_STRUCT_INFO=1', '-s', 'LLD_REPORT_UNDEFINED=1', '-s', 'STRICT',