| #!/usr/bin/env python3 |
| # |
| # 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 scripts.test import shared |
| from scripts.test import support |
| |
| |
| def test_asm2wasm(): |
| print('[ checking asm2wasm testcases... ]\n') |
| |
| for asm in shared.get_tests(shared.options.binaryen_test, ['.asm.js']): |
| basename = os.path.basename(asm) |
| for precise in [0, 1, 2]: |
| for opts in [1, 0]: |
| cmd = shared.ASM2WASM + [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 basename: |
| cmd += ['-g'] |
| if 'noffi' in basename: |
| cmd += ['--no-legalize-javascript-ffi'] |
| if precise and opts: |
| # test mem init importing |
| open('a.mem', 'w').write(basename) |
| cmd += ['--mem-init=a.mem'] |
| if basename[0] == 'e': |
| cmd += ['--mem-base=1024'] |
| if '4GB' in basename: |
| cmd += ['--mem-max=4294967296'] |
| if 'i64' in basename or 'wasm-only' in basename or 'noffi' in basename: |
| cmd += ['--wasm-only'] |
| print('..', basename, os.path.basename(wasm)) |
| |
| def do_asm2wasm_test(): |
| actual = support.run_command(cmd) |
| |
| # verify output |
| if not os.path.exists(wasm): |
| shared.fail_with_error('output .wast file %s does not exist' % wasm) |
| shared.fail_if_not_identical_to_file(actual, wasm) |
| |
| shared.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 shared.options.interpreter: |
| # remove imports, spec interpreter doesn't know what to do with them |
| subprocess.check_call(shared.WASM_OPT + ['--remove-imports', wasm], |
| stdout=open('ztemp.wast', 'w'), |
| stderr=subprocess.PIPE) |
| proc = subprocess.Popen([shared.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 |
| shared.fail_with_error('wasm interpreter error: ' + err) |
| shared.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'] |
| support.run_command(cmd) |
| if not os.path.isfile(jsmap): |
| shared.fail_with_error('Debug info map not created: %s' % jsmap) |
| with open(jsmap, 'rb') as actual: |
| shared.fail_if_not_identical_to_file(actual.read(), wasm + '.map') |
| with open('a.wasm', 'rb') as binary: |
| url_section_name = bytes([16]) + bytes('sourceMappingURL', 'utf-8') |
| url = 'http://example.org/' + jsmap |
| assert len(url) < 256, 'name too long' |
| url_section_contents = bytes([len(url)]) + bytes(url, 'utf-8') |
| print(url_section_name) |
| binary_contents = binary.read() |
| if url_section_name not in binary_contents: |
| shared.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:]: |
| shared.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(shared.options.binaryen_test, 'hello_world.asm.js') |
| shared.delete_from_orbit('a.wasm') |
| shared.delete_from_orbit('b.wast') |
| support.run_command(shared.ASM2WASM + [asmjs, '-o', 'a.wasm']) |
| assert open('a.wasm', 'rb').read()[0] == 0, 'we emit binary by default' |
| support.run_command(shared.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() |