diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 39 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 17 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 90 |
3 files changed, 98 insertions, 48 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d9b7e1a84..639f4b848 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -236,6 +236,19 @@ void WasmBinaryWriter::writeTypes() { lastGroup = currGroup; } } + + // As a temporary measure, detect which types have subtypes and always use + // `sub` or `sub final` for these types. The standard says that types without + // `sub` or `sub final` are final, but we currently treat them as non-final. + // To avoid unsafe ambiguity, only use the short form for types that it would + // be safe to treat as final, i.e. types without subtypes. + std::vector<bool> hasSubtypes(indexedTypes.types.size()); + for (auto type : indexedTypes.types) { + if (auto super = type.getSuperType()) { + hasSubtypes[indexedTypes.indices[*super]] = true; + } + } + BYN_TRACE("== writeTypes\n"); auto start = startSection(BinaryConsts::Section::Type); o << U32LEB(numGroups); @@ -251,10 +264,21 @@ void WasmBinaryWriter::writeTypes() { lastGroup = currGroup; // Emit the type definition. BYN_TRACE("write " << type << std::endl); - if (auto super = type.getSuperType()) { - // Subtype constructor and vector of 1 supertype. - o << S32LEB(BinaryConsts::EncodedType::Sub) << U32LEB(1); - writeHeapType(*super); + auto super = type.getSuperType(); + // TODO: Use the binary shorthand for final types once we parse MVP + // signatures as final. + if (type.isFinal() || super || hasSubtypes[i]) { + if (type.isFinal()) { + o << S32LEB(BinaryConsts::EncodedType::SubFinal); + } else { + o << S32LEB(BinaryConsts::EncodedType::Sub); + } + if (super) { + o << U32LEB(1); + writeHeapType(*super); + } else { + o << U32LEB(0); + } } if (type.isSignature()) { o << S32LEB(BinaryConsts::EncodedType::Func); @@ -2210,7 +2234,12 @@ void WasmBinaryReader::readTypes() { form = getS32LEB(); } std::optional<uint32_t> superIndex; - if (form == BinaryConsts::EncodedType::Sub) { + if (form == BinaryConsts::EncodedType::Sub || + form == BinaryConsts::EncodedType::SubFinal) { + if (form == BinaryConsts::EncodedType::SubFinal) { + // TODO: Interpret type definitions without any `sub` as final as well. + builder[i].setFinal(); + } uint32_t supers = getU32LEB(); if (supers > 0) { if (supers != 1) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index e99200d58..9b7a1a90d 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -52,7 +52,8 @@ namespace wasm { static Name STRUCT("struct"), FIELD("field"), ARRAY("array"), FUNC_SUBTYPE("func_subtype"), STRUCT_SUBTYPE("struct_subtype"), ARRAY_SUBTYPE("array_subtype"), EXTENDS("extends"), REC("rec"), I8("i8"), - I16("i16"), DECLARE("declare"), ITEM("item"), OFFSET("offset"), SUB("sub"); + I16("i16"), DECLARE("declare"), ITEM("item"), OFFSET("offset"), SUB("sub"), + FINAL("final"); static Address getAddress(const Element* s) { return std::stoll(s->toString()); @@ -926,11 +927,19 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) { Element& kind = *def[0]; Element* super = nullptr; if (kind == SUB) { - if (def.size() != 3) { + Index i = 1; + if (*def[i] == FINAL) { + builder[index].setFinal(); + ++i; + } + if (def[i]->dollared()) { + super = def[i]; + ++i; + } + Element& subtype = *def[i++]; + if (i != def.size()) { throw ParseException("invalid 'sub' form", kind.line, kind.col); } - super = def[1]; - Element& subtype = *def[2]; if (!subtype.isList() || subtype.size() < 1) { throw ParseException( "invalid subtype definition", subtype.line, subtype.col); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index aa08c52c2..6baf0feb0 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -85,6 +85,7 @@ struct HeapTypeInfo { // Used in assertions to ensure that temporary types don't leak into the // global store. bool isTemp = false; + bool isFinal = false; // The supertype of this HeapType, if it exists. HeapTypeInfo* supertype = nullptr; // The recursion group of this type or null if the recursion group is trivial @@ -153,12 +154,9 @@ struct TypePrinter { std::ostream& print(HeapType type); std::ostream& print(const Tuple& tuple); std::ostream& print(const Field& field); - std::ostream& print(const Signature& sig, - std::optional<HeapType> super = std::nullopt); - std::ostream& print(const Struct& struct_, - std::optional<HeapType> super = std::nullopt); - std::ostream& print(const Array& array, - std::optional<HeapType> super = std::nullopt); + std::ostream& print(const Signature& sig); + std::ostream& print(const Struct& struct_); + std::ostream& print(const Array& array); }; struct RecGroupHasher { @@ -1156,6 +1154,14 @@ bool HeapType::isBottom() const { return false; } +bool HeapType::isFinal() const { + if (isBasic()) { + return false; + } else { + return getHeapTypeInfo(*this)->isFinal; + } +} + Signature HeapType::getSignature() const { assert(isSignature()); return getHeapTypeInfo(*this)->signature; @@ -1735,19 +1741,38 @@ std::ostream& TypePrinter::print(HeapType type) { if (isTemp(type)) { os << "(; temp ;) "; } + #if TRACE_CANONICALIZATION os << "(;" << ((type.getID() >> 4) % 1000) << ";)"; #endif + + // TODO: Use shorthand for final types once we parse MVP signatures as final. + bool useSub = false; + auto super = type.getSuperType(); + if (super || type.isFinal()) { + useSub = true; + os << "(sub "; + if (type.isFinal()) { + os << "final "; + } + if (super) { + printHeapTypeName(*super); + os << ' '; + } + } if (type.isSignature()) { - print(type.getSignature(), type.getSuperType()); + print(type.getSignature()); } else if (type.isStruct()) { - print(type.getStruct(), type.getSuperType()); + print(type.getStruct()); } else if (type.isArray()) { - print(type.getArray(), type.getSuperType()); + print(type.getArray()); } else { WASM_UNREACHABLE("unexpected type"); } - return os << ")"; + if (useSub) { + os << ')'; + } + return os << ')'; } std::ostream& TypePrinter::print(const Tuple& tuple) { @@ -1783,8 +1808,7 @@ std::ostream& TypePrinter::print(const Field& field) { return os; } -std::ostream& TypePrinter::print(const Signature& sig, - std::optional<HeapType> super) { +std::ostream& TypePrinter::print(const Signature& sig) { auto printPrefixed = [&](const char* prefix, Type type) { os << '(' << prefix; for (Type t : type) { @@ -1795,9 +1819,6 @@ std::ostream& TypePrinter::print(const Signature& sig, }; os << "(func"; - if (super) { - os << "_subtype"; - } if (sig.params.getID() != Type::none) { os << ' '; printPrefixed("param", sig.params); @@ -1806,19 +1827,11 @@ std::ostream& TypePrinter::print(const Signature& sig, os << ' '; printPrefixed("result", sig.results); } - if (super) { - os << ' '; - printHeapTypeName(*super); - } return os << ')'; } -std::ostream& TypePrinter::print(const Struct& struct_, - std::optional<HeapType> super) { +std::ostream& TypePrinter::print(const Struct& struct_) { os << "(struct"; - if (super) { - os << "_subtype"; - } if (struct_.fields.size()) { os << " (field"; } @@ -1829,25 +1842,12 @@ std::ostream& TypePrinter::print(const Struct& struct_, if (struct_.fields.size()) { os << ')'; } - if (super) { - os << ' '; - printHeapTypeName(*super); - } return os << ')'; } -std::ostream& TypePrinter::print(const Array& array, - std::optional<HeapType> super) { - os << "(array"; - if (super) { - os << "_subtype"; - } - os << ' '; +std::ostream& TypePrinter::print(const Array& array) { + os << "(array "; print(array.element); - if (super) { - os << ' '; - printHeapTypeName(*super); - } return os << ')'; } @@ -1916,6 +1916,7 @@ size_t RecGroupHasher::hash(const HeapTypeInfo& info) const { if (info.supertype) { hash_combine(digest, hash(HeapType(uintptr_t(info.supertype)))); } + wasm::rehash(digest, info.isFinal); wasm::rehash(digest, info.kind); switch (info.kind) { case HeapTypeInfo::SignatureKind: @@ -2038,6 +2039,9 @@ bool RecGroupEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) const { return false; } } + if (a.isFinal != b.isFinal) { + return false; + } if (a.kind != b.kind) { return false; } @@ -2291,9 +2295,17 @@ void TypeBuilder::createRecGroup(size_t index, size_t length) { {RecGroup(uintptr_t(groupInfo.get())), std::move(groupInfo)}); } +void TypeBuilder::setFinal(size_t i, bool final) { + assert(i < size() && "index out of bounds"); + impl->entries[i].info->isFinal = final; +} + namespace { bool isValidSupertype(const HeapTypeInfo& sub, const HeapTypeInfo& super) { + if (super.isFinal) { + return false; + } if (sub.kind != super.kind) { return false; } |