diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 2 | ||||
-rw-r--r-- | src/passes/Print.cpp | 15 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 31 | ||||
-rw-r--r-- | src/tools/fuzzing/heap-types.cpp | 6 | ||||
-rw-r--r-- | src/wasm-binary.h | 2 | ||||
-rw-r--r-- | src/wasm-type.h | 1 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 10 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 45 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 34 |
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, |