From f109f3cae1cd81db22ba490a4da17a7a4c495047 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 30 Aug 2018 16:10:26 -0700 Subject: Rename `wasm2asm` to `wasm2js`, emit ESM by default (#1642) * Rename the `wasm2asm` tool to `wasm2js` This commit performs a relatively simple rename of the `wasm2asm` tool to `wasm2js`. The functionality of the tool doesn't change just yet but it's intended that we'll start generating an ES module instead of just an `asm.js` function soon. * wasm2js: Support `*.wasm` input files Previously `wasm2js` only supported `*.wast` files but to make it a bit easier to use in tooling pipelines this commit adds support for reading in a `*.wasm` file directly. Determining which parser to use depends on the input filename, where the binary parser is used with `*.wasm` files and the wast parser is used for all other files. * wasm2js: Emit ESM imports/exports by default This commit alters the default behavior of `wasm2js` to emit an ESM by default, either importing items from the environment or exporting. Items like initialization of memory are also handled here. --- scripts/test/node-esm-loader.mjs | 32 ++++++++++++ scripts/test/shared.py | 2 +- scripts/test/spectest.js | 3 ++ scripts/test/support.py | 14 ++--- scripts/test/wasm2asm.py | 110 --------------------------------------- scripts/test/wasm2js.py | 110 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 117 deletions(-) create mode 100644 scripts/test/node-esm-loader.mjs create mode 100644 scripts/test/spectest.js delete mode 100755 scripts/test/wasm2asm.py create mode 100755 scripts/test/wasm2js.py (limited to 'scripts/test') diff --git a/scripts/test/node-esm-loader.mjs b/scripts/test/node-esm-loader.mjs new file mode 100644 index 000000000..73ff47800 --- /dev/null +++ b/scripts/test/node-esm-loader.mjs @@ -0,0 +1,32 @@ +// originally lifted from https://nodejs.org/api/esm.html + +import path from 'path'; +import process from 'process'; +import Module from 'module'; + +const builtins = Module.builtinModules; + +const baseURL = new URL('file://'); +baseURL.pathname = `${process.cwd()}/`; + +export function resolve(specifier, parentModuleURL = baseURL, defaultResolve) { + if (builtins.includes(specifier)) { + return { + url: specifier, + format: 'builtin' + }; + } + // Resolve the 'spectest' module to our special module which has some builtins + if (specifier == 'spectest') { + const resolved = new URL('./scripts/test/spectest.js', parentModuleURL); + return { + url: resolved.href, + format: 'esm' + }; + } + const resolved = new URL(specifier, parentModuleURL); + return { + url: resolved.href, + format: 'esm' + }; +} diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 309f3b59a..a7bdda085 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -166,7 +166,7 @@ WASM_OPT = [os.path.join(options.binaryen_bin, 'wasm-opt')] WASM_AS = [os.path.join(options.binaryen_bin, 'wasm-as')] WASM_DIS = [os.path.join(options.binaryen_bin, 'wasm-dis')] ASM2WASM = [os.path.join(options.binaryen_bin, 'asm2wasm')] -WASM2ASM = [os.path.join(options.binaryen_bin, 'wasm2asm')] +WASM2JS = [os.path.join(options.binaryen_bin, 'wasm2js')] WASM_CTOR_EVAL = [os.path.join(options.binaryen_bin, 'wasm-ctor-eval')] WASM_SHELL = [os.path.join(options.binaryen_bin, 'wasm-shell')] WASM_MERGE = [os.path.join(options.binaryen_bin, 'wasm-merge')] diff --git a/scripts/test/spectest.js b/scripts/test/spectest.js new file mode 100644 index 000000000..0756209b6 --- /dev/null +++ b/scripts/test/spectest.js @@ -0,0 +1,3 @@ +export function print(...args) { + console.log(...args); +} diff --git a/scripts/test/support.py b/scripts/test/support.py index d04a85c59..5d03419b9 100644 --- a/scripts/test/support.py +++ b/scripts/test/support.py @@ -147,7 +147,7 @@ def split_wast(wastFile): def run_command(cmd, expected_status=0, stderr=None, - expected_err=None, err_contains=False): + expected_err=None, err_contains=False, err_ignore=None): if expected_err is not None: assert stderr == subprocess.PIPE or stderr is None,\ "Can't redirect stderr if using expected_err" @@ -158,11 +158,13 @@ def run_command(cmd, expected_status=0, stderr=None, code = proc.returncode if expected_status is not None and code != expected_status: raise Exception(('run_command failed (%s)' % code, out + str(err or ''))) - err_correct = expected_err is None or \ - (expected_err in err if err_contains else expected_err == err) - if not err_correct: - raise Exception(('run_command unexpected stderr', - "expected '%s', actual '%s'" % (expected_err, err))) + if expected_err is not None: + if err_ignore is not None: + err = "\n".join([line for line in err.split('\n') if err_ignore not in line]) + err_correct = expected_err in err if err_contains else expected_err == err + if not err_correct: + raise Exception(('run_command unexpected stderr', + "expected '%s', actual '%s'" % (expected_err, err))) return out diff --git a/scripts/test/wasm2asm.py b/scripts/test/wasm2asm.py deleted file mode 100755 index 41fdaf9b7..000000000 --- a/scripts/test/wasm2asm.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2016 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 - -from support import run_command -from shared import ( - WASM2ASM, MOZJS, NODEJS, fail_if_not_identical, options, tests, - fail_if_not_identical_to_file -) - -# tests with i64s, invokes, etc. -spec_dir = os.path.join(options.binaryen_test, 'spec') -spec_tests = [os.path.join(spec_dir, t) - for t in sorted(os.listdir(spec_dir)) - if '.fail' not in t] -wasm2asm_dir = os.path.join(options.binaryen_test, 'wasm2asm') -extra_wasm2asm_tests = [os.path.join(wasm2asm_dir, t) for t in - sorted(os.listdir(wasm2asm_dir))] -assert_tests = ['wasm2asm.wast.asserts'] - - -def test_wasm2asm_output(): - for wasm in tests + spec_tests + extra_wasm2asm_tests: - if not wasm.endswith('.wast'): - continue - - asm = os.path.basename(wasm).replace('.wast', '.2asm.js') - expected_file = os.path.join(wasm2asm_dir, asm) - - if not os.path.exists(expected_file): - continue - - print '..', wasm - - cmd = WASM2ASM + [os.path.join(options.binaryen_test, wasm)] - out = run_command(cmd) - fail_if_not_identical_to_file(out, expected_file) - - if not NODEJS and not MOZJS: - print 'No JS interpreters. Skipping spec tests.' - continue - - open('a.2asm.js', 'w').write(out) - - cmd += ['--allow-asserts'] - out = run_command(cmd) - - open('a.2asm.asserts.js', 'w').write(out) - - # verify asm.js is valid js - if NODEJS: - out = run_command([NODEJS, 'a.2asm.js']) - fail_if_not_identical(out, '') - out = run_command([NODEJS, 'a.2asm.asserts.js'], expected_err='') - fail_if_not_identical(out, '') - - if MOZJS: - # verify asm.js validates, if this is asm.js code (we emit - # almost-asm instead when we need to) - if 'use asm' in open('a.2asm.js').read(): - # check only subset of err because mozjs emits timing info - out = run_command([MOZJS, '-w', 'a.2asm.js'], - expected_err='Successfully compiled asm.js code', - err_contains=True) - fail_if_not_identical(out, '') - out = run_command([MOZJS, 'a.2asm.asserts.js'], expected_err='') - fail_if_not_identical(out, '') - - -def test_asserts_output(): - for wasm in assert_tests: - print '..', wasm - - asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') - traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') - asserts_expected_file = os.path.join(options.binaryen_test, asserts) - traps_expected_file = os.path.join(options.binaryen_test, traps) - - wasm = os.path.join(wasm2asm_dir, wasm) - cmd = WASM2ASM + [wasm, '--allow-asserts'] - out = run_command(cmd) - fail_if_not_identical_to_file(out, asserts_expected_file) - - cmd += ['--pedantic'] - out = run_command(cmd) - fail_if_not_identical_to_file(out, traps_expected_file) - - -def test_wasm2asm(): - print '\n[ checking wasm2asm testcases... ]\n' - test_wasm2asm_output() - test_asserts_output() - - -if __name__ == "__main__": - test_wasm2asm() diff --git a/scripts/test/wasm2js.py b/scripts/test/wasm2js.py new file mode 100755 index 000000000..9a72895c1 --- /dev/null +++ b/scripts/test/wasm2js.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# Copyright 2016 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 + +from support import run_command +from shared import ( + WASM2JS, MOZJS, NODEJS, fail_if_not_identical, options, tests, + fail_if_not_identical_to_file +) + +# tests with i64s, invokes, etc. +spec_dir = os.path.join(options.binaryen_test, 'spec') +spec_tests = [os.path.join(spec_dir, t) + for t in sorted(os.listdir(spec_dir)) + if '.fail' not in t] +wasm2js_dir = os.path.join(options.binaryen_test, 'wasm2js') +extra_wasm2js_tests = [os.path.join(wasm2js_dir, t) for t in + sorted(os.listdir(wasm2js_dir))] +assert_tests = ['wasm2js.wast.asserts'] +# These tests exercise functionality not supported by wasm2js +wasm2js_blacklist = ['empty_imported_table.wast'] + + +def test_wasm2js_output(): + for wasm in tests + spec_tests + extra_wasm2js_tests: + if not wasm.endswith('.wast'): + continue + basename = os.path.basename(wasm) + if basename in wasm2js_blacklist: + continue + + asm = basename.replace('.wast', '.2asm.js') + expected_file = os.path.join(wasm2js_dir, asm) + + if not os.path.exists(expected_file): + continue + + print '..', wasm + + cmd = WASM2JS + [os.path.join(options.binaryen_test, wasm)] + out = run_command(cmd) + fail_if_not_identical_to_file(out, expected_file) + + if not NODEJS and not MOZJS: + print 'No JS interpreters. Skipping spec tests.' + continue + + open('a.2asm.mjs', 'w').write(out) + + cmd += ['--allow-asserts'] + out = run_command(cmd) + + open('a.2asm.asserts.mjs', 'w').write(out) + + # verify asm.js is valid js, note that we're using --experimental-modules + # to enable ESM syntax and we're also passing a custom loader to handle the + # `spectest` module in our tests. + if NODEJS: + node = [NODEJS, '--experimental-modules', '--loader', './scripts/test/node-esm-loader.mjs'] + cmd = node[:] + cmd.append('a.2asm.mjs') + out = run_command(cmd) + fail_if_not_identical(out, '') + cmd = node[:] + cmd.append('a.2asm.asserts.mjs') + out = run_command(cmd, expected_err='', err_ignore='The ESM module loader is experimental') + fail_if_not_identical(out, '') + + +def test_asserts_output(): + for wasm in assert_tests: + print '..', wasm + + asserts = os.path.basename(wasm).replace('.wast.asserts', '.asserts.js') + traps = os.path.basename(wasm).replace('.wast.asserts', '.traps.js') + asserts_expected_file = os.path.join(options.binaryen_test, asserts) + traps_expected_file = os.path.join(options.binaryen_test, traps) + + wasm = os.path.join(wasm2js_dir, wasm) + cmd = WASM2JS + [wasm, '--allow-asserts'] + out = run_command(cmd) + fail_if_not_identical_to_file(out, asserts_expected_file) + + cmd += ['--pedantic'] + out = run_command(cmd) + fail_if_not_identical_to_file(out, traps_expected_file) + + +def test_wasm2js(): + print '\n[ checking wasm2js testcases... ]\n' + test_wasm2js_output() + test_asserts_output() + + +if __name__ == "__main__": + test_wasm2js() -- cgit v1.2.3