diff options
-rw-r--r-- | src/passes/Print.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 29 | ||||
-rw-r--r-- | test/spec/bulk-array.wast | 225 |
5 files changed, 238 insertions, 33 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 4a4fe60c7..c9a717058 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3283,7 +3283,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { } else { for (auto* entry : curr->data) { o << ' '; - printExpression(entry, o); + visit(entry); } } o << ')' << maybeNewLine; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 518a809fa..9368325b0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3222,9 +3222,6 @@ void WasmBinaryBuilder::readElementSegments() { if (isPassive || hasTableIdx) { if (usesExpressions) { segment->type = getType(); - if (!segment->type.isFunction()) { - throwError("Invalid type for a usesExpressions element segment"); - } } else { auto elemKind = getU32LEB(); if (elemKind != 0x0) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 522c3f3c6..77e265f16 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -3561,7 +3561,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { std::unique_ptr<Global> global = make_unique<Global>(); size_t i = 1; - if (s[i]->dollared() && !(s[i]->isStr() && isType(s[i]->str()))) { + if (s[i]->dollared()) { global->setExplicitName(s[i++]->str()); } else if (preParseImport) { global->name = Name("gimport$" + std::to_string(globalCounter)); @@ -3572,7 +3572,6 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { globalNames.push_back(global->name); bool mutable_ = false; Type type = Type::none; - bool exported = false; Name importModule, importBase; while (i < s.size() && s[i]->isList()) { auto& inner = *s[i++]; @@ -3585,7 +3584,6 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { throw ParseException("duplicate export", s.line, s.col); } wasm.addExport(ex.release()); - exported = true; } else if (elementStartsWith(inner, IMPORT)) { importModule = inner[1]->str(); importBase = inner[2]->str(); @@ -3598,9 +3596,6 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { break; } } - if (exported && mutable_) { - throw ParseException("cannot export a mutable global", s.line, s.col); - } if (type == Type::none) { type = stringToType(s[i++]->str()); } @@ -3784,11 +3779,6 @@ void SExpressionWasmBuilder::parseElem(Element& s, Table* table) { segment->type = elementToType(*s[i]); usesExpressions = true; i += 1; - - if (!segment->type.isFunction()) { - throw ParseException( - "Invalid type for an element segment.", s.line, s.col); - } } } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index e0391a73d..123a15c1e 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -3405,13 +3405,9 @@ static void validateTables(Module& module, ValidationInfo& info) { } for (auto& segment : module.elementSegments) { - // Since element segment items need to be constant expressions, that leaves - // us with ref.null, ref.func and global.get. As a result, the only possible - // type for element segments will be function references. - // TODO: This is not true! Allow GC data here (#4846). - info.shouldBeTrue(segment->type.isFunction(), + info.shouldBeTrue(segment->type.isRef(), "elem", - "element segment type must be of function type."); + "element segment type must be of reference type."); info.shouldBeTrue( segment->type.isNullable(), "elem", @@ -3443,18 +3439,15 @@ static void validateTables(Module& module, ValidationInfo& info) { "elem", "non-table segment offset should have no offset"); } - // Avoid double checking items - if (module.features.hasReferenceTypes()) { - for (auto* expr : segment->data) { - info.shouldBeTrue(Properties::isValidConstantExpression(module, expr), - expr, - "element must be a constant expression"); - info.shouldBeSubType(expr->type, - segment->type, - expr, - "element must be a subtype of the segment type"); - validator.validate(expr); - } + for (auto* expr : segment->data) { + info.shouldBeTrue(Properties::isValidConstantExpression(module, expr), + expr, + "element must be a constant expression"); + info.shouldBeSubType(expr->type, + segment->type, + expr, + "element must be a subtype of the segment type"); + validator.validate(expr); } } } diff --git a/test/spec/bulk-array.wast b/test/spec/bulk-array.wast new file mode 100644 index 000000000..06c341000 --- /dev/null +++ b/test/spec/bulk-array.wast @@ -0,0 +1,225 @@ +(module + ;; Array types used in tests. + (type $i8 (array (mut i8))) + (type $i16 (array (mut i16))) + (type $i32 (array (mut i32))) + (type $anyref (array (mut anyref))) + (type $funcref (array (mut funcref))) + (type $externref (array (mut externref))) + + ;; Array values used in tests. Reset in between tests with the "reset" + ;; function. + (global $i8 (mut (ref null $i8)) (ref.null none)) + (global $i16 (mut (ref null $i16)) (ref.null none)) + (global $i32 (mut (ref null $i32)) (ref.null none)) + (global $anyref (mut (ref null $anyref)) (ref.null none)) + (global $funcref (mut (ref null $funcref)) (ref.null none)) + (global $externref (mut (ref null $externref)) (ref.null none)) + + ;; GC objects with distinct identities used in anyref tests. + (global $g1 (export "g1") (mut anyref) (array.new_fixed $i8)) + (global $g2 (export "g2") (mut anyref) (array.new_fixed $i8)) + (global $g3 (export "g3") (mut anyref) (array.new_fixed $i8)) + (global $g4 (export "g4") (mut anyref) (array.new_fixed $i8)) + (global $g5 (export "g5") (mut anyref) (array.new_fixed $i8)) + + ;; Functions with distinct return values used in funcref tests. + (func $f1 (result i32) (i32.const 0)) + (func $f2 (result i32) (i32.const 1)) + (func $f3 (result i32) (i32.const 2)) + (func $f4 (result i32) (i32.const 3)) + (func $f5 (result i32) (i32.const 4)) + + ;; Passive element segment used in array.init_elem tests. + (elem $elem anyref + (array.new_fixed $i8) + (array.new_fixed $i8) + (array.new_fixed $i8) + (array.new_fixed $i8) + (array.new_fixed $i8)) + + (table $tab anyref 5 5) + + ;; Resets the array globals to known states. + (func (export "reset") + (global.set $i8 + (array.new_fixed $i8 + (i32.const 0) + (i32.const 1) + (i32.const 2) + (i32.const 3) + (i32.const 4))) + (global.set $i16 + (array.new_fixed $i16 + (i32.const 0) + (i32.const 1) + (i32.const 2) + (i32.const 3) + (i32.const 4))) + (global.set $i32 + (array.new_fixed $i32 + (i32.const 0) + (i32.const 1) + (i32.const 2) + (i32.const 3) + (i32.const 4))) + (global.set $anyref + (array.new_fixed $anyref + (global.get $g1) + (global.get $g2) + (global.get $g3) + (global.get $g4) + (global.get $g5))) + (global.set $funcref + (array.new_fixed $funcref + (ref.func $f1) + (ref.func $f2) + (ref.func $f3) + (ref.func $f4) + (ref.func $f5))) + (global.set $externref + (array.new_fixed $externref + (extern.externalize (global.get $g1)) + (extern.externalize (global.get $g2)) + (extern.externalize (global.get $g3)) + (extern.externalize (global.get $g4)) + (extern.externalize (global.get $g5))))) +) + +;; array.fill + +;; basic i8 +;; basic i16 +;; basic i32 +;; basic anyref +;; basic funcref +;; basic externref +;; basic ref subtype +;; basic ref nullability subtype + +;; zero size in bounds +;; zero size at bounds +;; zero size out of bounds traps + +;; out of bounds index traps +;; out of bounds size traps +;; out of bounds index + size traps + +;; null destination traps + +;; immutable field invalid + +;; ref supertype invalid +;; ref nullability supertype invalid + +;; array.copy + +;; basic i8 +;; basic i16 +;; basic i32 +;; basic anyref +;; basic funcref +;; basic externref +;; basic ref subtype +;; basic ref nullability subtype + +;; same i8 no overlap +;; same i8 overlap src first +;; same i8 overlap dest first +;; same i8 overlap complete + +;; same i32 no overlap +;; same i32 overlap src first +;; same i32 overlap dest first +;; same i32 overlap complete + +;; same anyref no overlap +;; same anyref overloap +;; same anyref src first +;; same anyref dest first +;; same anyref overlap complete + +;; zero size in bounds +;; zero size at dest bounds +;; zero size at src bounds +;; zero size out of dest bounds traps +;; zero size out of src bounds traps + +;; out of bounds dest index traps +;; out of bounds src index traps +;; out of bounds dest size traps +;; out of bounds src index traps +;; out of bounds dest index + size traps +;; out of bounds src index + size traps + +;; null dest traps +;; null src traps + +;; immutable dest field invalid +;; immutable src field ok + +;; ref supertype invalid +;; ref nullability supertype invalid + +;; array.init_data + +;; basic i8 +;; basic i16 +;; basic i32 +;; basic f32 + +;; zero size in bounds +;; zero size at dest bounds +;; zero size at src bounds +;; zero size out of dest bounds traps +;; zero size out of src bounds traps + +;; out of bounds dest index traps +;; out of bounds src index traps +;; out of bounds dest size traps +;; out of bounds src size traps +;; out of bounds src multiplied size traps +;; out of bounds dest index + size traps +;; out of bounds src index + size traps +;; out of bounds src index + multiplied size traps + +;; null dest traps +;; segment dropped traps + +;; immutable dest field invalid + +;; ref supertype invalid +;; ref nullability supertype invalid + +;; out of bounds segment index invalid + +;; array.init_elem + +;; basic anyref +;; basic funcref +;; basic externref +;; basic ref subtype +;; basic ref nullability subtype + +;; zero size in bounds +;; zero size at dest bounds +;; zero size at src bounds +;; zero size out of dest bounds traps +;; zero size out of src bounds traps + +;; out of bounds dest index traps +;; out of bounds src index traps +;; out of bounds dest size traps +;; out of bounds src size traps +;; out of bounds dest index + size traps +;; out of bounds src index + size traps + +;; null dest traps +;; segment dropped traps + +;; immutable dest field invalid + +;; ref supertype invalid +;; ref nullability supertype invalid + +;; out of bounds segment index invalid |