diff options
-rwxr-xr-x | check.py | 28 | ||||
-rw-r--r-- | scripts/test/shared.py | 1 | ||||
-rw-r--r-- | scripts/test/support.py | 2 | ||||
-rw-r--r-- | src/tools/wasm-shell.cpp | 31 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 21 | ||||
-rw-r--r-- | test/spec/imports.wast | 151 |
6 files changed, 171 insertions, 63 deletions
@@ -230,6 +230,8 @@ def run_spec_tests(): if 'exports.wast' in base: # FIXME continue + run_spec_test(wast) + # check binary format. here we can verify execution of the final # result, no need for an output verification # some wast files cannot be split: @@ -241,21 +243,21 @@ def run_spec_tests(): if base not in ['comments.wast', 'ref_null.wast', 'ref_is_null.wast', 'ref_func.wast', 'old_select.wast']: split_num = 0 actual = '' - for module, asserts in support.split_wast(wast): - print(' testing split module', split_num) - split_num += 1 - support.write_wast('split.wast', module, asserts) - run_spec_test('split.wast') # before binary stuff - just check it's still ok split out - run_opt_test('split.wast') # also that our optimizer doesn't break on it - result_wast = shared.binary_format_check('split.wast', verify_final_result=False, original_wast=wast) - # add the asserts, and verify that the test still passes - open(result_wast, 'a').write('\n' + '\n'.join(asserts)) - actual += run_spec_test(result_wast) + with open('spec.wast', 'w') as transformed_spec_file: + for module, asserts in support.split_wast(wast): + print(' testing split module', split_num) + split_num += 1 + support.write_wast('split.wast', module, asserts) + run_opt_test('split.wast') # also that our optimizer doesn't break on it + result_wast_file = shared.binary_format_check('split.wast', verify_final_result=False, original_wast=wast) + with open(result_wast_file) as f: + result_wast = f.read() + # add the asserts, and verify that the test still passes + transformed_spec_file.write(result_wast + '\n' + '\n'.join(asserts)) + # compare all the outputs to the expected output + actual = run_spec_test('spec.wast') check_expected(actual, os.path.join(shared.get_test_dir('spec'), 'expected-output', base + '.log')) - else: - # handle unsplittable wast files - run_spec_test(wast) def run_validator_tests(): diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 54c7c861d..d3af99455 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -424,7 +424,6 @@ SPEC_TESTS_TO_SKIP = [ 'utf8-invalid-encoding.wast', # 'register' command - 'imports.wast', 'linking.wast', # Misc. unsupported constructs diff --git a/scripts/test/support.py b/scripts/test/support.py index a4a61fc22..7313169fa 100644 --- a/scripts/test/support.py +++ b/scripts/test/support.py @@ -145,7 +145,7 @@ def split_wast(wastFile): ret += [(chunk, [])] elif chunk.startswith('(assert_invalid'): continue - elif chunk.startswith(('(assert', '(invoke')): + elif chunk.startswith(('(assert', '(invoke', '(register')): # ret may be empty if there are some asserts before the first # module. in that case these are asserts *without* a module, which # are valid (they may check something that doesn't refer to a module diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index a2d35f444..c6815c92d 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -81,9 +81,9 @@ struct ShellOptions : public Options { class Shell { protected: - std::map<Name, std::unique_ptr<Module>> modules; - std::map<Name, std::unique_ptr<SExpressionWasmBuilder>> builders; - std::map<Name, std::unique_ptr<ShellExternalInterface>> interfaces; + std::map<Name, std::shared_ptr<Module>> modules; + std::map<Name, std::shared_ptr<SExpressionWasmBuilder>> builders; + std::map<Name, std::shared_ptr<ShellExternalInterface>> interfaces; std::map<Name, std::shared_ptr<ModuleInstance>> instances; // used for imports std::map<Name, std::shared_ptr<ModuleInstance>> linkedInstances; @@ -92,7 +92,7 @@ protected: void instantiate(Module* wasm) { auto tempInterface = - wasm::make_unique<ShellExternalInterface>(linkedInstances); + std::make_shared<ShellExternalInterface>(linkedInstances); auto tempInstance = std::make_shared<ModuleInstance>( *wasm, tempInterface.get(), linkedInstances); interfaces[wasm->name].swap(tempInterface); @@ -123,12 +123,12 @@ protected: Colors::green(std::cerr); std::cerr << "BUILDING MODULE [line: " << s.line << "]\n"; Colors::normal(std::cerr); - auto module = wasm::make_unique<Module>(); + auto module = std::make_shared<Module>(); auto builder = - wasm::make_unique<SExpressionWasmBuilder>(*module, s, IRProfile::Normal); + std::make_shared<SExpressionWasmBuilder>(*module, s, IRProfile::Normal); auto moduleName = module->name; lastModule = module->name; - builders[moduleName].swap(builder); + builders[moduleName] = builder; modules[moduleName].swap(module); modules[moduleName]->features = FeatureSet::All; bool valid = WasmValidator().validate(*modules[moduleName]); @@ -150,15 +150,12 @@ protected: auto name = s[1]->str(); linkedInstances[name] = instance; - // swap to the new name in all maps - modules[name].swap(modules[lastModule]); - modules.erase(lastModule); - builders[name].swap(builders[lastModule]); - builders.erase(lastModule); - interfaces[name].swap(interfaces[lastModule]); - interfaces.erase(lastModule); - instances[name].swap(instances[lastModule]); - instances.erase(lastModule); + // we copy pointers as a registered module's name might still be used + // in an assertion or invoke command. + modules[name] = modules[lastModule]; + builders[name] = builders[lastModule]; + interfaces[name] = interfaces[lastModule]; + instances[name] = instances[lastModule]; Colors::green(std::cerr); std::cerr << "REGISTER MODULE INSTANCE AS \"" << name.c_str() @@ -316,7 +313,7 @@ protected: // TODO: spectest module is considered deprecated by the spec. Remove when // is actually removed from the spec test. void buildSpectestModule() { - auto spectest = std::make_unique<Module>(); + auto spectest = std::make_shared<Module>(); spectest->name = "spectest"; Builder builder(*spectest); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 8c772a96e..844716f95 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2422,23 +2422,24 @@ private: protected: // Returns the instance that defines the memory used by this one. SubType* getMemoryInstance() { - if (instance.wasm.memory.imported()) { - return instance.linkedInstances.at(instance.wasm.memory.module).get(); - } else { - return static_cast<SubType*>(&instance); + auto* inst = instance.self(); + while (inst->wasm.memory.imported()) { + inst = inst->linkedInstances.at(inst->wasm.memory.module).get(); } + return inst; } // Returns a reference to the current value of a potentially imported global Literals& getGlobal(Name name) { - auto* global = instance.wasm.getGlobal(name); - if (global->imported()) { - auto inst = instance.linkedInstances.at(global->module); + auto* inst = instance.self(); + auto* global = inst->wasm.getGlobal(name); + while (global->imported()) { + inst = inst->linkedInstances.at(global->module).get(); Export* globalExport = inst->wasm.getExport(global->base); - return inst->globals[globalExport->value]; - } else { - return instance.globals[name]; + global = inst->wasm.getGlobal(globalExport->value); } + + return inst->globals[global->name]; } public: diff --git a/test/spec/imports.wast b/test/spec/imports.wast index c39ae8dd3..43ffedaee 100644 --- a/test/spec/imports.wast +++ b/test/spec/imports.wast @@ -10,9 +10,13 @@ (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) (global (export "global-i32") i32 (i32.const 55)) (global (export "global-f32") f32 (f32.const 44)) + ;;; FIXME: Exporting a mutable global is currently not supported. Make mutable + ;;; when support is added. + (global (export "global-mut-i64") i64 (i64.const 66)) (table (export "table-10-inf") 10 funcref) - ;; (table (export "table-10-20") 10 20 funcref) + (table (export "table-10-20") 10 20 funcref) (memory (export "memory-2-inf") 2) + ;; Multiple memories are not yet supported ;; (memory (export "memory-2-4") 2 4) ) @@ -43,10 +47,13 @@ (func (export "p1") (import "spectest" "print_i32") (param i32)) (func $p (export "p2") (import "spectest" "print_i32") (param i32)) - (func (export "p3") (export "p4") (import "spectest" "print_i32") (param i32)) + (func (import "spectest" "print_i32") (param i32)) (func (export "p5") (import "spectest" "print_i32") (type 0)) (func (export "p6") (import "spectest" "print_i32") (type 0) (param i32) (result)) + ;; (export "p3" (func $print_i32)) + ;; (export "p4" (func $print_i32)) + (import "spectest" "print_i32" (func (type $forward))) (func (import "spectest" "print_i32") (type $forward)) (type $forward (func (param i32))) @@ -95,6 +102,26 @@ "unknown type" ) +;; Export sharing name with import +(module + (import "spectest" "print_i32" (func $imported_print (param i32))) + (func (export "print_i32") (param $i i32) + (call $imported_print (local.get $i)) + ) +) + +(assert_return (invoke "print_i32" (i32.const 13))) + +;; Export sharing name with import +(module + (import "spectest" "print_i32" (func $imported_print (param i32))) + (func (export "print_i32") (param $i i32) (param $j i32) (result i32) + (i32.add (local.get $i) (local.get $j)) + ) +) + +(assert_return (invoke "print_i32" (i32.const 5) (i32.const 11)) (i32.const 16)) + (module (import "test" "func" (func))) (module (import "test" "func-i32" (func (param i32)))) (module (import "test" "func-f32" (func (param f32)))) @@ -230,6 +257,7 @@ (module (import "test" "global-i32" (global i32))) (module (import "test" "global-f32" (global f32))) +(module (import "test" "global-mut-i64" (global (mut i64)))) (assert_unlinkable (module (import "test" "unknown" (global i32))) @@ -241,6 +269,55 @@ ) (assert_unlinkable + (module (import "test" "global-i32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f64)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global i64))) + "incompatible import type" +) + +(assert_unlinkable (module (import "test" "func" (global i32))) "incompatible import type" ) @@ -270,11 +347,11 @@ (module (type (func (result i32))) - (import "spectest" "table" (table 10 20 funcref)) - (elem (i32.const 1) $f $g) + (import "spectest" "table" (table $tab 10 20 funcref)) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) - (call_indirect (type 0) (local.get 0)) + (call_indirect $tab (type 0) (local.get 0)) ) (func $f (result i32) (i32.const 11)) (func $g (result i32) (i32.const 22)) @@ -289,11 +366,11 @@ (module (type (func (result i32))) - (table (import "spectest" "table") 10 20 funcref) - (elem (i32.const 1) $f $g) + (table $tab (import "spectest" "table") 10 20 funcref) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) - (call_indirect (type 0) (local.get 0)) + (call_indirect $tab (type 0) (local.get 0)) ) (func $f (result i32) (i32.const 11)) (func $g (result i32) (i32.const 22)) @@ -306,22 +383,25 @@ (assert_trap (invoke "call" (i32.const 100)) "undefined element") -(assert_invalid - (module (import "" "" (table 10 funcref)) (import "" "" (table 10 funcref))) - "multiple tables" -) -(assert_invalid - (module (import "" "" (table 10 funcref)) (table 10 funcref)) - "multiple tables" -) -(assert_invalid - (module (table 10 funcref) (table 10 funcref)) - "multiple tables" +(module + (import "spectest" "table" (table 0 funcref)) + (import "spectest" "table" (table 0 funcref)) + (table 10 funcref) + (table 10 funcref) ) (module (import "test" "table-10-inf" (table 10 funcref))) (module (import "test" "table-10-inf" (table 5 funcref))) (module (import "test" "table-10-inf" (table 0 funcref))) +(module (import "test" "table-10-20" (table 10 funcref))) +(module (import "test" "table-10-20" (table 5 funcref))) +(module (import "test" "table-10-20" (table 0 funcref))) +(module (import "test" "table-10-20" (table 10 20 funcref))) +(module (import "test" "table-10-20" (table 5 20 funcref))) +(module (import "test" "table-10-20" (table 0 20 funcref))) +(module (import "test" "table-10-20" (table 10 25 funcref))) +(module (import "test" "table-10-20" (table 5 25 funcref))) +(module (import "test" "table-10-20" (table 0 25 funcref))) (module (import "spectest" "table" (table 10 funcref))) (module (import "spectest" "table" (table 5 funcref))) (module (import "spectest" "table" (table 0 funcref))) @@ -349,6 +429,14 @@ "incompatible import type" ) (assert_unlinkable + (module (import "test" "table-10-20" (table 12 20 funcref))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "table-10-20" (table 10 18 funcref))) + "incompatible import type" +) +(assert_unlinkable (module (import "spectest" "table" (table 12 funcref))) "incompatible import type" ) @@ -380,7 +468,7 @@ (module (import "spectest" "memory" (memory 1 2)) - (data (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) @@ -392,7 +480,7 @@ (module (memory (import "spectest" "memory") 1 2) - (data (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) @@ -494,6 +582,27 @@ (assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) (assert_return (invoke "grow" (i32.const 0)) (i32.const 2)) +(module $Mgm + (memory (export "memory") 1) ;; initial size is 1 + (func (export "grow") (result i32) (memory.grow (i32.const 1))) +) +(register "grown-memory" $Mgm) +(assert_return (invoke $Mgm "grow") (i32.const 1)) ;; now size is 2 +(module $Mgim1 + ;; imported memory limits should match, because external memory size is 2 now + (memory (import "grown-memory" "memory") 2) + (export "memory" (memory 0)) + (func (export "grow") (result i32) (memory.grow (i32.const 1))) +) +(register "grown-imported-memory" $Mgim1) +(assert_return (invoke $Mgim1 "grow") (i32.const 2)) ;; now size is 3 +(module $Mgim2 + ;; imported memory limits should match, because external memory size is 3 now + (import "grown-imported-memory" "memory" (memory 3)) + (func (export "size") (result i32) (memory.size)) +) +(assert_return (invoke $Mgim2 "size") (i32.const 3)) + ;; Syntax errors |