summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp2
-rw-r--r--src/passes/Print.cpp15
-rw-r--r--src/tools/fuzzing/fuzzing.cpp31
-rw-r--r--src/tools/fuzzing/heap-types.cpp6
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-type.h1
-rw-r--r--src/wasm/literal.cpp2
-rw-r--r--src/wasm/wasm-binary.cpp16
-rw-r--r--src/wasm/wasm-s-parser.cpp10
-rw-r--r--src/wasm/wasm-stack.cpp7
-rw-r--r--src/wasm/wasm-type.cpp45
-rw-r--r--src/wasm/wasm-validator.cpp34
12 files changed, 125 insertions, 46 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index dccc52131..ec70baef2 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -86,6 +86,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
case HeapType::eq:
case HeapType::func:
case HeapType::data:
+ case HeapType::array:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::stringview_wtf8:
@@ -138,6 +139,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
case HeapType::eq:
case HeapType::func:
case HeapType::data:
+ case HeapType::array:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::stringview_wtf8:
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index ddd8f9cc1..0f4a314ae 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -108,6 +108,9 @@ bool maybePrintRefShorthand(std::ostream& o, Type type) {
case HeapType::data:
o << "dataref";
return true;
+ case HeapType::array:
+ o << "arrayref";
+ return true;
case HeapType::string:
o << "stringref";
return true;
@@ -2234,11 +2237,12 @@ struct PrintExpressionContents
TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType());
}
void visitArrayLen(ArrayLen* curr) {
- if (printUnreachableOrNullReplacement(curr->ref)) {
- return;
- }
printMedium(o, "array.len ");
- TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType());
+ if (curr->ref->type == Type::unreachable) {
+ TypeNamePrinter(o, wasm).print(HeapType::array);
+ } else {
+ TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType());
+ }
}
void visitArrayCopy(ArrayCopy* curr) {
if (printUnreachableOrNullReplacement(curr->srcRef) ||
@@ -2801,9 +2805,6 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
void visitArrayGet(ArrayGet* curr) {
maybePrintUnreachableOrNullReplacement(curr, curr->ref->type);
}
- void visitArrayLen(ArrayLen* curr) {
- maybePrintUnreachableOrNullReplacement(curr, curr->ref->type);
- }
// Module-level visitors
void printSupertypeOr(HeapType curr, std::string noSuper) {
if (auto super = curr.getSuperType()) {
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 8023ab4da..cda14c989 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -2069,7 +2069,7 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) {
}
return builder.makeI31New(makeConst(Type::i32));
}
- case HeapType::data: {
+ case HeapType::data:
assert(wasm.features.hasGC());
// TODO: Construct nontrivial types. For now just create a hard coded
// struct or array.
@@ -2078,13 +2078,14 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) {
// --nominal mode.
static HeapType trivialStruct = HeapType(Struct());
return builder.makeStructNew(trivialStruct, std::vector<Expression*>{});
- } else {
- // Use a local static to avoid creating a fresh nominal types in
- // --nominal mode.
- static HeapType trivialArray =
- HeapType(Array(Field(Field::PackedType::i8, Immutable)));
- return builder.makeArrayInit(trivialArray, {});
}
+ [[fallthrough]];
+ case HeapType::array: {
+ // Use a local static to avoid creating a fresh nominal types in
+ // --nominal mode.
+ static HeapType trivialArray =
+ HeapType(Array(Field(Field::PackedType::i8, Immutable)));
+ return builder.makeArrayInit(trivialArray, {});
}
case HeapType::string:
case HeapType::stringview_wtf8:
@@ -3052,7 +3053,9 @@ Type TranslateToFuzzReader::getSingleConcreteType() {
Type(HeapType::i31, Nullable),
// Type(HeapType::i31, NonNullable),
Type(HeapType::data, Nullable),
- Type(HeapType::data, NonNullable)));
+ Type(HeapType::data, NonNullable),
+ Type(HeapType::array, Nullable),
+ Type(HeapType::array, NonNullable)));
}
Type TranslateToFuzzReader::getReferenceType() {
@@ -3171,18 +3174,24 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) {
HeapType::eq,
HeapType::i31,
HeapType::data,
+ HeapType::array,
HeapType::none);
case HeapType::eq:
// TODO: nontrivial types as well.
assert(wasm.features.hasReferenceTypes());
assert(wasm.features.hasGC());
- return pick(
- HeapType::eq, HeapType::i31, HeapType::data, HeapType::none);
+ return pick(HeapType::eq,
+ HeapType::i31,
+ HeapType::data,
+ HeapType::array,
+ HeapType::none);
case HeapType::i31:
return pick(HeapType::i31, HeapType::none);
case HeapType::data:
// TODO: nontrivial types as well.
- return pick(HeapType::data, HeapType::none);
+ return pick(HeapType::data, HeapType::array, HeapType::none);
+ case HeapType::array:
+ return pick(HeapType::array, HeapType::none);
case HeapType::string:
case HeapType::stringview_wtf8:
case HeapType::stringview_wtf16:
diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp
index 351035f93..e93aae56c 100644
--- a/src/tools/fuzzing/heap-types.cpp
+++ b/src/tools/fuzzing/heap-types.cpp
@@ -152,7 +152,7 @@ struct HeapTypeGeneratorImpl {
if (rand.oneIn(16)) {
return rand.pick(HeapType::noext, HeapType::nofunc, HeapType::none);
}
- // TODO: strings
+ // TODO: strings and array
return rand.pick(HeapType::func,
HeapType::ext,
HeapType::any,
@@ -326,6 +326,8 @@ struct HeapTypeGeneratorImpl {
return HeapType::i31;
case HeapType::data:
return pickSubData();
+ case HeapType::array:
+ WASM_UNREACHABLE("TODO: fuzz array");
case HeapType::string:
case HeapType::stringview_wtf8:
case HeapType::stringview_wtf16:
@@ -463,6 +465,8 @@ struct HeapTypeGeneratorImpl {
return DataKind{};
case HeapType::data:
return DataKind{};
+ case HeapType::array:
+ WASM_UNREACHABLE("TODO: fuzz array");
case HeapType::string:
case HeapType::stringview_wtf8:
case HeapType::stringview_wtf16:
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index e85d67be2..709c0c9f9 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -378,6 +378,7 @@ enum EncodedType {
i31ref = -0x16, // 0x6a
// gc and string reference types
dataref = -0x19, // 0x67
+ arrayref = -0x1a, // 0x66
stringref = -0x1c, // 0x64
stringview_wtf8 = -0x1d, // 0x63
stringview_wtf16 = -0x1e, // 0x62
@@ -408,6 +409,7 @@ enum EncodedHeapType {
eq = -0x13, // 0x6d
i31 = -0x16, // 0x6a
data = -0x19, // 0x67
+ array = -0x1a, // 0x66
string = -0x1c, // 0x64
// stringview/iter constants are identical to type, and cannot be duplicated
// here as that would be a compiler error, so add _heap suffixes. See
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 36c2cbede..dbf99d512 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -325,6 +325,7 @@ public:
eq,
i31,
data,
+ array,
string,
stringview_wtf8,
stringview_wtf16,
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 09022eea0..8d60a4829 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -126,6 +126,7 @@ Literal::Literal(const Literal& other) : type(other.type) {
case HeapType::eq:
case HeapType::func:
case HeapType::data:
+ case HeapType::array:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::stringview_wtf8:
@@ -523,6 +524,7 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
case HeapType::eq:
case HeapType::func:
case HeapType::data:
+ case HeapType::array:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::stringview_wtf8:
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 5d21f5130..13c28f151 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1414,6 +1414,9 @@ void WasmBinaryWriter::writeType(Type type) {
case HeapType::data:
o << S32LEB(BinaryConsts::EncodedType::dataref);
return;
+ case HeapType::array:
+ o << S32LEB(BinaryConsts::EncodedType::arrayref);
+ return;
case HeapType::string:
o << S32LEB(BinaryConsts::EncodedType::stringref);
return;
@@ -1520,6 +1523,9 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
case HeapType::data:
ret = BinaryConsts::EncodedHeapType::data;
break;
+ case HeapType::array:
+ ret = BinaryConsts::EncodedHeapType::array;
+ break;
case HeapType::string:
ret = BinaryConsts::EncodedHeapType::string;
break;
@@ -1887,6 +1893,9 @@ bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) {
case BinaryConsts::EncodedType::dataref:
out = Type(HeapType::data, Nullable);
return true;
+ case BinaryConsts::EncodedType::arrayref:
+ out = Type(HeapType::array, Nullable);
+ return true;
case BinaryConsts::EncodedType::stringref:
out = Type(HeapType::string, Nullable);
return true;
@@ -1933,6 +1942,9 @@ bool WasmBinaryBuilder::getBasicHeapType(int64_t code, HeapType& out) {
case BinaryConsts::EncodedHeapType::data:
out = HeapType::data;
return true;
+ case BinaryConsts::EncodedHeapType::array:
+ out = HeapType::array;
+ return true;
case BinaryConsts::EncodedHeapType::string:
out = HeapType::string;
return true;
@@ -7102,9 +7114,9 @@ bool WasmBinaryBuilder::maybeVisitArrayLen(Expression*& out, uint32_t code) {
if (code != BinaryConsts::ArrayLen) {
return false;
}
- auto heapType = getIndexedHeapType();
+ // Ignore the type annotation and don't bother validating it.
+ getU32LEB();
auto* ref = popNonVoidExpression();
- validateHeapTypeUsingChild(ref, heapType);
out = Builder(wasm).makeArrayLen(ref);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 91d4c129c..41a0619f9 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -1194,6 +1194,9 @@ Type SExpressionWasmBuilder::stringToType(std::string_view str,
(str.substr(0, 9) == "structref" && (prefix || str.size() == 9))) {
return Type(HeapType::data, Nullable);
}
+ if (str.substr(0, 8) == "arrayref" && (prefix || str.size() == 8)) {
+ return Type(HeapType::array, Nullable);
+ }
if (str.substr(0, 9) == "stringref" && (prefix || str.size() == 9)) {
return Type(HeapType::string, Nullable);
}
@@ -1243,6 +1246,9 @@ HeapType SExpressionWasmBuilder::stringToHeapType(std::string_view str,
(str.substr(0, 6) == "struct" && (prefix || str.size() == 6))) {
return HeapType::data;
}
+ if (str.substr(0, 5) == "array" && (prefix || str.size() == 5)) {
+ return HeapType::array;
+ }
if (str.substr(0, 6) == "string" && (prefix || str.size() == 6)) {
return HeapType::string;
}
@@ -3021,9 +3027,9 @@ Expression* SExpressionWasmBuilder::makeArraySet(Element& s) {
}
Expression* SExpressionWasmBuilder::makeArrayLen(Element& s) {
- auto heapType = parseHeapType(*s[1]);
+ // Ignore the type annotation and don't bother validating it.
+ parseHeapType(*s[1]);
auto ref = parseExpression(*s[2]);
- validateHeapTypeUsingChild(ref, heapType, s);
return Builder(wasm).makeArrayLen(ref);
}
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 13d85d338..7c1c121d5 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2168,12 +2168,9 @@ void BinaryInstWriter::visitArraySet(ArraySet* curr) {
}
void BinaryInstWriter::visitArrayLen(ArrayLen* curr) {
- if (curr->ref->type.isNull()) {
- emitUnreachable();
- return;
- }
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayLen);
- parent.writeIndexedHeapType(curr->ref->type.getHeapType());
+ // Unused type index.
+ o << U32LEB(0);
}
void BinaryInstWriter::visitArrayCopy(ArrayCopy* curr) {
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index b2cde6050..4fa7ff9d5 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -567,8 +567,9 @@ HeapType::BasicHeapType getBasicHeapSupertype(HeapType type) {
case HeapTypeInfo::SignatureKind:
return HeapType::func;
case HeapTypeInfo::StructKind:
- case HeapTypeInfo::ArrayKind:
return HeapType::data;
+ case HeapTypeInfo::ArrayKind:
+ return HeapType::array;
}
WASM_UNREACHABLE("unexpected kind");
};
@@ -598,16 +599,21 @@ std::optional<HeapType> getBasicHeapTypeLUB(HeapType::BasicHeapType a,
case HeapType::any:
return {HeapType::any};
case HeapType::eq:
- if (b == HeapType::i31 || b == HeapType::data) {
+ if (b == HeapType::i31 || b == HeapType::data || b == HeapType::array) {
return {HeapType::eq};
}
return {HeapType::any};
case HeapType::i31:
- if (b == HeapType::data) {
+ if (b == HeapType::data || b == HeapType::array) {
return {HeapType::eq};
}
return {HeapType::any};
case HeapType::data:
+ if (b == HeapType::array) {
+ return {HeapType::data};
+ }
+ return {HeapType::any};
+ case HeapType::array:
case HeapType::string:
case HeapType::stringview_wtf8:
case HeapType::stringview_wtf16:
@@ -1086,13 +1092,14 @@ FeatureSet Type::getFeatures() const {
}
if (heapType.isBasic()) {
switch (heapType.getBasic()) {
- case HeapType::BasicHeapType::ext:
- case HeapType::BasicHeapType::func:
+ case HeapType::ext:
+ case HeapType::func:
return FeatureSet::ReferenceTypes;
- case HeapType::BasicHeapType::any:
- case HeapType::BasicHeapType::eq:
- case HeapType::BasicHeapType::i31:
- case HeapType::BasicHeapType::data:
+ case HeapType::any:
+ case HeapType::eq:
+ case HeapType::i31:
+ case HeapType::data:
+ case HeapType::array:
return FeatureSet::ReferenceTypes | FeatureSet::GC;
case HeapType::string:
case HeapType::stringview_wtf8:
@@ -1389,6 +1396,7 @@ bool HeapType::isBottom() const {
case eq:
case i31:
case data:
+ case array:
case string:
case stringview_wtf8:
case stringview_wtf16:
@@ -1441,9 +1449,12 @@ size_t HeapType::getDepth() const {
if (!isBasic()) {
if (isFunction()) {
depth++;
- } else if (isData()) {
+ } else if (isStruct()) {
// specific struct types <: data <: eq <: any
depth += 3;
+ } else if (isArray()) {
+ // specific array types <: array <: data <: eq <: any
+ depth += 4;
}
} else {
// Some basic types have supers.
@@ -1463,6 +1474,9 @@ size_t HeapType::getDepth() const {
case HeapType::stringview_iter:
depth += 2;
break;
+ case HeapType::array:
+ depth += 3;
+ break;
case HeapType::none:
case HeapType::nofunc:
case HeapType::noext:
@@ -1484,6 +1498,7 @@ HeapType::BasicHeapType HeapType::getBottom() const {
case eq:
case i31:
case data:
+ case array:
case string:
case stringview_wtf8:
case stringview_wtf16:
@@ -1753,11 +1768,13 @@ bool SubTyper::isSubType(HeapType a, HeapType b) {
return a.getBottom() == HeapType::none;
case HeapType::eq:
return a == HeapType::i31 || a == HeapType::data ||
- a == HeapType::none || a.isData();
+ a == HeapType::array || a == HeapType::none || a.isData();
case HeapType::i31:
return a == HeapType::none;
case HeapType::data:
- return a == HeapType::none || a.isData();
+ return a == HeapType::array || a == HeapType::none || a.isData();
+ case HeapType::array:
+ return a == HeapType::none || a.isArray();
case HeapType::string:
case HeapType::stringview_wtf8:
case HeapType::stringview_wtf16:
@@ -2120,6 +2137,8 @@ std::ostream& TypePrinter::print(Type type) {
return os << "i31ref";
case HeapType::data:
return os << "dataref";
+ case HeapType::array:
+ return os << "arrayref";
case HeapType::string:
return os << "stringref";
case HeapType::stringview_wtf8:
@@ -2164,6 +2183,8 @@ std::ostream& TypePrinter::print(HeapType type) {
return os << "i31";
case HeapType::data:
return os << "data";
+ case HeapType::array:
+ return os << "array";
case HeapType::string:
return os << "string";
case HeapType::stringview_wtf8:
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 91236fe54..0e7566528 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2696,9 +2696,8 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) {
if (curr->type == Type::unreachable) {
return;
}
- // TODO: array rather than data once we've implemented that.
if (!shouldBeSubType(curr->ref->type,
- Type(HeapType::data, Nullable),
+ Type(HeapType::array, Nullable),
curr,
"array.get target should be an array reference")) {
return;
@@ -2707,6 +2706,11 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) {
if (heapType == HeapType::none) {
return;
}
+ if (!shouldBeTrue(heapType != HeapType::array,
+ curr,
+ "array.get target should be a specific array reference")) {
+ return;
+ }
const auto& element = heapType.getArray().element;
// If the type is not packed, it must be marked internally as unsigned, by
// convention.
@@ -2725,9 +2729,8 @@ void FunctionValidator::visitArraySet(ArraySet* curr) {
if (curr->type == Type::unreachable) {
return;
}
- // TODO: array rather than data once we've implemented that.
if (!shouldBeSubType(curr->ref->type,
- Type(HeapType::data, Nullable),
+ Type(HeapType::array, Nullable),
curr,
"array.set target should be an array reference")) {
return;
@@ -2736,6 +2739,11 @@ void FunctionValidator::visitArraySet(ArraySet* curr) {
if (heapType == HeapType::none) {
return;
}
+ if (!shouldBeTrue(heapType != HeapType::array,
+ curr,
+ "array.set target should be a specific array reference")) {
+ return;
+ }
const auto& element = curr->ref->type.getHeapType().getArray().element;
shouldBeSubType(curr->value->type,
element.type,
@@ -2749,6 +2757,10 @@ void FunctionValidator::visitArrayLen(ArrayLen* curr) {
getModule()->features.hasGC(), curr, "array.len requires gc to be enabled");
shouldBeEqualOrFirstIsUnreachable(
curr->type, Type(Type::i32), curr, "array.len result must be an i32");
+ shouldBeSubType(curr->ref->type,
+ Type(HeapType::array, Nullable),
+ curr,
+ "array.len argument must be an array reference");
}
void FunctionValidator::visitArrayCopy(ArrayCopy* curr) {
@@ -2767,11 +2779,11 @@ void FunctionValidator::visitArrayCopy(ArrayCopy* curr) {
return;
}
if (!shouldBeSubType(curr->srcRef->type,
- Type(HeapType::data, Nullable),
+ Type(HeapType::array, Nullable),
curr,
"array.copy source should be an array reference") ||
!shouldBeSubType(curr->destRef->type,
- Type(HeapType::data, Nullable),
+ Type(HeapType::array, Nullable),
curr,
"array.copy destination should be an array reference")) {
return;
@@ -2781,6 +2793,16 @@ void FunctionValidator::visitArrayCopy(ArrayCopy* curr) {
if (srcHeapType == HeapType::none || destHeapType == HeapType::none) {
return;
}
+ if (!shouldBeTrue(
+ srcHeapType != HeapType::array,
+ curr,
+ "array.copy source needs to be a specific array reference") ||
+ !shouldBeTrue(
+ srcHeapType != HeapType::array,
+ curr,
+ "array.copy destination needs to be a specific array reference")) {
+ return;
+ }
const auto& srcElement = srcHeapType.getArray().element;
const auto& destElement = destHeapType.getArray().element;
shouldBeSubType(srcElement.type,