diff options
42 files changed, 427 insertions, 295 deletions
diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index 40868899d..cfc233fd8 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -6,6 +6,7 @@ set(ir_SOURCES ReFinalize.cpp stack-utils.cpp table-utils.cpp + type-updating.cpp module-splitting.cpp ${ir_HEADERS} ) diff --git a/src/ir/literal-utils.h b/src/ir/literal-utils.h index 3c2f36d9a..fbe5b3716 100644 --- a/src/ir/literal-utils.h +++ b/src/ir/literal-utils.h @@ -31,6 +31,12 @@ inline Expression* makeFromInt32(int32_t x, Type type, Module& wasm) { return ret; } +inline bool canMakeZero(Type type) { + // We can make a "zero" - a 0, or a null, or a trivial rtt, etc. - for pretty + // much anything except a non-nullable reference type. + return !type.isRef() || type.isNullable(); +} + inline Expression* makeZero(Type type, Module& wasm) { // TODO: Remove this function once V8 supports v128.const // (https://bugs.chromium.org/p/v8/issues/detail?id=8460) diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp new file mode 100644 index 000000000..54a83aa49 --- /dev/null +++ b/src/ir/type-updating.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2021 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "type-updating.h" +#include "find_all.h" + +namespace wasm { + +namespace TypeUpdating { + +void handleNonNullableLocals(Function* func, Module& wasm) { + // Check if this is an issue. + bool hasNonNullable = false; + for (auto type : func->vars) { + if (type.isRef() && !type.isNullable()) { + hasNonNullable = true; + break; + } + } + if (!hasNonNullable) { + return; + } + // Rewrite the local.gets. + Builder builder(wasm); + for (auto** getp : FindAllPointers<LocalGet>(func->body).list) { + auto* get = (*getp)->cast<LocalGet>(); + auto type = func->getLocalType(get->index); + if (type.isRef() && !type.isNullable()) { + // The get should now return a nullable value, and a ref.as_non_null + // fixes that up. + get->type = Type(type.getHeapType(), Nullable); + *getp = builder.makeRefAs(RefAsNonNull, get); + } + } + + // Rewrite the types of the function's vars (which we can do now, after we + // are done using them to know which local.gets to fix). + for (auto& type : func->vars) { + if (type.isRef() && !type.isNullable()) { + type = Type(type.getHeapType(), Nullable); + } + } +} + +} // namespace TypeUpdating + +} // namespace wasm diff --git a/src/ir/type-updating.h b/src/ir/type-updating.h index 1a117c239..fc438d53e 100644 --- a/src/ir/type-updating.h +++ b/src/ir/type-updating.h @@ -305,6 +305,15 @@ struct TypeUpdater } }; +namespace TypeUpdating { + +// Finds non-nullable locals, which are currently not supported, and handles +// them. Atm this turns them into nullable ones, and adds ref.as_non_null on +// their uses (which keeps the type of the users identical). +void handleNonNullableLocals(Function* func, Module& wasm); + +} // namespace TypeUpdating + } // namespace wasm #endif // wasm_ir_type_updating_h diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 41481b310..3f6263815 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -33,6 +33,7 @@ #include "ir/debug.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" +#include "ir/type-updating.h" #include "ir/utils.h" #include "parsing.h" #include "pass.h" @@ -296,6 +297,7 @@ doInlining(Module* module, Function* into, const InliningAction& action) { // Make the block reachable by adding a break to it block->list.push_back(builder.makeBreak(block->name)); } + TypeUpdating::handleNonNullableLocals(into, *module); return block; } diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index c9b83da78..c89a57976 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -145,13 +145,19 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { ExpressionAnalyzer::isResultUsed(expressionStack, getFunction()); auto* optimized = optimize(child, used, true); if (!optimized) { - if (child->type.isConcrete()) { - // We can't just skip a final concrete element, even if it isn't used. - // Instead, replace it with something that's easy to optimize out (for - // example, code-folding can merge out identical zeros at the end of - // if arms). - optimized = LiteralUtils::makeZero(child->type, *getModule()); - } else if (child->type == Type::unreachable) { + auto childType = child->type; + if (childType.isConcrete()) { + if (LiteralUtils::canMakeZero(childType)) { + // We can't just skip a final concrete element, even if it isn't + // used. Instead, replace it with something that's easy to optimize + // out (for example, code-folding can merge out identical zeros at + // the end of if arms). + optimized = LiteralUtils::makeZero(childType, *getModule()); + } else { + // Don't optimize it out. + optimized = child; + } + } else if (childType == Type::unreachable) { // Don't try to optimize out an unreachable child (dce can do that // properly). optimized = child; diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 8283fccd1..a0d5430d8 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -1490,7 +1490,7 @@ private: for (const auto& type : target->sig.params) { args.push_back(make(type)); } - auto targetType = Type(HeapType(target->sig), Nullable); + auto targetType = Type(HeapType(target->sig), NonNullable); // TODO: half the time make a completely random item with that type. return builder.makeCallRef( builder.makeRefFunc(target->name, targetType), args, type, isReturn); @@ -2096,9 +2096,7 @@ private: } // TODO: randomize the order for (auto& func : wasm.functions) { - // FIXME: RefFunc type should be non-nullable, but we emit nullable - // types for now. - if (type == Type(HeapType(func->sig), Nullable)) { + if (type == Type(HeapType(func->sig), NonNullable)) { return builder.makeRefFunc(func->name, type); } } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index ac095e0c0..dcf9d2540 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -207,7 +207,7 @@ public: if (!Type::isSubType(type, curr->type)) { std::cerr << "expected " << curr->type << ", seeing " << type << " from\n" - << curr << '\n'; + << *curr << '\n'; } #endif assert(Type::isSubType(type, curr->type)); @@ -1454,14 +1454,14 @@ public: auto* func = module->getFunction(cast.originalRef.getFunc()); seenRtt = Literal(Type(Rtt(0, func->sig))); cast.castRef = - Literal(func->name, Type(intendedRtt.type.getHeapType(), Nullable)); + Literal(func->name, Type(intendedRtt.type.getHeapType(), NonNullable)); } else { // GC data store an RTT in each instance. assert(cast.originalRef.isData()); auto gcData = cast.originalRef.getGCData(); seenRtt = gcData->rtt; cast.castRef = - Literal(gcData, Type(intendedRtt.type.getHeapType(), Nullable)); + Literal(gcData, Type(intendedRtt.type.getHeapType(), NonNullable)); } if (!seenRtt.isSubRtt(intendedRtt)) { cast.outcome = cast.Failure; @@ -1486,7 +1486,7 @@ public: return cast.breaking; } if (cast.outcome == cast.Null) { - return Literal::makeNull(curr->type); + return Literal::makeNull(Type(curr->type.getHeapType(), Nullable)); } if (cast.outcome == cast.Failure) { trap("cast error"); diff --git a/src/wasm-type.h b/src/wasm-type.h index bb499c7c1..b638108fc 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -144,6 +144,8 @@ public: bool isArray() const; bool isDefaultable() const; + Nullability getNullability() const; + private: template<bool (Type::*pred)() const> bool hasPredicate() { for (const auto& type : *this) { diff --git a/src/wasm.h b/src/wasm.h index 698de9520..630e5b003 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1397,8 +1397,6 @@ public: Expression* rtt; void finalize(); - - Type getCastType(); }; class RefCast : public SpecificExpression<Expression::RefCastId> { @@ -1409,8 +1407,6 @@ public: Expression* rtt; void finalize(); - - Type getCastType(); }; class BrOn : public SpecificExpression<Expression::BrOnId> { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 6cb837296..09d3287b0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -19,6 +19,7 @@ #include "ir/module-utils.h" #include "ir/table-utils.h" +#include "ir/type-updating.h" #include "support/bits.h" #include "support/debug.h" #include "wasm-binary.h" @@ -1595,12 +1596,10 @@ bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) { out = Type::eqref; return true; case BinaryConsts::EncodedType::i31ref: - // FIXME: for now, force all inputs to be nullable - out = Type(HeapType::i31, Nullable); + out = Type(HeapType::i31, NonNullable); return true; case BinaryConsts::EncodedType::dataref: - // FIXME: for now, force all inputs to be nullable - out = Type(HeapType::data, Nullable); + out = Type(HeapType::data, NonNullable); return true; default: return false; @@ -1647,9 +1646,9 @@ Type WasmBinaryBuilder::getType(int initial) { case BinaryConsts::EncodedType::Empty: return Type::none; case BinaryConsts::EncodedType::nullable: - case BinaryConsts::EncodedType::nonnullable: - // FIXME: for now, force all inputs to be nullable return Type(getHeapType(), Nullable); + case BinaryConsts::EncodedType::nonnullable: + return Type(getHeapType(), NonNullable); case BinaryConsts::EncodedType::rtt_n: { auto depth = getU32LEB(); auto heapType = getIndexedHeapType(); @@ -1790,16 +1789,18 @@ void WasmBinaryBuilder::readTypes() { switch (typeCode) { case BinaryConsts::EncodedType::nullable: case BinaryConsts::EncodedType::nonnullable: { - // FIXME: for now, force all inputs to be nullable + auto nullability = typeCode == BinaryConsts::EncodedType::nullable + ? Nullable + : NonNullable; int64_t htCode = getS64LEB(); // TODO: Actually s33 HeapType ht; if (getBasicHeapType(htCode, ht)) { - return Type(ht, Nullable); + return Type(ht, nullability); } if (size_t(htCode) >= numTypes) { throwError("invalid type index: " + std::to_string(htCode)); } - return builder.getTempRefType(size_t(htCode), Nullable); + return builder.getTempRefType(size_t(htCode), nullability); } case BinaryConsts::EncodedType::rtt_n: case BinaryConsts::EncodedType::rtt: { @@ -2172,6 +2173,9 @@ void WasmBinaryBuilder::readFunctions() { throwError("binary offset at function exit not at expected location"); } } + + TypeUpdating::handleNonNullableLocals(func, wasm); + std::swap(func->epilogLocation, debugLocation); currFunction = nullptr; debugLocation.clear(); @@ -6072,8 +6076,8 @@ void WasmBinaryBuilder::visitRefFunc(RefFunc* curr) { functionRefs[index].push_back(curr); // we don't know function names yet // To support typed function refs, we give the reference not just a general // funcref, but a specific subtype with the actual signature. - // FIXME: for now, emit a nullable type here - curr->finalize(Type(HeapType(getSignatureByFunctionIndex(index)), Nullable)); + curr->finalize( + Type(HeapType(getSignatureByFunctionIndex(index)), NonNullable)); } void WasmBinaryBuilder::visitRefEq(RefEq* curr) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 91ed5056f..45c7c9161 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -686,22 +686,20 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) { auto parseRefType = [&](Element& elem) -> Type { // '(' 'ref' 'null'? ht ')' - bool nullable = elem[1]->isStr() && *elem[1] == NULL_; + auto nullable = + elem[1]->isStr() && *elem[1] == NULL_ ? Nullable : NonNullable; auto& referent = nullable ? *elem[2] : *elem[1]; const char* name = referent.c_str(); if (referent.dollared()) { - // TODO: Support non-nullable types - return builder.getTempRefType(typeIndices[name], Nullable); + return builder.getTempRefType(typeIndices[name], nullable); } else if (String::isNumber(name)) { - // TODO: Support non-nullable types size_t index = atoi(name); if (index >= numTypes) { throw ParseException("invalid type index", elem.line, elem.col); } - return builder.getTempRefType(index, Nullable); + return builder.getTempRefType(index, nullable); } else { - // TODO: Support non-nullable types - return Type(stringToHeapType(name), Nullable); + return Type(stringToHeapType(name), nullable); } }; @@ -1091,12 +1089,10 @@ Type SExpressionWasmBuilder::stringToType(const char* str, return Type::eqref; } if (strncmp(str, "i31ref", 6) == 0 && (prefix || str[6] == 0)) { - // FIXME: for now, force all inputs to be nullable - return Type(HeapType::BasicHeapType::i31, Nullable); + return Type::i31ref; } if (strncmp(str, "dataref", 7) == 0 && (prefix || str[7] == 0)) { - // FIXME: for now, force all inputs to be nullable - return Type(HeapType::BasicHeapType::data, Nullable); + return Type::dataref; } if (allowError) { return Type::none; @@ -1161,8 +1157,7 @@ Type SExpressionWasmBuilder::elementToType(Element& s) { throw ParseException( std::string("invalid reference type qualifier"), s.line, s.col); } - // FIXME: for now, force all inputs to be nullable - Nullability nullable = Nullable; + Nullability nullable = NonNullable; size_t i = 1; if (size == 3) { nullable = Nullable; @@ -2385,7 +2380,7 @@ Expression* SExpressionWasmBuilder::makeRefFunc(Element& s) { ret->func = func; // To support typed function refs, we give the reference not just a general // funcref, but a specific subtype with the actual signature. - ret->finalize(Type(HeapType(functionSignatures[func]), Nullable)); + ret->finalize(Type(HeapType(functionSignatures[func]), NonNullable)); return ret; } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index f46d90854..832ee6367 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -520,6 +520,10 @@ bool Type::isDefaultable() const { return isConcrete() && (!isRef() || isNullable()) && !isRtt(); } +Nullability Type::getNullability() const { + return isNullable() ? Nullable : NonNullable; +} + bool Type::operator<(const Type& other) const { return TypeComparator().lessThan(*this, other); } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index c7423ad6d..71ecf208e 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2183,10 +2183,8 @@ void FunctionValidator::visitI31Get(I31Get* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "i31.get_s/u requires gc to be enabled"); - // FIXME: use i31ref here, which is non-nullable, when we support non- - // nullability. shouldBeSubType(curr->i31->type, - Type(HeapType::i31, Nullable), + Type::i31ref, curr->i31, "i31.get_s/u's argument should be i31ref"); } diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 5eea3f315..2dba93a4a 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -928,30 +928,16 @@ void RefTest::finalize() { } } -// Helper to get the cast type for a cast instruction. They all look at the rtt -// operand's type. -template<typename T> static Type doGetCastType(T* curr) { - if (curr->rtt->type == Type::unreachable) { - // We don't have the RTT type, so just return unreachable. The type in this - // case should not matter in practice, but it may be seen while debugging. - return Type::unreachable; - } - // TODO: make non-nullable when we support that - return Type(curr->rtt->type.getHeapType(), Nullable); -} - -Type RefTest::getCastType() { return doGetCastType(this); } - void RefCast::finalize() { if (ref->type == Type::unreachable || rtt->type == Type::unreachable) { type = Type::unreachable; } else { - type = getCastType(); + // The output of ref.cast may be null if the input is null (in that case the + // null is passed through). + type = Type(rtt->type.getHeapType(), ref->type.getNullability()); } } -Type RefCast::getCastType() { return doGetCastType(this); } - void BrOn::finalize() { if (ref->type == Type::unreachable || (rtt && rtt->type == Type::unreachable)) { @@ -960,8 +946,7 @@ void BrOn::finalize() { if (op == BrOnNull) { // If BrOnNull does not branch, it flows out the existing value as // non-null. - // FIXME: When we support non-nullable types, this should be non-nullable. - type = Type(ref->type.getHeapType(), Nullable); + type = Type(ref->type.getHeapType(), NonNullable); } else { type = ref->type; } @@ -974,8 +959,7 @@ Type BrOn::getCastType() { // BrOnNull does not send a value on the branch. return Type::none; case BrOnCast: - // FIXME: When we support non-nullable types, this should be non-nullable. - return Type(rtt->type.getHeapType(), Nullable); + return Type(rtt->type.getHeapType(), NonNullable); case BrOnFunc: return Type::funcref; case BrOnData: @@ -1007,8 +991,7 @@ void StructNew::finalize() { if (handleUnreachableOperands(this)) { return; } - // TODO: make non-nullable when we support that - type = Type(rtt->type.getHeapType(), Nullable); + type = Type(rtt->type.getHeapType(), NonNullable); } void StructGet::finalize() { @@ -1033,8 +1016,7 @@ void ArrayNew::finalize() { type = Type::unreachable; return; } - // TODO: make non-nullable when we support that - type = Type(rtt->type.getHeapType(), Nullable); + type = Type(rtt->type.getHeapType(), NonNullable); } void ArrayGet::finalize() { @@ -1069,8 +1051,7 @@ void RefAs::finalize() { } switch (op) { case RefAsNonNull: - // FIXME: when we support non-nullable types, switch to NonNullable - type = Type(value->type.getHeapType(), Nullable); + type = Type(value->type.getHeapType(), NonNullable); break; case RefAsFunc: type = Type::funcref; diff --git a/test/gc.wast b/test/gc.wast index c3a814c38..4d3cb866c 100644 --- a/test/gc.wast +++ b/test/gc.wast @@ -15,11 +15,12 @@ (global $global_eqref2 (mut eqref) (i31.new (i32.const 0))) (func $test + (param $local_i31ref i31ref) + (param $local_dataref dataref) + (local $local_i32 i32) (local $local_anyref anyref) (local $local_eqref eqref) - (local $local_i31ref i31ref) - (local $local_dataref dataref) ;; Test types for local.get/set (local.set $local_anyref (local.get $local_anyref)) @@ -71,9 +72,9 @@ ) (func $test-variants - (local $local_i31refnull (ref null i31)) - (local $local_i31refnonnull (ref i31)) - (local $local_datarefnull (ref null data)) - (local $local_datarefnonnull (ref data)) + (param $local_i31refnull (ref null i31)) + (param $local_i31refnonnull (ref i31)) + (param $local_datarefnull (ref null data)) + (param $local_datarefnonnull (ref data)) ) ) diff --git a/test/gc.wast.from-wast b/test/gc.wast.from-wast index f38c7416d..91cd83ec6 100644 --- a/test/gc.wast.from-wast +++ b/test/gc.wast.from-wast @@ -1,8 +1,9 @@ (module - (type $none_=>_none (func)) + (type $i31ref_dataref_=>_none (func (param i31ref dataref))) + (type $ref?|i31|_i31ref_ref?|data|_dataref_=>_none (func (param (ref null i31) i31ref (ref null data) dataref))) (global $global_anyref (mut anyref) (ref.null any)) (global $global_eqref (mut eqref) (ref.null eq)) - (global $global_i31ref (mut (ref null i31)) (i31.new + (global $global_i31ref (mut i31ref) (i31.new (i32.const 0) )) (global $global_anyref2 (mut anyref) (ref.null eq)) @@ -12,12 +13,10 @@ (global $global_eqref2 (mut eqref) (i31.new (i32.const 0) )) - (func $test + (func $test (param $local_i31ref i31ref) (param $local_dataref dataref) (local $local_i32 i32) (local $local_anyref anyref) (local $local_eqref eqref) - (local $local_i31ref (ref null i31)) - (local $local_dataref (ref null data)) (local.set $local_anyref (local.get $local_anyref) ) @@ -149,11 +148,7 @@ ) ) ) - (func $test-variants - (local $local_i31refnull (ref null i31)) - (local $local_i31refnonnull (ref null i31)) - (local $local_datarefnull (ref null data)) - (local $local_datarefnonnull (ref null data)) + (func $test-variants (param $local_i31refnull (ref null i31)) (param $local_i31refnonnull i31ref) (param $local_datarefnull (ref null data)) (param $local_datarefnonnull dataref) (nop) ) ) diff --git a/test/gc.wast.fromBinary b/test/gc.wast.fromBinary index 066928de4..3794a01f1 100644 --- a/test/gc.wast.fromBinary +++ b/test/gc.wast.fromBinary @@ -1,8 +1,9 @@ (module - (type $none_=>_none (func)) + (type $i31ref_dataref_=>_none (func (param i31ref dataref))) + (type $ref?|i31|_i31ref_ref?|data|_dataref_=>_none (func (param (ref null i31) i31ref (ref null data) dataref))) (global $global_anyref (mut anyref) (ref.null any)) (global $global_eqref (mut eqref) (ref.null eq)) - (global $global_i31ref (mut (ref null i31)) (i31.new + (global $global_i31ref (mut i31ref) (i31.new (i32.const 0) )) (global $global_anyref2 (mut anyref) (ref.null eq)) @@ -12,12 +13,10 @@ (global $global_eqref2 (mut eqref) (i31.new (i32.const 0) )) - (func $test + (func $test (param $local_i31ref i31ref) (param $local_dataref dataref) (local $local_i32 i32) (local $local_anyref anyref) (local $local_eqref eqref) - (local $local_i31ref (ref null i31)) - (local $local_dataref (ref null data)) (local.set $local_anyref (local.get $local_anyref) ) @@ -149,11 +148,7 @@ ) ) ) - (func $test-variants - (local $local_i31refnull (ref null i31)) - (local $local_i31refnonnull (ref null i31)) - (local $local_datarefnull (ref null data)) - (local $local_datarefnonnull (ref null data)) + (func $test-variants (param $local_i31refnull (ref null i31)) (param $local_i31refnonnull i31ref) (param $local_datarefnull (ref null data)) (param $local_datarefnonnull dataref) (nop) ) ) diff --git a/test/gc.wast.fromBinary.noDebugInfo b/test/gc.wast.fromBinary.noDebugInfo index 77f520257..a523e58d2 100644 --- a/test/gc.wast.fromBinary.noDebugInfo +++ b/test/gc.wast.fromBinary.noDebugInfo @@ -1,8 +1,9 @@ (module - (type $none_=>_none (func)) + (type $i31ref_dataref_=>_none (func (param i31ref dataref))) + (type $ref?|i31|_i31ref_ref?|data|_dataref_=>_none (func (param (ref null i31) i31ref (ref null data) dataref))) (global $global$0 (mut anyref) (ref.null any)) (global $global$1 (mut eqref) (ref.null eq)) - (global $global$2 (mut (ref null i31)) (i31.new + (global $global$2 (mut i31ref) (i31.new (i32.const 0) )) (global $global$3 (mut anyref) (ref.null eq)) @@ -12,74 +13,72 @@ (global $global$5 (mut eqref) (i31.new (i32.const 0) )) - (func $0 - (local $0 i32) - (local $1 anyref) - (local $2 eqref) - (local $3 (ref null i31)) - (local $4 (ref null data)) - (local.set $1 - (local.get $1) - ) - (local.set $1 + (func $0 (param $0 i31ref) (param $1 dataref) + (local $2 i32) + (local $3 anyref) + (local $4 eqref) + (local.set $3 + (local.get $3) + ) + (local.set $3 (global.get $global$0) ) - (local.set $1 + (local.set $3 (ref.null any) ) - (local.set $2 - (local.get $2) + (local.set $4 + (local.get $4) ) - (local.set $2 + (local.set $4 (global.get $global$1) ) - (local.set $2 + (local.set $4 (ref.null eq) ) - (local.set $3 - (local.get $3) + (local.set $0 + (local.get $0) ) - (local.set $3 + (local.set $0 (global.get $global$2) ) - (local.set $3 + (local.set $0 (i31.new (i32.const 0) ) ) - (local.set $1 - (local.get $2) + (local.set $3 + (local.get $4) ) - (local.set $1 + (local.set $3 (global.get $global$1) ) - (local.set $1 + (local.set $3 (ref.null eq) ) - (local.set $1 - (local.get $3) + (local.set $3 + (local.get $0) ) - (local.set $1 + (local.set $3 (global.get $global$2) ) - (local.set $1 + (local.set $3 (i31.new (i32.const 0) ) ) - (local.set $2 - (local.get $3) + (local.set $4 + (local.get $0) ) - (local.set $2 + (local.set $4 (global.get $global$2) ) - (local.set $2 + (local.set $4 (i31.new (i32.const 0) ) ) (global.set $global$0 - (local.get $1) + (local.get $3) ) (global.set $global$0 (global.get $global$0) @@ -88,7 +87,7 @@ (ref.null any) ) (global.set $global$1 - (local.get $2) + (local.get $4) ) (global.set $global$1 (global.get $global$1) @@ -97,7 +96,7 @@ (ref.null eq) ) (global.set $global$2 - (local.get $3) + (local.get $0) ) (global.set $global$2 (global.get $global$2) @@ -108,7 +107,7 @@ ) ) (global.set $global$0 - (local.get $2) + (local.get $4) ) (global.set $global$0 (global.get $global$1) @@ -117,7 +116,7 @@ (ref.null eq) ) (global.set $global$0 - (local.get $3) + (local.get $0) ) (global.set $global$0 (global.get $global$2) @@ -128,7 +127,7 @@ ) ) (global.set $global$1 - (local.get $3) + (local.get $0) ) (global.set $global$1 (global.get $global$2) @@ -138,22 +137,18 @@ (i32.const 0) ) ) - (local.set $0 + (local.set $2 (i31.get_s - (local.get $3) + (local.get $0) ) ) - (local.set $0 + (local.set $2 (i31.get_u - (local.get $3) + (local.get $0) ) ) ) - (func $1 - (local $0 (ref null i31)) - (local $1 (ref null i31)) - (local $2 (ref null data)) - (local $3 (ref null data)) + (func $1 (param $0 (ref null i31)) (param $1 i31ref) (param $2 (ref null data)) (param $3 dataref) (nop) ) ) diff --git a/test/heap-types.wast b/test/heap-types.wast index 137e847af..e932df82f 100644 --- a/test/heap-types.wast +++ b/test/heap-types.wast @@ -25,7 +25,7 @@ ;; Arrays (type $vector (array (mut f64))) - (type $matrix (array (ref $vector))) + (type $matrix (array (mut (ref null $vector)))) (type $bytes (array (mut i8))) (type $words (array (mut i32))) @@ -108,7 +108,9 @@ ;; values may be subtypes (struct.set $nested-child-struct 0 (ref.null $nested-child-struct) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (struct.new_default_with_rtt $struct.A @@ -158,7 +160,9 @@ (array.set $nested-child-array (ref.null $nested-child-array) (i32.const 3) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (array.len $vector @@ -223,7 +227,7 @@ ) (func $br_on_X (param $x anyref) (local $y anyref) - (local $z (ref any)) + (local $z (ref null any)) (block $null (local.set $z (br_on_null $null (local.get $x)) @@ -238,7 +242,7 @@ ) ) (drop - (block $data (result dataref) + (block $data (result (ref null data)) (local.set $y (br_on_data $data (local.get $x)) ) @@ -246,7 +250,7 @@ ) ) (drop - (block $i31 (result i31ref) + (block $i31 (result (ref null i31)) (local.set $y (br_on_i31 $i31 (local.get $x)) ) diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index 1e2df009d..4fbf5026c 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -1,22 +1,22 @@ (module (type $struct.A (struct (field i32) (field f32) (field $named f64))) - (type $struct.B (struct (field i8) (field (mut i16)) (field (ref null $struct.A)) (field (mut (ref null $struct.A))))) + (type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) (type $grandchild (struct (field i32) (field i64))) - (type $matrix (array (ref null $vector))) (type $vector (array (mut f64))) + (type $matrix (array (mut (ref null $vector)))) (type $anyref_=>_none (func (param anyref))) (type $parent (struct )) (type $child (struct (field i32))) (type $struct.C (struct (field $named-mut (mut f32)))) (type $none_=>_none (func)) - (type $nested-child-struct (struct (field (mut (ref null $child))))) + (type $nested-child-struct (struct (field (mut (ref $child))))) (type $rtt_1_$parent_=>_none (func (param (rtt 1 $parent)))) (type $rtt_$parent_=>_none (func (param (rtt $parent)))) - (type $ref?|$struct.A|_=>_ref?|$struct.B| (func (param (ref null $struct.A)) (result (ref null $struct.B)))) - (type $ref?|$vector|_=>_ref?|$matrix| (func (param (ref null $vector)) (result (ref null $matrix)))) + (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) + (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) (type $words (array (mut i32))) (type $bytes (array (mut i8))) - (type $nested-child-array (array (mut (ref null $child)))) + (type $nested-child-array (array (mut (ref $child)))) (global $rttparent (rtt 0 $parent) (rtt.canon $parent)) (global $rttchild (rtt 1 $child) (rtt.sub $child (global.get $rttparent) @@ -24,7 +24,7 @@ (global $rttgrandchild (rtt 2 $grandchild) (rtt.sub $grandchild (global.get $rttchild) )) - (func $structs (param $x (ref null $struct.A)) (result (ref null $struct.B)) + (func $structs (param $x (ref $struct.A)) (result (ref $struct.B)) (local $tA (ref null $struct.A)) (local $tB (ref null $struct.B)) (local $tc (ref null $struct.C)) @@ -106,7 +106,9 @@ ) (struct.set $nested-child-struct 0 (ref.null $nested-child-struct) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (struct.new_default_with_rtt $struct.A @@ -123,7 +125,7 @@ ) (unreachable) ) - (func $arrays (param $x (ref null $vector)) (result (ref null $matrix)) + (func $arrays (param $x (ref $vector)) (result (ref $matrix)) (local $tv (ref null $vector)) (local $tm (ref null $matrix)) (local $tb (ref null $bytes)) @@ -155,7 +157,9 @@ (array.set $nested-child-array (ref.null $nested-child-array) (i32.const 3) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (array.len $vector @@ -203,7 +207,7 @@ ) ) (drop - (block $out (result (ref null $struct.B)) + (block $out (result (ref $struct.B)) (local.set $temp.A (br_on_cast $out (ref.null $struct.A) diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index e6338dffd..65c04bd32 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -1,22 +1,22 @@ (module (type $struct.A (struct (field i32) (field f32) (field $named f64))) - (type $struct.B (struct (field i8) (field (mut i16)) (field (ref null $struct.A)) (field (mut (ref null $struct.A))))) + (type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) (type $grandchild (struct (field i32) (field i64))) - (type $matrix (array (ref null $vector))) (type $vector (array (mut f64))) + (type $matrix (array (mut (ref null $vector)))) (type $anyref_=>_none (func (param anyref))) (type $parent (struct )) (type $child (struct (field i32))) (type $struct.C (struct (field $named-mut (mut f32)))) (type $none_=>_none (func)) - (type $nested-child-struct (struct (field (mut (ref null $child))))) + (type $nested-child-struct (struct (field (mut (ref $child))))) (type $rtt_1_$parent_=>_none (func (param (rtt 1 $parent)))) (type $rtt_$parent_=>_none (func (param (rtt $parent)))) - (type $ref?|$struct.A|_=>_ref?|$struct.B| (func (param (ref null $struct.A)) (result (ref null $struct.B)))) - (type $ref?|$vector|_=>_ref?|$matrix| (func (param (ref null $vector)) (result (ref null $matrix)))) + (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) + (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) (type $words (array (mut i32))) (type $bytes (array (mut i8))) - (type $nested-child-array (array (mut (ref null $child)))) + (type $nested-child-array (array (mut (ref $child)))) (global $rttparent (rtt 0 $parent) (rtt.canon $parent)) (global $rttchild (rtt 1 $child) (rtt.sub $child (global.get $rttparent) @@ -24,7 +24,7 @@ (global $rttgrandchild (rtt 2 $grandchild) (rtt.sub $grandchild (global.get $rttchild) )) - (func $structs (param $x (ref null $struct.A)) (result (ref null $struct.B)) + (func $structs (param $x (ref $struct.A)) (result (ref $struct.B)) (local $tA (ref null $struct.A)) (local $tB (ref null $struct.B)) (local $tc (ref null $struct.C)) @@ -106,7 +106,9 @@ ) (struct.set $nested-child-struct 0 (ref.null $nested-child-struct) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (struct.new_default_with_rtt $struct.A @@ -123,7 +125,7 @@ ) (unreachable) ) - (func $arrays (param $x (ref null $vector)) (result (ref null $matrix)) + (func $arrays (param $x (ref $vector)) (result (ref $matrix)) (local $tv (ref null $vector)) (local $tm (ref null $matrix)) (local $tb (ref null $bytes)) @@ -155,7 +157,9 @@ (array.set $nested-child-array (ref.null $nested-child-array) (i32.const 3) - (ref.null $grandchild) + (ref.as_non_null + (ref.null $grandchild) + ) ) (drop (array.len $vector @@ -203,7 +207,7 @@ ) ) (drop - (block $label$1 (result (ref null $struct.B)) + (block $label$1 (result (ref $struct.B)) (local.set $temp.A (br_on_cast $label$1 (ref.null $struct.A) diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index 2651ba0d4..2a0156000 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -1,22 +1,22 @@ (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 ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref ${i32_f32_f64})) (field (mut (ref ${i32_f32_f64}))))) (type ${i32_i64} (struct (field i32) (field i64))) - (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64]))) (type $[mut:f64] (array (mut f64))) + (type $[mut:ref?|[mut:f64]|] (array (mut (ref null $[mut:f64])))) (type $anyref_=>_none (func (param anyref))) (type ${} (struct )) (type ${i32} (struct (field i32))) (type ${mut:f32} (struct (field (mut f32)))) (type $none_=>_none (func)) - (type ${mut:ref?|{i32}|} (struct (field (mut (ref null ${i32}))))) + (type ${mut:ref|{i32}|} (struct (field (mut (ref ${i32}))))) (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 $ref|{i32_f32_f64}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}| (func (param (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})))) + (type $ref|[mut:f64]|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])))) (type $[mut:i32] (array (mut i32))) (type $[mut:i8] (array (mut i8))) - (type $[mut:ref?|{i32}|] (array (mut (ref null ${i32})))) + (type $[mut:ref|{i32}|] (array (mut (ref ${i32})))) (global $global$0 (rtt 0 ${}) (rtt.canon ${})) (global $global$1 (rtt 1 ${i32}) (rtt.sub ${i32} (global.get $global$0) @@ -24,12 +24,12 @@ (global $global$2 (rtt 2 ${i32_i64}) (rtt.sub ${i32_i64} (global.get $global$1) )) - (func $0 (param $0 (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})) + (func $0 (param $0 (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) (local $1 (ref null ${i32_f32_f64})) - (local $2 (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})) + (local $2 (ref null ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) (local $3 (ref null ${mut:f32})) (local $4 (ref null $[mut:f64])) - (local $5 (ref null $[ref?|[mut:f64]|])) + (local $5 (ref null $[mut:ref?|[mut:f64]|])) (drop (local.get $0) ) @@ -59,12 +59,12 @@ ) ) (drop - (struct.get_u ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0 + (struct.get_u ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 (local.get $2) ) ) (drop - (struct.get_s ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0 + (struct.get_s ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 (local.get $2) ) ) @@ -104,9 +104,11 @@ (ref.null ${mut:f32}) (f32.const 100) ) - (struct.set ${mut:ref?|{i32}|} 0 - (ref.null ${mut:ref?|{i32}|}) - (ref.null ${i32_i64}) + (struct.set ${mut:ref|{i32}|} 0 + (ref.null ${mut:ref|{i32}|}) + (ref.as_non_null + (ref.null ${i32_i64}) + ) ) (drop (struct.new_default_with_rtt ${i32_f32_f64} @@ -123,9 +125,9 @@ ) (unreachable) ) - (func $1 (param $0 (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|])) + (func $1 (param $0 (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])) (local $1 (ref null $[mut:f64])) - (local $2 (ref null $[ref?|[mut:f64]|])) + (local $2 (ref null $[mut:ref?|[mut:f64]|])) (local $3 (ref null $[mut:i8])) (local $4 (ref null $[mut:i32])) (drop @@ -136,9 +138,9 @@ ) ) (drop - (array.new_default_with_rtt $[ref?|[mut:f64]|] + (array.new_default_with_rtt $[mut:ref?|[mut:f64]|] (i32.const 10) - (rtt.canon $[ref?|[mut:f64]|]) + (rtt.canon $[mut:ref?|[mut:f64]|]) ) ) (drop @@ -152,10 +154,12 @@ (i32.const 2) (f64.const 2.18281828) ) - (array.set $[mut:ref?|{i32}|] - (ref.null $[mut:ref?|{i32}|]) + (array.set $[mut:ref|{i32}|] + (ref.null $[mut:ref|{i32}|]) (i32.const 3) - (ref.null ${i32_i64}) + (ref.as_non_null + (ref.null ${i32_i64}) + ) ) (drop (array.len $[mut:f64] @@ -193,21 +197,21 @@ (drop (ref.test (ref.null ${i32_f32_f64}) - (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}) + (rtt.canon ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}) ) ) (drop (ref.cast (ref.null ${i32_f32_f64}) - (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}) + (rtt.canon ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}) ) ) (drop - (block $label$1 (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})) + (block $label$1 (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) (local.set $0 (br_on_cast $label$1 (ref.null ${i32_f32_f64}) - (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}) + (rtt.canon ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}) ) ) (block $label$2 diff --git a/test/let.wasm.fromBinary b/test/let.wasm.fromBinary index d3f1760ce..de51c1045 100644 --- a/test/let.wasm.fromBinary +++ b/test/let.wasm.fromBinary @@ -20,7 +20,9 @@ ) (block (drop - (local.get $2) + (ref.as_non_null + (local.get $2) + ) ) (drop (local.get $0) @@ -35,10 +37,14 @@ ) (block (drop - (local.get $2) + (ref.as_non_null + (local.get $2) + ) ) (drop - (local.get $3) + (ref.as_non_null + (local.get $3) + ) ) (drop (local.get $0) @@ -57,7 +63,9 @@ ) (block (drop - (local.get $4) + (ref.as_non_null + (local.get $4) + ) ) (drop (local.get $0) diff --git a/test/lit/forward-declared-types.wast b/test/lit/forward-declared-types.wast index a335f0d09..dc1407049 100644 --- a/test/lit/forward-declared-types.wast +++ b/test/lit/forward-declared-types.wast @@ -4,7 +4,7 @@ ;; CHECK: (type $func (func)) ;; CHECK: (type $none_=>_ref?|$struct| (func (result (ref null $struct)))) -;; CHECK: (type $struct (struct (field (ref null $array)) (field (ref null $func)))) +;; CHECK: (type $struct (struct (field (ref $array)) (field (ref null $func)))) ;; CHECK: (type $array (array (rtt 2 $func))) (module diff --git a/test/lit/passes/merge-blocks.wast b/test/lit/passes/merge-blocks.wast index 0a1defab5..10d6b1d71 100644 --- a/test/lit/passes/merge-blocks.wast +++ b/test/lit/passes/merge-blocks.wast @@ -4,7 +4,7 @@ (module (type $anyref_=>_none (func (param anyref))) - ;; CHECK: (func $br_on_to_drop + ;; CHECK: (func $br_on_to_drop ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $label$1 (result (ref null i31)) @@ -14,6 +14,9 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) (func $br_on_to_drop (nop) ;; ensure a block at the function level (drop diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt index 37b3f32fa..0f90a6ef7 100644 --- a/test/passes/Oz_fuzz-exec_all-features.txt +++ b/test/passes/Oz_fuzz-exec_all-features.txt @@ -47,8 +47,8 @@ (export "rtts" (func $2)) (export "br_on_cast" (func $3)) (export "cast-null-anyref-to-gc" (func $4)) - (export "br_on_data" (func $5)) - (export "$rtt-and-cast-on-func" (func $7)) + (export "br_on_data" (func $6)) + (export "$rtt-and-cast-on-func" (func $8)) (func $0 (; has Stack IR ;) (local $0 (ref null $struct)) (call $log @@ -182,9 +182,9 @@ (i32.const 0) ) ) - (func $5 (; has Stack IR ;) (param $0 anyref) + (func $6 (; has Stack IR ;) (param $0 anyref) (drop - (block $data (result (ref null data)) + (block $data (result dataref) (drop (br_on_data $data (local.get $0) @@ -193,7 +193,9 @@ (call $log (i32.const 1) ) - (ref.null data) + (struct.new_default_with_rtt $struct + (rtt.canon $struct) + ) ) ) ) @@ -202,7 +204,7 @@ (i32.const 1337) ) ) - (func $7 (; has Stack IR ;) + (func $8 (; has Stack IR ;) (call $log (i32.const 0) ) diff --git a/test/passes/Oz_fuzz-exec_all-features.wast b/test/passes/Oz_fuzz-exec_all-features.wast index f6bb23f69..34c9a224a 100644 --- a/test/passes/Oz_fuzz-exec_all-features.wast +++ b/test/passes/Oz_fuzz-exec_all-features.wast @@ -189,6 +189,11 @@ ) ) ) + (func $get_data (result dataref) + (struct.new_default_with_rtt $struct + (rtt.canon $struct) + ) + ) (func "br_on_data" (param $x anyref) (local $y anyref) (drop @@ -197,7 +202,7 @@ (br_on_data $data (local.get $x)) ) (call $log (i32.const 1)) - (ref.null data) + (call $get_data) ) ) ) diff --git a/test/passes/inlining_all-features.txt b/test/passes/inlining_all-features.txt index e4a563dec..8ecf9fa8e 100644 --- a/test/passes/inlining_all-features.txt +++ b/test/passes/inlining_all-features.txt @@ -110,3 +110,18 @@ ) ) ) +(module + (type $none_=>_ref|func| (func (result (ref func)))) + (elem declare func $1) + (func $1 (result (ref func)) + (local $0 funcref) + (block $__inlined_func$0 (result (ref func)) + (local.set $0 + (ref.func $1) + ) + (ref.as_non_null + (local.get $0) + ) + ) + ) +) diff --git a/test/passes/inlining_all-features.wast b/test/passes/inlining_all-features.wast index 4b20d4240..d11353aa4 100644 --- a/test/passes/inlining_all-features.wast +++ b/test/passes/inlining_all-features.wast @@ -66,7 +66,6 @@ ) ;; for now, do not inline a try-delegate (module - (type $none_=>_none (func)) (func $0 (try $label$3 (do) @@ -79,7 +78,6 @@ ) ;; properly support inlining into a function with a try-delegate (module - (type $none_=>_none (func)) (func $0 (result i32) (i32.const 42) ) @@ -91,3 +89,15 @@ (call $0) ) ) +;; handle non-nullable parameter types (which turn into local types after +;; inlining) +(module + (func $0 (param $non-null (ref func)) (result (ref func)) + (local.get $non-null) + ) + (func $1 (result (ref func)) + (call $0 + (ref.func $1) + ) + ) +) diff --git a/test/passes/simplify-globals_all-features_fuzz-exec.txt b/test/passes/simplify-globals_all-features_fuzz-exec.txt index 141fe9f01..464ef0912 100644 --- a/test/passes/simplify-globals_all-features_fuzz-exec.txt +++ b/test/passes/simplify-globals_all-features_fuzz-exec.txt @@ -1,12 +1,12 @@ [fuzz-exec] calling export [fuzz-exec] note result: export => funcref(0) (module - (type $f32_ref?|i31|_i64_f64_funcref_=>_none (func (param f32 (ref null i31) i64 f64 funcref))) + (type $f32_i31ref_i64_f64_funcref_=>_none (func (param f32 i31ref i64 f64 funcref))) (type $none_=>_funcref (func (result funcref))) (elem declare func $0) (global $global$0 (mut funcref) (ref.null func)) (export "export" (func $1)) - (func $0 (param $0 f32) (param $1 (ref null i31)) (param $2 i64) (param $3 f64) (param $4 funcref) + (func $0 (param $0 f32) (param $1 i31ref) (param $2 i64) (param $3 f64) (param $4 funcref) (nop) ) (func $1 (result funcref) diff --git a/test/passes/simplify-locals_all-features.wast b/test/passes/simplify-locals_all-features.wast index 2c54cdec3..390f879ae 100644 --- a/test/passes/simplify-locals_all-features.wast +++ b/test/passes/simplify-locals_all-features.wast @@ -1764,16 +1764,16 @@ ;; it is no longer equivalent ;; (see https://github.com/WebAssembly/binaryen/issues/3266) (module - (func "test" (param $0 eqref) (param $1 i31ref) (result i32) + (func "test" (param $0 eqref) (param $1 (ref null i31)) (result i32) (local $2 eqref) - (local $3 i31ref) + (local $3 (ref null i31)) (local.set $2 (local.get $0) ;; $0 and $2 are equivalent ) (local.set $0 ;; set $0 to something with another type (local.get $3) ) - ;; compares a null eqref and a zero i31ref - should be false + ;; compares a null eqref and a zero (ref null i31) - should be false (ref.eq (local.get $2) (local.get $1) diff --git a/test/passes/vacuum_all-features.txt b/test/passes/vacuum_all-features.txt index 740c7a2eb..c7c22572a 100644 --- a/test/passes/vacuum_all-features.txt +++ b/test/passes/vacuum_all-features.txt @@ -488,3 +488,9 @@ (unreachable) ) ) +(module + (type $none_=>_none (func)) + (func $foo + (nop) + ) +) diff --git a/test/passes/vacuum_all-features.wast b/test/passes/vacuum_all-features.wast index 94f952f5d..46678bd8e 100644 --- a/test/passes/vacuum_all-features.wast +++ b/test/passes/vacuum_all-features.wast @@ -869,3 +869,19 @@ ) ) ) +(module + (type $A (struct (field (mut i32)))) + (func $foo + (drop + (block (result dataref) + ;; this dropped item can be vacuumed out in principle, but it is a non- + ;; nullable reference type and we don't have a type to put in its place, so + ;; don't try to replace it. (later operations will remove all the body of + ;; this function; this test verifies we don't crash along the way) + (struct.new_default_with_rtt $A + (rtt.canon $A) + ) + ) + ) + ) +) diff --git a/test/spec/ref_cast.wast b/test/spec/ref_cast.wast index aa51ef23f..8712e5954 100644 --- a/test/spec/ref_cast.wast +++ b/test/spec/ref_cast.wast @@ -15,14 +15,14 @@ (global $t3 (rtt $t3) (rtt.sub $t3 (global.get $t0))) (global $t4 (rtt $t3) (rtt.sub $t3 (rtt.sub $t0 (global.get $t0)))) - (global $tab.0 (mut dataref) (ref.null data)) - (global $tab.1 (mut dataref) (ref.null data)) - (global $tab.2 (mut dataref) (ref.null data)) - (global $tab.3 (mut dataref) (ref.null data)) - (global $tab.4 (mut dataref) (ref.null data)) - (global $tab.10 (mut dataref) (ref.null data)) - (global $tab.11 (mut dataref) (ref.null data)) - (global $tab.12 (mut dataref) (ref.null data)) + (global $tab.0 (mut (ref null data)) (ref.null data)) + (global $tab.1 (mut (ref null data)) (ref.null data)) + (global $tab.2 (mut (ref null data)) (ref.null data)) + (global $tab.3 (mut (ref null data)) (ref.null data)) + (global $tab.4 (mut (ref null data)) (ref.null data)) + (global $tab.10 (mut (ref null data)) (ref.null data)) + (global $tab.11 (mut (ref null data)) (ref.null data)) + (global $tab.12 (mut (ref null data)) (ref.null data)) (func $init (global.set $tab.0 (struct.new_default_with_rtt $t0 (global.get $t0))) diff --git a/test/subtypes.wast b/test/subtypes.wast index 06f85a273..bb67f9d72 100644 --- a/test/subtypes.wast +++ b/test/subtypes.wast @@ -30,7 +30,7 @@ (func $foo (param $no-null (ref $vector-i32)) (param $yes-null (ref null $vector-i32)) ;; ok to set a non-nullable reference to a nullable target - (local.set $no-null (local.get $yes-null)) + (local.set $yes-null (local.get $no-null)) ) (func $bar (param $v-i31 (ref $vector-i31)) diff --git a/test/subtypes.wast.from-wast b/test/subtypes.wast.from-wast index 3e811109a..a79ea12f2 100644 --- a/test/subtypes.wast.from-wast +++ b/test/subtypes.wast.from-wast @@ -1,38 +1,38 @@ (module - (type $struct-rec-two (struct (field (ref null $struct-rec-two)) (field (ref null $struct-rec-two)))) - (type $struct-i31 (struct (field (ref null i31)))) - (type $struct-rec-one (struct (field (ref null $struct-rec-one)))) + (type $struct-rec-two (struct (field (ref $struct-rec-two)) (field (ref $struct-rec-two)))) + (type $struct-i31 (struct (field i31ref))) + (type $struct-rec-one (struct (field (ref $struct-rec-one)))) (type $vector-i32 (array i32)) - (type $ref?|$struct-i31|_ref?|$struct-any|_=>_none (func (param (ref null $struct-i31) (ref null $struct-any)))) - (type $ref?|$struct-i31|_ref?|$struct-i31_any|_=>_none (func (param (ref null $struct-i31) (ref null $struct-i31_any)))) - (type $ref?|$struct-rec-one|_ref?|$struct-rec-two|_=>_none (func (param (ref null $struct-rec-one) (ref null $struct-rec-two)))) - (type $ref?|$vector-i32|_ref?|$vector-i32|_=>_none (func (param (ref null $vector-i32) (ref null $vector-i32)))) - (type $ref?|$vector-i31|_ref?|$vector-any|_=>_none (func (param (ref null $vector-i31) (ref null $vector-any)))) - (type $struct-any (struct (field anyref))) - (type $struct-i31_any (struct (field (ref null i31)) (field anyref))) - (type $vector-any (array anyref)) - (type $vector-i31 (array (ref null i31))) - (func $foo (param $no-null (ref null $vector-i32)) (param $yes-null (ref null $vector-i32)) - (local.set $no-null - (local.get $yes-null) + (type $ref|$struct-i31|_ref|$struct-i31_any|_=>_none (func (param (ref $struct-i31) (ref $struct-i31_any)))) + (type $ref|$struct-i31|_ref|$struct-any|_=>_none (func (param (ref $struct-i31) (ref $struct-any)))) + (type $ref|$struct-rec-one|_ref|$struct-rec-two|_=>_none (func (param (ref $struct-rec-one) (ref $struct-rec-two)))) + (type $ref|$vector-i32|_ref?|$vector-i32|_=>_none (func (param (ref $vector-i32) (ref null $vector-i32)))) + (type $ref|$vector-i31|_ref|$vector-any|_=>_none (func (param (ref $vector-i31) (ref $vector-any)))) + (type $struct-i31_any (struct (field i31ref) (field (ref any)))) + (type $struct-any (struct (field (ref any)))) + (type $vector-i31 (array i31ref)) + (type $vector-any (array (ref any))) + (func $foo (param $no-null (ref $vector-i32)) (param $yes-null (ref null $vector-i32)) + (local.set $yes-null + (local.get $no-null) ) ) - (func $bar (param $v-i31 (ref null $vector-i31)) (param $v-any (ref null $vector-any)) + (func $bar (param $v-i31 (ref $vector-i31)) (param $v-any (ref $vector-any)) (local.set $v-any (local.get $v-i31) ) ) - (func $baz (param $s-i31 (ref null $struct-i31)) (param $s-any (ref null $struct-any)) + (func $baz (param $s-i31 (ref $struct-i31)) (param $s-any (ref $struct-any)) (local.set $s-any (local.get $s-i31) ) ) - (func $boo (param $s-i31 (ref null $struct-i31)) (param $s-i31_any (ref null $struct-i31_any)) + (func $boo (param $s-i31 (ref $struct-i31)) (param $s-i31_any (ref $struct-i31_any)) (local.set $s-i31 (local.get $s-i31_any) ) ) - (func $coinductive (param $rec-one (ref null $struct-rec-one)) (param $rec-two (ref null $struct-rec-two)) + (func $coinductive (param $rec-one (ref $struct-rec-one)) (param $rec-two (ref $struct-rec-two)) (local.set $rec-one (local.get $rec-two) ) diff --git a/test/subtypes.wast.fromBinary b/test/subtypes.wast.fromBinary index c2fcb0e3d..930e0044b 100644 --- a/test/subtypes.wast.fromBinary +++ b/test/subtypes.wast.fromBinary @@ -1,38 +1,38 @@ (module - (type $struct-rec-two (struct (field (ref null $struct-rec-two)) (field (ref null $struct-rec-two)))) - (type $struct-i31 (struct (field (ref null i31)))) - (type $struct-rec-one (struct (field (ref null $struct-rec-one)))) + (type $struct-rec-two (struct (field (ref $struct-rec-two)) (field (ref $struct-rec-two)))) + (type $struct-i31 (struct (field i31ref))) + (type $struct-rec-one (struct (field (ref $struct-rec-one)))) (type $vector-i32 (array i32)) - (type $ref?|$struct-i31|_ref?|$struct-any|_=>_none (func (param (ref null $struct-i31) (ref null $struct-any)))) - (type $ref?|$struct-i31|_ref?|$struct-i31_any|_=>_none (func (param (ref null $struct-i31) (ref null $struct-i31_any)))) - (type $ref?|$struct-rec-one|_ref?|$struct-rec-two|_=>_none (func (param (ref null $struct-rec-one) (ref null $struct-rec-two)))) - (type $ref?|$vector-i32|_ref?|$vector-i32|_=>_none (func (param (ref null $vector-i32) (ref null $vector-i32)))) - (type $ref?|$vector-i31|_ref?|$vector-any|_=>_none (func (param (ref null $vector-i31) (ref null $vector-any)))) - (type $struct-any (struct (field anyref))) - (type $struct-i31_any (struct (field (ref null i31)) (field anyref))) - (type $vector-any (array anyref)) - (type $vector-i31 (array (ref null i31))) - (func $foo (param $no-null (ref null $vector-i32)) (param $yes-null (ref null $vector-i32)) - (local.set $no-null - (local.get $yes-null) + (type $ref|$struct-i31|_ref|$struct-i31_any|_=>_none (func (param (ref $struct-i31) (ref $struct-i31_any)))) + (type $ref|$struct-i31|_ref|$struct-any|_=>_none (func (param (ref $struct-i31) (ref $struct-any)))) + (type $ref|$struct-rec-one|_ref|$struct-rec-two|_=>_none (func (param (ref $struct-rec-one) (ref $struct-rec-two)))) + (type $ref|$vector-i32|_ref?|$vector-i32|_=>_none (func (param (ref $vector-i32) (ref null $vector-i32)))) + (type $ref|$vector-i31|_ref|$vector-any|_=>_none (func (param (ref $vector-i31) (ref $vector-any)))) + (type $struct-i31_any (struct (field i31ref) (field (ref any)))) + (type $struct-any (struct (field (ref any)))) + (type $vector-i31 (array i31ref)) + (type $vector-any (array (ref any))) + (func $foo (param $no-null (ref $vector-i32)) (param $yes-null (ref null $vector-i32)) + (local.set $yes-null + (local.get $no-null) ) ) - (func $bar (param $v-i31 (ref null $vector-i31)) (param $v-any (ref null $vector-any)) + (func $bar (param $v-i31 (ref $vector-i31)) (param $v-any (ref $vector-any)) (local.set $v-any (local.get $v-i31) ) ) - (func $baz (param $s-i31 (ref null $struct-i31)) (param $s-any (ref null $struct-any)) + (func $baz (param $s-i31 (ref $struct-i31)) (param $s-any (ref $struct-any)) (local.set $s-any (local.get $s-i31) ) ) - (func $boo (param $s-i31 (ref null $struct-i31)) (param $s-i31_any (ref null $struct-i31_any)) + (func $boo (param $s-i31 (ref $struct-i31)) (param $s-i31_any (ref $struct-i31_any)) (local.set $s-i31 (local.get $s-i31_any) ) ) - (func $coinductive (param $rec-one (ref null $struct-rec-one)) (param $rec-two (ref null $struct-rec-two)) + (func $coinductive (param $rec-one (ref $struct-rec-one)) (param $rec-two (ref $struct-rec-two)) (local.set $rec-one (local.get $rec-two) ) diff --git a/test/subtypes.wast.fromBinary.noDebugInfo b/test/subtypes.wast.fromBinary.noDebugInfo index a108cf151..f91ee1589 100644 --- a/test/subtypes.wast.fromBinary.noDebugInfo +++ b/test/subtypes.wast.fromBinary.noDebugInfo @@ -1,38 +1,38 @@ (module - (type ${ref?|...0|_ref?|...0|} (struct (field (ref null ${ref?|...0|_ref?|...0|})) (field (ref null ${ref?|...0|_ref?|...0|})))) - (type ${ref?|i31|} (struct (field (ref null i31)))) - (type ${ref?|...0|} (struct (field (ref null ${ref?|...0|})))) + (type ${ref|...0|_ref|...0|} (struct (field (ref ${ref|...0|_ref|...0|})) (field (ref ${ref|...0|_ref|...0|})))) + (type ${i31ref} (struct (field i31ref))) + (type ${ref|...0|} (struct (field (ref ${ref|...0|})))) (type $[i32] (array i32)) - (type $ref?|{ref?|i31|}|_ref?|{anyref}|_=>_none (func (param (ref null ${ref?|i31|}) (ref null ${anyref})))) - (type $ref?|{ref?|i31|}|_ref?|{ref?|i31|_anyref}|_=>_none (func (param (ref null ${ref?|i31|}) (ref null ${ref?|i31|_anyref})))) - (type $ref?|{ref?|...0|}|_ref?|{ref?|...0|_ref?|...0|}|_=>_none (func (param (ref null ${ref?|...0|}) (ref null ${ref?|...0|_ref?|...0|})))) - (type $ref?|[i32]|_ref?|[i32]|_=>_none (func (param (ref null $[i32]) (ref null $[i32])))) - (type $ref?|[ref?|i31|]|_ref?|[anyref]|_=>_none (func (param (ref null $[ref?|i31|]) (ref null $[anyref])))) - (type ${anyref} (struct (field anyref))) - (type ${ref?|i31|_anyref} (struct (field (ref null i31)) (field anyref))) - (type $[anyref] (array anyref)) - (type $[ref?|i31|] (array (ref null i31))) - (func $0 (param $0 (ref null $[i32])) (param $1 (ref null $[i32])) - (local.set $0 - (local.get $1) + (type $ref|{i31ref}|_ref|{i31ref_ref|any|}|_=>_none (func (param (ref ${i31ref}) (ref ${i31ref_ref|any|})))) + (type $ref|{i31ref}|_ref|{ref|any|}|_=>_none (func (param (ref ${i31ref}) (ref ${ref|any|})))) + (type $ref|{ref|...0|}|_ref|{ref|...0|_ref|...0|}|_=>_none (func (param (ref ${ref|...0|}) (ref ${ref|...0|_ref|...0|})))) + (type $ref|[i32]|_ref?|[i32]|_=>_none (func (param (ref $[i32]) (ref null $[i32])))) + (type $ref|[i31ref]|_ref|[ref|any|]|_=>_none (func (param (ref $[i31ref]) (ref $[ref|any|])))) + (type ${i31ref_ref|any|} (struct (field i31ref) (field (ref any)))) + (type ${ref|any|} (struct (field (ref any)))) + (type $[i31ref] (array i31ref)) + (type $[ref|any|] (array (ref any))) + (func $0 (param $0 (ref $[i32])) (param $1 (ref null $[i32])) + (local.set $1 + (local.get $0) ) ) - (func $1 (param $0 (ref null $[ref?|i31|])) (param $1 (ref null $[anyref])) + (func $1 (param $0 (ref $[i31ref])) (param $1 (ref $[ref|any|])) (local.set $1 (local.get $0) ) ) - (func $2 (param $0 (ref null ${ref?|i31|})) (param $1 (ref null ${anyref})) + (func $2 (param $0 (ref ${i31ref})) (param $1 (ref ${ref|any|})) (local.set $1 (local.get $0) ) ) - (func $3 (param $0 (ref null ${ref?|i31|})) (param $1 (ref null ${ref?|i31|_anyref})) + (func $3 (param $0 (ref ${i31ref})) (param $1 (ref ${i31ref_ref|any|})) (local.set $0 (local.get $1) ) ) - (func $4 (param $0 (ref null ${ref?|...0|})) (param $1 (ref null ${ref?|...0|_ref?|...0|})) + (func $4 (param $0 (ref ${ref|...0|})) (param $1 (ref ${ref|...0|_ref|...0|})) (local.set $0 (local.get $1) ) diff --git a/test/typed-function-references.wast.from-wast b/test/typed-function-references.wast.from-wast index aa7d23477..f1a36cd48 100644 --- a/test/typed-function-references.wast.from-wast +++ b/test/typed-function-references.wast.from-wast @@ -1,9 +1,10 @@ (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 $=>eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) + (type $ref|$i32-i32|_=>_i32 (func (param (ref $i32-i32)) (result i32))) + (type $ref?|$i32-i32|_=>_i32 (func (param (ref null $i32-i32)) (result i32))) (type $=>anyref (func (result anyref))) (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) (type $mixed_results (func (result anyref f32 anyref f32))) @@ -25,7 +26,7 @@ (ref.func $call-ref-more) ) ) - (func $call_from-param (param $f (ref null $i32-i32)) (result i32) + (func $call_from-param (param $f (ref $i32-i32)) (result i32) (call_ref (i32.const 42) (local.get $f) diff --git a/test/typed-function-references.wast.fromBinary b/test/typed-function-references.wast.fromBinary index 798c02512..985c50edf 100644 --- a/test/typed-function-references.wast.fromBinary +++ b/test/typed-function-references.wast.fromBinary @@ -1,10 +1,11 @@ (module (type $none_=>_none (func)) - (type $mixed_results (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 $mixed_results (func (result anyref f32 anyref f32))) (type $=>eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) + (type $ref|$i32-i32|_=>_i32 (func (param (ref $i32-i32)) (result i32))) + (type $ref?|$i32-i32|_=>_i32 (func (param (ref null $i32-i32)) (result i32))) (type $=>anyref (func (result anyref))) (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) (type $f64_=>_ref_null<_->_eqref> (func (param f64) (result (ref null $=>eqref)))) @@ -25,7 +26,7 @@ (ref.func $call-ref-more) ) ) - (func $call_from-param (param $f (ref null $i32-i32)) (result i32) + (func $call_from-param (param $f (ref $i32-i32)) (result i32) (call_ref (i32.const 42) (local.get $f) diff --git a/test/typed-function-references.wast.fromBinary.noDebugInfo b/test/typed-function-references.wast.fromBinary.noDebugInfo index 01d474e45..f8f3f476a 100644 --- a/test/typed-function-references.wast.fromBinary.noDebugInfo +++ b/test/typed-function-references.wast.fromBinary.noDebugInfo @@ -1,10 +1,11 @@ (module (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_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32))) (type $none_=>_eqref (func (result eqref))) (type $none_=>_i32 (func (result i32))) + (type $ref|i32_->_i32|_=>_i32 (func (param (ref $i32_=>_i32)) (result i32))) + (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) (type $none_=>_anyref (func (result anyref))) (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)))) @@ -25,7 +26,7 @@ (ref.func $2) ) ) - (func $3 (param $0 (ref null $i32_=>_i32)) (result i32) + (func $3 (param $0 (ref $i32_=>_i32)) (result i32) (call_ref (i32.const 42) (local.get $0) |