| #!/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, fail_with_error, fail_if_not_identical, options, tests |
| ) |
| |
| |
| 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)] |
| 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) |
| expected = open(wasm, 'rb').read() |
| if actual != expected: |
| fail(actual, expected) |
| |
| 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(wasm + '.map', 'rb') as expected: |
| with open(jsmap, 'rb') as actual: |
| fail_if_not_identical(actual.read(), expected.read()) |
| 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() |