summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/clean_c_api_trace.py23
-rwxr-xr-xscripts/embedwast.py6
-rw-r--r--scripts/fuzz_opt.py788
-rwxr-xr-xscripts/fuzz_passes.py156
-rwxr-xr-xscripts/fuzz_passes_wast.py148
-rwxr-xr-xscripts/fuzz_relooper.py272
-rwxr-xr-xscripts/gen-s-parser.py212
-rwxr-xr-xscripts/process_optimize_instructions.py2
-rwxr-xr-xscripts/storage.py48
-rw-r--r--scripts/strip_local_names.py13
-rwxr-xr-xscripts/test/asm2wasm.py254
-rwxr-xr-xscripts/test/binaryenjs.py88
-rwxr-xr-xscripts/test/generate_lld_tests.py106
-rwxr-xr-xscripts/test/lld.py112
-rw-r--r--scripts/test/shared.py553
-rw-r--r--scripts/test/support.py280
-rwxr-xr-xscripts/test/wasm2js.py220
17 files changed, 1640 insertions, 1641 deletions
diff --git a/scripts/clean_c_api_trace.py b/scripts/clean_c_api_trace.py
index e2bfa30ab..006a0ce4f 100755
--- a/scripts/clean_c_api_trace.py
+++ b/scripts/clean_c_api_trace.py
@@ -14,9 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-'''
-Cleans up output from the C api, makes a runnable C file
-'''
+"""Cleans up output from the C api, makes a runnable C file
+"""
import sys
@@ -24,14 +23,14 @@ trace = open(sys.argv[1]).read()
start = trace.find('// beginning a Binaryen API trace')
if start >= 0:
- trace = trace[start:]
+ trace = trace[start:]
- while 1:
- start = trace.find('\n(')
- if start < 0:
- break
- end = trace.find('\n)', start + 1)
- assert end > 0
- trace = trace[:start] + trace[end + 2:]
+ while 1:
+ start = trace.find('\n(')
+ if start < 0:
+ break
+ end = trace.find('\n)', start + 1)
+ assert end > 0
+ trace = trace[:start] + trace[end + 2:]
- print(trace)
+ print(trace)
diff --git a/scripts/embedwast.py b/scripts/embedwast.py
index 6d97b21e9..804be4211 100755
--- a/scripts/embedwast.py
+++ b/scripts/embedwast.py
@@ -20,7 +20,7 @@ input_file = sys.argv[1]
output_file = sys.argv[2]
with open(input_file) as f:
- wast = f.read()
+ wast = f.read()
output = """\
// Automatically generated by embedwast.py
@@ -31,7 +31,7 @@ static const char theModule[%d] = {
""" % (len(wast) + 1)
for c in wast:
- output += str(ord(c)) + ', '
+ output += str(ord(c)) + ', '
output += '''0
};
@@ -42,4 +42,4 @@ const char* IntrinsicsModuleWast = theModule;
'''
with open(output_file, 'w') as f:
- f.write(output)
+ f.write(output)
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index 9af65b09d..4591b4150 100644
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -47,49 +47,49 @@ LOG_LIMIT = 125
def in_binaryen(*args):
- return os.path.join(options.binaryen_root, *args)
+ return os.path.join(options.binaryen_root, *args)
def in_bin(tool):
- return os.path.join(options.binaryen_root, 'bin', tool)
+ return os.path.join(options.binaryen_root, 'bin', tool)
def random_size():
- return random.randint(1, INPUT_SIZE_LIMIT)
+ return random.randint(1, INPUT_SIZE_LIMIT)
def run(cmd):
- print(' '.join(cmd)[:LOG_LIMIT])
- return subprocess.check_output(cmd)
+ print(' '.join(cmd)[:LOG_LIMIT])
+ return subprocess.check_output(cmd)
def run_unchecked(cmd):
- print(' '.join(cmd)[:LOG_LIMIT])
- return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
+ print(' '.join(cmd)[:LOG_LIMIT])
+ return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
def randomize_pass_debug():
- if random.random() < 0.125:
- print('[pass-debug]')
- os.environ['BINARYEN_PASS_DEBUG'] = '1'
- else:
- os.environ['BINARYEN_PASS_DEBUG'] = '0'
- del os.environ['BINARYEN_PASS_DEBUG']
+ if random.random() < 0.125:
+ print('[pass-debug]')
+ os.environ['BINARYEN_PASS_DEBUG'] = '1'
+ else:
+ os.environ['BINARYEN_PASS_DEBUG'] = '0'
+ del os.environ['BINARYEN_PASS_DEBUG']
def randomize_feature_opts():
- global FEATURE_OPTS
- FEATURE_OPTS = CONSTANT_FEATURE_OPTS[:]
- # half the time apply all the possible opts. this lets all test runners work at max
- # capacity at least half the time, as otherwise if they need almost all the opts, the
- # chance of getting them is exponentially small.
- if random.random() < 0.5:
- FEATURE_OPTS += POSSIBLE_FEATURE_OPTS
- else:
- for possible in POSSIBLE_FEATURE_OPTS:
- if random.random() < 0.5:
- FEATURE_OPTS.append(possible)
- print('feature opts:', ' '.join(FEATURE_OPTS))
+ global FEATURE_OPTS
+ FEATURE_OPTS = CONSTANT_FEATURE_OPTS[:]
+ # half the time apply all the possible opts. this lets all test runners work at max
+ # capacity at least half the time, as otherwise if they need almost all the opts, the
+ # chance of getting them is exponentially small.
+ if random.random() < 0.5:
+ FEATURE_OPTS += POSSIBLE_FEATURE_OPTS
+ else:
+ for possible in POSSIBLE_FEATURE_OPTS:
+ if random.random() < 0.5:
+ FEATURE_OPTS.append(possible)
+ print('feature opts:', ' '.join(FEATURE_OPTS))
# Test outputs we want to ignore are marked this way.
@@ -97,59 +97,59 @@ IGNORE = '[binaryen-fuzzer-ignore]'
def compare(x, y, context):
- if x != y and x != IGNORE and y != IGNORE:
- message = ''.join([a + '\n' for a in difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile='expected', tofile='actual')])
- raise Exception(context + " comparison error, expected to have '%s' == '%s', diff:\n\n%s" % (
- x, y,
- message
- ))
+ if x != y and x != IGNORE and y != IGNORE:
+ message = ''.join([a + '\n' for a in difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile='expected', tofile='actual')])
+ raise Exception(context + " comparison error, expected to have '%s' == '%s', diff:\n\n%s" % (
+ x, y,
+ message
+ ))
def fix_output(out):
- # large doubles may print slightly different on different VMs
- def fix_double(x):
- x = x.group(1)
- if 'nan' in x or 'NaN' in x:
- x = 'nan'
- else:
- x = x.replace('Infinity', 'inf')
- x = str(float(x))
- return 'f64.const ' + x
- out = re.sub(r'f64\.const (-?[nanN:abcdefxIity\d+-.]+)', fix_double, out)
+ # large doubles may print slightly different on different VMs
+ def fix_double(x):
+ x = x.group(1)
+ if 'nan' in x or 'NaN' in x:
+ x = 'nan'
+ else:
+ x = x.replace('Infinity', 'inf')
+ x = str(float(x))
+ return 'f64.const ' + x
+ out = re.sub(r'f64\.const (-?[nanN:abcdefxIity\d+-.]+)', fix_double, out)
- # mark traps from wasm-opt as exceptions, even though they didn't run in a vm
- out = out.replace('[trap ', 'exception: [trap ')
+ # mark traps from wasm-opt as exceptions, even though they didn't run in a vm
+ out = out.replace('[trap ', 'exception: [trap ')
- # exceptions may differ when optimizing, but an exception should occur. so ignore their types
- # also js engines print them out slightly differently
- return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.splitlines()))
+ # exceptions may differ when optimizing, but an exception should occur. so ignore their types
+ # also js engines print them out slightly differently
+ return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.splitlines()))
def fix_spec_output(out):
- out = fix_output(out)
- # spec shows a pointer when it traps, remove that
- out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.splitlines()))
- # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up
- out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.splitlines()))
- return out
+ out = fix_output(out)
+ # spec shows a pointer when it traps, remove that
+ out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.splitlines()))
+ # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up
+ out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.splitlines()))
+ return out
def run_vm(cmd):
- # ignore some vm assertions, if bugs have already been filed
- known_issues = [
- 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes
- 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
- 'liftoff-assembler.cc, line 245\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
- 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632
- ]
- try:
- return run(cmd)
- except subprocess.CalledProcessError:
- output = run_unchecked(cmd)
- for issue in known_issues:
- if issue in output:
- return IGNORE
- raise
+ # ignore some vm assertions, if bugs have already been filed
+ known_issues = [
+ 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes
+ 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
+ 'liftoff-assembler.cc, line 245\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631
+ 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632
+ ]
+ try:
+ return run(cmd)
+ except subprocess.CalledProcessError:
+ output = run_unchecked(cmd)
+ for issue in known_issues:
+ if issue in output:
+ return IGNORE
+ raise
MAX_INTERPRETER_ENV_VAR = 'BINARYEN_MAX_INTERPRETER_DEPTH'
@@ -157,101 +157,101 @@ MAX_INTERPRETER_DEPTH = 1000
def run_bynterp(wasm, args):
- # increase the interpreter stack depth, to test more things
- os.environ[MAX_INTERPRETER_ENV_VAR] = str(MAX_INTERPRETER_DEPTH)
- try:
- return run_vm([in_bin('wasm-opt'), wasm] + FEATURE_OPTS + args)
- finally:
- del os.environ['BINARYEN_MAX_INTERPRETER_DEPTH']
+ # increase the interpreter stack depth, to test more things
+ os.environ[MAX_INTERPRETER_ENV_VAR] = str(MAX_INTERPRETER_DEPTH)
+ try:
+ return run_vm([in_bin('wasm-opt'), wasm] + FEATURE_OPTS + args)
+ finally:
+ del os.environ['BINARYEN_MAX_INTERPRETER_DEPTH']
def run_d8(wasm):
- return run_vm(['d8'] + V8_OPTS + [in_binaryen('scripts', 'fuzz_shell.js'), '--', wasm])
+ return run_vm(['d8'] + V8_OPTS + [in_binaryen('scripts', 'fuzz_shell.js'), '--', wasm])
# There are two types of test case handlers:
-# * get_commands() users: these return a list of commands to run (for example, "run this wasm-opt
-# command, then that one"). The calling code gets and runs those commands on the test wasm
-# file, and has enough information and control to be able to perform auto-reduction of any
-# bugs found.
-# * Totally generic: These receive the input pattern, a wasm generated from it, and a wasm
-# optimized from that, and can then do anything it wants with those.
+# * get_commands() users: these return a list of commands to run (for example, "run this wasm-opt
+# command, then that one"). The calling code gets and runs those commands on the test wasm
+# file, and has enough information and control to be able to perform auto-reduction of any
+# bugs found.
+# * Totally generic: These receive the input pattern, a wasm generated from it, and a wasm
+# optimized from that, and can then do anything it wants with those.
class TestCaseHandler:
- # If the core handle_pair() method is not overridden, it calls handle_single()
- # on each of the pair. That is useful if you just want the two wasms, and don't
- # care about their relationship
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- self.handle(before_wasm)
- self.handle(after_wasm)
+ # If the core handle_pair() method is not overridden, it calls handle_single()
+ # on each of the pair. That is useful if you just want the two wasms, and don't
+ # care about their relationship
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ self.handle(before_wasm)
+ self.handle(after_wasm)
- def can_run_on_feature_opts(self, feature_opts):
- return True
+ def can_run_on_feature_opts(self, feature_opts):
+ return True
# Run VMs and compare results
class CompareVMs(TestCaseHandler):
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- run([in_bin('wasm-opt'), before_wasm, '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat'] + FEATURE_OPTS)
- run([in_bin('wasm-opt'), after_wasm, '--emit-js-wrapper=b.js', '--emit-spec-wrapper=b.wat'] + FEATURE_OPTS)
- before = self.run_vms('a.js', before_wasm)
- after = self.run_vms('b.js', after_wasm)
- self.compare_vs(before, after)
-
- def run_vms(self, js, wasm):
- results = []
- results.append(fix_output(run_bynterp(wasm, ['--fuzz-exec-before'])))
- results.append(fix_output(run_vm(['d8', js] + V8_OPTS + ['--', wasm])))
-
- # append to add results from VMs
- # results += [fix_output(run_vm(['d8', js] + V8_OPTS + ['--', wasm]))]
- # results += [fix_output(run_vm([os.path.expanduser('~/.jsvu/jsc'), js, '--', wasm]))]
- # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically
- # run(['../spec/interpreter/wasm', wasm])
- # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', wasm, '-e', open(prefix + 'wat').read()]))]
-
- if len(results) == 0:
- results = [0]
-
- # NaNs are a source of nondeterminism between VMs; don't compare them
- if not NANS:
- first = results[0]
- for i in range(len(results)):
- compare(first, results[i], 'CompareVMs at ' + str(i))
-
- return results
-
- def compare_vs(self, before, after):
- for i in range(len(before)):
- compare(before[i], after[i], 'CompareVMs at ' + str(i))
- # with nans, we can only compare the binaryen interpreter to itself
- if NANS:
- break
-
- def can_run_on_feature_opts(self, feature_opts):
- return all([x in feature_opts for x in ['--disable-simd']])
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ run([in_bin('wasm-opt'), before_wasm, '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat'] + FEATURE_OPTS)
+ run([in_bin('wasm-opt'), after_wasm, '--emit-js-wrapper=b.js', '--emit-spec-wrapper=b.wat'] + FEATURE_OPTS)
+ before = self.run_vms('a.js', before_wasm)
+ after = self.run_vms('b.js', after_wasm)
+ self.compare_vs(before, after)
+
+ def run_vms(self, js, wasm):
+ results = []
+ results.append(fix_output(run_bynterp(wasm, ['--fuzz-exec-before'])))
+ results.append(fix_output(run_vm(['d8', js] + V8_OPTS + ['--', wasm])))
+
+ # append to add results from VMs
+ # results += [fix_output(run_vm(['d8', js] + V8_OPTS + ['--', wasm]))]
+ # results += [fix_output(run_vm([os.path.expanduser('~/.jsvu/jsc'), js, '--', wasm]))]
+ # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically
+ # run(['../spec/interpreter/wasm', wasm])
+ # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', wasm, '-e', open(prefix + 'wat').read()]))]
+
+ if len(results) == 0:
+ results = [0]
+
+ # NaNs are a source of nondeterminism between VMs; don't compare them
+ if not NANS:
+ first = results[0]
+ for i in range(len(results)):
+ compare(first, results[i], 'CompareVMs at ' + str(i))
+
+ return results
+
+ def compare_vs(self, before, after):
+ for i in range(len(before)):
+ compare(before[i], after[i], 'CompareVMs at ' + str(i))
+ # with nans, we can only compare the binaryen interpreter to itself
+ if NANS:
+ break
+
+ def can_run_on_feature_opts(self, feature_opts):
+ return all([x in feature_opts for x in ['--disable-simd']])
# Fuzz the interpreter with --fuzz-exec. This tests everything in a single command (no
# two separate binaries) so it's easy to reproduce.
class FuzzExec(TestCaseHandler):
- def get_commands(self, wasm, opts, random_seed):
- return [
- '%(MAX_INTERPRETER_ENV_VAR)s=%(MAX_INTERPRETER_DEPTH)d %(wasm_opt)s --fuzz-exec --fuzz-binary %(opts)s %(wasm)s' % {
- 'MAX_INTERPRETER_ENV_VAR': MAX_INTERPRETER_ENV_VAR,
- 'MAX_INTERPRETER_DEPTH': MAX_INTERPRETER_DEPTH,
- 'wasm_opt': in_bin('wasm-opt'),
- 'opts': ' '.join(opts),
- 'wasm': wasm
- }
- ]
+ def get_commands(self, wasm, opts, random_seed):
+ return [
+ '%(MAX_INTERPRETER_ENV_VAR)s=%(MAX_INTERPRETER_DEPTH)d %(wasm_opt)s --fuzz-exec --fuzz-binary %(opts)s %(wasm)s' % {
+ 'MAX_INTERPRETER_ENV_VAR': MAX_INTERPRETER_ENV_VAR,
+ 'MAX_INTERPRETER_DEPTH': MAX_INTERPRETER_DEPTH,
+ 'wasm_opt': in_bin('wasm-opt'),
+ 'opts': ' '.join(opts),
+ 'wasm': wasm
+ }
+ ]
# As FuzzExec, but without a separate invocation. This can find internal bugs with generating
# the IR (which might be worked around by writing it and then reading it).
class FuzzExecImmediately(TestCaseHandler):
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- # fuzz binaryen interpreter itself. separate invocation so result is easily reduceable
- run_bynterp(before_wasm, ['--fuzz-exec', '--fuzz-binary'] + opts)
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ # fuzz binaryen interpreter itself. separate invocation so result is easily reduceable
+ run_bynterp(before_wasm, ['--fuzz-exec', '--fuzz-binary'] + opts)
# Check for determinism - the same command must have the same output.
@@ -259,274 +259,274 @@ class FuzzExecImmediately(TestCaseHandler):
# for something that autoreduction won't help with anyhow (nondeterminism is very
# hard to reduce).
class CheckDeterminism(TestCaseHandler):
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- # check for determinism
- run([in_bin('wasm-opt'), before_wasm, '-o', 'b1.wasm'] + opts)
- run([in_bin('wasm-opt'), before_wasm, '-o', 'b2.wasm'] + opts)
- assert open('b1.wasm').read() == open('b2.wasm').read(), 'output must be deterministic'
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ # check for determinism
+ run([in_bin('wasm-opt'), before_wasm, '-o', 'b1.wasm'] + opts)
+ run([in_bin('wasm-opt'), before_wasm, '-o', 'b2.wasm'] + opts)
+ assert open('b1.wasm').read() == open('b2.wasm').read(), 'output must be deterministic'
class Wasm2JS(TestCaseHandler):
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- compare(self.run(before_wasm), self.run(after_wasm), 'Wasm2JS')
-
- def run(self, wasm):
- # TODO: wasm2js does not handle nans precisely, and does not
- # handle oob loads etc. with traps, should we use
- # FUZZ_OPTS += ['--no-fuzz-nans']
- # FUZZ_OPTS += ['--no-fuzz-oob']
- # ?
- wrapper = run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=/dev/stdout'] + FEATURE_OPTS)
- cmd = [in_bin('wasm2js'), wasm, '--emscripten']
- if random.random() < 0.5:
- cmd += ['-O']
- main = run(cmd + FEATURE_OPTS)
- with open(os.path.join(options.binaryen_root, 'scripts', 'wasm2js.js')) as f:
- glue = f.read()
- with open('js.js', 'w') as f:
- f.write(glue)
- f.write(main)
- f.write(wrapper)
- out = fix_output(run_vm([NODEJS, 'js.js', 'a.wasm']))
- if 'exception' in out:
- # exception, so ignoring - wasm2js does not have normal wasm trapping, so opts can eliminate a trap
- out = IGNORE
- return out
-
- def can_run_on_feature_opts(self, feature_opts):
- return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-threads', '--disable-bulk-memory', '--disable-nontrapping-float-to-int', '--disable-tail-call', '--disable-sign-ext']])
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ compare(self.run(before_wasm), self.run(after_wasm), 'Wasm2JS')
+
+ def run(self, wasm):
+ # TODO: wasm2js does not handle nans precisely, and does not
+ # handle oob loads etc. with traps, should we use
+ # FUZZ_OPTS += ['--no-fuzz-nans']
+ # FUZZ_OPTS += ['--no-fuzz-oob']
+ # ?
+ wrapper = run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=/dev/stdout'] + FEATURE_OPTS)
+ cmd = [in_bin('wasm2js'), wasm, '--emscripten']
+ if random.random() < 0.5:
+ cmd += ['-O']
+ main = run(cmd + FEATURE_OPTS)
+ with open(os.path.join(options.binaryen_root, 'scripts', 'wasm2js.js')) as f:
+ glue = f.read()
+ with open('js.js', 'w') as f:
+ f.write(glue)
+ f.write(main)
+ f.write(wrapper)
+ out = fix_output(run_vm([NODEJS, 'js.js', 'a.wasm']))
+ if 'exception' in out:
+ # exception, so ignoring - wasm2js does not have normal wasm trapping, so opts can eliminate a trap
+ out = IGNORE
+ return out
+
+ def can_run_on_feature_opts(self, feature_opts):
+ return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-threads', '--disable-bulk-memory', '--disable-nontrapping-float-to-int', '--disable-tail-call', '--disable-sign-ext']])
class Asyncify(TestCaseHandler):
- def handle_pair(self, input, before_wasm, after_wasm, opts):
- # we must legalize in order to run in JS
- run([in_bin('wasm-opt'), before_wasm, '--legalize-js-interface', '-o', before_wasm] + FEATURE_OPTS)
- run([in_bin('wasm-opt'), after_wasm, '--legalize-js-interface', '-o', after_wasm] + FEATURE_OPTS)
- before = fix_output(run_d8(before_wasm))
- after = fix_output(run_d8(after_wasm))
-
- # TODO: also something that actually does async sleeps in the code, say
- # on the logging commands?
- # --remove-unused-module-elements removes the asyncify intrinsics, which are not valid to call
-
- def do_asyncify(wasm):
- cmd = [in_bin('wasm-opt'), wasm, '--asyncify', '-o', 't.wasm']
- if random.random() < 0.5:
- cmd += ['--optimize-level=%d' % random.randint(1, 3)]
- if random.random() < 0.5:
- cmd += ['--shrink-level=%d' % random.randint(1, 2)]
- cmd += FEATURE_OPTS
- run(cmd)
- out = run_d8('t.wasm')
- # emit some status logging from asyncify
- print(out.splitlines()[-1])
- # ignore the output from the new asyncify API calls - the ones with asserts will trap, too
- for ignore in ['[fuzz-exec] calling $asyncify_start_unwind\nexception!\n',
- '[fuzz-exec] calling $asyncify_start_unwind\n',
- '[fuzz-exec] calling $asyncify_start_rewind\nexception!\n',
- '[fuzz-exec] calling $asyncify_start_rewind\n',
- '[fuzz-exec] calling $asyncify_stop_rewind\n',
- '[fuzz-exec] calling $asyncify_stop_unwind\n']:
- out = out.replace(ignore, '')
- out = '\n'.join([l for l in out.splitlines() if 'asyncify: ' not in l])
- return fix_output(out)
-
- before_asyncify = do_asyncify(before_wasm)
- after_asyncify = do_asyncify(after_wasm)
-
- compare(before, after, 'Asyncify (before/after)')
- compare(before, before_asyncify, 'Asyncify (before/before_asyncify)')
- compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')
-
- def can_run_on_feature_opts(self, feature_opts):
- return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call']])
+ def handle_pair(self, input, before_wasm, after_wasm, opts):
+ # we must legalize in order to run in JS
+ run([in_bin('wasm-opt'), before_wasm, '--legalize-js-interface', '-o', before_wasm] + FEATURE_OPTS)
+ run([in_bin('wasm-opt'), after_wasm, '--legalize-js-interface', '-o', after_wasm] + FEATURE_OPTS)
+ before = fix_output(run_d8(before_wasm))
+ after = fix_output(run_d8(after_wasm))
+
+ # TODO: also something that actually does async sleeps in the code, say
+ # on the logging commands?
+ # --remove-unused-module-elements removes the asyncify intrinsics, which are not valid to call
+
+ def do_asyncify(wasm):
+ cmd = [in_bin('wasm-opt'), wasm, '--asyncify', '-o', 't.wasm']
+ if random.random() < 0.5:
+ cmd += ['--optimize-level=%d' % random.randint(1, 3)]
+ if random.random() < 0.5:
+ cmd += ['--shrink-level=%d' % random.randint(1, 2)]
+ cmd += FEATURE_OPTS
+ run(cmd)
+ out = run_d8('t.wasm')
+ # emit some status logging from asyncify
+ print(out.splitlines()[-1])
+ # ignore the output from the new asyncify API calls - the ones with asserts will trap, too
+ for ignore in ['[fuzz-exec] calling $asyncify_start_unwind\nexception!\n',
+ '[fuzz-exec] calling $asyncify_start_unwind\n',
+ '[fuzz-exec] calling $asyncify_start_rewind\nexception!\n',
+ '[fuzz-exec] calling $asyncify_start_rewind\n',
+ '[fuzz-exec] calling $asyncify_stop_rewind\n',
+ '[fuzz-exec] calling $asyncify_stop_unwind\n']:
+ out = out.replace(ignore, '')
+ out = '\n'.join([l for l in out.splitlines() if 'asyncify: ' not in l])
+ return fix_output(out)
+
+ before_asyncify = do_asyncify(before_wasm)
+ after_asyncify = do_asyncify(after_wasm)
+
+ compare(before, after, 'Asyncify (before/after)')
+ compare(before, before_asyncify, 'Asyncify (before/before_asyncify)')
+ compare(before, after_asyncify, 'Asyncify (before/after_asyncify)')
+
+ def can_run_on_feature_opts(self, feature_opts):
+ return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call']])
# The global list of all test case handlers
testcase_handlers = [
- FuzzExec(),
- CompareVMs(),
- CheckDeterminism(),
- Wasm2JS(),
- Asyncify(),
- FuzzExecImmediately(),
+ FuzzExec(),
+ CompareVMs(),
+ CheckDeterminism(),
+ Wasm2JS(),
+ Asyncify(),
+ FuzzExecImmediately(),
]
# Do one test, given an input file for -ttf and some optimizations to run
def test_one(random_input, opts):
- randomize_pass_debug()
- randomize_feature_opts()
-
- run([in_bin('wasm-opt'), random_input, '-ttf', '-o', 'a.wasm'] + FUZZ_OPTS + FEATURE_OPTS)
- wasm_size = os.stat('a.wasm').st_size
- bytes = wasm_size
- print('pre wasm size:', wasm_size)
-
- # first, run all handlers that use get_commands(). those don't need the second wasm in the
- # pair, since they all they do is return their commands, and expect us to run them, and
- # those commands do the actual testing, by operating on the original input wasm file. by
- # fuzzing the get_commands() ones first we can find bugs in creating the second wasm (that
- # has the opts run on it) before we try to create it later down for the passes that
- # expect to get it as one of their inputs.
- for testcase_handler in testcase_handlers:
- if testcase_handler.can_run_on_feature_opts(FEATURE_OPTS):
- if hasattr(testcase_handler, 'get_commands'):
- print('running testcase handler:', testcase_handler.__class__.__name__)
- # if the testcase handler supports giving us a list of commands, then we can get those commands
- # and use them to do useful things like automatic reduction. in this case we give it the input
- # wasm plus opts and a random seed (if it needs any internal randomness; we want to have the same
- # value there if we reduce).
- random_seed = random.random()
-
- # gets commands from the handler, for a given set of optimizations. this is all the commands
- # needed to run the testing that that handler wants to do.
- def get_commands(opts):
- return testcase_handler.get_commands(wasm='a.wasm', opts=opts + FUZZ_OPTS + FEATURE_OPTS, random_seed=random_seed)
-
- def write_commands_and_test(opts):
- commands = get_commands(opts)
- write_commands(commands, 't.sh')
- subprocess.check_call(['bash', 't.sh'])
-
- try:
- write_commands_and_test(opts)
- except subprocess.CalledProcessError:
- print('')
- print('====================')
- print('Found a problem! See "t.sh" for the commands, and "input.wasm" for the input. Auto-reducing to "reduced.wasm" and "tt.sh"...')
- print('====================')
- print('')
- # first, reduce the fuzz opts: keep removing until we can't
- while 1:
- reduced = False
- for i in range(len(opts)):
- # some opts can't be removed, like --flatten --dfo requires flatten
- if opts[i] == '--flatten':
- if i != len(opts) - 1 and opts[i + 1] in ('--dfo', '--local-cse', '--rereloop'):
- continue
- shorter = opts[:i] + opts[i + 1:]
- try:
- write_commands_and_test(shorter)
- except subprocess.CalledProcessError:
- # great, the shorter one is good as well
- opts = shorter
- print('reduced opts to ' + ' '.join(opts))
- reduced = True
- break
- if not reduced:
- break
- # second, reduce the wasm
- # copy a.wasm to a safe place as the reducer will use the commands on new inputs, and the commands work on a.wasm
- shutil.copyfile('a.wasm', 'input.wasm')
- # add a command to verify the input. this lets the reducer see that it is indeed working on the input correctly
- commands = [in_bin('wasm-opt') + ' -all a.wasm'] + get_commands(opts)
- write_commands(commands, 'tt.sh')
- # reduce the input to something smaller with the same behavior on the script
- subprocess.check_call([in_bin('wasm-reduce'), 'input.wasm', '--command=bash tt.sh', '-t', 'a.wasm', '-w', 'reduced.wasm'])
- print('Finished reduction. See "tt.sh" and "reduced.wasm".')
- sys.exit(1)
- print('')
-
- # created a second wasm for handlers that want to look at pairs.
- run([in_bin('wasm-opt'), 'a.wasm', '-o', 'b.wasm'] + opts + FUZZ_OPTS + FEATURE_OPTS)
- wasm_size = os.stat('b.wasm').st_size
- bytes += wasm_size
- print('post wasm size:', wasm_size)
-
- for testcase_handler in testcase_handlers:
- if testcase_handler.can_run_on_feature_opts(FEATURE_OPTS):
- if not hasattr(testcase_handler, 'get_commands'):
- print('running testcase handler:', testcase_handler.__class__.__name__)
- # let the testcase handler handle this testcase however it wants. in this case we give it
- # the input and both wasms.
- testcase_handler.handle_pair(input=random_input, before_wasm='a.wasm', after_wasm='b.wasm', opts=opts + FUZZ_OPTS + FEATURE_OPTS)
- print('')
-
- return bytes
+ randomize_pass_debug()
+ randomize_feature_opts()
+
+ run([in_bin('wasm-opt'), random_input, '-ttf', '-o', 'a.wasm'] + FUZZ_OPTS + FEATURE_OPTS)
+ wasm_size = os.stat('a.wasm').st_size
+ bytes = wasm_size
+ print('pre wasm size:', wasm_size)
+
+ # first, run all handlers that use get_commands(). those don't need the second wasm in the
+ # pair, since they all they do is return their commands, and expect us to run them, and
+ # those commands do the actual testing, by operating on the original input wasm file. by
+ # fuzzing the get_commands() ones first we can find bugs in creating the second wasm (that
+ # has the opts run on it) before we try to create it later down for the passes that
+ # expect to get it as one of their inputs.
+ for testcase_handler in testcase_handlers:
+ if testcase_handler.can_run_on_feature_opts(FEATURE_OPTS):
+ if hasattr(testcase_handler, 'get_commands'):
+ print('running testcase handler:', testcase_handler.__class__.__name__)
+ # if the testcase handler supports giving us a list of commands, then we can get those commands
+ # and use them to do useful things like automatic reduction. in this case we give it the input
+ # wasm plus opts and a random seed (if it needs any internal randomness; we want to have the same
+ # value there if we reduce).
+ random_seed = random.random()
+
+ # gets commands from the handler, for a given set of optimizations. this is all the commands
+ # needed to run the testing that that handler wants to do.
+ def get_commands(opts):
+ return testcase_handler.get_commands(wasm='a.wasm', opts=opts + FUZZ_OPTS + FEATURE_OPTS, random_seed=random_seed)
+
+ def write_commands_and_test(opts):
+ commands = get_commands(opts)
+ write_commands(commands, 't.sh')
+ subprocess.check_call(['bash', 't.sh'])
+
+ try:
+ write_commands_and_test(opts)
+ except subprocess.CalledProcessError:
+ print('')
+ print('====================')
+ print('Found a problem! See "t.sh" for the commands, and "input.wasm" for the input. Auto-reducing to "reduced.wasm" and "tt.sh"...')
+ print('====================')
+ print('')
+ # first, reduce the fuzz opts: keep removing until we can't
+ while 1:
+ reduced = False
+ for i in range(len(opts)):
+ # some opts can't be removed, like --flatten --dfo requires flatten
+ if opts[i] == '--flatten':
+ if i != len(opts) - 1 and opts[i + 1] in ('--dfo', '--local-cse', '--rereloop'):
+ continue
+ shorter = opts[:i] + opts[i + 1:]
+ try:
+ write_commands_and_test(shorter)
+ except subprocess.CalledProcessError:
+ # great, the shorter one is good as well
+ opts = shorter
+ print('reduced opts to ' + ' '.join(opts))
+ reduced = True
+ break
+ if not reduced:
+ break
+ # second, reduce the wasm
+ # copy a.wasm to a safe place as the reducer will use the commands on new inputs, and the commands work on a.wasm
+ shutil.copyfile('a.wasm', 'input.wasm')
+ # add a command to verify the input. this lets the reducer see that it is indeed working on the input correctly
+ commands = [in_bin('wasm-opt') + ' -all a.wasm'] + get_commands(opts)
+ write_commands(commands, 'tt.sh')
+ # reduce the input to something smaller with the same behavior on the script
+ subprocess.check_call([in_bin('wasm-reduce'), 'input.wasm', '--command=bash tt.sh', '-t', 'a.wasm', '-w', 'reduced.wasm'])
+ print('Finished reduction. See "tt.sh" and "reduced.wasm".')
+ sys.exit(1)
+ print('')
+
+ # created a second wasm for handlers that want to look at pairs.
+ run([in_bin('wasm-opt'), 'a.wasm', '-o', 'b.wasm'] + opts + FUZZ_OPTS + FEATURE_OPTS)
+ wasm_size = os.stat('b.wasm').st_size
+ bytes += wasm_size
+ print('post wasm size:', wasm_size)
+
+ for testcase_handler in testcase_handlers:
+ if testcase_handler.can_run_on_feature_opts(FEATURE_OPTS):
+ if not hasattr(testcase_handler, 'get_commands'):
+ print('running testcase handler:', testcase_handler.__class__.__name__)
+ # let the testcase handler handle this testcase however it wants. in this case we give it
+ # the input and both wasms.
+ testcase_handler.handle_pair(input=random_input, before_wasm='a.wasm', after_wasm='b.wasm', opts=opts + FUZZ_OPTS + FEATURE_OPTS)
+ print('')
+
+ return bytes
def write_commands(commands, filename):
- with open(filename, 'w') as f:
- f.write('set -e\n')
- for command in commands:
- f.write('echo "%s"\n' % command)
- pre = 'BINARYEN_PASS_DEBUG=%s ' % (os.environ.get('BINARYEN_PASS_DEBUG') or '0')
- f.write(pre + command + ' &> /dev/null\n')
- f.write('echo "ok"\n')
+ with open(filename, 'w') as f:
+ f.write('set -e\n')
+ for command in commands:
+ f.write('echo "%s"\n' % command)
+ pre = 'BINARYEN_PASS_DEBUG=%s ' % (os.environ.get('BINARYEN_PASS_DEBUG') or '0')
+ f.write(pre + command + ' &> /dev/null\n')
+ f.write('echo "ok"\n')
# main
opt_choices = [
- [],
- ['-O1'], ['-O2'], ['-O3'], ['-O4'], ['-Os'], ['-Oz'],
- ["--coalesce-locals"],
- # XXX slow, non-default ["--coalesce-locals-learning"],
- ["--code-pushing"],
- ["--code-folding"],
- ["--const-hoisting"],
- ["--dae"],
- ["--dae-optimizing"],
- ["--dce"],
- ["--directize"],
- ["--flatten", "--dfo"],
- ["--duplicate-function-elimination"],
- ["--flatten"],
- # ["--fpcast-emu"], # removes indirect call failures as it makes them go through regardless of type
- ["--inlining"],
- ["--inlining-optimizing"],
- ["--flatten", "--local-cse"],
- ["--generate-stack-ir"],
- ["--licm"],
- ["--memory-packing"],
- ["--merge-blocks"],
- ['--merge-locals'],
- ["--optimize-instructions"],
- ["--optimize-stack-ir"],
- ["--generate-stack-ir", "--optimize-stack-ir"],
- ["--pick-load-signs"],
- ["--precompute"],
- ["--precompute-propagate"],
- ["--print"],
- ["--remove-unused-brs"],
- ["--remove-unused-nonfunction-module-elements"],
- ["--remove-unused-module-elements"],
- ["--remove-unused-names"],
- ["--reorder-functions"],
- ["--reorder-locals"],
- ["--flatten", "--rereloop"],
- ["--rse"],
- ["--simplify-locals"],
- ["--simplify-locals-nonesting"],
- ["--simplify-locals-nostructure"],
- ["--simplify-locals-notee"],
- ["--simplify-locals-notee-nostructure"],
- ["--ssa"],
- ["--vacuum"],
+ [],
+ ['-O1'], ['-O2'], ['-O3'], ['-O4'], ['-Os'], ['-Oz'],
+ ["--coalesce-locals"],
+ # XXX slow, non-default ["--coalesce-locals-learning"],
+ ["--code-pushing"],
+ ["--code-folding"],
+ ["--const-hoisting"],
+ ["--dae"],
+ ["--dae-optimizing"],
+ ["--dce"],
+ ["--directize"],
+ ["--flatten", "--dfo"],
+ ["--duplicate-function-elimination"],
+ ["--flatten"],
+ # ["--fpcast-emu"], # removes indirect call failures as it makes them go through regardless of type
+ ["--inlining"],
+ ["--inlining-optimizing"],
+ ["--flatten", "--local-cse"],
+ ["--generate-stack-ir"],
+ ["--licm"],
+ ["--memory-packing"],
+ ["--merge-blocks"],
+ ['--merge-locals'],
+ ["--optimize-instructions"],
+ ["--optimize-stack-ir"],
+ ["--generate-stack-ir", "--optimize-stack-ir"],
+ ["--pick-load-signs"],
+ ["--precompute"],
+ ["--precompute-propagate"],
+ ["--print"],
+ ["--remove-unused-brs"],
+ ["--remove-unused-nonfunction-module-elements"],
+ ["--remove-unused-module-elements"],
+ ["--remove-unused-names"],
+ ["--reorder-functions"],
+ ["--reorder-locals"],
+ ["--flatten", "--rereloop"],
+ ["--rse"],
+ ["--simplify-locals"],
+ ["--simplify-locals-nonesting"],
+ ["--simplify-locals-nostructure"],
+ ["--simplify-locals-notee"],
+ ["--simplify-locals-notee-nostructure"],
+ ["--ssa"],
+ ["--vacuum"],
]
def get_multiple_opt_choices():
- ret = []
- # core opts
- while 1:
- ret += random.choice(opt_choices)
- if len(ret) > 20 or random.random() < 0.3:
- break
- # modifiers (if not already implied by a -O? option)
- if '-O' not in str(ret):
- if random.random() < 0.5:
- ret += ['--optimize-level=' + str(random.randint(0, 3))]
- if random.random() < 0.5:
- ret += ['--shrink-level=' + str(random.randint(0, 3))]
- return ret
+ ret = []
+ # core opts
+ while 1:
+ ret += random.choice(opt_choices)
+ if len(ret) > 20 or random.random() < 0.3:
+ break
+ # modifiers (if not already implied by a -O? option)
+ if '-O' not in str(ret):
+ if random.random() < 0.5:
+ ret += ['--optimize-level=' + str(random.randint(0, 3))]
+ if random.random() < 0.5:
+ ret += ['--shrink-level=' + str(random.randint(0, 3))]
+ return ret
# main
if not NANS:
- FUZZ_OPTS += ['--no-fuzz-nans']
+ FUZZ_OPTS += ['--no-fuzz-nans']
# possible feature options that are sometimes passed to the tools. this
# contains the list of all possible feature flags we can disable (after
@@ -535,21 +535,21 @@ POSSIBLE_FEATURE_OPTS = run([in_bin('wasm-opt'), '--print-features', '-all', in_
print('POSSIBLE_FEATURE_OPTS:', POSSIBLE_FEATURE_OPTS)
if __name__ == '__main__':
- print('checking infinite random inputs')
- random.seed(time.time() * os.getpid())
- temp = 'input.dat'
- counter = 0
- bytes = 0 # wasm bytes tested
- start_time = time.time()
- while True:
- counter += 1
- f = open(temp, 'w')
- size = random_size()
- print('')
- print('ITERATION:', counter, 'size:', size, 'speed:', counter / (time.time() - start_time), 'iters/sec, ', bytes / (time.time() - start_time), 'bytes/sec\n')
- for x in range(size):
- f.write(chr(random.randint(0, 255)))
- f.close()
- opts = get_multiple_opt_choices()
- print('opts:', ' '.join(opts))
- bytes += test_one('input.dat', opts)
+ print('checking infinite random inputs')
+ random.seed(time.time() * os.getpid())
+ temp = 'input.dat'
+ counter = 0
+ bytes = 0 # wasm bytes tested
+ start_time = time.time()
+ while True:
+ counter += 1
+ f = open(temp, 'w')
+ size = random_size()
+ print('')
+ print('ITERATION:', counter, 'size:', size, 'speed:', counter / (time.time() - start_time), 'iters/sec, ', bytes / (time.time() - start_time), 'bytes/sec\n')
+ for x in range(size):
+ f.write(chr(random.randint(0, 255)))
+ f.close()
+ opts = get_multiple_opt_choices()
+ print('opts:', ' '.join(opts))
+ bytes += test_one('input.dat', opts)
diff --git a/scripts/fuzz_passes.py b/scripts/fuzz_passes.py
index 60ae95817..678e132c3 100755
--- a/scripts/fuzz_passes.py
+++ b/scripts/fuzz_passes.py
@@ -58,90 +58,90 @@ args = sys.argv[2:]
def run():
- if os.path.exists(wast):
- print('>>> running using a wast of size', os.stat(wast).st_size)
- cmd = ['mozjs', base] + args
- try:
- return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
- except Exception as e:
- print(">>> !!! ", e, " !!!")
+ if os.path.exists(wast):
+ print('>>> running using a wast of size', os.stat(wast).st_size)
+ cmd = ['mozjs', base] + args
+ try:
+ return subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ except Exception as e:
+ print(">>> !!! ", e, " !!!")
original_wast = None
try:
- # get normal output
-
- normal = run()
- print('>>> normal output:\n', normal)
- assert normal, 'must be output'
-
- # ensure we actually use the wast
-
- original_wast = wast + '.original.wast'
- shutil.move(wast, original_wast)
- assert run() != normal, 'running without the wast must fail'
-
- # ensure a bad pass makes it fail
-
- def apply_passes(passes):
- wasm_opt = os.path.join('bin', 'wasm-opt')
- subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast])
+ # get normal output
+
+ normal = run()
+ print('>>> normal output:\n', normal)
+ assert normal, 'must be output'
+
+ # ensure we actually use the wast
+
+ original_wast = wast + '.original.wast'
+ shutil.move(wast, original_wast)
+ assert run() != normal, 'running without the wast must fail'
+
+ # ensure a bad pass makes it fail
+
+ def apply_passes(passes):
+ wasm_opt = os.path.join('bin', 'wasm-opt')
+ subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast])
+
+ apply_passes(['--remove-imports'])
+ assert run() != normal, 'running after a breaking pass must fail'
+
+ # loop, looking for failures
+
+ def simplify(passes):
+ # passes is known to fail, try to simplify down by removing
+ more = True
+ while more:
+ more = False
+ print('>>> trying to reduce:', ' '.join(passes), ' [' + str(len(passes)) + ']')
+ for i in range(len(passes)):
+ smaller = passes[:i] + passes[i + 1:]
+ print('>>>>>> try to reduce to:', ' '.join(smaller), ' [' + str(len(smaller)) + ']')
+ try:
+ apply_passes(smaller)
+ assert run() == normal
+ except Exception:
+ # this failed too, so it's a good reduction
+ passes = smaller
+ print('>>> reduction successful')
+ more = True
+ break
+ print('>>> reduced to:', ' '.join(passes))
+
+ tested = set()
+
+ def pick_passes():
+ ret = []
+ while 1:
+ str_ret = str(ret)
+ if random.random() < 0.1 and str_ret not in tested:
+ tested.add(str_ret)
+ return ret
+ ret.append('--' + random.choice(PASSES))
+
+ counter = 0
- apply_passes(['--remove-imports'])
- assert run() != normal, 'running after a breaking pass must fail'
-
- # loop, looking for failures
-
- def simplify(passes):
- # passes is known to fail, try to simplify down by removing
- more = True
- while more:
- more = False
- print('>>> trying to reduce:', ' '.join(passes), ' [' + str(len(passes)) + ']')
- for i in range(len(passes)):
- smaller = passes[:i] + passes[i + 1:]
- print('>>>>>> try to reduce to:', ' '.join(smaller), ' [' + str(len(smaller)) + ']')
- try:
- apply_passes(smaller)
- assert run() == normal
- except Exception:
- # this failed too, so it's a good reduction
- passes = smaller
- print('>>> reduction successful')
- more = True
- break
- print('>>> reduced to:', ' '.join(passes))
-
- tested = set()
-
- def pick_passes():
- ret = []
while 1:
- str_ret = str(ret)
- if random.random() < 0.1 and str_ret not in tested:
- tested.add(str_ret)
- return ret
- ret.append('--' + random.choice(PASSES))
-
- counter = 0
-
- while 1:
- passes = pick_passes()
- print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
- counter += 1
- try:
- apply_passes(passes)
- except Exception as e:
- print(e)
- simplify(passes)
- break
- seen = run()
- if seen != normal:
- print('>>> bad output:\n', seen)
- simplify(passes)
- break
+ passes = pick_passes()
+ print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
+ counter += 1
+ try:
+ apply_passes(passes)
+ except Exception as e:
+ print(e)
+ simplify(passes)
+ break
+ seen = run()
+ if seen != normal:
+ print('>>> bad output:\n', seen)
+ simplify(passes)
+ break
finally:
- if original_wast:
- shutil.move(original_wast, wast)
+ if original_wast:
+ shutil.move(original_wast, wast)
diff --git a/scripts/fuzz_passes_wast.py b/scripts/fuzz_passes_wast.py
index 18506c377..0ef452c7d 100755
--- a/scripts/fuzz_passes_wast.py
+++ b/scripts/fuzz_passes_wast.py
@@ -54,86 +54,86 @@ args = sys.argv[2:]
def run():
- try:
- cmd = ['bin/wasm-opt', wast]
- print('run', cmd)
- subprocess.check_call(cmd, stderr=open('/dev/null'))
- except Exception as e:
- return ">>> !!! ", e, " !!!"
- return 'ok'
+ try:
+ cmd = ['bin/wasm-opt', wast]
+ print('run', cmd)
+ subprocess.check_call(cmd, stderr=open('/dev/null'))
+ except Exception as e:
+ return ">>> !!! ", e, " !!!"
+ return 'ok'
original_wast = None
try:
- # get normal output
-
- normal = run()
- print('>>> normal output:\n', normal)
- assert normal, 'must be output'
-
- # ensure we actually use the wast
-
- original_wast = wast + '.original.wast'
- shutil.move(wast, original_wast)
-
- def apply_passes(passes):
- wasm_opt = os.path.join('bin', 'wasm-opt')
- subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast],
- stderr=open('/dev/null'))
+ # get normal output
+
+ normal = run()
+ print('>>> normal output:\n', normal)
+ assert normal, 'must be output'
+
+ # ensure we actually use the wast
+
+ original_wast = wast + '.original.wast'
+ shutil.move(wast, original_wast)
+
+ def apply_passes(passes):
+ wasm_opt = os.path.join('bin', 'wasm-opt')
+ subprocess.check_call([wasm_opt, original_wast] + passes + ['-o', wast],
+ stderr=open('/dev/null'))
+
+ # loop, looking for failures
+
+ def simplify(passes):
+ # passes is known to fail, try to simplify down by removing
+ more = True
+ while more:
+ more = False
+ print('>>> trying to reduce:', ' '.join(passes), ' [' + str(len(passes)) + ']')
+ for i in range(len(passes)):
+ smaller = passes[:i] + passes[i + 1:]
+ print('>>>>>> try to reduce to:', ' '.join(smaller), ' [' + str(len(smaller)) + ']')
+ try:
+ apply_passes(smaller)
+ assert run() == normal
+ except Exception:
+ # this failed too, so it's a good reduction
+ passes = smaller
+ print('>>> reduction successful')
+ more = True
+ break
+ print('>>> reduced to:', ' '.join(passes))
+
+ tested = set()
+
+ def pick_passes():
+ # return '--waka'.split(' ')
+ ret = []
+ while 1:
+ str_ret = str(ret)
+ if random.random() < 0.5 and str_ret not in tested:
+ tested.add(str_ret)
+ return ret
+ ret.append('--' + random.choice(PASSES))
+
+ counter = 0
- # loop, looking for failures
-
- def simplify(passes):
- # passes is known to fail, try to simplify down by removing
- more = True
- while more:
- more = False
- print('>>> trying to reduce:', ' '.join(passes), ' [' + str(len(passes)) + ']')
- for i in range(len(passes)):
- smaller = passes[:i] + passes[i + 1:]
- print('>>>>>> try to reduce to:', ' '.join(smaller), ' [' + str(len(smaller)) + ']')
- try:
- apply_passes(smaller)
- assert run() == normal
- except Exception:
- # this failed too, so it's a good reduction
- passes = smaller
- print('>>> reduction successful')
- more = True
- break
- print('>>> reduced to:', ' '.join(passes))
-
- tested = set()
-
- def pick_passes():
- # return '--waka'.split(' ')
- ret = []
while 1:
- str_ret = str(ret)
- if random.random() < 0.5 and str_ret not in tested:
- tested.add(str_ret)
- return ret
- ret.append('--' + random.choice(PASSES))
-
- counter = 0
-
- while 1:
- passes = pick_passes()
- print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
- counter += 1
- try:
- apply_passes(passes)
- except Exception as e:
- print(e)
- simplify(passes)
- break
- seen = run()
- if seen != normal:
- print('>>> bad output:\n', seen)
- simplify(passes)
- break
+ passes = pick_passes()
+ print('>>> [' + str(counter) + '] testing:', ' '.join(passes))
+ counter += 1
+ try:
+ apply_passes(passes)
+ except Exception as e:
+ print(e)
+ simplify(passes)
+ break
+ seen = run()
+ if seen != normal:
+ print('>>> bad output:\n', seen)
+ simplify(passes)
+ break
finally:
- if original_wast:
- shutil.move(original_wast, wast)
+ if original_wast:
+ shutil.move(original_wast, wast)
diff --git a/scripts/fuzz_relooper.py b/scripts/fuzz_relooper.py
index 359b0fa90..badd939a6 100755
--- a/scripts/fuzz_relooper.py
+++ b/scripts/fuzz_relooper.py
@@ -6,7 +6,7 @@
# 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
+# 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,
@@ -31,67 +31,67 @@ seed_init *= seed_init
seed_init %= (2**32)
if os.environ.get('LD_LIBRARY_PATH'):
- os.environ['LD_LIBRARY_PATH'] += os.pathsep + 'lib'
+ os.environ['LD_LIBRARY_PATH'] += os.pathsep + 'lib'
else:
- os.environ['LD_LIBRARY_PATH'] = 'lib'
+ os.environ['LD_LIBRARY_PATH'] = 'lib'
counter = 0
while True:
- # Random decisions
- seed = seed_init
- random.seed(seed)
- seed_init += 1
- num = random.randint(2, 250)
- density = random.random() * random.random()
- code_likelihood = random.random()
- code_max = random.randint(0, num if random.random() < 0.5 else 3)
- max_printed = random.randint(1, num if random.random() < 0.5 else 3)
- max_decision = num * 20
- decisions = [random.randint(1, max_decision) for x in range(num * 3)]
- branches = [0] * num
- defaults = [0] * num
- branch_codes = [0] * num # code on the branch, which may alter the global state
-
- # with some probability print the same id for different blocks,
- # as the printing is the block contents - allow merging etc. opts
- def printed_id(i):
- if random.random() < 0.5:
- return i
- return i % max_printed
-
- printed_ids = [printed_id(i) for i in range(num)]
-
- def random_code():
- if code_max == 0 or random.random() > code_likelihood:
- return 0 # no code
- # A random number to perturb/increment the global state
- return random.randint(1, code_max)
-
- for i in range(num):
- b = set([])
- bs = random.randint(1, max(1,
- round(density * random.random() * (num - 1))))
- for j in range(bs):
- b.add(random.randint(1, num - 1))
- b = list(b)
- defaults[i] = random.choice(b)
- b.remove(defaults[i])
- branches[i] = b
- branch_codes[i] = [random_code() for item in range(len(b) + 1)] # one for each branch, plus the default
- optimize = random.random() < 0.5
- print(counter, ':', num, density, optimize, code_likelihood, code_max, max_printed, ', seed =', seed)
- counter += 1
-
- for temp in ['fuzz.wasm', 'fuzz.wast', 'fast.txt', 'fuzz.slow.js',
- 'fuzz.c']:
- try:
- os.unlink(temp)
- except OSError:
- pass
-
- # parts
- entry = '''
+ # Random decisions
+ seed = seed_init
+ random.seed(seed)
+ seed_init += 1
+ num = random.randint(2, 250)
+ density = random.random() * random.random()
+ code_likelihood = random.random()
+ code_max = random.randint(0, num if random.random() < 0.5 else 3)
+ max_printed = random.randint(1, num if random.random() < 0.5 else 3)
+ max_decision = num * 20
+ decisions = [random.randint(1, max_decision) for x in range(num * 3)]
+ branches = [0] * num
+ defaults = [0] * num
+ branch_codes = [0] * num # code on the branch, which may alter the global state
+
+ # with some probability print the same id for different blocks,
+ # as the printing is the block contents - allow merging etc. opts
+ def printed_id(i):
+ if random.random() < 0.5:
+ return i
+ return i % max_printed
+
+ printed_ids = [printed_id(i) for i in range(num)]
+
+ def random_code():
+ if code_max == 0 or random.random() > code_likelihood:
+ return 0 # no code
+ # A random number to perturb/increment the global state
+ return random.randint(1, code_max)
+
+ for i in range(num):
+ b = set([])
+ bs = random.randint(1, max(1,
+ round(density * random.random() * (num - 1))))
+ for j in range(bs):
+ b.add(random.randint(1, num - 1))
+ b = list(b)
+ defaults[i] = random.choice(b)
+ b.remove(defaults[i])
+ branches[i] = b
+ branch_codes[i] = [random_code() for item in range(len(b) + 1)] # one for each branch, plus the default
+ optimize = random.random() < 0.5
+ print(counter, ':', num, density, optimize, code_likelihood, code_max, max_printed, ', seed =', seed)
+ counter += 1
+
+ for temp in ['fuzz.wasm', 'fuzz.wast', 'fast.txt', 'fuzz.slow.js',
+ 'fuzz.c']:
+ try:
+ os.unlink(temp)
+ except OSError:
+ pass
+
+ # parts
+ entry = '''
var label = 0;
var state;
var decisions = %s;
@@ -103,14 +103,14 @@ function check() {
}
''' % str(decisions)
- slow = entry + '\n'
- slow += 'label = 0;\n'
+ slow = entry + '\n'
+ slow += 'label = 0;\n'
- slow += '''
+ slow += '''
while(1) switch(label) {
'''
- fast = '''
+ fast = '''
#include <assert.h>
#include <stdio.h>
@@ -190,27 +190,27 @@ int main() {
''' % len(decisions)
- for i in range(num):
- slow += ' case %d: console.log("(i32.const %d)"); state = check(); \n' % (
+ for i in range(num):
+ slow += ' case %d: console.log("(i32.const %d)"); state = check(); \n' % (
i, printed_ids[i])
- b = branches[i]
- bc = branch_codes[i]
+ b = branches[i]
+ bc = branch_codes[i]
- def get_phi(j):
- phi = ''
- if bc[j]:
- phi = 'index += %d; ' % bc[j]
- return phi
+ def get_phi(j):
+ phi = ''
+ if bc[j]:
+ phi = 'index += %d; ' % bc[j]
+ return phi
- for j in range(len(b)):
- slow += ' if (state %% %d == %d) { %s label = %d; break }\n' % (
- len(b) + 1, j, get_phi(j), b[j]) # TODO: split range 1-n into these options
- slow += ' %slabel = %d; break\n' % (get_phi(-1), defaults[i])
+ for j in range(len(b)):
+ slow += ' if (state %% %d == %d) { %s label = %d; break }\n' % (
+ len(b) + 1, j, get_phi(j), b[j]) # TODO: split range 1-n into these options
+ slow += ' %slabel = %d; break\n' % (get_phi(-1), defaults[i])
- use_switch = [random.random() < 0.5 for i in range(num)]
+ use_switch = [random.random() < 0.5 for i in range(num)]
- for i in range(num):
- fast += '''
+ for i in range(num):
+ fast += '''
RelooperBlockRef b%d;
{
BinaryenExpressionRef args[] = {
@@ -222,8 +222,8 @@ int main() {
BinaryenTypeInt32()))
};
''' % (i, printed_ids[i])
- if use_switch[i]:
- fast += '''
+ if use_switch[i]:
+ fast += '''
b%d = RelooperAddBlockWithSwitch(relooper,
BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()),
BinaryenBinary(module,
@@ -233,23 +233,23 @@ int main() {
)
);
''' % (i, len(branches[i]) + 1)
- else: # non-switch
- fast += '''
+ else: # non-switch
+ fast += '''
b%d = RelooperAddBlock(relooper, BinaryenBlock(module, NULL, list, 2, BinaryenTypeNone()));
''' % i
- fast += '''
+ fast += '''
}
'''
- for i in range(num):
- b = branches[i]
- bc = branch_codes[i]
+ for i in range(num):
+ b = branches[i]
+ bc = branch_codes[i]
- def get_phi(j):
- phi = 'NULL'
- if bc[j]:
- # increment the index of global state
- phi = '''
+ def get_phi(j):
+ phi = 'NULL'
+ if bc[j]:
+ # increment the index of global state
+ phi = '''
BinaryenStore(module,
4, 0, 0,
BinaryenConst(module, BinaryenLiteralInt32(4)),
@@ -261,22 +261,22 @@ int main() {
),
BinaryenTypeInt32()
)''' % bc[j]
- return phi
-
- for j in range(len(b)):
- if use_switch[i]:
- total = len(b) + 1
- values = ','.join([str(x) for x in range(random.randint(len(b) + 1,
- max_decision + 2)) if x % total == j])
- fast += '''
+ return phi
+
+ for j in range(len(b)):
+ if use_switch[i]:
+ total = len(b) + 1
+ values = ','.join([str(x) for x in range(random.randint(len(b) + 1,
+ max_decision + 2)) if x % total == j])
+ fast += '''
{
BinaryenIndex values[] = { %s };
RelooperAddBranchForSwitch(b%d, b%d, values,
sizeof(values) / sizeof(BinaryenIndex), %s);
}
''' % (values, i, b[j], get_phi(j))
- else: # non-switch
- fast += '''
+ else: # non-switch
+ fast += '''
RelooperAddBranch(b%d, b%d, BinaryenBinary(module,
BinaryenEqInt32(),
BinaryenBinary(module,
@@ -287,17 +287,17 @@ int main() {
BinaryenConst(module, BinaryenLiteralInt32(%d))
), %s);
''' % (i, b[j], len(b) + 1, j, get_phi(j))
- # default branch
- if use_switch[i]:
- fast += '''
+ # default branch
+ if use_switch[i]:
+ fast += '''
RelooperAddBranchForSwitch(b%d, b%d, NULL, 0, %s);
''' % (i, defaults[i], get_phi(-1))
- else:
- fast += '''
+ else:
+ fast += '''
RelooperAddBranch(b%d, b%d, NULL, %s);
''' % (i, defaults[i], get_phi(-1))
- fast += '''
+ fast += '''
BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
int decisions[] = { %s };
@@ -357,33 +357,33 @@ int main() {
}
''' % (', '.join(map(str, decisions)), optimize)
- slow += '}'
-
- open('fuzz.slow.js', 'w').write(slow)
- open('fuzz.c', 'w').write(fast)
-
- print('.')
- cmd = [os.environ.get('CC') or 'gcc', 'fuzz.c', '-Isrc',
- '-lbinaryen', '-lasmjs',
- '-lsupport', '-Llib/.', '-pthread', '-o', 'fuzz']
- subprocess.check_call(cmd)
- print('^')
- subprocess.check_call(['./fuzz'], stdout=open('fuzz.wast', 'w'))
- print('*')
- fast_out = subprocess.Popen(['bin/wasm-shell', 'fuzz.wast'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()[0]
- print('-')
- node = os.getenv('NODE', 'nodejs')
- slow_out = subprocess.Popen([node, 'fuzz.slow.js'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()[0]
- print('_')
-
- if slow_out != fast_out:
- print(''.join([a.rstrip() + '\n' for a in difflib.unified_diff(
- slow_out.split('\n'),
- fast_out.split('\n'),
- fromfile='slow',
- tofile='fast')]))
- assert False
+ slow += '}'
+
+ open('fuzz.slow.js', 'w').write(slow)
+ open('fuzz.c', 'w').write(fast)
+
+ print('.')
+ cmd = [os.environ.get('CC') or 'gcc', 'fuzz.c', '-Isrc',
+ '-lbinaryen', '-lasmjs',
+ '-lsupport', '-Llib/.', '-pthread', '-o', 'fuzz']
+ subprocess.check_call(cmd)
+ print('^')
+ subprocess.check_call(['./fuzz'], stdout=open('fuzz.wast', 'w'))
+ print('*')
+ fast_out = subprocess.Popen(['bin/wasm-shell', 'fuzz.wast'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+ print('-')
+ node = os.getenv('NODE', 'nodejs')
+ slow_out = subprocess.Popen([node, 'fuzz.slow.js'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate()[0]
+ print('_')
+
+ if slow_out != fast_out:
+ print(''.join([a.rstrip() + '\n' for a in difflib.unified_diff(
+ slow_out.split('\n'),
+ fast_out.split('\n'),
+ fromfile='slow',
+ tofile='fast')]))
+ assert False
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py
index 5b18ed340..d6653e112 100755
--- a/scripts/gen-s-parser.py
+++ b/scripts/gen-s-parser.py
@@ -434,143 +434,143 @@ instructions = [
class CodePrinter:
- indents = 0
+ indents = 0
- def __enter__(self):
- CodePrinter.indents += 1
+ def __enter__(self):
+ CodePrinter.indents += 1
- def __exit__(self, *args):
- CodePrinter.indents -= 1
+ def __exit__(self, *args):
+ CodePrinter.indents -= 1
- def indent(self):
- # call in a 'with' statement
- return self
+ def indent(self):
+ # call in a 'with' statement
+ return self
- def print_line(self, line):
- print(" " * CodePrinter.indents + line)
+ def print_line(self, line):
+ print(" " * CodePrinter.indents + line)
class Node:
- def __init__(self, expr=None, children=None, inst=None):
- # the expression to return if this is the string has ended
- self.expr = expr
- # map unique strings to children nodes
- self.children = children if children else {}
- # full instruction leading to this node
- self.inst = inst
+ def __init__(self, expr=None, children=None, inst=None):
+ # the expression to return if this is the string has ended
+ self.expr = expr
+ # map unique strings to children nodes
+ self.children = children if children else {}
+ # full instruction leading to this node
+ self.inst = inst
- def _common_prefix(a, b):
- """Return the common prefix of two strings."""
- prefix = []
- while a and b and a[0] == b[0]:
- prefix.append(a[0])
- a = a[1:]
- b = b[1:]
- return "".join(prefix)
+ def _common_prefix(a, b):
+ """Return the common prefix of two strings."""
+ prefix = []
+ while a and b and a[0] == b[0]:
+ prefix.append(a[0])
+ a = a[1:]
+ b = b[1:]
+ return "".join(prefix)
- def do_insert(self, full_inst, inst, expr):
- if not inst:
- assert self.expr is None, "Repeated instruction " + full_inst
- self.expr = expr
- self.inst = full_inst
- return
- # find key with shared prefix
- prefix, key = "", None
- for k in self.children:
- prefix = Node._common_prefix(inst, k)
- if prefix:
- key = k
- break
- if key is None:
- # unique prefix, insert and stop
- self.children[inst] = Node(expr, inst=full_inst)
- return
- key_remainder = key[len(prefix):]
- if key_remainder:
- # split key and move everything after the prefix to a new node
- child = self.children.pop(key)
- self.children[prefix] = Node(children={key_remainder: child})
- # update key for recursive insert
- key = prefix
- # chop off prefix and recurse
- self.children[key].do_insert(full_inst, inst[len(key):], expr)
+ def do_insert(self, full_inst, inst, expr):
+ if not inst:
+ assert self.expr is None, "Repeated instruction " + full_inst
+ self.expr = expr
+ self.inst = full_inst
+ return
+ # find key with shared prefix
+ prefix, key = "", None
+ for k in self.children:
+ prefix = Node._common_prefix(inst, k)
+ if prefix:
+ key = k
+ break
+ if key is None:
+ # unique prefix, insert and stop
+ self.children[inst] = Node(expr, inst=full_inst)
+ return
+ key_remainder = key[len(prefix):]
+ if key_remainder:
+ # split key and move everything after the prefix to a new node
+ child = self.children.pop(key)
+ self.children[prefix] = Node(children={key_remainder: child})
+ # update key for recursive insert
+ key = prefix
+ # chop off prefix and recurse
+ self.children[key].do_insert(full_inst, inst[len(key):], expr)
- def insert(self, inst, expr):
- self.do_insert(inst, inst, expr)
+ def insert(self, inst, expr):
+ self.do_insert(inst, inst, expr)
def instruction_parser():
- """Build a trie out of all the instructions, then emit it as C++ code."""
- trie = Node()
- inst_length = 0
- for inst, expr in instructions:
- inst_length = max(inst_length, len(inst))
- trie.insert(inst, expr)
+ """Build a trie out of all the instructions, then emit it as C++ code."""
+ trie = Node()
+ inst_length = 0
+ for inst, expr in instructions:
+ inst_length = max(inst_length, len(inst))
+ trie.insert(inst, expr)
- printer = CodePrinter()
+ printer = CodePrinter()
- printer.print_line("char op[{}] = {{'\\0'}};".format(inst_length + 1))
- printer.print_line("strncpy(op, s[0]->c_str(), {});".format(inst_length))
+ printer.print_line("char op[{}] = {{'\\0'}};".format(inst_length + 1))
+ printer.print_line("strncpy(op, s[0]->c_str(), {});".format(inst_length))
- def print_leaf(expr, inst):
- printer.print_line("if (strcmp(op, \"{inst}\") == 0) {{ return {expr}; }}"
- .format(inst=inst, expr=expr))
- printer.print_line("goto parse_error;")
+ def print_leaf(expr, inst):
+ printer.print_line("if (strcmp(op, \"{inst}\") == 0) {{ return {expr}; }}"
+ .format(inst=inst, expr=expr))
+ printer.print_line("goto parse_error;")
- def emit(node, idx=0):
- assert node.children
- printer.print_line("switch (op[{}]) {{".format(idx))
- with printer.indent():
- if node.expr:
- printer.print_line("case '\\0':")
+ def emit(node, idx=0):
+ assert node.children
+ printer.print_line("switch (op[{}]) {{".format(idx))
with printer.indent():
- print_leaf(node.expr, node.inst)
- children = sorted(node.children.items(), key=lambda pair: pair[0])
- for prefix, child in children:
- if child.children:
- printer.print_line("case '{}': {{".format(prefix[0]))
- with printer.indent():
- emit(child, idx + len(prefix))
- printer.print_line("}")
- else:
- assert child.expr
- printer.print_line("case '{}':".format(prefix[0]))
- with printer.indent():
- print_leaf(child.expr, child.inst)
- printer.print_line("default: goto parse_error;")
- printer.print_line("}")
+ if node.expr:
+ printer.print_line("case '\\0':")
+ with printer.indent():
+ print_leaf(node.expr, node.inst)
+ children = sorted(node.children.items(), key=lambda pair: pair[0])
+ for prefix, child in children:
+ if child.children:
+ printer.print_line("case '{}': {{".format(prefix[0]))
+ with printer.indent():
+ emit(child, idx + len(prefix))
+ printer.print_line("}")
+ else:
+ assert child.expr
+ printer.print_line("case '{}':".format(prefix[0]))
+ with printer.indent():
+ print_leaf(child.expr, child.inst)
+ printer.print_line("default: goto parse_error;")
+ printer.print_line("}")
- emit(trie)
- printer.print_line("parse_error:")
- with printer.indent():
- printer.print_line("throw ParseException(std::string(op), s.line, s.col);")
+ emit(trie)
+ printer.print_line("parse_error:")
+ with printer.indent():
+ printer.print_line("throw ParseException(std::string(op), s.line, s.col);")
def print_header():
- print("// DO NOT EDIT! This file generated by scripts/gen-s-parser.py\n")
- print("// clang-format off\n")
+ print("// DO NOT EDIT! This file generated by scripts/gen-s-parser.py\n")
+ print("// clang-format off\n")
def print_footer():
- print("\n// clang-format on")
+ print("\n// clang-format on")
def generate_with_guard(generator, guard):
- print("#ifdef {}".format(guard))
- print("#undef {}".format(guard))
- generator()
- print("#endif // {}".format(guard))
+ print("#ifdef {}".format(guard))
+ print("#undef {}".format(guard))
+ generator()
+ print("#endif // {}".format(guard))
def main():
- if sys.version_info.major != 3:
- import datetime
- print("It's " + str(datetime.datetime.now().year) + "! Use Python 3!")
- sys.exit(1)
- print_header()
- generate_with_guard(instruction_parser, "INSTRUCTION_PARSER")
- print_footer()
+ if sys.version_info.major != 3:
+ import datetime
+ print("It's " + str(datetime.datetime.now().year) + "! Use Python 3!")
+ sys.exit(1)
+ print_header()
+ generate_with_guard(instruction_parser, "INSTRUCTION_PARSER")
+ print_footer()
if __name__ == "__main__":
- main()
+ main()
diff --git a/scripts/process_optimize_instructions.py b/scripts/process_optimize_instructions.py
index a9337b13b..f10e66a8b 100755
--- a/scripts/process_optimize_instructions.py
+++ b/scripts/process_optimize_instructions.py
@@ -11,6 +11,6 @@ outfile = os.path.join(root, 'src', 'passes',
out = open(outfile, 'w')
for line in open(infile):
- out.write('"' + line.strip().replace('"', '\\"') + '\\n"\n')
+ out.write('"' + line.strip().replace('"', '\\"') + '\\n"\n')
out.close()
diff --git a/scripts/storage.py b/scripts/storage.py
index 89e5f6107..3db76bf76 100755
--- a/scripts/storage.py
+++ b/scripts/storage.py
@@ -26,30 +26,30 @@ STORAGE_BASE = 'https://storage.googleapis.com/wasm-llvm/builds/git/'
def download_revision(force_latest):
- name = 'latest' if force_latest else 'lkgr'
- downloaded = urllib2.urlopen(STORAGE_BASE + name).read().strip()
- # TODO: for now try opening as JSON, if that doesn't work then the content is
- # just a hash. The waterfall is in the process of migrating to JSON.
- info = None
- try:
- info = json.loads(downloaded)
- except ValueError:
- pass
- return info['build'] if type(info) == dict else downloaded
+ name = 'latest' if force_latest else 'lkgr'
+ downloaded = urllib2.urlopen(STORAGE_BASE + name).read().strip()
+ # TODO: for now try opening as JSON, if that doesn't work then the content is
+ # just a hash. The waterfall is in the process of migrating to JSON.
+ info = None
+ try:
+ info = json.loads(downloaded)
+ except ValueError:
+ pass
+ return info['build'] if type(info) == dict else downloaded
def download_tar(tar_pattern, directory, revision):
- tar_path = os.path.join(directory, tar_pattern)
- revision_tar_path = tar_path % revision
- if os.path.isfile(revision_tar_path):
- print('Already have `%s`' % revision_tar_path)
- else:
- print('Downloading `%s`' % revision_tar_path)
- with open(revision_tar_path, 'w+') as f:
- f.write(urllib2.urlopen(STORAGE_BASE + tar_pattern % revision).read())
- # Remove any previous tarfiles.
- for older_tar in glob.glob(tar_path % '*'):
- if older_tar != revision_tar_path:
- print('Removing older tar file `%s`' % older_tar)
- os.remove(older_tar)
- return revision_tar_path
+ tar_path = os.path.join(directory, tar_pattern)
+ revision_tar_path = tar_path % revision
+ if os.path.isfile(revision_tar_path):
+ print('Already have `%s`' % revision_tar_path)
+ else:
+ print('Downloading `%s`' % revision_tar_path)
+ with open(revision_tar_path, 'w+') as f:
+ f.write(urllib2.urlopen(STORAGE_BASE + tar_pattern % revision).read())
+ # Remove any previous tarfiles.
+ for older_tar in glob.glob(tar_path % '*'):
+ if older_tar != revision_tar_path:
+ print('Removing older tar file `%s`' % older_tar)
+ os.remove(older_tar)
+ return revision_tar_path
diff --git a/scripts/strip_local_names.py b/scripts/strip_local_names.py
index bd10d8dab..959e56dd8 100644
--- a/scripts/strip_local_names.py
+++ b/scripts/strip_local_names.py
@@ -1,13 +1,12 @@
-'''
-Removes local names. When you don't care about local names but do want
+"""Removes local names. When you don't care about local names but do want
to diff for structural changes, this can help.
-'''
+"""
import sys
for line in open(sys.argv[1]).readlines():
- if '(local.tee ' in line or '(local.set ' in line or '(local.get ' in line:
- print(line[:line.find('$')])
- else:
- print(line.rstrip())
+ if '(local.tee ' in line or '(local.set ' in line or '(local.get ' in line:
+ print(line[:line.find('$')])
+ else:
+ print(line.rstrip())
diff --git a/scripts/test/asm2wasm.py b/scripts/test/asm2wasm.py
index 356d8c0f2..356a3d85c 100755
--- a/scripts/test/asm2wasm.py
+++ b/scripts/test/asm2wasm.py
@@ -25,137 +25,137 @@ from .shared import (
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)]
- 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 asm:
- cmd += ['-g']
- if 'noffi' in asm:
- cmd += ['--no-legalize-javascript-ffi']
- if precise and opts:
- # test mem init importing
- open('a.mem', 'w').write(asm)
- cmd += ['--mem-init=a.mem']
- if asm[0] == 'e':
- cmd += ['--mem-base=1024']
- if '4GB' in asm:
- cmd += ['--mem-max=4294967296']
- 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)
- fail_if_not_identical_to_file(actual, wasm)
-
- 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(jsmap, 'rb') as actual:
- 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:
- 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')
+ 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)]
+ 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 asm:
+ cmd += ['-g']
+ if 'noffi' in asm:
+ cmd += ['--no-legalize-javascript-ffi']
+ if precise and opts:
+ # test mem init importing
+ open('a.mem', 'w').write(asm)
+ cmd += ['--mem-init=a.mem']
+ if asm[0] == 'e':
+ cmd += ['--mem-base=1024']
+ if '4GB' in asm:
+ cmd += ['--mem-max=4294967296']
+ 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)
+ fail_if_not_identical_to_file(actual, wasm)
+
+ 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(jsmap, 'rb') as actual:
+ 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:
+ 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')
+ 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'
+ 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()
+ test_asm2wasm()
+ test_asm2wasm_binary()
diff --git a/scripts/test/binaryenjs.py b/scripts/test/binaryenjs.py
index f701f25c1..a102c2ae4 100755
--- a/scripts/test/binaryenjs.py
+++ b/scripts/test/binaryenjs.py
@@ -22,56 +22,56 @@ from .shared import BINARYEN_JS, MOZJS, NODEJS, options, fail
def test_binaryen_js():
- if not (MOZJS or NODEJS):
- print('no vm to run binaryen.js tests')
- return
+ if not (MOZJS or NODEJS):
+ print('no vm to run binaryen.js tests')
+ return
- node_has_wasm = NODEJS and node_has_webassembly(NODEJS)
+ node_has_wasm = NODEJS and node_has_webassembly(NODEJS)
- if not os.path.exists(BINARYEN_JS):
- print('no binaryen.js build to test')
- return
+ if not os.path.exists(BINARYEN_JS):
+ print('no binaryen.js build to test')
+ return
- print('\n[ checking binaryen.js testcases... ]\n')
+ print('\n[ checking binaryen.js testcases... ]\n')
- for s in sorted(os.listdir(os.path.join(options.binaryen_test, 'binaryen.js'))):
- if not s.endswith('.js'):
- continue
- print(s)
- f = open('a.js', 'w')
- # avoid stdout/stderr ordering issues in some js shells - use just stdout
- f.write('''
- console.warn = function(x) { console.log(x) };
- ''')
- binaryen_js = open(BINARYEN_JS).read()
- f.write(binaryen_js)
- if NODEJS:
- f.write(node_test_glue())
- test_path = os.path.join(options.binaryen_test, 'binaryen.js', s)
- test_src = open(test_path).read()
- f.write(test_src)
- f.close()
+ for s in sorted(os.listdir(os.path.join(options.binaryen_test, 'binaryen.js'))):
+ if not s.endswith('.js'):
+ continue
+ print(s)
+ f = open('a.js', 'w')
+ # avoid stdout/stderr ordering issues in some js shells - use just stdout
+ f.write('''
+ console.warn = function(x) { console.log(x) };
+ ''')
+ binaryen_js = open(BINARYEN_JS).read()
+ f.write(binaryen_js)
+ if NODEJS:
+ f.write(node_test_glue())
+ test_path = os.path.join(options.binaryen_test, 'binaryen.js', s)
+ test_src = open(test_path).read()
+ f.write(test_src)
+ f.close()
- def test(engine):
- cmd = [engine, 'a.js']
- if 'fatal' not in s:
- out = run_command(cmd, stderr=subprocess.STDOUT)
- else:
- # expect an error - the specific error code will depend on the vm
- out = run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
- expected = open(os.path.join(options.binaryen_test, 'binaryen.js', s + '.txt')).read()
- if expected not in out:
- fail(out, expected)
+ def test(engine):
+ cmd = [engine, 'a.js']
+ if 'fatal' not in s:
+ out = run_command(cmd, stderr=subprocess.STDOUT)
+ else:
+ # expect an error - the specific error code will depend on the vm
+ out = run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
+ expected = open(os.path.join(options.binaryen_test, 'binaryen.js', s + '.txt')).read()
+ if expected not in out:
+ fail(out, expected)
- # run in all possible shells
- if MOZJS:
- test(MOZJS)
- if NODEJS:
- if node_has_wasm or 'WebAssembly.' not in test_src:
- test(NODEJS)
- else:
- print('Skipping ' + test_path + ' because WebAssembly might not be supported')
+ # run in all possible shells
+ if MOZJS:
+ test(MOZJS)
+ if NODEJS:
+ if node_has_wasm or 'WebAssembly.' not in test_src:
+ test(NODEJS)
+ else:
+ print('Skipping ' + test_path + ' because WebAssembly might not be supported')
if __name__ == "__main__":
- test_binaryen_js()
+ test_binaryen_js()
diff --git a/scripts/test/generate_lld_tests.py b/scripts/test/generate_lld_tests.py
index 9447fe973..b5cb6b140 100755
--- a/scripts/test/generate_lld_tests.py
+++ b/scripts/test/generate_lld_tests.py
@@ -23,69 +23,69 @@ import shared
def files_with_extensions(path, extensions):
- for file in sorted(os.listdir(path)):
- ext = os.path.splitext(file)[1]
- if ext in extensions:
- yield file, ext
+ for file in sorted(os.listdir(path)):
+ ext = os.path.splitext(file)[1]
+ if ext in extensions:
+ yield file, ext
def generate_wast_files(llvm_bin, emscripten_root):
- print('\n[ building wast files from C sources... ]\n')
+ print('\n[ building wast files from C sources... ]\n')
- lld_path = os.path.join(shared.options.binaryen_test, 'lld')
- for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']):
- print('..', src_file)
- obj_file = src_file.replace(ext, '.o')
+ lld_path = os.path.join(shared.options.binaryen_test, 'lld')
+ for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']):
+ print('..', src_file)
+ obj_file = src_file.replace(ext, '.o')
- src_path = os.path.join(lld_path, src_file)
- obj_path = os.path.join(lld_path, obj_file)
+ src_path = os.path.join(lld_path, src_file)
+ obj_path = os.path.join(lld_path, obj_file)
- wasm_file = src_file.replace(ext, '.wasm')
- wast_file = src_file.replace(ext, '.wast')
+ wasm_file = src_file.replace(ext, '.wasm')
+ wast_file = src_file.replace(ext, '.wast')
- obj_path = os.path.join(lld_path, obj_file)
- wasm_path = os.path.join(lld_path, wasm_file)
- wast_path = os.path.join(lld_path, wast_file)
- is_shared = 'shared' in src_file
+ obj_path = os.path.join(lld_path, obj_file)
+ wasm_path = os.path.join(lld_path, wasm_file)
+ wast_path = os.path.join(lld_path, wast_file)
+ is_shared = 'shared' in src_file
- compile_cmd = [
- os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path,
- '--target=wasm32-unknown-unknown-wasm',
- '-c',
- '-nostdinc',
- '-Xclang', '-nobuiltininc',
- '-Xclang', '-nostdsysteminc',
- '-Xclang', '-I%s/system/include' % emscripten_root,
- '-O1',
- ]
+ compile_cmd = [
+ os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path,
+ '--target=wasm32-unknown-unknown-wasm',
+ '-c',
+ '-nostdinc',
+ '-Xclang', '-nobuiltininc',
+ '-Xclang', '-nostdsysteminc',
+ '-Xclang', '-I%s/system/include' % emscripten_root,
+ '-O1',
+ ]
- link_cmd = [
- os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm',
- '-z', '-stack-size=1048576',
- obj_path, '-o', wasm_path,
- '--allow-undefined',
- '--export', '__wasm_call_ctors',
- '--global-base=568',
- ]
- if is_shared:
- compile_cmd.append('-fPIC')
- compile_cmd.append('-fvisibility=default')
- link_cmd.append('-shared')
- else:
- link_cmd.append('--entry=main')
+ link_cmd = [
+ os.path.join(llvm_bin, 'wasm-ld'), '-flavor', 'wasm',
+ '-z', '-stack-size=1048576',
+ obj_path, '-o', wasm_path,
+ '--allow-undefined',
+ '--export', '__wasm_call_ctors',
+ '--global-base=568',
+ ]
+ if is_shared:
+ compile_cmd.append('-fPIC')
+ compile_cmd.append('-fvisibility=default')
+ link_cmd.append('-shared')
+ else:
+ link_cmd.append('--entry=main')
- try:
- run_command(compile_cmd)
- run_command(link_cmd)
- run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path])
- finally:
- # Don't need the .o or .wasm files, don't leave them around
- shared.delete_from_orbit(obj_path)
- shared.delete_from_orbit(wasm_path)
+ try:
+ run_command(compile_cmd)
+ run_command(link_cmd)
+ run_command(shared.WASM_DIS + [wasm_path, '-o', wast_path])
+ finally:
+ # Don't need the .o or .wasm files, don't leave them around
+ shared.delete_from_orbit(obj_path)
+ shared.delete_from_orbit(wasm_path)
if __name__ == '__main__':
- if len(shared.options.positional_args) != 2:
- print('Usage: generate_lld_tests.py [llvm/bin/dir] [path/to/emscripten]')
- sys.exit(1)
- generate_wast_files(*shared.options.positional_args)
+ if len(shared.options.positional_args) != 2:
+ print('Usage: generate_lld_tests.py [llvm/bin/dir] [path/to/emscripten]')
+ sys.exit(1)
+ generate_wast_files(*shared.options.positional_args)
diff --git a/scripts/test/lld.py b/scripts/test/lld.py
index 1a553506f..4aafd9549 100755
--- a/scripts/test/lld.py
+++ b/scripts/test/lld.py
@@ -22,72 +22,72 @@ from .shared import (
def args_for_finalize(filename):
- if 'safe_stack' in filename:
- return ['--check-stack-overflow', '--global-base=568']
- elif 'shared' in filename:
- return ['--side-module']
- else:
- return ['--global-base=568']
+ if 'safe_stack' in filename:
+ return ['--check-stack-overflow', '--global-base=568']
+ elif 'shared' in filename:
+ return ['--side-module']
+ else:
+ return ['--global-base=568']
def test_wasm_emscripten_finalize():
- print('\n[ checking wasm-emscripten-finalize testcases... ]\n')
+ print('\n[ checking wasm-emscripten-finalize testcases... ]\n')
- for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
- print('..', wast_path)
- is_passive = '.passive.' in wast_path
- mem_file = wast_path + '.mem'
- extension_arg_map = {
- '.out': [],
- }
- if not is_passive:
- extension_arg_map.update({
- '.mem.out': ['--separate-data-segments', mem_file],
- })
- for ext, ext_args in extension_arg_map.items():
- expected_file = wast_path + ext
- if ext != '.out' and not os.path.exists(expected_file):
- continue
+ for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
+ print('..', wast_path)
+ is_passive = '.passive.' in wast_path
+ mem_file = wast_path + '.mem'
+ extension_arg_map = {
+ '.out': [],
+ }
+ if not is_passive:
+ extension_arg_map.update({
+ '.mem.out': ['--separate-data-segments', mem_file],
+ })
+ for ext, ext_args in extension_arg_map.items():
+ expected_file = wast_path + ext
+ if ext != '.out' and not os.path.exists(expected_file):
+ continue
- cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args
- cmd += args_for_finalize(os.path.basename(wast_path))
- actual = run_command(cmd)
+ cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args
+ cmd += args_for_finalize(os.path.basename(wast_path))
+ actual = run_command(cmd)
- if not os.path.exists(expected_file):
- print(actual)
- fail_with_error('output ' + expected_file + ' does not exist')
- fail_if_not_identical_to_file(actual, expected_file)
- if ext == '.mem.out':
- with open(mem_file) as mf:
- mem = mf.read()
- fail_if_not_identical_to_file(mem, wast_path + '.mem.mem')
- os.remove(mem_file)
+ if not os.path.exists(expected_file):
+ print(actual)
+ fail_with_error('output ' + expected_file + ' does not exist')
+ fail_if_not_identical_to_file(actual, expected_file)
+ if ext == '.mem.out':
+ with open(mem_file) as mf:
+ mem = mf.read()
+ fail_if_not_identical_to_file(mem, wast_path + '.mem.mem')
+ os.remove(mem_file)
def update_lld_tests():
- print('\n[ updatring wasm-emscripten-finalize testcases... ]\n')
+ print('\n[ updatring wasm-emscripten-finalize testcases... ]\n')
- for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
- print('..', wast_path)
- is_passive = '.passive.' in wast_path
- mem_file = wast_path + '.mem'
- extension_arg_map = {
- '.out': [],
- }
- if not is_passive:
- extension_arg_map.update({
- '.mem.out': ['--separate-data-segments', mem_file + '.mem'],
- })
- for ext, ext_args in extension_arg_map.items():
- out_path = wast_path + ext
- if ext != '.out' and not os.path.exists(out_path):
- continue
- cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args
- cmd += args_for_finalize(os.path.basename(wast_path))
- actual = run_command(cmd)
- with open(out_path, 'w') as o:
- o.write(actual)
+ for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
+ print('..', wast_path)
+ is_passive = '.passive.' in wast_path
+ mem_file = wast_path + '.mem'
+ extension_arg_map = {
+ '.out': [],
+ }
+ if not is_passive:
+ extension_arg_map.update({
+ '.mem.out': ['--separate-data-segments', mem_file + '.mem'],
+ })
+ for ext, ext_args in extension_arg_map.items():
+ out_path = wast_path + ext
+ if ext != '.out' and not os.path.exists(out_path):
+ continue
+ cmd = WASM_EMSCRIPTEN_FINALIZE + [wast_path, '-S'] + ext_args
+ cmd += args_for_finalize(os.path.basename(wast_path))
+ actual = run_command(cmd)
+ with open(out_path, 'w') as o:
+ o.write(actual)
if __name__ == '__main__':
- test_wasm_emscripten_finalize()
+ test_wasm_emscripten_finalize()
diff --git a/scripts/test/shared.py b/scripts/test/shared.py
index a712f5176..2440077a8 100644
--- a/scripts/test/shared.py
+++ b/scripts/test/shared.py
@@ -24,61 +24,61 @@ import sys
def parse_args(args):
- usage_str = ("usage: 'python check.py [options]'\n\n"
- "Runs the Binaryen test suite.")
- parser = argparse.ArgumentParser(description=usage_str)
- parser.add_argument(
- '--torture', dest='torture', action='store_true', default=True,
- help='Chooses whether to run the torture testcases. Default: true.')
- parser.add_argument(
- '--no-torture', dest='torture', action='store_false',
- help='Disables running the torture testcases.')
- parser.add_argument(
- '--abort-on-first-failure', dest='abort_on_first_failure',
- action='store_true', default=True,
- help=('Specifies whether to halt test suite execution on first test error.'
- ' Default: true.'))
- parser.add_argument(
- '--no-abort-on-first-failure', dest='abort_on_first_failure',
- action='store_false',
- help=('If set, the whole test suite will run to completion independent of'
- ' earlier errors.'))
-
- parser.add_argument(
- '--interpreter', dest='interpreter', default='',
- help='Specifies the wasm interpreter executable to run tests on.')
- parser.add_argument(
- '--binaryen-bin', dest='binaryen_bin', default='',
- help=('Specifies a path to where the built Binaryen executables reside at.'
- ' Default: bin/ of current directory (i.e. assume an in-tree build).'
- ' If not specified, the environment variable BINARYEN_ROOT= can also'
- ' be used to adjust this.'))
- parser.add_argument(
- '--binaryen-root', dest='binaryen_root', default='',
- help=('Specifies a path to the root of the Binaryen repository tree.'
- ' Default: the directory where this file check.py resides.'))
- parser.add_argument(
- '--valgrind', dest='valgrind', default='',
- help=('Specifies a path to Valgrind tool, which will be used to validate'
- ' execution if specified. (Pass --valgrind=valgrind to search in'
- ' PATH)'))
- parser.add_argument(
- '--valgrind-full-leak-check', dest='valgrind_full_leak_check',
- action='store_true', default=False,
- help=('If specified, all unfreed (but still referenced) pointers at the'
- ' end of execution are considered memory leaks. Default: disabled.'))
- parser.add_argument(
- '--spec-test', action='append', nargs='*', default=[], dest='spec_tests',
- help='Names specific spec tests to run.')
- parser.add_argument(
- 'positional_args', metavar='TEST_SUITE', nargs='*',
- help=('Names specific test suites to run. Use --list-suites to see a '
- 'list of all test suites'))
- parser.add_argument(
- '--list-suites', action='store_true',
- help='List the test suites that can be run.')
-
- return parser.parse_args(args)
+ usage_str = ("usage: 'python check.py [options]'\n\n"
+ "Runs the Binaryen test suite.")
+ parser = argparse.ArgumentParser(description=usage_str)
+ parser.add_argument(
+ '--torture', dest='torture', action='store_true', default=True,
+ help='Chooses whether to run the torture testcases. Default: true.')
+ parser.add_argument(
+ '--no-torture', dest='torture', action='store_false',
+ help='Disables running the torture testcases.')
+ parser.add_argument(
+ '--abort-on-first-failure', dest='abort_on_first_failure',
+ action='store_true', default=True,
+ help=('Specifies whether to halt test suite execution on first test error.'
+ ' Default: true.'))
+ parser.add_argument(
+ '--no-abort-on-first-failure', dest='abort_on_first_failure',
+ action='store_false',
+ help=('If set, the whole test suite will run to completion independent of'
+ ' earlier errors.'))
+
+ parser.add_argument(
+ '--interpreter', dest='interpreter', default='',
+ help='Specifies the wasm interpreter executable to run tests on.')
+ parser.add_argument(
+ '--binaryen-bin', dest='binaryen_bin', default='',
+ help=('Specifies a path to where the built Binaryen executables reside at.'
+ ' Default: bin/ of current directory (i.e. assume an in-tree build).'
+ ' If not specified, the environment variable BINARYEN_ROOT= can also'
+ ' be used to adjust this.'))
+ parser.add_argument(
+ '--binaryen-root', dest='binaryen_root', default='',
+ help=('Specifies a path to the root of the Binaryen repository tree.'
+ ' Default: the directory where this file check.py resides.'))
+ parser.add_argument(
+ '--valgrind', dest='valgrind', default='',
+ help=('Specifies a path to Valgrind tool, which will be used to validate'
+ ' execution if specified. (Pass --valgrind=valgrind to search in'
+ ' PATH)'))
+ parser.add_argument(
+ '--valgrind-full-leak-check', dest='valgrind_full_leak_check',
+ action='store_true', default=False,
+ help=('If specified, all unfreed (but still referenced) pointers at the'
+ ' end of execution are considered memory leaks. Default: disabled.'))
+ parser.add_argument(
+ '--spec-test', action='append', nargs='*', default=[], dest='spec_tests',
+ help='Names specific spec tests to run.')
+ parser.add_argument(
+ 'positional_args', metavar='TEST_SUITE', nargs='*',
+ help=('Names specific test suites to run. Use --list-suites to see a '
+ 'list of all test suites'))
+ parser.add_argument(
+ '--list-suites', action='store_true',
+ help='List the test suites that can be run.')
+
+ return parser.parse_args(args)
options = parse_args(sys.argv[1:])
@@ -89,23 +89,23 @@ warnings = []
def warn(text):
- global warnings
- warnings.append(text)
- print('warning:', text, file=sys.stderr)
+ global warnings
+ warnings.append(text)
+ print('warning:', text, file=sys.stderr)
# setup
# Locate Binaryen build artifacts directory (bin/ by default)
if not options.binaryen_bin:
- if os.environ.get('BINARYEN_ROOT'):
- if os.path.isdir(os.path.join(os.environ.get('BINARYEN_ROOT'), 'bin')):
- options.binaryen_bin = os.path.join(
- os.environ.get('BINARYEN_ROOT'), 'bin')
+ if os.environ.get('BINARYEN_ROOT'):
+ if os.path.isdir(os.path.join(os.environ.get('BINARYEN_ROOT'), 'bin')):
+ options.binaryen_bin = os.path.join(
+ os.environ.get('BINARYEN_ROOT'), 'bin')
+ else:
+ options.binaryen_bin = os.environ.get('BINARYEN_ROOT')
else:
- options.binaryen_bin = os.environ.get('BINARYEN_ROOT')
- else:
- options.binaryen_bin = 'bin'
+ options.binaryen_bin = 'bin'
options.binaryen_bin = os.path.normpath(os.path.abspath(options.binaryen_bin))
@@ -115,12 +115,12 @@ os.environ['BINARYEN_ROOT'] = os.path.dirname(options.binaryen_bin)
wasm_dis_filenames = ['wasm-dis', 'wasm-dis.exe']
if not any(os.path.isfile(os.path.join(options.binaryen_bin, f))
for f in wasm_dis_filenames):
- warn('Binaryen not found (or has not been successfully built to bin/ ?')
+ warn('Binaryen not found (or has not been successfully built to bin/ ?')
# Locate Binaryen source directory if not specified.
if not options.binaryen_root:
- path_parts = os.path.abspath(__file__).split(os.path.sep)
- options.binaryen_root = os.path.sep.join(path_parts[:-3])
+ path_parts = os.path.abspath(__file__).split(os.path.sep)
+ options.binaryen_root = os.path.sep.join(path_parts[:-3])
options.binaryen_test = os.path.join(options.binaryen_root, 'test')
@@ -128,30 +128,29 @@ options.binaryen_test = os.path.join(options.binaryen_root, 'test')
# Finds the given executable 'program' in PATH.
# Operates like the Unix tool 'which'.
def which(program):
- def is_exe(fpath):
- return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
- fpath, fname = os.path.split(program)
- if fpath:
- if is_exe(program):
- return program
- else:
- for path in os.environ["PATH"].split(os.pathsep):
- path = path.strip('"')
- exe_file = os.path.join(path, program)
- if is_exe(exe_file):
- return exe_file
- if '.' not in fname:
- if is_exe(exe_file + '.exe'):
- return exe_file + '.exe'
- if is_exe(exe_file + '.cmd'):
- return exe_file + '.cmd'
- if is_exe(exe_file + '.bat'):
- return exe_file + '.bat'
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+ if '.' not in fname:
+ if is_exe(exe_file + '.exe'):
+ return exe_file + '.exe'
+ if is_exe(exe_file + '.cmd'):
+ return exe_file + '.cmd'
+ if is_exe(exe_file + '.bat'):
+ return exe_file + '.bat'
WATERFALL_BUILD_DIR = os.path.join(options.binaryen_test, 'wasm-install')
-BIN_DIR = os.path.abspath(os.path.join(
- WATERFALL_BUILD_DIR, 'wasm-install', 'bin'))
+BIN_DIR = os.path.abspath(os.path.join(WATERFALL_BUILD_DIR, 'wasm-install', 'bin'))
NATIVECC = (os.environ.get('CC') or which('mingw32-gcc') or
which('gcc') or which('clang'))
@@ -178,53 +177,53 @@ BINARYEN_JS = os.path.join(options.binaryen_root, 'out', 'binaryen.js')
def wrap_with_valgrind(cmd):
- # Exit code 97 is arbitrary, used to easily detect when an error occurs that
- # is detected by Valgrind.
- valgrind = [options.valgrind, '--quiet', '--error-exitcode=97']
- if options.valgrind_full_leak_check:
- valgrind += ['--leak-check=full', '--show-leak-kinds=all']
- return valgrind + cmd
+ # Exit code 97 is arbitrary, used to easily detect when an error occurs that
+ # is detected by Valgrind.
+ valgrind = [options.valgrind, '--quiet', '--error-exitcode=97']
+ if options.valgrind_full_leak_check:
+ valgrind += ['--leak-check=full', '--show-leak-kinds=all']
+ return valgrind + cmd
if options.valgrind:
- WASM_OPT = wrap_with_valgrind(WASM_OPT)
- WASM_AS = wrap_with_valgrind(WASM_AS)
- WASM_DIS = wrap_with_valgrind(WASM_DIS)
- ASM2WASM = wrap_with_valgrind(ASM2WASM)
- WASM_SHELL = wrap_with_valgrind(WASM_SHELL)
+ WASM_OPT = wrap_with_valgrind(WASM_OPT)
+ WASM_AS = wrap_with_valgrind(WASM_AS)
+ WASM_DIS = wrap_with_valgrind(WASM_DIS)
+ ASM2WASM = wrap_with_valgrind(ASM2WASM)
+ WASM_SHELL = wrap_with_valgrind(WASM_SHELL)
def in_binaryen(*args):
- __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
- return os.path.join(__rootpath__, *args)
+ __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+ return os.path.join(__rootpath__, *args)
os.environ['BINARYEN'] = in_binaryen()
def get_platform():
- return {'linux': 'linux',
- 'linux2': 'linux',
- 'darwin': 'mac',
- 'win32': 'windows',
- 'cygwin': 'windows'}[sys.platform]
+ return {'linux': 'linux',
+ 'linux2': 'linux',
+ 'darwin': 'mac',
+ 'win32': 'windows',
+ 'cygwin': 'windows'}[sys.platform]
def has_shell_timeout():
- return get_platform() != 'windows' and os.system('timeout 1s pwd') == 0
+ return get_platform() != 'windows' and os.system('timeout 1s pwd') == 0
# Default options to pass to v8. These enable all features.
V8_OPTS = [
- '--experimental-wasm-eh',
- '--experimental-wasm-mv',
- '--experimental-wasm-sat-f2i-conversions',
- '--experimental-wasm-se',
- '--experimental-wasm-threads',
- '--experimental-wasm-simd',
- '--experimental-wasm-anyref',
- '--experimental-wasm-bulk-memory',
- '--experimental-wasm-return-call'
+ '--experimental-wasm-eh',
+ '--experimental-wasm-mv',
+ '--experimental-wasm-sat-f2i-conversions',
+ '--experimental-wasm-se',
+ '--experimental-wasm-threads',
+ '--experimental-wasm-simd',
+ '--experimental-wasm-anyref',
+ '--experimental-wasm-bulk-memory',
+ '--experimental-wasm-return-call'
]
has_vanilla_llvm = False
@@ -232,232 +231,234 @@ has_vanilla_llvm = False
# external tools
try:
- if NODEJS is not None:
- subprocess.check_call(
- [NODEJS, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if NODEJS is not None:
+ subprocess.check_call([NODEJS, '--version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except (OSError, subprocess.CalledProcessError):
- NODEJS = None
+ NODEJS = None
if NODEJS is None:
- warn('no node found (did not check proper js form)')
+ warn('no node found (did not check proper js form)')
try:
- if MOZJS is not None:
- subprocess.check_call(
- [MOZJS, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if MOZJS is not None:
+ subprocess.check_call([MOZJS, '--version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except (OSError, subprocess.CalledProcessError):
- MOZJS = None
+ MOZJS = None
if MOZJS is None:
- warn('no mozjs found (did not check native wasm support nor asm.js'
- ' validation)')
+ warn('no mozjs found (did not check native wasm support nor asm.js'
+ ' validation)')
try:
- if EMCC is not None:
- subprocess.check_call(
- [EMCC, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if EMCC is not None:
+ subprocess.check_call([EMCC, '--version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except (OSError, subprocess.CalledProcessError):
- EMCC = None
+ EMCC = None
if EMCC is None:
- warn('no emcc found (did not check non-vanilla emscripten/binaryen'
- ' integration)')
+ warn('no emcc found (did not check non-vanilla emscripten/binaryen'
+ ' integration)')
has_vanilla_emcc = False
try:
- subprocess.check_call(
- [os.path.join(options.binaryen_test, 'emscripten', 'emcc'), '--version'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- has_vanilla_emcc = True
+ subprocess.check_call(
+ [os.path.join(options.binaryen_test, 'emscripten', 'emcc'), '--version'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ has_vanilla_emcc = True
except (OSError, subprocess.CalledProcessError):
- pass
+ pass
# utilities
# removes a file if it exists, using any and all ways of doing so
def delete_from_orbit(filename):
- try:
- os.unlink(filename)
- except OSError:
- pass
- if not os.path.exists(filename):
- return
- try:
- shutil.rmtree(filename, ignore_errors=True)
- except OSError:
- pass
- if not os.path.exists(filename):
- return
- try:
- import stat
- os.chmod(filename, os.stat(filename).st_mode | stat.S_IWRITE)
-
- def remove_readonly_and_try_again(func, path, exc_info):
- if not (os.stat(path).st_mode & stat.S_IWRITE):
- os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE)
- func(path)
- else:
- raise
- shutil.rmtree(filename, onerror=remove_readonly_and_try_again)
- except OSError:
- pass
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+ if not os.path.exists(filename):
+ return
+ try:
+ shutil.rmtree(filename, ignore_errors=True)
+ except OSError:
+ pass
+ if not os.path.exists(filename):
+ return
+ try:
+ import stat
+ os.chmod(filename, os.stat(filename).st_mode | stat.S_IWRITE)
+
+ def remove_readonly_and_try_again(func, path, exc_info):
+ if not (os.stat(path).st_mode & stat.S_IWRITE):
+ os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE)
+ func(path)
+ else:
+ raise
+ shutil.rmtree(filename, onerror=remove_readonly_and_try_again)
+ except OSError:
+ pass
# This is a workaround for https://bugs.python.org/issue9400
class Py2CalledProcessError(subprocess.CalledProcessError):
- def __init__(self, returncode, cmd, output=None, stderr=None):
- super(Exception, self).__init__(returncode, cmd, output, stderr)
- self.returncode = returncode
- self.cmd = cmd
- self.output = output
- self.stderr = stderr
+ def __init__(self, returncode, cmd, output=None, stderr=None):
+ super(Exception, self).__init__(returncode, cmd, output, stderr)
+ self.returncode = returncode
+ self.cmd = cmd
+ self.output = output
+ self.stderr = stderr
def run_process(cmd, check=True, input=None, capture_output=False, *args, **kw):
- if input and type(input) == str:
- input = bytes(input, 'utf-8')
- if capture_output:
- kw['stdout'] = subprocess.PIPE
- kw['stderr'] = subprocess.PIPE
- ret = subprocess.run(cmd, check=check, input=input, *args, **kw)
- if ret.stdout is not None:
- ret.stdout = ret.stdout.decode('utf-8')
- if ret.stderr is not None:
- ret.stderr = ret.stderr.decode('utf-8')
- return ret
+ if input and type(input) == str:
+ input = bytes(input, 'utf-8')
+ if capture_output:
+ kw['stdout'] = subprocess.PIPE
+ kw['stderr'] = subprocess.PIPE
+ ret = subprocess.run(cmd, check=check, input=input, *args, **kw)
+ if ret.stdout is not None:
+ ret.stdout = ret.stdout.decode('utf-8')
+ if ret.stderr is not None:
+ ret.stderr = ret.stderr.decode('utf-8')
+ return ret
def fail_with_error(msg):
- global num_failures
- try:
- num_failures += 1
- raise Exception(msg)
- except Exception as e:
- print(str(e))
- if options.abort_on_first_failure:
- raise
+ global num_failures
+ try:
+ num_failures += 1
+ raise Exception(msg)
+ except Exception as e:
+ print(str(e))
+ if options.abort_on_first_failure:
+ raise
def fail(actual, expected, fromfile='expected'):
- diff_lines = difflib.unified_diff(
- expected.split('\n'), actual.split('\n'),
- fromfile=fromfile, tofile='actual')
- diff_str = ''.join([a.rstrip() + '\n' for a in diff_lines])[:]
- fail_with_error("incorrect output, diff:\n\n%s" % diff_str)
+ diff_lines = difflib.unified_diff(
+ expected.split('\n'), actual.split('\n'),
+ fromfile=fromfile, tofile='actual')
+ diff_str = ''.join([a.rstrip() + '\n' for a in diff_lines])[:]
+ fail_with_error("incorrect output, diff:\n\n%s" % diff_str)
def fail_if_not_identical(actual, expected, fromfile='expected'):
- if expected != actual:
- fail(actual, expected, fromfile=fromfile)
+ if expected != actual:
+ fail(actual, expected, fromfile=fromfile)
def fail_if_not_contained(actual, expected):
- if expected not in actual:
- fail(actual, expected)
+ if expected not in actual:
+ fail(actual, expected)
def fail_if_not_identical_to_file(actual, expected_file):
- binary = expected_file.endswith(".wasm") or type(actual) == bytes
- with open(expected_file, 'rb' if binary else 'r') as f:
- fail_if_not_identical(actual, f.read(), fromfile=expected_file)
+ binary = expected_file.endswith(".wasm") or type(actual) == bytes
+ with open(expected_file, 'rb' if binary else 'r') as f:
+ fail_if_not_identical(actual, f.read(), fromfile=expected_file)
if len(requested) == 0:
- tests = sorted(os.listdir(os.path.join(options.binaryen_test)))
+ tests = sorted(os.listdir(os.path.join(options.binaryen_test)))
else:
- tests = requested[:]
+ tests = requested[:]
if not options.interpreter:
- warn('no interpreter provided (did not test spec interpreter validation)')
+ warn('no interpreter provided (did not test spec interpreter validation)')
if not has_vanilla_emcc:
- warn('no functional emcc submodule found')
+ warn('no functional emcc submodule found')
# check utilities
def validate_binary(wasm):
- if V8:
- cmd = [V8] + V8_OPTS + [in_binaryen('scripts', 'validation_shell.js'), '--', wasm]
- print(' ', ' '.join(cmd))
- subprocess.check_call(cmd, stdout=subprocess.PIPE)
- else:
- print('(skipping v8 binary validation)')
+ if V8:
+ cmd = [V8] + V8_OPTS + [in_binaryen('scripts', 'validation_shell.js'), '--', wasm]
+ print(' ', ' '.join(cmd))
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
+ else:
+ print('(skipping v8 binary validation)')
def binary_format_check(wast, verify_final_result=True, wasm_as_args=['-g'],
binary_suffix='.fromBinary', original_wast=None):
- # checks we can convert the wast to binary and back
-
- print(' (binary format check)')
- cmd = WASM_AS + [wast, '-o', 'a.wasm', '-all'] + wasm_as_args
- print(' ', ' '.join(cmd))
- if os.path.exists('a.wasm'):
- os.unlink('a.wasm')
- subprocess.check_call(cmd, stdout=subprocess.PIPE)
- assert os.path.exists('a.wasm')
-
- # make sure it is a valid wasm, using a real wasm VM
- if os.path.basename(original_wast or wast) not in [
- 'atomics.wast', # https://bugs.chromium.org/p/v8/issues/detail?id=9425
- 'simd.wast', # https://bugs.chromium.org/p/v8/issues/detail?id=8460
- ]:
- validate_binary('a.wasm')
-
- cmd = WASM_DIS + ['a.wasm', '-o', 'ab.wast']
- print(' ', ' '.join(cmd))
- if os.path.exists('ab.wast'):
- os.unlink('ab.wast')
- subprocess.check_call(cmd, stdout=subprocess.PIPE)
- assert os.path.exists('ab.wast')
-
- # make sure it is a valid wast
- cmd = WASM_OPT + ['ab.wast', '-all']
- print(' ', ' '.join(cmd))
- subprocess.check_call(cmd, stdout=subprocess.PIPE)
-
- if verify_final_result:
- actual = open('ab.wast').read()
- fail_if_not_identical_to_file(actual, wast + binary_suffix)
-
- return 'ab.wast'
+ # checks we can convert the wast to binary and back
+
+ print(' (binary format check)')
+ cmd = WASM_AS + [wast, '-o', 'a.wasm', '-all'] + wasm_as_args
+ print(' ', ' '.join(cmd))
+ if os.path.exists('a.wasm'):
+ os.unlink('a.wasm')
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
+ assert os.path.exists('a.wasm')
+
+ # make sure it is a valid wasm, using a real wasm VM
+ if os.path.basename(original_wast or wast) not in [
+ 'atomics.wast', # https://bugs.chromium.org/p/v8/issues/detail?id=9425
+ 'simd.wast', # https://bugs.chromium.org/p/v8/issues/detail?id=8460
+ ]:
+ validate_binary('a.wasm')
+
+ cmd = WASM_DIS + ['a.wasm', '-o', 'ab.wast']
+ print(' ', ' '.join(cmd))
+ if os.path.exists('ab.wast'):
+ os.unlink('ab.wast')
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
+ assert os.path.exists('ab.wast')
+
+ # make sure it is a valid wast
+ cmd = WASM_OPT + ['ab.wast', '-all']
+ print(' ', ' '.join(cmd))
+ subprocess.check_call(cmd, stdout=subprocess.PIPE)
+
+ if verify_final_result:
+ actual = open('ab.wast').read()
+ fail_if_not_identical_to_file(actual, wast + binary_suffix)
+
+ return 'ab.wast'
def minify_check(wast, verify_final_result=True):
- # checks we can parse minified output
-
- print(' (minify check)')
- cmd = WASM_OPT + [wast, '--print-minified', '-all']
- print(' ', ' '.join(cmd))
- subprocess.check_call(cmd, stdout=open('a.wast', 'w'), stderr=subprocess.PIPE)
- assert os.path.exists('a.wast')
- subprocess.check_call(
- WASM_OPT + ['a.wast', '--print-minified', '-all'],
- stdout=open('b.wast', 'w'), stderr=subprocess.PIPE)
- assert os.path.exists('b.wast')
- if verify_final_result:
- expected = open('a.wast').read()
- actual = open('b.wast').read()
- if actual != expected:
- fail(actual, expected)
- if os.path.exists('a.wast'):
- os.unlink('a.wast')
- if os.path.exists('b.wast'):
- os.unlink('b.wast')
+ # checks we can parse minified output
+
+ print(' (minify check)')
+ cmd = WASM_OPT + [wast, '--print-minified', '-all']
+ print(' ', ' '.join(cmd))
+ subprocess.check_call(cmd, stdout=open('a.wast', 'w'), stderr=subprocess.PIPE)
+ assert os.path.exists('a.wast')
+ subprocess.check_call(WASM_OPT + ['a.wast', '--print-minified', '-all'],
+ stdout=open('b.wast', 'w'), stderr=subprocess.PIPE)
+ assert os.path.exists('b.wast')
+ if verify_final_result:
+ expected = open('a.wast').read()
+ actual = open('b.wast').read()
+ if actual != expected:
+ fail(actual, expected)
+ if os.path.exists('a.wast'):
+ os.unlink('a.wast')
+ if os.path.exists('b.wast'):
+ os.unlink('b.wast')
def files_with_pattern(*path_pattern):
- return sorted(glob.glob(os.path.join(*path_pattern)))
+ return sorted(glob.glob(os.path.join(*path_pattern)))
# run a check with BINARYEN_PASS_DEBUG set, to do full validation
def with_pass_debug(check):
- old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG')
- try:
- os.environ['BINARYEN_PASS_DEBUG'] = '1'
- check()
- 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']
+ old_pass_debug = os.environ.get('BINARYEN_PASS_DEBUG')
+ try:
+ os.environ['BINARYEN_PASS_DEBUG'] = '1'
+ check()
+ 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']
diff --git a/scripts/test/support.py b/scripts/test/support.py
index 90bc531eb..8f48a7af9 100644
--- a/scripts/test/support.py
+++ b/scripts/test/support.py
@@ -21,178 +21,178 @@ import tempfile
def _open_archive(tarfile, tmp_dir):
- with tempfile.TemporaryFile(mode='w+') as f:
- try:
- subprocess.check_call(['tar', '-xvf', tarfile], cwd=tmp_dir, stdout=f)
- except Exception:
- f.seek(0)
- sys.stderr.write(f.read())
- raise
- return os.listdir(tmp_dir)
+ with tempfile.TemporaryFile(mode='w+') as f:
+ try:
+ subprocess.check_call(['tar', '-xvf', tarfile], cwd=tmp_dir, stdout=f)
+ except Exception:
+ f.seek(0)
+ sys.stderr.write(f.read())
+ raise
+ return os.listdir(tmp_dir)
def _files_same(dir1, dir2, basenames):
- diff = filecmp.cmpfiles(dir1, dir2, basenames)
- return 0 == len(diff[1] + diff[2])
+ diff = filecmp.cmpfiles(dir1, dir2, basenames)
+ return 0 == len(diff[1] + diff[2])
def _dirs_same(dir1, dir2, basenames):
- for d in basenames:
- left = os.path.join(dir1, d)
- right = os.path.join(dir2, d)
- if not (os.path.isdir(left) and os.path.isdir(right)):
- return False
- diff = filecmp.dircmp(right, right)
- if 0 != len(diff.left_only + diff.right_only + diff.diff_files +
- diff.common_funny + diff.funny_files):
- return False
- return True
+ for d in basenames:
+ left = os.path.join(dir1, d)
+ right = os.path.join(dir2, d)
+ if not (os.path.isdir(left) and os.path.isdir(right)):
+ return False
+ diff = filecmp.dircmp(right, right)
+ if 0 != len(diff.left_only + diff.right_only + diff.diff_files +
+ diff.common_funny + diff.funny_files):
+ return False
+ return True
def _move_files(dirfrom, dirto, basenames):
- for f in basenames:
- from_file = os.path.join(dirfrom, f)
- to_file = os.path.join(dirto, f)
- if os.path.isfile(to_file):
- os.path.remove(to_file)
- shutil.move(from_file, to_file)
+ for f in basenames:
+ from_file = os.path.join(dirfrom, f)
+ to_file = os.path.join(dirto, f)
+ if os.path.isfile(to_file):
+ os.path.remove(to_file)
+ shutil.move(from_file, to_file)
def _move_dirs(dirfrom, dirto, basenames):
for d in basenames:
- from_dir = os.path.join(dirfrom, d)
- to_dir = os.path.join(dirto, d)
- if os.path.isdir(to_dir):
- shutil.rmtree(to_dir)
- shutil.move(from_dir, to_dir)
+ from_dir = os.path.join(dirfrom, d)
+ to_dir = os.path.join(dirto, d)
+ if os.path.isdir(to_dir):
+ shutil.rmtree(to_dir)
+ shutil.move(from_dir, to_dir)
def untar(tarfile, outdir):
- """Returns True if untar content differs from pre-existing outdir content."""
- tmpdir = tempfile.mkdtemp()
- try:
- untared = _open_archive(tarfile, tmpdir)
- files = [f for f in untared if os.path.isfile(os.path.join(tmpdir, f))]
- dirs = [d for d in untared if os.path.isdir(os.path.join(tmpdir, d))]
- assert len(files) + len(dirs) == len(untared), 'Only files and directories'
- if _files_same(tmpdir, outdir, files) and _dirs_same(tmpdir, outdir, dirs):
- # Nothing new or different in the tarfile.
- return False
- # Some or all of the files / directories are new.
- _move_files(tmpdir, outdir, files)
- _move_dirs(tmpdir, outdir, dirs)
- return True
- finally:
- if os.path.isdir(tmpdir):
- shutil.rmtree(tmpdir)
+ """Returns True if untar content differs from pre-existing outdir content."""
+ tmpdir = tempfile.mkdtemp()
+ try:
+ untared = _open_archive(tarfile, tmpdir)
+ files = [f for f in untared if os.path.isfile(os.path.join(tmpdir, f))]
+ dirs = [d for d in untared if os.path.isdir(os.path.join(tmpdir, d))]
+ assert len(files) + len(dirs) == len(untared), 'Only files and directories'
+ if _files_same(tmpdir, outdir, files) and _dirs_same(tmpdir, outdir, dirs):
+ # Nothing new or different in the tarfile.
+ return False
+ # Some or all of the files / directories are new.
+ _move_files(tmpdir, outdir, files)
+ _move_dirs(tmpdir, outdir, dirs)
+ return True
+ finally:
+ if os.path.isdir(tmpdir):
+ shutil.rmtree(tmpdir)
def split_wast(wastFile):
- # if it's a binary, leave it as is, we can't split it
- wast = None
- if not wastFile.endswith('.wasm'):
- try:
- wast = open(wastFile, 'r').read()
- except Exception:
- pass
-
- if not wast:
- return ((open(wastFile, 'rb').read(), []),)
-
- # .wast files can contain multiple modules, and assertions for each one.
- # this splits out a wast into [(module, assertions), ..]
- # we ignore module invalidity tests here.
- ret = []
-
- def to_end(j):
- depth = 1
- while depth > 0 and j < len(wast):
- if wast[j] == '"':
- while 1:
- j = wast.find('"', j + 1)
- if wast[j - 1] == '\\':
+ # if it's a binary, leave it as is, we can't split it
+ wast = None
+ if not wastFile.endswith('.wasm'):
+ try:
+ wast = open(wastFile, 'r').read()
+ except Exception:
+ pass
+
+ if not wast:
+ return ((open(wastFile, 'rb').read(), []),)
+
+ # .wast files can contain multiple modules, and assertions for each one.
+ # this splits out a wast into [(module, assertions), ..]
+ # we ignore module invalidity tests here.
+ ret = []
+
+ def to_end(j):
+ depth = 1
+ while depth > 0 and j < len(wast):
+ if wast[j] == '"':
+ while 1:
+ j = wast.find('"', j + 1)
+ if wast[j - 1] == '\\':
+ continue
+ break
+ assert j > 0
+ elif wast[j] == '(':
+ depth += 1
+ elif wast[j] == ')':
+ depth -= 1
+ elif wast[j] == ';' and wast[j + 1] == ';':
+ j = wast.find('\n', j)
+ j += 1
+ return j
+
+ i = 0
+ while i >= 0:
+ start = wast.find('(', i)
+ if start >= 0 and wast[start + 1] == ';':
+ # block comment
+ i = wast.find(';)', start + 2)
+ assert i > 0, wast[start:]
+ i += 2
+ continue
+ skip = wast.find(';', i)
+ if skip >= 0 and skip < start and skip + 1 < len(wast):
+ if wast[skip + 1] == ';':
+ i = wast.find('\n', i) + 1
+ continue
+ if start < 0:
+ break
+ i = to_end(start + 1)
+ chunk = wast[start:i]
+ if chunk.startswith('(module'):
+ ret += [(chunk, [])]
+ elif chunk.startswith('(assert_invalid'):
continue
- break
- assert j > 0
- elif wast[j] == '(':
- depth += 1
- elif wast[j] == ')':
- depth -= 1
- elif wast[j] == ';' and wast[j + 1] == ';':
- j = wast.find('\n', j)
- j += 1
- return j
-
- i = 0
- while i >= 0:
- start = wast.find('(', i)
- if start >= 0 and wast[start + 1] == ';':
- # block comment
- i = wast.find(';)', start + 2)
- assert i > 0, wast[start:]
- i += 2
- continue
- skip = wast.find(';', i)
- if skip >= 0 and skip < start and skip + 1 < len(wast):
- if wast[skip + 1] == ';':
- i = wast.find('\n', i) + 1
- continue
- if start < 0:
- break
- i = to_end(start + 1)
- chunk = wast[start:i]
- if chunk.startswith('(module'):
- ret += [(chunk, [])]
- elif chunk.startswith('(assert_invalid'):
- continue
- elif chunk.startswith(('(assert', '(invoke')):
- ret[-1][1].append(chunk)
- return ret
+ elif chunk.startswith(('(assert', '(invoke')):
+ ret[-1][1].append(chunk)
+ return ret
# write a split wast from split_wast. the wast may be binary if the original
# file was binary
def write_wast(filename, wast, asserts=[]):
- if type(wast) == bytes:
- assert not asserts
- with open(filename, 'wb') as o:
- o.write(wast)
- else:
- with open(filename, 'w') as o:
- o.write(wast + '\n'.join(asserts))
+ if type(wast) == bytes:
+ assert not asserts
+ with open(filename, 'wb') as o:
+ o.write(wast)
+ else:
+ with open(filename, 'w') as o:
+ o.write(wast + '\n'.join(asserts))
def run_command(cmd, expected_status=0, stderr=None,
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"
- stderr = subprocess.PIPE
- print('executing: ', ' '.join(cmd))
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=stderr, universal_newlines=True)
- out, err = proc.communicate()
- code = proc.returncode
- if expected_status is not None and code != expected_status:
- raise Exception(('run_command failed (%s)' % code, out + str(err or '')))
- 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
+ if expected_err is not None:
+ assert stderr == subprocess.PIPE or stderr is None,\
+ "Can't redirect stderr if using expected_err"
+ stderr = subprocess.PIPE
+ print('executing: ', ' '.join(cmd))
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=stderr, universal_newlines=True)
+ out, err = proc.communicate()
+ code = proc.returncode
+ if expected_status is not None and code != expected_status:
+ raise Exception(('run_command failed (%s)' % code, out + str(err or '')))
+ 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
def node_has_webassembly(cmd):
- cmd = [cmd, '-e', 'process.stdout.write(typeof WebAssembly)']
- return run_command(cmd) == 'object'
+ cmd = [cmd, '-e', 'process.stdout.write(typeof WebAssembly)']
+ return run_command(cmd) == 'object'
def node_test_glue():
- # running concatenated files (a.js) in node interferes with module loading
- # because the concatenated file expects a 'var Binaryen' but binaryen.js
- # assigned to module.exports. this is correct behavior but tests then need
- # a workaround:
- return ('if (typeof module === "object" && typeof exports === "object")\n'
- ' Binaryen = module.exports;\n')
+ # running concatenated files (a.js) in node interferes with module loading
+ # because the concatenated file expects a 'var Binaryen' but binaryen.js
+ # assigned to module.exports. this is correct behavior but tests then need
+ # a workaround:
+ return ('if (typeof module === "object" && typeof exports === "object")\n'
+ ' Binaryen = module.exports;\n')
diff --git a/scripts/test/wasm2js.py b/scripts/test/wasm2js.py
index 8c8f9a840..39ba946fe 100755
--- a/scripts/test/wasm2js.py
+++ b/scripts/test/wasm2js.py
@@ -36,155 +36,155 @@ wasm2js_blacklist = ['empty_imported_table.wast']
def test_wasm2js_output():
- for opt in (0, 1):
- 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
+ for opt in (0, 1):
+ 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 opt:
- expected_file += '.opt'
+ asm = basename.replace('.wast', '.2asm.js')
+ expected_file = os.path.join(wasm2js_dir, asm)
+ if opt:
+ expected_file += '.opt'
- if not os.path.exists(expected_file):
- continue
+ if not os.path.exists(expected_file):
+ continue
- print('..', wasm)
+ print('..', wasm)
- t = os.path.join(options.binaryen_test, wasm)
+ t = os.path.join(options.binaryen_test, wasm)
- all_out = []
+ all_out = []
- for module, asserts in split_wast(t):
- write_wast('split.wast', module, asserts)
+ for module, asserts in split_wast(t):
+ write_wast('split.wast', module, asserts)
- cmd = WASM2JS + ['split.wast']
- if opt:
- cmd += ['-O']
- if 'emscripten' in wasm:
- cmd += ['--emscripten']
- out = run_command(cmd)
- all_out.append(out)
+ cmd = WASM2JS + ['split.wast']
+ if opt:
+ cmd += ['-O']
+ if 'emscripten' in wasm:
+ cmd += ['--emscripten']
+ out = run_command(cmd)
+ all_out.append(out)
- if not NODEJS and not MOZJS:
- print('No JS interpreters. Skipping spec tests.')
- continue
+ if not NODEJS and not MOZJS:
+ print('No JS interpreters. Skipping spec tests.')
+ continue
- open('a.2asm.mjs', 'w').write(out)
+ open('a.2asm.mjs', 'w').write(out)
- cmd += ['--allow-asserts']
- out = run_command(cmd)
- # also verify it passes pass-debug verifications
- with_pass_debug(lambda: run_command(cmd))
+ cmd += ['--allow-asserts']
+ out = run_command(cmd)
+ # also verify it passes pass-debug verifications
+ with_pass_debug(lambda: run_command(cmd))
- open('a.2asm.asserts.mjs', 'w').write(out)
+ 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` and `env` modules 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, '')
+ # 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` and `env` modules 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, '')
- fail_if_not_identical_to_file(''.join(all_out), expected_file)
+ fail_if_not_identical_to_file(''.join(all_out), expected_file)
def test_asserts_output():
- for wasm in assert_tests:
- print('..', wasm)
+ 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)
+ 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)
+ 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)
+ 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()
+ print('\n[ checking wasm2js testcases... ]\n')
+ test_wasm2js_output()
+ test_asserts_output()
def update_wasm2js_tests():
- print('\n[ checking wasm2js ]\n')
+ print('\n[ checking wasm2js ]\n')
- for opt in (0, 1):
- for wasm in tests + spec_tests + extra_wasm2js_tests:
- if not wasm.endswith('.wast'):
- continue
+ for opt in (0, 1):
+ for wasm in tests + spec_tests + extra_wasm2js_tests:
+ if not wasm.endswith('.wast'):
+ continue
- if os.path.basename(wasm) in wasm2js_blacklist:
- continue
+ if os.path.basename(wasm) in wasm2js_blacklist:
+ continue
- asm = os.path.basename(wasm).replace('.wast', '.2asm.js')
- expected_file = os.path.join(wasm2js_dir, asm)
- if opt:
- expected_file += '.opt'
+ asm = os.path.basename(wasm).replace('.wast', '.2asm.js')
+ expected_file = os.path.join(wasm2js_dir, asm)
+ if opt:
+ expected_file += '.opt'
- # we run wasm2js on tests and spec tests only if the output
- # exists - only some work so far. the tests in extra are in
- # the test/wasm2js dir and so are specific to wasm2js, and
- # we run all of those.
- if wasm not in extra_wasm2js_tests and not os.path.exists(expected_file):
- continue
+ # we run wasm2js on tests and spec tests only if the output
+ # exists - only some work so far. the tests in extra are in
+ # the test/wasm2js dir and so are specific to wasm2js, and
+ # we run all of those.
+ if wasm not in extra_wasm2js_tests and not os.path.exists(expected_file):
+ continue
- print('..', wasm)
+ print('..', wasm)
- t = os.path.join(options.binaryen_test, wasm)
+ t = os.path.join(options.binaryen_test, wasm)
- all_out = []
+ all_out = []
- for module, asserts in split_wast(t):
- write_wast('split.wast', module, asserts)
+ for module, asserts in split_wast(t):
+ write_wast('split.wast', module, asserts)
- cmd = WASM2JS + ['split.wast']
- if opt:
- cmd += ['-O']
- if 'emscripten' in wasm:
- cmd += ['--emscripten']
- out = run_command(cmd)
- all_out.append(out)
+ cmd = WASM2JS + ['split.wast']
+ if opt:
+ cmd += ['-O']
+ if 'emscripten' in wasm:
+ cmd += ['--emscripten']
+ out = run_command(cmd)
+ all_out.append(out)
- with open(expected_file, 'w') as o:
- o.write(''.join(all_out))
+ with open(expected_file, 'w') as o:
+ o.write(''.join(all_out))
- for wasm in assert_tests:
- print('..', wasm)
+ 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('test', asserts)
- traps_expected_file = os.path.join('test', traps)
+ 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('test', asserts)
+ traps_expected_file = os.path.join('test', traps)
- cmd = WASM2JS + [os.path.join(wasm2js_dir, wasm), '--allow-asserts']
- out = run_command(cmd)
- with open(asserts_expected_file, 'w') as o:
- o.write(out)
+ cmd = WASM2JS + [os.path.join(wasm2js_dir, wasm), '--allow-asserts']
+ out = run_command(cmd)
+ with open(asserts_expected_file, 'w') as o:
+ o.write(out)
- cmd += ['--pedantic']
- out = run_command(cmd)
- with open(traps_expected_file, 'w') as o:
- o.write(out)
+ cmd += ['--pedantic']
+ out = run_command(cmd)
+ with open(traps_expected_file, 'w') as o:
+ o.write(out)
if __name__ == "__main__":
- test_wasm2js()
+ test_wasm2js()