def test_s2wasm(): print '\n[ checking .s testcases... ]\n' for dot_s_dir in ['dot_s', 'llvm_autogenerated']: dot_s_path = os.path.join(options.binaryen_test, dot_s_dir) for s in sorted(os.listdir(dot_s_path)): if not s.endswith('.s'): continue print '..', s wasm = s.replace('.s', '.wast') full = os.path.join(options.binaryen_test, dot_s_dir, s) stack_alloc = (['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else []) cmd = S2WASM + [full, '--emscripten-glue'] + stack_alloc if s.startswith('start_'): cmd.append('--start') actual = run_command(cmd) # verify output expected_file = os.path.join(options.binaryen_test, dot_s_dir, wasm) if not os.path.exists(expected_file): print actual fail_with_error('output ' + expected_file + ' does not exist') expected = open(expected_file, 'rb').read() if actual != expected: fail(actual, expected) # verify with options cmd = S2WASM + [full, '--global-base=1024'] + stack_alloc run_command(cmd) # run wasm-shell on the .wast to verify that it parses cmd = WASM_SHELL + [expected_file] run_command(cmd)
def generate_wast_files(lld_bin): print '\n[ linking wasm files from object files... ]\n' lld_path = os.path.join(shared.options.binaryen_test, 'lld') for obj_file, ext in files_with_extensions(lld_path, ['.o']): print '..', obj_file wasm_file = obj_file.replace(ext, '.wasm') wast_file = obj_file.replace(ext, '.wast') obj_path = os.path.join(lld_path, obj_file) wasm_path = os.path.join(lld_path, wasm_file) wast_path = os.path.join(lld_path, wast_file) run_command([ lld_bin, '-flavor', 'wasm', '-z', '-stack-size=1048576', obj_path, '-o', wasm_path, '--entry=main', '--allow-undefined', '--export', '__wasm_call_ctors', ]) try: run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path]) finally: # Don't need the .wasm file, don't leave it around shared.delete_from_orbit(wasm_path)
def generate_object_files(clang_bin): print '\n[ building object files from C sources... ]\n' lld_path = os.path.join(shared.options.binaryen_test, 'lld') for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']): print '..', src_file obj_file = src_file.replace(ext, '.o') src_path = os.path.join(lld_path, src_file) obj_path = os.path.join(lld_path, obj_file) run_command([ clang_bin, src_path, '-o', obj_path, '--target=wasm32-unknown-unknown-wasm', '-c', '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-I/s/work/emscripten/system/include', '-O1', ])
def test_wasm2js_output(): for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue basename = os.path.basename(wasm) if basename in wasm2js_blacklist: continue asm = basename.replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) if not os.path.exists(expected_file): continue print '..', wasm t = os.path.join(options.binaryen_test, wasm) all_out = [] for module, asserts in split_wast(t): with open('split.wast', 'w') as o: o.write(module + '\n'.join(asserts)) cmd = WASM2JS + ['split.wast', '-O'] if 'emscripten' in wasm: cmd += ['--emscripten'] out = run_command(cmd) all_out.append(out) if not NODEJS and not MOZJS: print 'No JS interpreters. Skipping spec tests.' continue open('a.2asm.mjs', 'w').write(out) cmd += ['--allow-asserts'] out = run_command(cmd) # also verify it passes pass-debug verifications with_pass_debug(lambda: run_command(cmd)) open('a.2asm.asserts.mjs', 'w').write(out) # verify asm.js is valid js, note that we're using --experimental-modules # to enable ESM syntax and we're also passing a custom loader to handle the # `spectest` and `env` modules in our tests. if NODEJS: node = [NODEJS, '--experimental-modules', '--loader', './scripts/test/node-esm-loader.mjs'] cmd = node[:] cmd.append('a.2asm.mjs') out = run_command(cmd) fail_if_not_identical(out, '') cmd = node[:] cmd.append('a.2asm.asserts.mjs') out = run_command(cmd, expected_err='', err_ignore='The ESM module loader is experimental') fail_if_not_identical(out, '') fail_if_not_identical_to_file(''.join(all_out), expected_file)
def test_linker(): print '\n[ running linker tests... ]\n' # The {main,foo,bar,baz}.s files were created by running clang over the # respective c files. The foobar.bar archive was created by running: # llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'foobar.a') ] output = run_command(cmd) # foo should come from main.s and return 42 fail_if_not_contained(output, '(func $foo') fail_if_not_contained(output, '(i32.const 42)') # bar should be linked in from bar.s fail_if_not_contained(output, '(func $bar') # quux should be linked in from bar.s even though it comes before bar.s in # the archive fail_if_not_contained(output, '(func $quux') # baz should not be linked in at all if 'baz' in output: fail_with_error('output should not contain "baz": ' + output) # Test an archive using a string table cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'barlong.a') ] output = run_command(cmd) # bar should be linked from the archive fail_if_not_contained(output, '(func $bar') # Test exporting memory growth function and emscripten runtime functions cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '--emscripten-glue', '--allow-memory-growth' ] output = run_command(cmd) expected_funcs = [ ('__growWasmMemory', '(param $newSize i32)'), ('stackSave', '(result i32)'), ('stackAlloc', '(param $0 i32) (result i32)'), ('stackRestore', '(param $0 i32)'), ] for name, extra in expected_funcs: space = ' ' if extra else '' fail_if_not_contained(output, '(export "{0}" (func ${0}))'.format(name)) for line in output.split('\n'): if '(func ${0}'.format(name + space) in line: # we found the relevant line for the function definition. remove # a (; X ;) comment with its index start = line.find('(; ') if start >= 0: end = line.find(' ;)') line = line[:start] + line[end + 4:] fail_if_not_contained( line, '(func ${0}'.format(name + space + extra))
def update_wasm2js_tests(): print '\n[ checking wasm2js ]\n' for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue if os.path.basename(wasm) in wasm2js_blacklist: continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) # we run wasm2js on tests and spec tests only if the output # exists - only some work so far. the tests in extra are in # the test/wasm2js dir and so are specific to wasm2js, and # we run all of those. if wasm not in extra_wasm2js_tests and not os.path.exists(expected_file): continue print '..', wasm t = os.path.join(options.binaryen_test, wasm) all_out = [] for module, asserts in split_wast(t): with open('split.wast', 'w') as o: o.write(module + '\n'.join(asserts)) cmd = WASM2JS + ['split.wast', '-O'] if 'emscripten' in wasm: cmd += ['--emscripten'] out = run_command(cmd) all_out.append(out) with open(expected_file, 'w') as o: o.write(''.join(all_out)) for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join('test', asserts) traps_expected_file = os.path.join('test', traps) cmd = WASM2JS + [os.path.join(wasm2js_dir, wasm), '--allow-asserts'] out = run_command(cmd) with open(asserts_expected_file, 'w') as o: o.write(out) cmd += ['--pedantic'] out = run_command(cmd) with open(traps_expected_file, 'w') as o: o.write(out)
def test_asm2wasm_binary(): print '\n[ checking asm2wasm binary reading/writing... ]\n' asmjs = os.path.join(options.binaryen_test, 'hello_world.asm.js') delete_from_orbit('a.wasm') delete_from_orbit('b.wast') run_command(ASM2WASM + [asmjs, '-o', 'a.wasm']) assert open('a.wasm', 'rb').read()[0] == '\0', 'we emit binary by default' run_command(ASM2WASM + [asmjs, '-o', 'b.wast', '-S']) assert open('b.wast', 'rb').read()[0] != '\0', 'we emit text with -S'
def test_wasm2js_output(): for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue basename = os.path.basename(wasm) if basename in wasm2js_blacklist: continue asm = basename.replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) if not os.path.exists(expected_file): continue print '..', wasm cmd = WASM2JS + [os.path.join(options.binaryen_test, wasm)] out = run_command(cmd) fail_if_not_identical_to_file(out, expected_file) if not NODEJS and not MOZJS: print 'No JS interpreters. Skipping spec tests.' continue open('a.2asm.mjs', 'w').write(out) cmd += ['--allow-asserts'] out = run_command(cmd) open('a.2asm.asserts.mjs', 'w').write(out) # verify asm.js is valid js, note that we're using --experimental-modules # to enable ESM syntax and we're also passing a custom loader to handle the # `spectest` module in our tests. if NODEJS: node = [ NODEJS, '--experimental-modules', '--loader', './scripts/test/node-esm-loader.mjs' ] cmd = node[:] cmd.append('a.2asm.mjs') out = run_command(cmd) fail_if_not_identical(out, '') cmd = node[:] cmd.append('a.2asm.asserts.mjs') out = run_command( cmd, expected_err='', err_ignore='The ESM module loader is experimental') fail_if_not_identical(out, '')
def test(engine): cmd = [engine, 'a.js'] if 'fatal' not in s: out = run_command(cmd, stderr=subprocess.STDOUT) else: # expect an error - the specific error code will depend on the vm out = run_command(cmd, stderr=subprocess.STDOUT, expected_status=None) expected = open( os.path.join(options.binaryen_test, 'binaryen.js', s + '.txt')).read() if expected not in out: fail(out, expected)
def test_wasm_emscripten_finalize(): print '\n[ checking wasm-emscripten-finalize testcases... ]\n' for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'): print '..', wast_path mem_file = wast_path + '.mem' extension_arg_map = { '.out': [], '.mem.out': ['--separate-data-segments', mem_file], } for ext, ext_args in extension_arg_map.items(): expected_file = wast_path + ext if ext != '.out' and not os.path.exists(expected_file): continue cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args cmd += args_for_finalize(os.path.basename(wast_path)) actual = run_command(cmd) if not os.path.exists(expected_file): print actual fail_with_error('output ' + expected_file + ' does not exist') fail_if_not_identical_to_file(actual, expected_file) if ext == '.mem.out': with open(mem_file) as mf: mem = mf.read() fail_if_not_identical_to_file(mem, wast_path + '.mem.mem') os.remove(mem_file)
def test_wasm_emscripten_finalize(): print '\n[ checking wasm-emscripten-finalize testcases... ]\n' extension_arg_map = { '.out': [], '.jscall.out': ['--emscripten-reserved-function-pointers=3'], } for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'): print '..', wast_path for ext, ext_args in extension_arg_map.items(): expected_file = wast_path + ext if ext != '.out' and not os.path.exists(expected_file): continue cmd = (WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S', '--global-base=568'] + ext_args) actual = run_command(cmd) if not os.path.exists(expected_file): print actual fail_with_error('output ' + expected_file + ' does not exist') expected = open(expected_file, 'rb').read() if actual != expected: fail(actual, expected)
def update_wasm2js_tests(): print '\n[ checking wasm2js ]\n' for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue if os.path.basename(wasm) in wasm2js_blacklist: continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) # we run wasm2js on tests and spec tests only if the output # exists - only some work so far. the tests in extra are in # the test/wasm2js dir and so are specific to wasm2js, and # we run all of those. if wasm not in extra_wasm2js_tests and not os.path.exists( expected_file): continue print '..', wasm cmd = WASM2JS + [os.path.join('test', wasm)] out = run_command(cmd) with open(expected_file, 'w') as o: o.write(out) for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join('test', asserts) traps_expected_file = os.path.join('test', traps) cmd = WASM2JS + [os.path.join(wasm2js_dir, wasm), '--allow-asserts'] out = run_command(cmd) with open(asserts_expected_file, 'w') as o: o.write(out) cmd += ['--pedantic'] out = run_command(cmd) with open(traps_expected_file, 'w') as o: o.write(out)
def test_asserts_output(): for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join(options.binaryen_test, asserts) traps_expected_file = os.path.join(options.binaryen_test, traps) wasm = os.path.join(wasm2js_dir, wasm) cmd = WASM2JS + [wasm, '--allow-asserts'] out = run_command(cmd) fail_if_not_identical_to_file(out, asserts_expected_file) cmd += ['--pedantic'] out = run_command(cmd) fail_if_not_identical_to_file(out, traps_expected_file)
def do_asm2wasm_test(): actual = run_command(cmd) # verify output if not os.path.exists(wasm): fail_with_error('output .wast file %s does not exist' % wasm) fail_if_not_identical_to_file(actual, wasm) binary_format_check(wasm, verify_final_result=False)
def test_asserts_output(): for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join(options.binaryen_test, asserts) traps_expected_file = os.path.join(options.binaryen_test, traps) wasm = os.path.join(wasm2asm_dir, wasm) cmd = WASM2ASM + [wasm, '--allow-asserts'] out = run_command(cmd) fail_if_not_identical_to_file(out, asserts_expected_file) cmd += ['--pedantic'] out = run_command(cmd) fail_if_not_identical_to_file(out, traps_expected_file)
def test_asserts_output(): for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join('test', asserts) traps_expected_file = os.path.join('test', traps) cmd = WASM2ASM + [os.path.join('test', wasm), '--allow-asserts'] out = run_command(cmd) expected = open(asserts_expected_file).read() fail_if_not_identical(out, expected) cmd += ['--pedantic'] out = run_command(cmd) expected = open(traps_expected_file).read() fail_if_not_identical(out, expected)
def test_linker(): print '\n[ running linker tests... ]\n' # The {main,foo,bar,baz}.s files were created by running clang over the # respective c files. The foobar.bar archive was created by running: # llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'foobar.a') ] output = run_command(cmd) # foo should come from main.s and return 42 fail_if_not_contained(output, '(func $foo') fail_if_not_contained(output, '(i32.const 42)') # bar should be linked in from bar.s fail_if_not_contained(output, '(func $bar') # quux should be linked in from bar.s even though it comes before bar.s in # the archive fail_if_not_contained(output, '(func $quux') # baz should not be linked in at all if 'baz' in output: fail_with_error('output should not contain "baz": ' + output) # Test an archive using a string table cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'barlong.a') ] output = run_command(cmd) # bar should be linked from the archive fail_if_not_contained(output, '(func $bar') # Test exporting memory growth function cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '--emscripten-glue', '--allow-memory-growth' ] output = run_command(cmd) fail_if_not_contained( output, '(export "__growWasmMemory" (func $__growWasmMemory))') fail_if_not_contained(output, '(func $__growWasmMemory (param $newSize i32)')
def test_wasm2asm(): print '\n[ checking wasm2asm testcases... ]\n' # tests with i64s, invokes, etc. blacklist = ['atomics.wast', 'address.wast'] spec_tests = [ os.path.join('spec', t) for t in sorted(os.listdir(os.path.join('test', 'spec'))) ] for wasm in tests + spec_tests: if not wasm.endswith('.wast') or os.path.basename(wasm) in blacklist: continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join('test', asm) if not os.path.exists(expected_file): continue print '..', wasm cmd = WASM2ASM + [os.path.join('test', wasm)] out = run_command(cmd) # verify output expected = open(expected_file).read() fail_if_not_identical(out, expected) open('a.2asm.js', 'w').write(out) if NODEJS: # verify asm.js is valid js out = run_command([NODEJS, 'a.2asm.js']) fail_if_not_identical(out, '') if MOZJS: # verify asm.js validates # check only subset of err because mozjs emits timing info out = run_command([MOZJS, '-w', 'a.2asm.js'], expected_err='Successfully compiled asm.js code', err_contains=True) fail_if_not_identical(out, '')
def do_asm2wasm_test(): actual = run_command(cmd) # verify output if not os.path.exists(wasm): fail_with_error('output .wast file %s does not exist' % wasm) expected = open(wasm, 'rb').read() if actual != expected: fail(actual, expected) binary_format_check(wasm, verify_final_result=False)
def generate_wat_files(llvm_bin, emscripten_root): print('\n[ building wat files from C sources... ]\n') lld_path = os.path.join(shared.options.binaryen_test, 'lld') for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp', '.s']): print('..', src_file) obj_file = src_file.replace(ext, '.o') src_path = os.path.join(lld_path, src_file) obj_path = os.path.join(lld_path, obj_file) wasm_file = src_file.replace(ext, '.wasm') wat_file = src_file.replace(ext, '.wat') obj_path = os.path.join(lld_path, obj_file) wasm_path = os.path.join(lld_path, wasm_file) wat_path = os.path.join(lld_path, wat_file) is_shared = 'shared' in src_file compile_cmd = [ os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path, '--target=wasm32-emscripten', '-mllvm', '-enable-emscripten-sjlj', '-c', '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-I%s/system/include' % emscripten_root, '-O1', ] link_cmd = [ os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm', '-z', '-stack-size=1048576', obj_path, '-o', wasm_path, '--allow-undefined', '--export', '__wasm_call_ctors', '--export', '__data_end', '--global-base=568', ] # We had a regression where this test only worked if debug names # were included. if 'longjmp' in src_file: link_cmd.append('--strip-debug') if is_shared: compile_cmd.append('-fPIC') compile_cmd.append('-fvisibility=default') link_cmd.append('-shared') link_cmd.append('--experimental-pic') else: link_cmd.append('--entry=main') try: support.run_command(compile_cmd) support.run_command(link_cmd) support.run_command(shared.WASM_DIS + [wasm_path, '-o', wat_path]) finally: # Don't need the .o or .wasm files, don't leave them around shared.delete_from_orbit(obj_path) shared.delete_from_orbit(wasm_path)
def test_linker(): print '\n[ running linker tests... ]\n' # The {main,foo,bar,baz}.s files were created by running clang over the # respective c files. The foobar.bar archive was created by running: # llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'foobar.a')] output = run_command(cmd) # foo should come from main.s and return 42 fail_if_not_contained(output, '(func $foo') fail_if_not_contained(output, '(i32.const 42)') # bar should be linked in from bar.s fail_if_not_contained(output, '(func $bar') # quux should be linked in from bar.s even though it comes before bar.s in # the archive fail_if_not_contained(output, '(func $quux') # baz should not be linked in at all if 'baz' in output: fail_with_error('output should not contain "baz": ' + output) # Test an archive using a string table cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '-l', os.path.join(options.binaryen_test, 'linker', 'archive', 'barlong.a')] output = run_command(cmd) # bar should be linked from the archive fail_if_not_contained(output, '(func $bar') # Test exporting memory growth function cmd = S2WASM + [ os.path.join(options.binaryen_test, 'linker', 'main.s'), '--emscripten-glue', '--allow-memory-growth'] output = run_command(cmd) fail_if_not_contained( output, '(export "__growWasmMemory" (func $__growWasmMemory))') fail_if_not_contained(output, '(func $__growWasmMemory (param $newSize i32)')
def test_wasm_emscripten_finalize(): print '\n[ checking wasm-emscripten-finalize testcases... ]\n' for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'): print '..', wast_path expected_file = wast_path + '.out' cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] actual = run_command(cmd) if not os.path.exists(expected_file): print actual fail_with_error('output ' + expected_file + ' does not exist') expected = open(expected_file, 'rb').read() if actual != expected: fail(actual, expected)
def test_wasm_link_metadata(): print '\n[ checking wasm-link-metadata testcases... ]\n' for obj_path in files_with_pattern(options.binaryen_test, 'lld', '*.o'): print '..', obj_path expected_file = obj_path.replace('.o', '.json') cmd = WASM_LINK_METADATA + [obj_path] actual = run_command(cmd) if not os.path.exists(expected_file): print actual fail_with_error('output ' + expected_file + ' does not exist') expected = open(expected_file, 'rb').read() if actual != expected: fail(actual, expected)
def test_s2wasm(): print '\n[ checking .s testcases... ]\n' cmd = S2WASM + [ os.path.join(options.binaryen_test, 'dot_s', 'basics.s'), '--import-memory' ] output = run_command(cmd) fail_if_not_contained(output, '(import "env" "memory" (memory $0 1))') extension_arg_map = { '.wast': [], '.clamp.wast': ['--trap-mode=clamp'], '.js.wast': ['--trap-mode=js'], '.jscall.wast': ['--emscripten-reserved-function-pointers=3'], } for dot_s_dir in ['dot_s', 'llvm_autogenerated']: dot_s_path = os.path.join(options.binaryen_test, dot_s_dir) for s in sorted(os.listdir(dot_s_path)): if not s.endswith('.s'): continue print '..', s for ext, ext_args in extension_arg_map.iteritems(): wasm = s.replace('.s', ext) expected_file = os.path.join(options.binaryen_test, dot_s_dir, wasm) expected_exists = os.path.exists(expected_file) if ext != '.wast' and not expected_exists: continue full = os.path.join(options.binaryen_test, dot_s_dir, s) stack_alloc = (['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else []) cmd = S2WASM + [full, '--emscripten-glue' ] + stack_alloc + ext_args if s.startswith('start_'): cmd.append('--start') actual = run_command(cmd) # verify output if not expected_exists: print actual fail_with_error('output ' + expected_file + ' does not exist') expected = open(expected_file, 'rb').read() if actual != expected: fail(actual, expected) # verify with options cmd = S2WASM + [full, '--global-base=1024'] + stack_alloc run_command(cmd) # run wasm-shell on the .wast to verify that it parses cmd = WASM_SHELL + [expected_file] run_command(cmd)
def generate_wast_files(clang_bin, lld_bin, emscripten_root): print '\n[ building wast files from C sources... ]\n' lld_path = os.path.join(shared.options.binaryen_test, 'lld') for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']): print '..', src_file try: obj_file = src_file.replace(ext, '.o') src_path = os.path.join(lld_path, src_file) obj_path = os.path.join(lld_path, obj_file) run_command([ clang_bin, src_path, '-o', obj_path, '--target=wasm32-unknown-unknown-wasm', '-c', '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-I%s/system/include' % emscripten_root, '-O1', ]) wasm_file = src_file.replace(ext, '.wasm') wast_file = src_file.replace(ext, '.wast') obj_path = os.path.join(lld_path, obj_file) wasm_path = os.path.join(lld_path, wasm_file) wast_path = os.path.join(lld_path, wast_file) run_command([ lld_bin, '-flavor', 'wasm', '-z', '-stack-size=1048576', obj_path, '-o', wasm_path, '--entry=main', '--allow-undefined', '--export', '__wasm_call_ctors', '--global-base=568', ]) run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path]) finally: # Don't need the .o or .wasm files, don't leave them around shared.delete_from_orbit(obj_path) shared.delete_from_orbit(wasm_path)
def generate_wast_files(llvm_bin, emscripten_root): print '\n[ building wast files from C sources... ]\n' lld_path = os.path.join(shared.options.binaryen_test, 'lld') for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']): print '..', src_file obj_file = src_file.replace(ext, '.o') src_path = os.path.join(lld_path, src_file) obj_path = os.path.join(lld_path, obj_file) wasm_file = src_file.replace(ext, '.wasm') wast_file = src_file.replace(ext, '.wast') obj_path = os.path.join(lld_path, obj_file) wasm_path = os.path.join(lld_path, wasm_file) wast_path = os.path.join(lld_path, wast_file) is_shared = 'shared' in src_file compile_cmd = [ os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path, '--target=wasm32-unknown-unknown-wasm', '-c', '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-I%s/system/include' % emscripten_root, '-O1', ] link_cmd = [ os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm', '-z', '-stack-size=1048576', obj_path, '-o', wasm_path, '--allow-undefined', '--export', '__wasm_call_ctors', '--global-base=568', ] if is_shared: compile_cmd.append('-fPIC') compile_cmd.append('-fvisibility=default') link_cmd.append('-shared') else: link_cmd.append('--entry=main') try: run_command(compile_cmd) run_command(link_cmd) run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path]) finally: # Don't need the .o or .wasm files, don't leave them around shared.delete_from_orbit(obj_path) shared.delete_from_orbit(wasm_path)
def update_lld_tests(): print '\n[ updatring wasm-emscripten-finalize testcases... ]\n' for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'): print '..', wast_path mem_file = wast_path + '.mem' extension_arg_map = { '.out': [], '.mem.out': ['--separate-data-segments', mem_file + '.mem'], } for ext, ext_args in extension_arg_map.items(): out_path = wast_path + ext if ext != '.out' and not os.path.exists(out_path): continue cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args cmd += args_for_finalize(os.path.basename(wast_path)) actual = run_command(cmd) with open(out_path, 'w') as o: o.write(actual)
def test_wasm2asm_output(): for wasm in tests + spec_tests + extra_tests: if not wasm.endswith('.wast'): continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join(options.binaryen_test, asm) if not os.path.exists(expected_file): continue print '..', wasm cmd = WASM2ASM + [os.path.join(options.binaryen_test, wasm)] out = run_command(cmd) expected = open(expected_file).read() fail_if_not_identical(out, expected) if not NODEJS and not MOZJS: print 'No JS interpreters. Skipping spec tests.' continue open('a.2asm.js', 'w').write(out) cmd += ['--allow-asserts'] out = run_command(cmd) open('a.2asm.asserts.js', 'w').write(out) # verify asm.js is valid js if NODEJS: out = run_command([NODEJS, 'a.2asm.js']) fail_if_not_identical(out, '') out = run_command([NODEJS, 'a.2asm.asserts.js'], expected_err='') fail_if_not_identical(out, '') if MOZJS: # verify asm.js validates, if this is asm.js code (we emit # almost-asm instead when we need to) if 'use asm' in open('a.2asm.js').read(): # check only subset of err because mozjs emits timing info out = run_command( [MOZJS, '-w', 'a.2asm.js'], expected_err='Successfully compiled asm.js code', err_contains=True) fail_if_not_identical(out, '') out = run_command([MOZJS, 'a.2asm.asserts.js'], expected_err='') fail_if_not_identical(out, '')
def test_wasm2asm_output(): for wasm in tests + [w for w in spec_tests if '.fail' not in w]: if not wasm.endswith('.wast') or os.path.basename(wasm) in blacklist: continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join('test', asm) if not os.path.exists(expected_file): continue print '..', wasm cmd = WASM2ASM + [os.path.join('test', wasm)] out = run_command(cmd) expected = open(expected_file).read() fail_if_not_identical(out, expected) if not NODEJS and not MOZJS: print 'No JS interpreters. Skipping spec tests.' continue open('a.2asm.js', 'w').write(out) cmd += ['--allow-asserts'] out = run_command(cmd) open('a.2asm.asserts.js', 'w').write(out) # verify asm.js is valid js if NODEJS: out = run_command([NODEJS, 'a.2asm.js']) fail_if_not_identical(out, '') out = run_command([NODEJS, 'a.2asm.asserts.js'], expected_err='') fail_if_not_identical(out, '') if MOZJS: # verify asm.js validates # check only subset of err because mozjs emits timing info out = run_command([MOZJS, '-w', 'a.2asm.js'], expected_err='Successfully compiled asm.js code', err_contains=True) fail_if_not_identical(out, '') out = run_command([MOZJS, 'a.2asm.asserts.js'], expected_err='') fail_if_not_identical(out, '')
def generate_wast_files(llvm_bin, emscripten_root): print('\n[ building wast files from C sources... ]\n') lld_path = os.path.join(shared.options.binaryen_test, 'lld') for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']): print('..', src_file) obj_file = src_file.replace(ext, '.o') src_path = os.path.join(lld_path, src_file) obj_path = os.path.join(lld_path, obj_file) wasm_file = src_file.replace(ext, '.wasm') wast_file = src_file.replace(ext, '.wast') obj_path = os.path.join(lld_path, obj_file) wasm_path = os.path.join(lld_path, wasm_file) wast_path = os.path.join(lld_path, wast_file) is_shared = 'shared' in src_file compile_cmd = [ os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path, '--target=wasm32-unknown-unknown-wasm', '-c', '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-I%s/system/include' % emscripten_root, '-O1', ] link_cmd = [ os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm', '-z', '-stack-size=1048576', obj_path, '-o', wasm_path, '--allow-undefined', '--export', '__wasm_call_ctors', '--global-base=568', ] if is_shared: compile_cmd.append('-fPIC') compile_cmd.append('-fvisibility=default') link_cmd.append('-shared') else: link_cmd.append('--entry=main') try: run_command(compile_cmd) run_command(link_cmd) run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path]) finally: # Don't need the .o or .wasm files, don't leave them around shared.delete_from_orbit(obj_path) shared.delete_from_orbit(wasm_path)
def update_wasm2js_tests(): print '\n[ checking wasm2js ]\n' for opt in (0, 1): for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue if os.path.basename(wasm) in wasm2js_blacklist: continue asm = os.path.basename(wasm).replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) if opt: expected_file += '.opt' # we run wasm2js on tests and spec tests only if the output # exists - only some work so far. the tests in extra are in # the test/wasm2js dir and so are specific to wasm2js, and # we run all of those. if wasm not in extra_wasm2js_tests and not os.path.exists( expected_file): continue print '..', wasm t = os.path.join(options.binaryen_test, wasm) all_out = [] for module, asserts in split_wast(t): with open('split.wast', 'w') as o: o.write(module + '\n'.join(asserts)) cmd = WASM2JS + ['split.wast'] if opt: cmd += ['-O'] if 'emscripten' in wasm: cmd += ['--emscripten'] out = run_command(cmd) all_out.append(out) with open(expected_file, 'w') as o: o.write(''.join(all_out)) for wasm in assert_tests: print '..', wasm asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') asserts_expected_file = os.path.join('test', asserts) traps_expected_file = os.path.join('test', traps) cmd = WASM2JS + [os.path.join(wasm2js_dir, wasm), '--allow-asserts'] out = run_command(cmd) with open(asserts_expected_file, 'w') as o: o.write(out) cmd += ['--pedantic'] out = run_command(cmd) with open(traps_expected_file, 'w') as o: o.write(out)
def test_wasm2js_output(): for opt in (0, 1): for wasm in tests + spec_tests + extra_wasm2js_tests: if not wasm.endswith('.wast'): continue basename = os.path.basename(wasm) if basename in wasm2js_blacklist: continue asm = basename.replace('.wast', '.2asm.js') expected_file = os.path.join(wasm2js_dir, asm) if opt: expected_file += '.opt' if not os.path.exists(expected_file): continue print '..', wasm t = os.path.join(options.binaryen_test, wasm) all_out = [] for module, asserts in split_wast(t): with open('split.wast', 'w') as o: o.write(module + '\n'.join(asserts)) cmd = WASM2JS + ['split.wast'] if opt: cmd += ['-O'] if 'emscripten' in wasm: cmd += ['--emscripten'] out = run_command(cmd) all_out.append(out) if not NODEJS and not MOZJS: print 'No JS interpreters. Skipping spec tests.' continue open('a.2asm.mjs', 'w').write(out) cmd += ['--allow-asserts'] out = run_command(cmd) # also verify it passes pass-debug verifications with_pass_debug(lambda: run_command(cmd)) open('a.2asm.asserts.mjs', 'w').write(out) # verify asm.js is valid js, note that we're using --experimental-modules # to enable ESM syntax and we're also passing a custom loader to handle the # `spectest` and `env` modules in our tests. if NODEJS: node = [ NODEJS, '--experimental-modules', '--loader', './scripts/test/node-esm-loader.mjs' ] cmd = node[:] cmd.append('a.2asm.mjs') out = run_command(cmd) fail_if_not_identical(out, '') cmd = node[:] cmd.append('a.2asm.asserts.mjs') out = run_command( cmd, expected_err='', err_ignore='The ESM module loader is experimental') fail_if_not_identical(out, '') fail_if_not_identical_to_file(''.join(all_out), expected_file)
def test_asm2wasm(): print '[ checking asm2wasm testcases... ]\n' for asm in tests: if not asm.endswith('.asm.js'): continue for precise in [0, 1, 2]: for opts in [1, 0]: cmd = ASM2WASM + [os.path.join(options.binaryen_test, asm)] if 'threads' in asm: cmd += ['--enable-threads'] wasm = asm.replace('.asm.js', '.fromasm') if not precise: cmd += ['--trap-mode=allow', '--ignore-implicit-traps'] wasm += '.imprecise' elif precise == 2: cmd += ['--trap-mode=clamp'] wasm += '.clamp' if not opts: wasm += '.no-opts' if precise: cmd += ['-O0'] # test that -O0 does nothing else: cmd += ['-O'] if 'debugInfo' in asm: cmd += ['-g'] if 'noffi' in asm: cmd += ['--no-legalize-javascript-ffi'] if precise and opts: # test mem init importing open('a.mem', 'wb').write(asm) cmd += ['--mem-init=a.mem'] if asm[0] == 'e': cmd += ['--mem-base=1024'] if '4GB' in asm: cmd += ['--mem-max=4294967296'] if 'i64' in asm or 'wasm-only' in asm or 'noffi' in asm: cmd += ['--wasm-only'] wasm = os.path.join(options.binaryen_test, wasm) print '..', asm, wasm def do_asm2wasm_test(): actual = run_command(cmd) # verify output if not os.path.exists(wasm): fail_with_error('output .wast file %s does not exist' % wasm) fail_if_not_identical_to_file(actual, wasm) binary_format_check(wasm, verify_final_result=False) # test both normally and with pass debug (so each inter-pass state # is validated) old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG') try: os.environ['BINARYEN_PASS_DEBUG'] = '1' print "With BINARYEN_PASS_DEBUG=1:" do_asm2wasm_test() del os.environ['BINARYEN_PASS_DEBUG'] print "With BINARYEN_PASS_DEBUG disabled:" do_asm2wasm_test() finally: if old_pass_debug is not None: os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug else: if 'BINARYEN_PASS_DEBUG' in os.environ: del os.environ['BINARYEN_PASS_DEBUG'] # verify in wasm if options.interpreter: # remove imports, spec interpreter doesn't know what to do with them subprocess.check_call(WASM_OPT + ['--remove-imports', wasm], stdout=open('ztemp.wast', 'w'), stderr=subprocess.PIPE) proc = subprocess.Popen([options.interpreter, 'ztemp.wast'], stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode != 0: try: # to parse the error reported = err.split(':')[1] start, end = reported.split('-') start_line, start_col = map(int, start.split('.')) lines = open('ztemp.wast').read().split('\n') print print '=' * 80 print lines[start_line - 1] print (' ' * (start_col - 1)) + '^' print (' ' * (start_col - 2)) + '/_\\' print '=' * 80 print err except Exception: # failed to pretty-print fail_with_error('wasm interpreter error: ' + err) fail_with_error('wasm interpreter error') # verify debug info if 'debugInfo' in asm: jsmap = 'a.wasm.map' cmd += ['--source-map', jsmap, '--source-map-url', 'http://example.org/' + jsmap, '-o', 'a.wasm'] run_command(cmd) if not os.path.isfile(jsmap): fail_with_error('Debug info map not created: %s' % jsmap) with open(jsmap, 'rb') as actual: fail_if_not_identical_to_file(actual.read(), wasm + '.map') with open('a.wasm', 'rb') as binary: url_section_name = bytearray([16]) + bytearray('sourceMappingURL') url = 'http://example.org/' + jsmap assert len(url) < 256, 'name too long' url_section_contents = bytearray([len(url)]) + bytearray(url) print url_section_name binary_contents = bytearray(binary.read()) if url_section_name not in binary_contents: fail_with_error('source map url section not found in binary') url_section_index = binary_contents.index(url_section_name) if url_section_contents not in binary_contents[url_section_index:]: fail_with_error('source map url not found in url section')
def test_asm2wasm(): print '[ checking asm2wasm testcases... ]\n' for asm in tests: if not asm.endswith('.asm.js'): continue for precise in [0, 1, 2]: for opts in [1, 0]: cmd = ASM2WASM + [os.path.join(options.binaryen_test, asm)] if 'threads' in asm: cmd += ['--enable-threads'] wasm = asm.replace('.asm.js', '.fromasm') if not precise: cmd += ['--trap-mode=allow', '--ignore-implicit-traps'] wasm += '.imprecise' elif precise == 2: cmd += ['--trap-mode=clamp'] wasm += '.clamp' if not opts: wasm += '.no-opts' if precise: cmd += ['-O0'] # test that -O0 does nothing else: cmd += ['-O'] if 'debugInfo' in asm: cmd += ['-g'] if 'noffi' in asm: cmd += ['--no-legalize-javascript-ffi'] if precise and opts: # test mem init importing open('a.mem', 'wb').write(asm) cmd += ['--mem-init=a.mem'] if asm[0] == 'e': cmd += ['--mem-base=1024'] if 'i64' in asm or 'wasm-only' in asm or 'noffi' in asm: cmd += ['--wasm-only'] wasm = os.path.join(options.binaryen_test, wasm) print '..', asm, wasm def do_asm2wasm_test(): actual = run_command(cmd) # verify output if not os.path.exists(wasm): fail_with_error('output .wast file %s does not exist' % wasm) fail_if_not_identical_to_file(actual, wasm) binary_format_check(wasm, verify_final_result=False) # test both normally and with pass debug (so each inter-pass state # is validated) old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG') try: os.environ['BINARYEN_PASS_DEBUG'] = '1' print "With BINARYEN_PASS_DEBUG=1:" do_asm2wasm_test() del os.environ['BINARYEN_PASS_DEBUG'] print "With BINARYEN_PASS_DEBUG disabled:" do_asm2wasm_test() finally: if old_pass_debug is not None: os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug else: if 'BINARYEN_PASS_DEBUG' in os.environ: del os.environ['BINARYEN_PASS_DEBUG'] # verify in wasm if options.interpreter: # remove imports, spec interpreter doesn't know what to do with them subprocess.check_call(WASM_OPT + ['--remove-imports', wasm], stdout=open('ztemp.wast', 'w'), stderr=subprocess.PIPE) proc = subprocess.Popen([options.interpreter, 'ztemp.wast'], stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode != 0: try: # to parse the error reported = err.split(':')[1] start, end = reported.split('-') start_line, start_col = map(int, start.split('.')) lines = open('ztemp.wast').read().split('\n') print print '=' * 80 print lines[start_line - 1] print (' ' * (start_col - 1)) + '^' print (' ' * (start_col - 2)) + '/_\\' print '=' * 80 print err except Exception: # failed to pretty-print fail_with_error('wasm interpreter error: ' + err) fail_with_error('wasm interpreter error') # verify debug info if 'debugInfo' in asm: jsmap = 'a.wasm.map' cmd += ['--source-map', jsmap, '--source-map-url', 'http://example.org/' + jsmap, '-o', 'a.wasm'] run_command(cmd) if not os.path.isfile(jsmap): fail_with_error('Debug info map not created: %s' % jsmap) with open(jsmap, 'rb') as actual: fail_if_not_identical_to_file(actual.read(), wasm + '.map') with open('a.wasm', 'rb') as binary: url_section_name = bytearray([16]) + bytearray('sourceMappingURL') url = 'http://example.org/' + jsmap assert len(url) < 256, 'name too long' url_section_contents = bytearray([len(url)]) + bytearray(url) print url_section_name binary_contents = bytearray(binary.read()) if url_section_name not in binary_contents: fail_with_error('source map url section not found in binary') url_section_index = binary_contents.index(url_section_name) if url_section_contents not in binary_contents[url_section_index:]: fail_with_error('source map url not found in url section')