diff options
author | jgravelle-google <jgravelle@google.com> | 2017-10-02 13:51:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-02 13:51:55 -0700 |
commit | a9f91b9774d117a13c231ef0f40861372456878f (patch) | |
tree | 1bda2f8fed8a3affe5538732f4ac11c6b8b2599a /scripts/test/asm2wasm.py | |
parent | 28d670ade33ab7a1d091bafee243a2c5ffc93bc9 (diff) | |
download | binaryen-a9f91b9774d117a13c231ef0f40861372456878f.tar.gz binaryen-a9f91b9774d117a13c231ef0f40861372456878f.tar.bz2 binaryen-a9f91b9774d117a13c231ef0f40861372456878f.zip |
Share trap mode between asm2wasm and s2wasm (#1168)
* Extract Asm2WasmBuilder::TrapMode to shared FloatTrapMode
* Extract makeTrappingI32Binary
* Extract makeTrappingI64Binary
* Extract asm2wasm test script into scripts/test/asm2wasm.py
This matches s2wasm.py, and makes iterating on asm2wasm slightly faster.
* Simplify callsites with an arg struct
* Combine func adding across i32 and i64
* Support f32-to-int in asm2wasm
* Add BinaryenTrapMode pass, run pass from s2wasm
* BinaryenTrapMode pass takes trap context as a parameter
* Pass fully supports non-trapping binary ops
* Defer adding functions until after iteration (hackily)
* Update asm2wasm to work with deferred function adding, rebuild tests
* Extract makeTrappingFloatToInt32
* Extract makeTrappingFloatToInt64
* Add unary conversions to trap pass
* Add functions in the pass itself
* Set s2wasm trap mode with command-line arguments
* Print BINARYEN_PASS_DEBUG state when testing
* Get asm2wasm using the BinaryenTrapMode pass instead of handling it inline
* Also handle f32 to int in asm2wasm
* Make BinaryenTrapMode only need a FloatTrapMode from the caller
* Just pass the current binary Expression directly
* Combine makeTrappingI32Binary with makeTrappingI64Binary
* Pass Unary expr to makeTrappingFloatToInt32
* Unify makeTrappingFloatToInt32 & 64
* Move makeTrapping* functions inside BinaryenTrapMode, make addedFunctions non-static
* Remove FloatTrapContext
* Minor cleanups
* Extract some smaller subfunctions
* Emit name switch/casing, rename is32Bit to isI64 for consistency
* Rename BinaryenTrapMode to FloatTrap, make trap mode a nested enum
* Add some comments explaining why FloatTrap is non-parallel
* Rename addedFunctions to generatedFunctions for precision
* Rename move and split float-clamp.h to passes/FloatTrap.(h|cpp)
* Use builder instead of allocator
* Instantiate trap handling passes via the pass manager
* Move passes/FloatTrap.h to ast/trapping.h
* Add helper function to add trap-handling passes
* Add trap mode pass tests
* Rename FloatTrap.cpp to TrapMode.cpp
* Add s2wasm trap mode tests. Force float->int conversion to be signed
* Add trapping_sint_div_s test to unit.asm.js
* Fix flake8 issues with test scripts
* Update pass description comment
* Extract building functions methods
* Make generate functions into top-level functions
* Add GeneratedTrappingFunctions class to manage function/import additions
* Move ensure/makeTrapping functions outside class scope
* Use GeneratedTrappingFunctions to add immediately in asm2wasm mode
* Remove trapping_sint_div_s test
We only added it to test that trapping divisions would get
constant-folded at the correct time. Now that we're not changing the
timing of trapping modes, the test is unneeded (and problematic).
* Review feedback, add validator/*.wasm to .gitignore
* Add support for unsigned float-to-int conversion
* Use opcode directly instead of bools
* Update s2wasm clamp test for unsigned ftoi
Diffstat (limited to 'scripts/test/asm2wasm.py')
-rw-r--r-- | scripts/test/asm2wasm.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/scripts/test/asm2wasm.py b/scripts/test/asm2wasm.py new file mode 100644 index 000000000..db37a237a --- /dev/null +++ b/scripts/test/asm2wasm.py @@ -0,0 +1,160 @@ +#!/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 += ['--emit-potential-traps', '--ignore-implicit-traps'] + wasm += '.imprecise' + elif precise == 2: + cmd += ['--emit-clamped-potential-traps'] + 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() |