summaryrefslogtreecommitdiff
path: root/scripts/test/asm2wasm.py
diff options
context:
space:
mode:
authorjgravelle-google <jgravelle@google.com>2017-10-02 13:51:55 -0700
committerGitHub <noreply@github.com>2017-10-02 13:51:55 -0700
commita9f91b9774d117a13c231ef0f40861372456878f (patch)
tree1bda2f8fed8a3affe5538732f4ac11c6b8b2599a /scripts/test/asm2wasm.py
parent28d670ade33ab7a1d091bafee243a2c5ffc93bc9 (diff)
downloadbinaryen-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.py160
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()