#!/usr/bin/env python # Copyright 2017 WebAssembly Community Group participants # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import subprocess from support import run_command from shared import ( ASM2WASM, WASM_OPT, binary_format_check, delete_from_orbit, fail_with_error, options, tests, fail_if_not_identical_to_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 '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_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' if __name__ == '__main__': test_asm2wasm() test_asm2wasm_binary()