|
17 | 17 | import difflib |
18 | 18 | import subprocess |
19 | 19 | import random |
| 20 | +import re |
20 | 21 | import shutil |
21 | 22 | import time |
22 | 23 |
|
@@ -64,85 +65,88 @@ def randomize_pass_debug(): |
64 | 65 | IGNORE = '[binaryen-fuzzer-ignore]' |
65 | 66 |
|
66 | 67 |
|
67 | | -def test_one(infile, opts): |
68 | | - def compare(x, y, comment): |
69 | | - if x != y and x != IGNORE and y != IGNORE: |
70 | | - message = ''.join([a.rstrip() + '\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')]) |
71 | | - raise Exception(str(comment) + ": Expected to have '%s' == '%s', diff:\n\n%s" % ( |
72 | | - x, y, |
73 | | - message |
74 | | - )) |
75 | | - |
76 | | - def run_vms(prefix): |
77 | | - def fix_output(out): |
78 | | - # exceptions may differ when optimizing, but an exception should occur. so ignore their types |
79 | | - # also js engines print them out slightly differently |
80 | | - return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.split('\n'))) |
81 | | - |
82 | | - # normalize different vm output |
83 | | - # also the binaryen optimizer can reorder traps (but not remove them), so |
84 | | - # it really just matters if you trap, not how you trap |
85 | | - return out.replace('unreachable executed', 'unreachable') \ |
86 | | - .replace('integer result unrepresentable', 'integer overflow') \ |
87 | | - .replace('invalid conversion to integer', 'integer overflow') \ |
88 | | - .replace('memory access out of bounds', 'index out of bounds') \ |
89 | | - .replace('integer divide by zero', 'divide by zero') \ |
90 | | - .replace('integer remainder by zero', 'remainder by zero') \ |
91 | | - .replace('remainder by zero', 'divide by zero') \ |
92 | | - .replace('divide result unrepresentable', 'integer overflow') \ |
93 | | - .replace('divide by zero', 'integer overflow') \ |
94 | | - .replace('index out of bounds', 'integer overflow') \ |
95 | | - .replace('out of bounds memory access', 'integer overflow') |
96 | | - |
97 | | - def fix_spec_output(out): |
98 | | - out = fix_output(out) |
99 | | - # spec shows a pointer when it traps, remove that |
100 | | - out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.split('\n'))) |
101 | | - # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up |
102 | | - out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.split('\n'))) |
103 | | - return out |
104 | | - |
105 | | - def run_vm(cmd): |
106 | | - # ignore some vm assertions, if bugs have already been filed |
107 | | - known_issues = [ |
108 | | - 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes |
109 | | - 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631 |
110 | | - 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632 |
111 | | - ] |
112 | | - try: |
113 | | - return run(cmd) |
114 | | - except: |
115 | | - output = run_unchecked(cmd) |
116 | | - for issue in known_issues: |
117 | | - if issue in output: |
118 | | - return IGNORE |
119 | | - raise |
120 | | - |
121 | | - results = [] |
122 | | - # append to this list to add results from VMs |
123 | | - results += [fix_output(run_vm([os.path.expanduser('d8'), prefix + 'js', '--', prefix + 'wasm']))] |
124 | | - results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))] |
125 | | - results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--no-wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))] |
126 | | - # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically |
127 | | - # run(['../spec/interpreter/wasm', prefix + 'wasm']) |
128 | | - # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', prefix + 'wasm', '-e', open(prefix + 'wat').read()]))] |
129 | | - |
130 | | - if len(results) == 0: |
131 | | - results = [0] |
132 | | - |
133 | | - first = results[0] |
134 | | - for i in range(len(results)): |
135 | | - compare(first, results[i], 'comparing between vms at ' + str(i)) |
136 | | - |
137 | | - return results |
| 68 | +def compare(x, y, comment): |
| 69 | + if x != y and x != IGNORE and y != IGNORE: |
| 70 | + message = ''.join([a.rstrip() + '\n' for a in difflib.unified_diff(x.split('\n'), y.split('\n'), fromfile='expected', tofile='actual')]) |
| 71 | + raise Exception(str(comment) + ": Expected to have '%s' == '%s', diff:\n\n%s" % ( |
| 72 | + x, y, |
| 73 | + message |
| 74 | + )) |
| 75 | + |
| 76 | + |
| 77 | +def run_vms(prefix): |
| 78 | + def fix_output(out): |
| 79 | + # large doubles may print slightly different on different VMs |
| 80 | + def fix_double(x): |
| 81 | + x = x.group(1) |
| 82 | + if 'nan' in x or 'NaN' in x: |
| 83 | + x = 'nan' |
| 84 | + else: |
| 85 | + x = x.replace('Infinity', 'inf') |
| 86 | + x = str(float(x)) |
| 87 | + return 'f64.const ' + x |
| 88 | + out = re.sub(r'f64\.const (-?[nanN:abcdefxIity\d+-.]+)', fix_double, out) |
| 89 | + |
| 90 | + # mark traps from wasm-opt as exceptions, even though they didn't run in a vm |
| 91 | + out = out.replace('[trap ', 'exception: [trap ') |
| 92 | + |
| 93 | + # exceptions may differ when optimizing, but an exception should occur. so ignore their types |
| 94 | + # also js engines print them out slightly differently |
| 95 | + return '\n'.join(map(lambda x: ' *exception*' if 'exception' in x else x, out.split('\n'))) |
| 96 | + |
| 97 | + def fix_spec_output(out): |
| 98 | + out = fix_output(out) |
| 99 | + # spec shows a pointer when it traps, remove that |
| 100 | + out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.split('\n'))) |
| 101 | + # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up |
| 102 | + out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.split('\n'))) |
| 103 | + return out |
| 104 | + |
| 105 | + def run_vm(cmd): |
| 106 | + # ignore some vm assertions, if bugs have already been filed |
| 107 | + known_issues = [ |
| 108 | + 'local count too large', # ignore this; can be caused by flatten, ssa, etc. passes |
| 109 | + 'liftoff-assembler.cc, line 239\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631 |
| 110 | + 'liftoff-assembler.cc, line 245\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8631 |
| 111 | + 'liftoff-register.h, line 86\n', # https://bugs.chromium.org/p/v8/issues/detail?id=8632 |
| 112 | + ] |
| 113 | + try: |
| 114 | + return run(cmd) |
| 115 | + except: |
| 116 | + output = run_unchecked(cmd) |
| 117 | + for issue in known_issues: |
| 118 | + if issue in output: |
| 119 | + return IGNORE |
| 120 | + raise |
| 121 | + |
| 122 | + results = [] |
| 123 | + # append to this list to add results from VMs |
| 124 | + results += [fix_output(run_vm([in_bin('wasm-opt'), prefix + 'wasm', '--fuzz-exec-before']))] |
| 125 | + results += [fix_output(run_vm([os.path.expanduser('d8'), '--experimental-wasm-sat_f2i_conversions', prefix + 'js', '--', prefix + 'wasm']))] |
| 126 | + results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--experimental-wasm-sat_f2i_conversions', '--wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))] |
| 127 | + results += [fix_output(run_vm([os.path.expanduser('d8-debug'), '--experimental-wasm-sat_f2i_conversions', '--no-wasm-tier-up', prefix + 'js', '--', prefix + 'wasm']))] |
| 128 | + # spec has no mechanism to not halt on a trap. so we just check until the first trap, basically |
| 129 | + # run(['../spec/interpreter/wasm', prefix + 'wasm']) |
| 130 | + # results += [fix_spec_output(run_unchecked(['../spec/interpreter/wasm', prefix + 'wasm', '-e', open(prefix + 'wat').read()]))] |
| 131 | + |
| 132 | + if len(results) == 0: |
| 133 | + results = [0] |
| 134 | + |
| 135 | + first = results[0] |
| 136 | + for i in range(len(results)): |
| 137 | + compare(first, results[i], 'comparing between vms at ' + str(i)) |
| 138 | + |
| 139 | + return results |
| 140 | + |
138 | 141 |
|
| 142 | +def test_one(infile, opts): |
139 | 143 | randomize_pass_debug() |
140 | 144 |
|
141 | 145 | bytes = 0 |
142 | 146 |
|
143 | 147 | # fuzz vms |
144 | 148 | # gather VM outputs on input file |
145 | | - run([in_bin('wasm-opt'), infile, '-ttf', '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat', '-o', 'a.wasm', '--mvp-features']) |
| 149 | + run([in_bin('wasm-opt'), infile, '-ttf', '--emit-js-wrapper=a.js', '--emit-spec-wrapper=a.wat', '-o', 'a.wasm', '--mvp-features', '--enable-nontrapping-float-to-int']) |
146 | 150 | wasm_size = os.stat('a.wasm').st_size |
147 | 151 | bytes += wasm_size |
148 | 152 | print('pre js size :', os.stat('a.js').st_size, ' wasm size:', wasm_size) |
|
0 commit comments