Skip to content

Stack machine + 0xc update #678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 78 commits into from
Sep 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
b349c22
better printing when assert_invalids fail
kripken Aug 3, 2016
96c4740
debugging in print
kripken Aug 1, 2016
981c7ef
make sure to create unique implicit block names in s-parser
kripken Jul 30, 2016
c846fb7
fix parsing in split_wast
kripken Jul 29, 2016
f9020a0
remove drop-return-values pass
kripken Aug 7, 2016
9507066
remove lower-if-else, as it's no longer needed
kripken Aug 7, 2016
0783d60
remove wasm2asm tests, temporarily disable .s tests
kripken Aug 30, 2016
9d27d68
add drop and tee expressions
kripken Aug 7, 2016
1cc3390
it is not cool to return a nop
kripken Aug 3, 2016
7261697
call_indirect now has the target at the end
kripken Aug 3, 2016
f30d9f6
loops no longer have an out label and other upstream loop updates
kripken Aug 3, 2016
4215505
move drop into blocks, dropping all the breaks as well, when possible
kripken Aug 4, 2016
f48690c
select values must be valid
kripken Aug 5, 2016
e9d057d
fix compilation error on recent clang
kripken Aug 7, 2016
abb4981
don't depend on order of operations in calls, it varies by compiler
kripken Aug 7, 2016
676be66
TEMP no torture tests for now
kripken Aug 7, 2016
fb5d853
TEMP no wasm backend tests for now
kripken Aug 7, 2016
15240ea
update binary version to 0x0c
kripken Aug 9, 2016
ef82c85
wasm-shell improvements: print out which module is built, add option …
kripken Aug 9, 2016
0b6faf4
throw a parse error on bad result arities
kripken Aug 9, 2016
af7985c
tolerate returning a nop
kripken Aug 9, 2016
08293f0
ignore unused return values in functions
kripken Aug 9, 2016
f0bc2a7
WIP get spec tests to pass by ignoring stacky stuff
kripken Aug 9, 2016
5d1af1e
parse s-expression quoted strings more carefully
kripken Aug 9, 2016
b19f9fe
print wasm types in full mode
kripken Aug 9, 2016
8014a63
check store value type, and validation printing improvements
kripken Aug 9, 2016
34d614a
call_indirect is now structural, so no need to pass the type name around
kripken Aug 16, 2016
c774db5
a table is needed if there is a call_indirect
kripken Aug 16, 2016
a8356e1
support (memory (data ..)) notation
kripken Aug 16, 2016
ccec65e
some additional validations
kripken Aug 16, 2016
2f5c818
SetGlobal should not return a value
kripken Aug 16, 2016
38fdfdd
globals printing fix, handle the case with no module
kripken Aug 16, 2016
99410c9
interpreter debug and asserts fixing
kripken Aug 16, 2016
1780339
grow_memory no longer traps
kripken Aug 17, 2016
094a4e8
update tests
kripken Aug 17, 2016
fbd3c89
update check.py skip lists for spec tests
kripken Aug 17, 2016
15a264e
add an ExpressionStack traversal
kripken Aug 17, 2016
ada1e26
add a drop for final elements in blocks if they are not used
kripken Aug 17, 2016
e080968
support (data .. ..), separate strings in a data()
kripken Aug 17, 2016
2e2e024
export kinds
kripken Aug 18, 2016
793863a
import kinds
kripken Aug 18, 2016
a10ca64
import type for globals
kripken Aug 19, 2016
9660c20
get_global and set_global use a Name instead of an Index, to be more …
kripken Aug 19, 2016
266e922
use globals in asm2wasm
kripken Aug 19, 2016
db5ee8d
set type of calls to their target, instead of the previous behavior w…
kripken Aug 22, 2016
3eb8c8b
asm2wasm debugging asserts
kripken Aug 22, 2016
2607050
fix ControlFlowWalker handling of ifs when looking for break targets
kripken Aug 22, 2016
9c1947f
improve full mode printing
kripken Aug 22, 2016
83e0dde
fix AutoDrop block handling - the block type might change as we modif…
kripken Aug 22, 2016
f3bb9de
handle asm.js globals that are set and the return value used
kripken Aug 22, 2016
d044aea
run vacuum again after autodrop in asm2wasm, if optimizing
kripken Aug 22, 2016
c9b4cd0
drop the first element in a block too, if necessary
kripken Aug 23, 2016
31fca05
finalize loops in asm2wasm, which is now necessary as they may need t…
kripken Aug 23, 2016
c05ac6a
add a test for loop finalization
kripken Aug 23, 2016
eb1def3
add some finalize() calls for ifs
kripken Aug 23, 2016
1d3f3dd
allow forcing full print mode in the env
kripken Aug 23, 2016
14fe75e
when replacing an if with its condition (when it has no body), we mus…
kripken Aug 23, 2016
8384ada
use ControlFlowWalker in CFGWalker
kripken Aug 23, 2016
e125ae7
don't simplify locals out of loops if they contain branching, as it m…
kripken Aug 23, 2016
323e32b
autodrop must be run before we optimize in asm2wasm, as otherwise its…
kripken Aug 23, 2016
e073b8f
sink a drop into a single if arm
kripken Aug 23, 2016
fd3f6db
do a little more optimization at the end of asm2wasm processing
kripken Aug 23, 2016
5e8ae17
FIXME disable spec tests on the bots for now
kripken Aug 23, 2016
b8ff5de
add asm2wasm option to import a mem init file
kripken Aug 24, 2016
88e8b71
update empty.fromast test output
kripken Aug 26, 2016
304fef1
refactor reallocBuffer assignment location, it is not technically par…
kripken Aug 28, 2016
42ad2cd
import memory #684
kripken Aug 28, 2016
28767f6
import table
kripken Aug 28, 2016
fd0160d
import memoryBase and tableBase
kripken Aug 28, 2016
d58adf4
support HEAP8[x | 0| notation in asm2wasm
kripken Aug 29, 2016
0793f2f
Add a ReFinalize helper, and use that to properly handle asm.js impor…
kripken Aug 29, 2016
f1c74af
re-enable spec tests
kripken Aug 30, 2016
e62f54d
new import syntax in spec repo
kripken Aug 31, 2016
6b21659
new export syntax in spec repo
kripken Sep 2, 2016
a07797f
additional parsing support for new spec things
kripken Sep 2, 2016
52b0fe2
new validation checks for upcoming spec tests
kripken Sep 3, 2016
b116d3a
if we don't recognize the platform in colors.h, just do nothing for c…
kripken Sep 7, 2016
dd197d3
update wasm.js and binaryen.js
kripken Sep 7, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions auto_update_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@
if not opts:
cmd += ['--no-opts']
wasm += '.no-opts'
if precise and opts:
# test mem init importing
open('a.mem', 'wb').write(asm)
cmd += ['--mem-init=a.mem']
print '..', asm, wasm
print ' ', ' '.join(cmd)
actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
with open(os.path.join('test', wasm), 'w') as o: o.write(actual)

'''
for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
for s in sorted(os.listdir(os.path.join('test', dot_s_dir))):
if not s.endswith('.s'): continue
if s in ['indirect-import.s', 'memops.s', 'byval.s', 'cfg-stackify.s', 'dead-vreg.s', 'i128.s', 'legalize.s', 'mem-intrinsics.s', 'offset.s', 'reg-stackify.s', 'store-results.s', 'userstack.s', 'varargs.s']: continue # tests with invalid drop() code (use return of store)
print '..', s
wasm = s.replace('.s', '.wast')
full = os.path.join('test', dot_s_dir, s)
Expand All @@ -38,6 +44,7 @@

expected_file = os.path.join('test', dot_s_dir, wasm)
with open(expected_file, 'w') as o: o.write(actual)
'''

'''
for wasm in ['address.wast']:#os.listdir(os.path.join('test', 'spec')):
Expand Down
841 changes: 423 additions & 418 deletions bin/binaryen.js

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions bin/wasm.js

Large diffs are not rendered by default.

228 changes: 109 additions & 119 deletions check.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def binary_format_check(wast, verify_final_result=True):
assert os.path.exists('ab.wast')

# make sure it is a valid wast
cmd = [os.path.join('bin', 'wasm-shell'), 'ab.wast']
cmd = [os.path.join('bin', 'wasm-opt'), 'ab.wast']
print ' ', ' '.join(cmd)
subprocess.check_call(cmd, stdout=subprocess.PIPE)

Expand Down Expand Up @@ -291,6 +291,10 @@ def minify_check(wast, verify_final_result=True):
if not opts:
cmd += ['--no-opts']
wasm += '.no-opts'
if precise and opts:
# test mem init importing
open('a.mem', 'wb').write(asm)
cmd += ['--mem-init=a.mem']
wasm = os.path.join('test', wasm)
print '..', asm, wasm
actual = run_command(cmd)
Expand Down Expand Up @@ -373,8 +377,15 @@ def minify_check(wast, verify_final_result=True):
wast = os.path.join('test', t)

def run_spec_test(wast):
print ' run wasm-shell on', wast
cmd = [os.path.join('bin', 'wasm-shell'), wast]
# we must skip the stack machine portions of spec tests or apply other extra args
extra = {
'call.wast': ['--skip=207'],
'call_indirect.wast': ['--skip=302'],
'nop.wast': ['--skip=3'],
'stack.wast': ['--skip=0'],
}
cmd = cmd + (extra.get(os.path.basename(wast)) or [])
return run_command(cmd, stderr=subprocess.PIPE)

def check_expected(actual, expected):
Expand Down Expand Up @@ -408,11 +419,24 @@ def fix(x):

check_expected(actual, expected)

# we must ignore some binary format splits
splits_to_skip = {
'call.wast': [1],
'call_indirect.wast': [1],
'nop.wast': [0],
'stack.wast': [0],
}

# check binary format. here we can verify execution of the final result, no need for an output verification
split_num = 0
if os.path.basename(wast) not in ['call_indirect.wast']: # avoid some tests with things still being sorted out in the spec https://github.com/WebAssembly/spec/pull/301
if os.path.basename(wast) not in []: # avoid some tests with things still being sorted out in the spec
actual = ''
for module, asserts in split_wast(wast):
skip = splits_to_skip.get(os.path.basename(wast)) or []
if split_num in skip:
print ' skipping split module', split_num - 1
split_num += 1
continue
print ' testing split module', split_num
split_num += 1
with open('split.wast', 'w') as o: o.write(module + '\n' + '\n'.join(asserts))
Expand All @@ -424,43 +448,6 @@ def fix(x):
# compare all the outputs to the expected output
check_expected(actual, os.path.join('test', 'spec', 'expected-output', os.path.basename(wast) + '.log'))

''' XXX disable wasm2asm for now, too much flux
print '\n[ checking wasm2asm testcases... ]\n'

for wasm in tests + [os.path.join('spec', name) for name in ['address.wast']]:#spec_tests:
if wasm.endswith('.wast') and os.path.basename(wasm) not in ['kitchen_sink.wast']: # i64s in kitchen_sink
print '..', wasm
asm = os.path.basename(wasm).replace('.wast', '.2asm.js')
actual, err = subprocess.Popen([os.path.join('bin', 'wasm2asm'), os.path.join('test', wasm)], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
assert err == '', 'bad err:' + err

# verify output
expected_file = os.path.join('test', asm)
if not os.path.exists(expected_file):
print actual
raise Exception('output ' + expected_file + ' does not exist')
expected = open(expected_file).read()
if actual != expected:
fail(actual, expected)

open('a.2asm.js', 'w').write(actual)

if has_node:
# verify asm.js is valid js
proc = subprocess.Popen([has_node, 'a.2asm.js'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
assert proc.returncode == 0
assert not out and not err, [out, err]

if has_mozjs:
# verify asm.js validates
open('a.2asm.js', 'w').write(actual)
proc = subprocess.Popen(['mozjs', '-w', 'a.2asm.js'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
assert proc.returncode == 0
fail_if_not_contained(err, 'Successfully compiled asm.js code')
'''

if has_node:
print '\n[ checking binaryen.js testcases... ]\n'

Expand All @@ -477,76 +464,78 @@ def fix(x):
if expected not in out:
fail(out, expected)

print '\n[ checking .s testcases... ]\n'

for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
for s in sorted(os.listdir(os.path.join('test', dot_s_dir))):
if not s.endswith('.s'): continue
print '..', s
wasm = s.replace('.s', '.wast')
full = os.path.join('test', dot_s_dir, s)
stack_alloc = ['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else []
cmd = [os.path.join('bin', 's2wasm'), full, '--emscripten-glue'] + stack_alloc
if s.startswith('start_'):
cmd.append('--start')
actual = run_command(cmd)

# verify output
expected_file = os.path.join('test', dot_s_dir, wasm)
if not os.path.exists(expected_file):
print actual
raise Exception('output ' + expected_file + ' does not exist')
expected = open(expected_file).read()
if actual != expected:
fail(actual, expected)

# verify with options
cmd = [os.path.join('bin', 's2wasm'), full, '--global-base=1024'] + stack_alloc
run_command(cmd)

# run wasm-shell on the .wast to verify that it parses
cmd = [os.path.join('bin', 'wasm-shell'), expected_file]
run_command(cmd)

print '\n[ running linker tests... ]\n'
# The {main,foo,bar,baz}.s files were created by running clang over the respective
# c files. The foobar.bar archive was created by running:
# llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s
s2wasm = os.path.join('bin', 's2wasm')
cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '-l', os.path.join('test', 'linker', 'archive', 'foobar.a')]
output = run_command(cmd)
# foo should come from main.s and return 42
fail_if_not_contained(output, '(func $foo')
fail_if_not_contained(output, '(i32.const 42)')
# bar should be linked in from bar.s
fail_if_not_contained(output, '(func $bar')
# quux should be linked in from bar.s even though it comes before bar.s in the archive
fail_if_not_contained(output, '(func $quux')
# baz should not be linked in at all
if 'baz' in output:
raise Exception('output should not contain "baz": ' + output)

# Test an archive using a string table
cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '-l', os.path.join('test', 'linker', 'archive', 'barlong.a')]
output = run_command(cmd)
# bar should be linked from the archive
fail_if_not_contained(output, '(func $bar')

print '\n[ running validation tests... ]\n'
wasm_as = os.path.join('bin', 'wasm-as')
# Ensure the tests validate by default
cmd = [wasm_as, os.path.join('test', 'validator', 'invalid_export.wast')]
run_command(cmd)
cmd = [wasm_as, os.path.join('test', 'validator', 'invalid_import.wast')]
run_command(cmd)
cmd = [wasm_as, '--validate=web', os.path.join('test', 'validator', 'invalid_export.wast')]
run_command(cmd, expected_status=1)
cmd = [wasm_as, '--validate=web', os.path.join('test', 'validator', 'invalid_import.wast')]
run_command(cmd, expected_status=1)
cmd = [wasm_as, '--validate=none', os.path.join('test', 'validator', 'invalid_return.wast')]
run_command(cmd)

if torture:
if 0: # TODO: figure out the story. will .s files have drops?
print '\n[ checking .s testcases... ]\n'

for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
for s in sorted(os.listdir(os.path.join('test', dot_s_dir))):
if not s.endswith('.s'): continue
if s in ['indirect-import.s', 'memops.s', 'byval.s', 'cfg-stackify.s', 'dead-vreg.s', 'i128.s', 'legalize.s', 'mem-intrinsics.s', 'offset.s', 'reg-stackify.s', 'store-results.s', 'userstack.s', 'varargs.s']: continue # tests with invalid drop() code (use return of store)
print '..', s
wasm = s.replace('.s', '.wast')
full = os.path.join('test', dot_s_dir, s)
stack_alloc = ['--allocate-stack=1024'] if dot_s_dir == 'llvm_autogenerated' else []
cmd = [os.path.join('bin', 's2wasm'), full, '--emscripten-glue'] + stack_alloc
if s.startswith('start_'):
cmd.append('--start')
actual = run_command(cmd)

# verify output
expected_file = os.path.join('test', dot_s_dir, wasm)
if not os.path.exists(expected_file):
print actual
raise Exception('output ' + expected_file + ' does not exist')
expected = open(expected_file).read()
if actual != expected:
fail(actual, expected)

# verify with options
cmd = [os.path.join('bin', 's2wasm'), full, '--global-base=1024'] + stack_alloc
run_command(cmd)

# run wasm-shell on the .wast to verify that it parses
cmd = [os.path.join('bin', 'wasm-shell'), expected_file]
run_command(cmd)

print '\n[ running linker tests... ]\n'
# The {main,foo,bar,baz}.s files were created by running clang over the respective
# c files. The foobar.bar archive was created by running:
# llvm-ar -format=gnu rc foobar.a quux.s foo.s bar.s baz.s
s2wasm = os.path.join('bin', 's2wasm')
cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '-l', os.path.join('test', 'linker', 'archive', 'foobar.a')]
output = run_command(cmd)
# foo should come from main.s and return 42
fail_if_not_contained(output, '(func $foo')
fail_if_not_contained(output, '(i32.const 42)')
# bar should be linked in from bar.s
fail_if_not_contained(output, '(func $bar')
# quux should be linked in from bar.s even though it comes before bar.s in the archive
fail_if_not_contained(output, '(func $quux')
# baz should not be linked in at all
if 'baz' in output:
raise Exception('output should not contain "baz": ' + output)

# Test an archive using a string table
cmd = [s2wasm, os.path.join('test', 'linker', 'main.s'), '-l', os.path.join('test', 'linker', 'archive', 'barlong.a')]
output = run_command(cmd)
# bar should be linked from the archive
fail_if_not_contained(output, '(func $bar')

print '\n[ running validation tests... ]\n'
wasm_as = os.path.join('bin', 'wasm-as')
# Ensure the tests validate by default
cmd = [wasm_as, os.path.join('test', 'validator', 'invalid_export.wast')]
run_command(cmd)
cmd = [wasm_as, os.path.join('test', 'validator', 'invalid_import.wast')]
run_command(cmd)
cmd = [wasm_as, '--validate=web', os.path.join('test', 'validator', 'invalid_export.wast')]
run_command(cmd, expected_status=1)
cmd = [wasm_as, '--validate=web', os.path.join('test', 'validator', 'invalid_import.wast')]
run_command(cmd, expected_status=1)
cmd = [wasm_as, '--validate=none', os.path.join('test', 'validator', 'invalid_return.wast')]
run_command(cmd)

if torture and 0:

print '\n[ checking torture testcases... ]\n'

Expand Down Expand Up @@ -576,7 +565,7 @@ def fix(x):
if unexpected_result_count:
fail('%s failures' % unexpected_result_count, '0 failures')

if has_vanilla_emcc and has_vanilla_llvm:
if has_vanilla_emcc and has_vanilla_llvm and 0:

print '\n[ checking emcc WASM_BACKEND testcases...]\n'

Expand Down Expand Up @@ -670,7 +659,7 @@ def fix(x):

if has_emcc:

if has_mozjs:
if has_mozjs and 0:

print '\n[ checking native wasm support ]\n'

Expand All @@ -689,8 +678,9 @@ def fix(x):

print '\n[ checking wasm.js methods... ]\n'

for method_init in ['interpret-asm2wasm', 'interpret-s-expr', 'asmjs', 'interpret-binary']:
for success in [1, 0]:
for method_init in ['interpret-asm2wasm', 'interpret-s-expr', 'asmjs', 'interpret-binary', 'asmjs,interpret-binary', 'interpret-binary,asmjs']:
# check success and failure for simple modes, only success for combined/fallback ones
for success in [1, 0] if ',' not in method_init else [1]:
method = method_init
command = ['emcc', '-o', 'a.wasm.js', '-s', 'BINARYEN=1', os.path.join('test', 'hello_world.c') ]
command += ['-s', 'BINARYEN_METHOD="' + method + '"']
Expand All @@ -709,20 +699,20 @@ def break_cashew():
asm = asm.replace('"almost asm"', '"use asm"; var not_in_asm = [].length + (true || { x: 5 }.x);')
asm = asm.replace("'almost asm'", '"use asm"; var not_in_asm = [].length + (true || { x: 5 }.x);')
with open('a.wasm.asm.js', 'w') as o: o.write(asm)
if method == 'interpret-asm2wasm':
if method.startswith('interpret-asm2wasm'):
os.unlink('a.wasm.wast') # we should not need the .wast
if not success:
break_cashew() # we need cashew
elif method == 'interpret-s-expr':
elif method.startswith('interpret-s-expr'):
os.unlink('a.wasm.asm.js') # we should not need the .asm.js
if not success:
os.unlink('a.wasm.wast.mappedGlobals')
elif method == 'asmjs':
os.unlink('a.wasm.wast')
elif method.startswith('asmjs'):
os.unlink('a.wasm.wast') # we should not need the .wast
break_cashew() # we don't use cashew, so ok to break it
if not success:
os.unlink('a.wasm.js')
elif method == 'interpret-binary':
elif method.startswith('interpret-binary'):
os.unlink('a.wasm.wast') # we should not need the .wast
os.unlink('a.wasm.asm.js') # we should not need the .asm.js
if not success:
Expand Down
6 changes: 4 additions & 2 deletions scripts/fuzz_relooper.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@
BinaryenLoad(module, 4, 0, 0, 0, BinaryenInt32(),
BinaryenConst(module, BinaryenLiteralInt32(4))),
BinaryenConst(module, BinaryenLiteralInt32(4))
)
),
BinaryenInt32()
);

// optionally, print the return value
Expand Down Expand Up @@ -252,7 +253,8 @@
full[i] = BinaryenStore(module,
4, 0, 0,
BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
BinaryenConst(module, BinaryenLiteralInt32(decisions[i]))
BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
BinaryenInt32()
);
}
}
Expand Down
7 changes: 6 additions & 1 deletion scripts/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,12 @@ def to_end(j):
depth = 1
while depth > 0 and j < len(wast):
if wast[j] == '"':
j = wast.find('"', j + 1)
while 1:
j = wast.find('"', j + 1)
if wast[j - 1] == '\\':
continue
break
assert j > 0
elif wast[j] == '(':
depth += 1
elif wast[j] == ')':
Expand Down
Loading