summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Print.cpp2
-rw-r--r--src/wasm/wasm-binary.cpp3
-rw-r--r--src/wasm/wasm-s-parser.cpp12
-rw-r--r--src/wasm/wasm-validator.cpp29
-rw-r--r--test/spec/bulk-array.wast225
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