From e7d65ab97fb3a35292248ae81557ab4a5685306e Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 18 Feb 2021 16:34:38 -0800 Subject: [PATCH 1/3] Support type use before definition in binaries Update parsing of binary type sections to use TypeBuilder to support uses before definitions. Now that both the binary and text parsers support out-of-order type uses, this PR also relaxes the logic for emitting types to allow uses to be emitted before definitions. --- src/ir/module-utils.h | 54 +--- src/wasm-binary.h | 4 +- src/wasm-type.h | 3 + src/wasm/wasm-binary.cpp | 271 ++++++++++++------ src/wasm/wasm-type.cpp | 1 - test/heap-types.wast.from-wast | 12 +- test/heap-types.wast.fromBinary | 12 +- test/heap-types.wast.fromBinary.noDebugInfo | 12 +- .../O_all-features_ignore-implicit-traps.txt | 2 +- test/typed-function-references.wast.from-wast | 4 +- .../typed-function-references.wast.fromBinary | 2 +- ...ion-references.wast.fromBinary.noDebugInfo | 2 +- 12 files changed, 214 insertions(+), 165 deletions(-) diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index 29ebcc2b54e..84ef3a50851 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -433,10 +433,7 @@ inline void collectHeapTypes(Module& wasm, std::unordered_map& typeIndices) { struct Counts : public std::unordered_map { bool isRelevant(Type type) { - if (type.isRef()) { - return !type.getHeapType().isBasic(); - } - return type.isRtt(); + return (type.isRef() || type.isRtt()) && !type.getHeapType().isBasic(); } void note(HeapType type) { (*this)[type]++; } void maybeNote(Type type) { @@ -469,10 +466,11 @@ inline void collectHeapTypes(Module& wasm, } else if (auto* set = curr->dynCast()) { counts.maybeNote(set->ref->type); } else if (Properties::isControlFlowStructure(curr)) { - counts.maybeNote(curr->type); if (curr->type.isTuple()) { // TODO: Allow control flow to have input types as well counts.note(Signature(Type::none, curr->type)); + } else { + counts.maybeNote(curr->type); } } } @@ -509,8 +507,7 @@ inline void collectHeapTypes(Module& wasm, } // A generic utility to traverse the child types of a type. // TODO: work with tlively to refactor this to a shared place - auto walkRelevantChildren = [&](HeapType type, - std::function callback) { + auto walkRelevantChildren = [&](HeapType type, auto callback) { auto callIfRelevant = [&](Type type) { if (counts.isRelevant(type)) { callback(type.getHeapType()); @@ -538,7 +535,6 @@ inline void collectHeapTypes(Module& wasm, // As we do this we may find more and more types, as nested children of // previous ones. Each such type will appear in the type section once, so // we just need to visit it once. - // TODO: handle struct and array fields std::unordered_set newTypes; for (auto& pair : counts) { newTypes.insert(pair.first); @@ -555,49 +551,9 @@ inline void collectHeapTypes(Module& wasm, }); } - // We must sort all the dependencies of a type before it. For example, - // (func (param (ref (func)))) must appear after (func). To do that, find the - // depth of dependencies of each type. For example, if A depends on B - // which depends on C, then A's depth is 2, B's is 1, and C's is 0 (assuming - // no other dependencies). - Counts depthOfDependencies; - std::unordered_map> isDependencyOf; - // To calculate the depth of dependencies, we'll do a flow analysis, visiting - // each type as we find out new things about it. - std::set toVisit; - for (auto& pair : counts) { - auto type = pair.first; - depthOfDependencies[type] = 0; - toVisit.insert(type); - walkRelevantChildren(type, [&](HeapType childType) { - isDependencyOf[childType].insert(type); // XXX flip? - }); - } - while (!toVisit.empty()) { - auto iter = toVisit.begin(); - auto type = *iter; - toVisit.erase(iter); - // Anything that depends on this has a depth of dependencies equal to this - // type's, plus this type itself. - auto newDepth = depthOfDependencies[type] + 1; - if (newDepth > counts.size()) { - Fatal() << "Cyclic types detected, cannot sort them."; - } - for (auto& other : isDependencyOf[type]) { - if (depthOfDependencies[other] < newDepth) { - // We found something new to propagate. - depthOfDependencies[other] = newDepth; - toVisit.insert(other); - } - } - } - // Sort by frequency and then simplicity, and also keeping every type - // before things that depend on it. + // Sort by frequency and then simplicity. std::vector> sorted(counts.begin(), counts.end()); std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) { - if (depthOfDependencies[a.first] != depthOfDependencies[b.first]) { - return depthOfDependencies[a.first] < depthOfDependencies[b.first]; - } if (a.second != b.second) { return a.second > b.second; } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 99305acb22e..3f76a44216a 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1322,14 +1322,14 @@ class WasmBinaryBuilder { int64_t getS64LEB(); uint64_t getUPtrLEB(); + bool getBasicType(int32_t code, Type& out); + bool getBasicHeapType(int64_t code, HeapType& out); // Read a value and get a type for it. Type getType(); // Get a type given the initial S32LEB has already been read, and is provided. Type getType(int initial); HeapType getHeapType(); - Mutability getMutability(); - Field getField(); Type getConcreteType(); Name getInlineString(); void verifyInt8(int8_t x); diff --git a/src/wasm-type.h b/src/wasm-type.h index 4188c438d4f..b445e412d2d 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -308,6 +308,9 @@ class HeapType { data, }; static constexpr BasicHeapType _last_basic_type = data; + static constexpr uintptr_t _invalid_type = -1; + + constexpr HeapType() : id(_invalid_type) {} // BasicHeapType can be implicitly upgraded to HeapType constexpr HeapType(BasicHeapType id) : id(id) {} diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index dc0b1ab21ad..1c0090c60c8 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1444,45 +1444,91 @@ uint64_t WasmBinaryBuilder::getUPtrLEB() { return wasm.memory.is64() ? getU64LEB() : getU32LEB(); } +bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) { + switch (code) { + case BinaryConsts::EncodedType::i32: + out = Type::i32; + return true; + case BinaryConsts::EncodedType::i64: + out = Type::i64; + return true; + case BinaryConsts::EncodedType::f32: + out = Type::f32; + return true; + case BinaryConsts::EncodedType::f64: + out = Type::f64; + return true; + case BinaryConsts::EncodedType::v128: + out = Type::v128; + return true; + case BinaryConsts::EncodedType::funcref: + out = Type::funcref; + return true; + case BinaryConsts::EncodedType::externref: + out = Type::externref; + return true; + case BinaryConsts::EncodedType::anyref: + out = Type::anyref; + return true; + case BinaryConsts::EncodedType::eqref: + out = Type::eqref; + return true; + case BinaryConsts::EncodedType::i31ref: + // FIXME: for now, force all inputs to be nullable + out = Type(HeapType::i31, Nullable); + return true; + case BinaryConsts::EncodedType::dataref: + // FIXME: for now, force all inputs to be nullable + out = Type(HeapType::data, Nullable); + return true; + default: + return false; + } +} + +bool WasmBinaryBuilder::getBasicHeapType(int64_t code, HeapType& out) { + switch (code) { + case BinaryConsts::EncodedHeapType::func: + out = HeapType::func; + return true; + case BinaryConsts::EncodedHeapType::extern_: + out = HeapType::ext; + return true; + case BinaryConsts::EncodedHeapType::any: + out = HeapType::any; + return true; + case BinaryConsts::EncodedHeapType::eq: + out = HeapType::eq; + return true; + case BinaryConsts::EncodedHeapType::i31: + out = HeapType::i31; + return true; + case BinaryConsts::EncodedHeapType::data: + out = HeapType::data; + return true; + default: + return false; + } +} + Type WasmBinaryBuilder::getType(int initial) { // Single value types are negative; signature indices are non-negative if (initial >= 0) { // TODO: Handle block input types properly. return getSignatureByTypeIndex(initial).results; } + Type type; + if (getBasicType(initial, type)) { + return type; + } switch (initial) { // None only used for block signatures. TODO: Separate out? case BinaryConsts::EncodedType::Empty: return Type::none; - case BinaryConsts::EncodedType::i32: - return Type::i32; - case BinaryConsts::EncodedType::i64: - return Type::i64; - case BinaryConsts::EncodedType::f32: - return Type::f32; - case BinaryConsts::EncodedType::f64: - return Type::f64; - case BinaryConsts::EncodedType::v128: - return Type::v128; - case BinaryConsts::EncodedType::funcref: - return Type::funcref; - case BinaryConsts::EncodedType::externref: - return Type::externref; - case BinaryConsts::EncodedType::anyref: - return Type::anyref; - case BinaryConsts::EncodedType::eqref: - return Type::eqref; case BinaryConsts::EncodedType::nullable: - return Type(getHeapType(), Nullable); case BinaryConsts::EncodedType::nonnullable: // FIXME: for now, force all inputs to be nullable return Type(getHeapType(), Nullable); - case BinaryConsts::EncodedType::i31ref: - // FIXME: for now, force all inputs to be nullable - return Type(HeapType::BasicHeapType::i31, Nullable); - case BinaryConsts::EncodedType::dataref: - // FIXME: for now, force all inputs to be nullable - return Type(HeapType::BasicHeapType::data, Nullable); case BinaryConsts::EncodedType::rtt_n: { auto depth = getU32LEB(); auto heapType = getHeapType(); @@ -1508,54 +1554,15 @@ HeapType WasmBinaryBuilder::getHeapType() { } return types[type]; } - switch (type) { - case BinaryConsts::EncodedHeapType::func: - return HeapType::func; - case BinaryConsts::EncodedHeapType::extern_: - return HeapType::ext; - case BinaryConsts::EncodedHeapType::any: - return HeapType::any; - case BinaryConsts::EncodedHeapType::eq: - return HeapType::eq; - case BinaryConsts::EncodedHeapType::i31: - return HeapType::i31; - case BinaryConsts::EncodedHeapType::data: - return HeapType::data; - default: - throwError("invalid wasm heap type: " + std::to_string(type)); + HeapType ht; + if (getBasicHeapType(type, ht)) { + return ht; + } else { + throwError("invalid wasm heap type: " + std::to_string(type)); } WASM_UNREACHABLE("unexpected type"); } -Mutability WasmBinaryBuilder::getMutability() { - switch (getU32LEB()) { - case 0: - return Immutable; - case 1: - return Mutable; - default: - throw ParseException("Expected 0 or 1 for mutability"); - } -} - -Field WasmBinaryBuilder::getField() { - // The value may be a general wasm type, or one of the types only possible in - // a field. - auto initial = getS32LEB(); - if (initial == BinaryConsts::EncodedType::i8) { - auto mutable_ = getMutability(); - return Field(Field::i8, mutable_); - } - if (initial == BinaryConsts::EncodedType::i16) { - auto mutable_ = getMutability(); - return Field(Field::i16, mutable_); - } - // It's a regular wasm value. - auto type = getType(initial); - auto mutable_ = getMutability(); - return Field(type, mutable_); -} - Type WasmBinaryBuilder::getConcreteType() { auto type = getType(); if (!type.isConcrete()) { @@ -1643,37 +1650,121 @@ void WasmBinaryBuilder::readTypes() { BYN_TRACE("== readTypes\n"); size_t numTypes = getU32LEB(); BYN_TRACE("num: " << numTypes << std::endl); + TypeBuilder builder(numTypes); + + auto makeType = [&](int32_t typeCode) { + Type type; + if (getBasicType(typeCode, type)) { + return type; + } + + switch (typeCode) { + case BinaryConsts::EncodedType::nullable: + case BinaryConsts::EncodedType::nonnullable: { + // FIXME: for now, force all inputs to be nullable + int64_t htCode = getS64LEB(); // TODO: Actually s33 + HeapType ht; + if (getBasicHeapType(htCode, ht)) { + return Type(ht, Nullable); + } + if (size_t(htCode) >= numTypes) { + throwError("invalid type index: " + std::to_string(htCode)); + } + return builder.getTempRefType(size_t(htCode), Nullable); + } + case BinaryConsts::EncodedType::rtt_n: + case BinaryConsts::EncodedType::rtt: { + auto depth = typeCode == BinaryConsts::EncodedType::rtt ? Rtt::NoDepth + : getU32LEB(); + int64_t htCode = getS64LEB(); // TODO: Actually s33 + HeapType ht; + if (getBasicHeapType(htCode, ht)) { + return Type(Rtt(depth, ht)); + } + if (size_t(htCode) >= numTypes) { + throwError("invalid type index: " + std::to_string(htCode)); + } + return builder.getTempRttType(htCode, depth); + } + default: + throwError("unexpected type index: " + std::to_string(typeCode)); + } + WASM_UNREACHABLE("unexpected type"); + }; + + auto readType = [&]() { return makeType(getS32LEB()); }; + + auto readSignatureDef = [&]() { + std::vector params; + std::vector results; + size_t numParams = getU32LEB(); + BYN_TRACE("num params: " << numParams << std::endl); + for (size_t j = 0; j < numParams; j++) { + params.push_back(readType()); + } + auto numResults = getU32LEB(); + BYN_TRACE("num results: " << numResults << std::endl); + for (size_t j = 0; j < numResults; j++) { + results.push_back(readType()); + } + return Signature(builder.getTempTupleType(params), + builder.getTempTupleType(results)); + }; + + auto readMutability = [&]() { + switch (getU32LEB()) { + case 0: + return Immutable; + case 1: + return Mutable; + default: + throw ParseException("Expected 0 or 1 for mutability"); + } + }; + + auto readFieldDef = [&]() { + // The value may be a general wasm type, or one of the types only possible + // in a field. + auto typeCode = getS32LEB(); + if (typeCode == BinaryConsts::EncodedType::i8) { + auto mutable_ = readMutability(); + return Field(Field::i8, mutable_); + } + if (typeCode == BinaryConsts::EncodedType::i16) { + auto mutable_ = readMutability(); + return Field(Field::i16, mutable_); + } + // It's a regular wasm value. + auto type = makeType(typeCode); + auto mutable_ = readMutability(); + return Field(type, mutable_); + }; + + auto readStructDef = [&]() { + FieldList fields; + size_t numFields = getU32LEB(); + BYN_TRACE("num fields: " << numFields << std::endl); + for (size_t j = 0; j < numFields; j++) { + fields.push_back(readFieldDef()); + } + return Struct(std::move(fields)); + }; + for (size_t i = 0; i < numTypes; i++) { BYN_TRACE("read one\n"); auto form = getS32LEB(); if (form == BinaryConsts::EncodedType::Func) { - std::vector params; - std::vector results; - size_t numParams = getU32LEB(); - BYN_TRACE("num params: " << numParams << std::endl); - for (size_t j = 0; j < numParams; j++) { - params.push_back(getConcreteType()); - } - auto numResults = getU32LEB(); - BYN_TRACE("num results: " << numResults << std::endl); - for (size_t j = 0; j < numResults; j++) { - results.push_back(getConcreteType()); - } - types.emplace_back(Signature(Type(params), Type(results))); + builder.setHeapType(i, readSignatureDef()); } else if (form == BinaryConsts::EncodedType::Struct) { - FieldList fields; - size_t numFields = getU32LEB(); - BYN_TRACE("num fields: " << numFields << std::endl); - for (size_t j = 0; j < numFields; j++) { - fields.push_back(getField()); - } - types.emplace_back(Struct(fields)); + builder.setHeapType(i, readStructDef()); } else if (form == BinaryConsts::EncodedType::Array) { - types.emplace_back(Array(getField())); + builder.setHeapType(i, Array(readFieldDef())); } else { throwError("bad type form " + std::to_string(form)); } } + + types = builder.build(); } Name WasmBinaryBuilder::getFunctionName(Index index) { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 87dd2b28964..4936bc3ff60 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -1304,7 +1304,6 @@ void Canonicalizer::makeAncestorsFixedPoint() { std::vector Canonicalizer::getOrderedItems() { // Topologically sort the Types and HeapTypes so that all children are // canonicalized before their parents. - std::vector sorted; std::unordered_set seen; diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index 458842a7ba4..d45e5c37c5c 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -1,20 +1,20 @@ (module (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64))) + (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) + (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $[mut:f64] (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type ${} (struct )) (type ${mut:f32} (struct (field (mut f32)))) (type $none_=>_none (func)) - (type ${i32} (struct (field i32))) - (type ${i32_i64} (struct (field i32) (field i64))) - (type $[mut:i32] (array (mut i32))) - (type $[mut:i8] (array (mut i8))) - (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) - (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $rtt_1_${}_=>_none (func (param (rtt 1 ${})))) (type $rtt_${}_=>_none (func (param (rtt ${})))) (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})))) (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|])))) + (type ${i32} (struct (field i32))) + (type ${i32_i64} (struct (field i32) (field i64))) + (type $[mut:i32] (array (mut i32))) + (type $[mut:i8] (array (mut i8))) (global $rttparent (rtt 0 ${}) (rtt.canon ${})) (global $rttchild (rtt 1 ${i32}) (rtt.sub ${i32} (global.get $rttparent) diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index 5e48da1169e..303038693ac 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -1,20 +1,20 @@ (module (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64))) + (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) + (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $[mut:f64] (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type ${} (struct )) (type ${mut:f32} (struct (field (mut f32)))) (type $none_=>_none (func)) - (type ${i32} (struct (field i32))) - (type ${i32_i64} (struct (field i32) (field i64))) - (type $[mut:i32] (array (mut i32))) - (type $[mut:i8] (array (mut i8))) - (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) - (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $rtt_1_${}_=>_none (func (param (rtt 1 ${})))) (type $rtt_${}_=>_none (func (param (rtt ${})))) (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})))) (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|])))) + (type ${i32} (struct (field i32))) + (type ${i32_i64} (struct (field i32) (field i64))) + (type $[mut:i32] (array (mut i32))) + (type $[mut:i8] (array (mut i8))) (global $rttparent (rtt 0 ${}) (rtt.canon ${})) (global $rttchild (rtt 1 ${i32}) (rtt.sub ${i32} (global.get $rttparent) diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index d49d5fa1ec2..1ae5792cb5f 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -1,20 +1,20 @@ (module (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64))) + (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) + (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $[mut:f64] (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type ${} (struct )) (type ${mut:f32} (struct (field (mut f32)))) (type $none_=>_none (func)) - (type ${i32} (struct (field i32))) - (type ${i32_i64} (struct (field i32) (field i64))) - (type $[mut:i32] (array (mut i32))) - (type $[mut:i8] (array (mut i8))) - (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64}))))) - (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $rtt_1_${}_=>_none (func (param (rtt 1 ${})))) (type $rtt_${}_=>_none (func (param (rtt ${})))) (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})))) (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|])))) + (type ${i32} (struct (field i32))) + (type ${i32_i64} (struct (field i32) (field i64))) + (type $[mut:i32] (array (mut i32))) + (type $[mut:i8] (array (mut i8))) (global $global$0 (rtt 0 ${}) (rtt.canon ${})) (global $global$1 (rtt 1 ${i32}) (rtt.sub ${i32} (global.get $global$0) diff --git a/test/passes/O_all-features_ignore-implicit-traps.txt b/test/passes/O_all-features_ignore-implicit-traps.txt index 8e57a2e4b5d..993bd10e59d 100644 --- a/test/passes/O_all-features_ignore-implicit-traps.txt +++ b/test/passes/O_all-features_ignore-implicit-traps.txt @@ -1,6 +1,6 @@ (module - (type ${i32} (struct (field i32))) (type $ref?|{i32}|_=>_none (func (param (ref null ${i32})))) + (type ${i32} (struct (field i32))) (export "foo" (func $0)) (func $0 (; has Stack IR ;) (param $0 (ref null ${i32})) (nop) diff --git a/test/typed-function-references.wast.from-wast b/test/typed-function-references.wast.from-wast index a31eeecea29..dde689fa0b1 100644 --- a/test/typed-function-references.wast.from-wast +++ b/test/typed-function-references.wast.from-wast @@ -1,12 +1,12 @@ (module (type $none_=>_none (func)) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) (type $none_=>_anyref (func (result anyref))) - (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32))) - (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64))) + (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32))) (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref)))) (func $call-ref (call_ref diff --git a/test/typed-function-references.wast.fromBinary b/test/typed-function-references.wast.fromBinary index 0e4385c84e8..fb13b73c481 100644 --- a/test/typed-function-references.wast.fromBinary +++ b/test/typed-function-references.wast.fromBinary @@ -2,10 +2,10 @@ (type $none_=>_none (func)) (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32))) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) (type $none_=>_anyref (func (result anyref))) - (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64))) (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref)))) (func $call-ref diff --git a/test/typed-function-references.wast.fromBinary.noDebugInfo b/test/typed-function-references.wast.fromBinary.noDebugInfo index ad50ea1f7ca..7d09438df6a 100644 --- a/test/typed-function-references.wast.fromBinary.noDebugInfo +++ b/test/typed-function-references.wast.fromBinary.noDebugInfo @@ -2,10 +2,10 @@ (type $none_=>_none (func)) (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32))) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) (type $none_=>_anyref (func (result anyref))) - (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64))) (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref)))) (func $0 From 623904dfc98a3843d476bacbc9355407426f99f1 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 19 Feb 2021 12:18:35 -0800 Subject: [PATCH 2/3] Fix lit test type order --- test/lit/forward-declared-types.wast | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lit/forward-declared-types.wast b/test/lit/forward-declared-types.wast index e9b66175bf8..002e7ceb307 100644 --- a/test/lit/forward-declared-types.wast +++ b/test/lit/forward-declared-types.wast @@ -3,9 +3,9 @@ ;; RUN: wasm-opt %s -all -S -o - | filecheck %s ;; CHECK: (type $none_=>_none (func)) -;; CHECK: (type $[rtt_2_$none_=>_none] (array (rtt 2 $none_=>_none))) -;; CHECK: (type ${ref?|[rtt_2_$none_=>_none]|_ref?|none_->_none|} (struct (field (ref null $[rtt_2_$none_=>_none])) (field (ref null $none_=>_none)))) ;; CHECK: (type $none_=>_ref?|{ref?|[rtt_2_$none_=>_none]|_ref?|none_->_none|}| (func (result (ref null ${ref?|[rtt_2_$none_=>_none]|_ref?|none_->_none|})))) +;; CHECK: (type ${ref?|[rtt_2_$none_=>_none]|_ref?|none_->_none|} (struct (field (ref null $[rtt_2_$none_=>_none])) (field (ref null $none_=>_none)))) +;; CHECK: (type $[rtt_2_$none_=>_none] (array (rtt 2 $none_=>_none))) (module (type $struct (struct From 3548196e4b3fe27ca713a6379f7e1b8efbcf751a Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 19 Feb 2021 12:39:11 -0800 Subject: [PATCH 3/3] No invalid HeapTypes --- src/wasm-type.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index b445e412d2d..b61fe68a65d 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -308,9 +308,6 @@ class HeapType { data, }; static constexpr BasicHeapType _last_basic_type = data; - static constexpr uintptr_t _invalid_type = -1; - - constexpr HeapType() : id(_invalid_type) {} // BasicHeapType can be implicitly upgraded to HeapType constexpr HeapType(BasicHeapType id) : id(id) {} @@ -318,6 +315,9 @@ class HeapType { // But converting raw TypeID is more dangerous, so make it explicit explicit HeapType(TypeID id) : id(id) {} + // Choose an arbitrary heap type as the default. + constexpr HeapType() : HeapType(func) {} + HeapType(Signature signature); HeapType(const Struct& struct_); HeapType(Struct&& struct_);