diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h index d0b2ef4dc92..e079e0c8140 100644 --- a/src/ir/child-typer.h +++ b/src/ir/child-typer.h @@ -103,18 +103,6 @@ template struct ChildTyper : OverriddenVisitor { self().noteAnyTupleType(childp, arity); } - // Used only for string.new_lossy_utf8_array to work around a missing type - // annotation in the stringref spec. - void noteAnyI8ArrayReferenceType(Expression** childp) { - self().noteAnyI8ArrayReferenceType(childp); - } - - // Used only for string.new_wtf16_array to work around a missing type - // annotation in the stringref spec. - void noteAnyI16ArrayReferenceType(Expression** childp) { - self().noteAnyI16ArrayReferenceType(childp); - } - Type getLabelType(Name label) { return self().getLabelType(label); } bool skipUnreachable() { return false; } @@ -1180,16 +1168,18 @@ template struct ChildTyper : OverriddenVisitor { void visitStringNew(StringNew* curr) { switch (curr->op) { - case StringNewLossyUTF8Array: - noteAnyI8ArrayReferenceType(&curr->ref); + case StringNewLossyUTF8Array: { + note(&curr->ref, Type(HeapTypes::getMutI8Array(), Nullable)); note(&curr->start, Type::i32); note(&curr->end, Type::i32); return; - case StringNewWTF16Array: - noteAnyI16ArrayReferenceType(&curr->ref); + } + case StringNewWTF16Array: { + note(&curr->ref, Type(HeapTypes::getMutI16Array(), Nullable)); note(&curr->start, Type::i32); note(&curr->end, Type::i32); return; + } case StringNewFromCodePoint: note(&curr->ref, Type::i32); return; @@ -1203,16 +1193,18 @@ template struct ChildTyper : OverriddenVisitor { note(&curr->ref, Type(HeapType::string, Nullable)); } - void visitStringEncode(StringEncode* curr, - std::optional ht = std::nullopt) { - if (!ht) { - if (self().skipUnreachable() && !curr->array->type.isRef()) { - return; + void visitStringEncode(StringEncode* curr) { + note(&curr->str, Type(HeapType::string, Nullable)); + switch (curr->op) { + case StringEncodeLossyUTF8Array: { + note(&curr->array, Type(HeapTypes::getMutI8Array(), Nullable)); + break; + } + case StringEncodeWTF16Array: { + note(&curr->array, Type(HeapTypes::getMutI16Array(), Nullable)); + break; } - ht = curr->array->type.getHeapType(); } - note(&curr->str, Type(HeapType::string, Nullable)); - note(&curr->array, Type(*ht, Nullable)); note(&curr->start, Type::i32); } diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 63d71d7ff48..b5179f5afa0 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -217,19 +217,19 @@ class PrecomputingExpressionRunner return Flow(NONCONSTANT_FLOW); } - // string.encode_wtf16_array is effectively an Array read operation, so - // just like ArrayGet above we must check for immutability. + // string.new_wtf16_array is effectively an Array read operation, so + // we cannot optimize mutable arrays. Unfortunately, it is only valid with + // mutable arrays, so we cannot generally precompute it. As a special + // exception, we can precompute if the child is an array allocation because + // then we know the allocation will not escape anywhere else. auto refType = curr->ref->type; - if (refType.isRef()) { - auto heapType = refType.getHeapType(); - if (heapType.isArray()) { - if (heapType.getArray().element.mutable_ == Immutable) { - return Super::visitStringNew(curr); - } - } + if (refType.isRef() && + (curr->ref->is() || curr->ref->is() || + curr->ref->is())) { + return Super::visitStringNew(curr); } - // Otherwise, this is mutable or unreachable or otherwise uninteresting. + // TODO: Handle more general cases as well. return Flow(NONCONSTANT_FLOW); } diff --git a/src/passes/StringLowering.cpp b/src/passes/StringLowering.cpp index 5ee6c40cda8..b19ccbc9d6e 100644 --- a/src/passes/StringLowering.cpp +++ b/src/passes/StringLowering.cpp @@ -37,13 +37,13 @@ #include "ir/module-utils.h" #include "ir/names.h" -#include "ir/subtype-exprs.h" #include "ir/type-updating.h" #include "ir/utils.h" #include "pass.h" #include "passes/string-utils.h" #include "support/string.h" #include "wasm-builder.h" +#include "wasm-type.h" #include "wasm.h" namespace wasm { @@ -283,7 +283,7 @@ struct StringLowering : public StringGathering { } // Common types used in imports. - Type nullArray16 = Type(Array(Field(Field::i16, Mutable)), Nullable); + Type nullArray16 = Type(HeapTypes::getMutI16Array(), Nullable); Type nullExt = Type(HeapType::ext, Nullable); Type nnExt = Type(HeapType::ext, NonNullable); @@ -337,22 +337,6 @@ struct StringLowering : public StringGathering { // Strings turn into externref. updates[HeapType::string] = HeapType::ext; - // The module may have its own array16 type inside a big rec group, but - // imported strings expects that type in its own rec group as part of the - // ABI. Fix that up here. (This is valid to do as this type has no sub- or - // super-types anyhow; it is "plain old data" for communicating with the - // outside.) - auto allTypes = ModuleUtils::collectHeapTypes(*module); - auto array16 = nullArray16.getHeapType(); - auto array16Element = array16.getArray().element; - for (auto type : allTypes) { - // Match an array type with no super and that is closed. - if (type.isArray() && !type.getDeclaredSuperType() && !type.isOpen() && - type.getArray().element == array16Element) { - updates[type] = array16; - } - } - TypeMapper(*module, updates).map(); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index f48eacb2d70..c1235163050 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -3677,7 +3677,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) { } Expression* TranslateToFuzzReader::makeStringNewArray() { - auto* array = makeTrappingRefUse(getArrayTypeForString()); + auto* array = makeTrappingRefUse(HeapTypes::getMutI16Array()); auto* start = make(Type::i32); auto* end = make(Type::i32); return builder.makeStringNew(StringNewWTF16Array, array, start, end); @@ -5161,7 +5161,7 @@ Expression* TranslateToFuzzReader::makeStringEncode(Type type) { assert(type == Type::i32); auto* ref = makeTrappingRefUse(HeapType::string); - auto* array = makeTrappingRefUse(getArrayTypeForString()); + auto* array = makeTrappingRefUse(HeapTypes::getMutI16Array()); auto* start = make(Type::i32); // Only rarely emit without a bounds check, which might trap. See related @@ -5625,12 +5625,6 @@ Type TranslateToFuzzReader::getSuperType(Type type) { return superType; } -HeapType TranslateToFuzzReader::getArrayTypeForString() { - // Emit an array that can be used with JS-style strings, containing 16-bit - // elements. For now, this must be a mutable type as that is all V8 accepts. - return HeapType(Array(Field(Field::PackedType::i16, Mutable))); -} - Name TranslateToFuzzReader::getTargetName(Expression* target) { if (auto* block = target->dynCast()) { return block->name; diff --git a/src/wasm-type.h b/src/wasm-type.h index cce6cb16565..6a0b9709f54 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -591,6 +591,11 @@ constexpr HeapType nofunc = HeapType::nofunc; constexpr HeapType nocont = HeapType::nocont; constexpr HeapType noexn = HeapType::noexn; +// Certain heap types are used by standard operations. Provide central accessors +// for them to avoid having to build them everywhere they are used. +HeapType getMutI8Array(); +HeapType getMutI16Array(); + } // namespace HeapTypes // A recursion group consisting of one or more HeapTypes. HeapTypes with single diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 9567a237ac7..2380842dcb9 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -518,24 +518,6 @@ struct IRBuilder::ChildPopper if (!Type::isSubType(type, *bound)) { return true; } - } else if (constraint.isAnyI8ArrayReference()) { - bool isI8Array = - type.isRef() && type.getHeapType().isArray() && - type.getHeapType().getArray().element.packedType == Field::i8; - bool isNone = - type.isRef() && type.getHeapType().isMaybeShared(HeapType::none); - if (!isI8Array && !isNone && type != Type::unreachable) { - return true; - } - } else if (constraint.isAnyI16ArrayReference()) { - bool isI16Array = - type.isRef() && type.getHeapType().isArray() && - type.getHeapType().getArray().element.packedType == Field::i16; - bool isNone = - type.isRef() && type.getHeapType().isMaybeShared(HeapType::none); - if (!isI16Array && !isNone && type != Type::unreachable) { - return true; - } } else { WASM_UNREACHABLE("unexpected constraint"); } @@ -686,13 +668,6 @@ struct IRBuilder::ChildPopper return popConstrainedChildren(children); } - Result<> visitStringEncode(StringEncode* curr, - std::optional ht = std::nullopt) { - std::vector children; - ConstraintCollector{builder, children}.visitStringEncode(curr, ht); - return popConstrainedChildren(children); - } - Result<> visitCallRef(CallRef* curr, std::optional ht = std::nullopt) { std::vector children; @@ -2488,11 +2463,7 @@ Result<> IRBuilder::makeStringMeasure(StringMeasureOp op) { Result<> IRBuilder::makeStringEncode(StringEncodeOp op) { StringEncode curr; curr.op = op; - // There's no type annotation on these instructions due to a bug in the - // stringref proposal, so we just fudge it and pass `array` instead of a - // defined heap type. This will allow us to pop a child with an invalid - // array type, but that's just too bad. - CHECK_ERR(ChildPopper{*this}.visitStringEncode(&curr, HeapType::array)); + CHECK_ERR(visitStringEncode(&curr)); push(builder.makeStringEncode(op, curr.str, curr.array, curr.start)); return Ok{}; } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 1f5ee13dd30..ed5c360fb48 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -2721,22 +2721,28 @@ void TypeBuilder::dump() { } std::unordered_set getIgnorablePublicTypes() { - auto array8 = Array(Field(Field::i8, Mutable)); - auto array16 = Array(Field(Field::i16, Mutable)); - TypeBuilder builder(2); - builder[0] = array8; - builder[1] = array16; - auto result = builder.build(); - assert(result); - std::unordered_set ret; - for (auto type : *result) { - ret.insert(type); - } - return ret; + std::unordered_set set; + set.insert(HeapTypes::getMutI8Array()); + set.insert(HeapTypes::getMutI16Array()); + return set; } } // namespace wasm +namespace wasm::HeapTypes { + +HeapType getMutI8Array() { + static HeapType i8Array = Array(Field(Field::i8, Mutable)); + return i8Array; +} + +HeapType getMutI16Array() { + static HeapType i16Array = Array(Field(Field::i16, Mutable)); + return i16Array; +} + +} // namespace wasm::HeapTypes + namespace std { template<> class hash { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 609dc57937c..a2db1a2bbaa 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -31,6 +31,7 @@ #include "ir/stack-utils.h" #include "ir/utils.h" #include "support/colors.h" +#include "wasm-type.h" #include "wasm-validator.h" #include "wasm.h" @@ -3851,11 +3852,19 @@ void FunctionValidator::visitStringNew(StringNew* curr) { refType.isRef(), curr, "string.new input must have array type")) { return; } - auto heapType = refType.getHeapType(); - if (!shouldBeTrue(heapType.isBottom() || heapType.isArray(), - curr, - "string.new input must have array type")) { - return; + if (curr->op == StringNewLossyUTF8Array) { + shouldBeSubType( + refType, + Type(HeapTypes::getMutI8Array(), Nullable), + curr, + "string.new_lossy_utf8_array input must have proper i8 array type"); + } else { + assert(curr->op == StringNewWTF16Array); + shouldBeSubType( + refType, + Type(HeapTypes::getMutI16Array(), Nullable), + curr, + "string.new_wtf16_array input must have proper i16 array type"); } shouldBeEqualOrFirstIsUnreachable(curr->start->type, Type(Type::i32), @@ -3896,6 +3905,31 @@ void FunctionValidator::visitStringEncode(StringEncode* curr) { shouldBeTrue(!getModule() || getModule()->features.hasStrings(), curr, "string operations require strings [--enable-strings]"); + shouldBeSubTypeIgnoringShared(curr->str->type, + Type(HeapType::ext, Nullable), + curr, + "string.encode input should be an externref"); + switch (curr->op) { + case StringEncodeLossyUTF8Array: + shouldBeSubType( + curr->array->type, + Type(HeapTypes::getMutI8Array(), Nullable), + curr, + "string.encode_lossy_utf8_array should have mutable i8 array"); + break; + case StringEncodeWTF16Array: { + shouldBeSubType( + curr->array->type, + Type(HeapTypes::getMutI16Array(), Nullable), + curr, + "string.encode_wtf16_array should have mutable i16 array"); + break; + } + } + shouldBeSubType(curr->start->type, + Type(Type::i32), + curr, + "string.encode start should be an i32"); } void FunctionValidator::visitStringConcat(StringConcat* curr) { diff --git a/test/lit/basic/unreachable-string-new.wast b/test/lit/basic/unreachable-string-new.wast index 89310e20c6c..91dd9d28930 100644 --- a/test/lit/basic/unreachable-string-new.wast +++ b/test/lit/basic/unreachable-string-new.wast @@ -3,14 +3,14 @@ ;; RUN: wasm-opt -all --preserve-type-order %s -S -o - | filecheck %s (module - ;; CHECK: (type $array8 (array i8)) - (type $array8 (array i8)) - ;; CHECK: (type $array16 (array i16)) - (type $array16 (array i16)) - ;; CHECK: (type $shared-array8 (shared (array i8))) - (type $shared-array8 (shared (array i8))) - ;; CHECK: (type $shared-array16 (shared (array i16))) - (type $shared-array16 (shared (array i16))) + ;; CHECK: (type $array8 (array (mut i8))) + (type $array8 (array (mut i8))) + ;; CHECK: (type $array16 (array (mut i16))) + (type $array16 (array (mut i16))) + ;; CHECK: (type $shared-array8 (shared (array (mut i8)))) + (type $shared-array8 (shared (array (mut i8)))) + ;; CHECK: (type $shared-array16 (shared (array (mut i16)))) + (type $shared-array16 (shared (array (mut i16)))) ;; CHECK: (func $i8-bad-array (type $4) (result (ref string)) ;; CHECK-NEXT: (drop @@ -73,8 +73,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $i8-ok (result (ref string)) - ;; Now we have a valid type, so it can be popped as the first child of the - ;; string.new. + ;; Now we have the correct type, so it can be popped as the first child of + ;; the string.new. block (result (ref $array8)) unreachable end @@ -102,18 +102,23 @@ string.new_lossy_utf8_array ) - ;; CHECK: (func $i8-ok-shared (type $4) (result (ref string)) - ;; CHECK-NEXT: (string.new_lossy_utf8_array + ;; CHECK: (func $i8-bad-shared (type $4) (result (ref string)) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref $shared-array8)) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (string.new_lossy_utf8_array + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $i8-ok-shared (result (ref string)) - ;; Shared arrays work as well. TODO: Should the result be shared in this - ;; case? + (func $i8-bad-shared (result (ref string)) + ;; Shared arrays do not work as well. TODO: find a good way to support them. block (result (ref $shared-array8)) unreachable end @@ -122,17 +127,23 @@ string.new_lossy_utf8_array ) - ;; CHECK: (func $i8-ok-shared-none (type $4) (result (ref string)) - ;; CHECK-NEXT: (string.new_lossy_utf8_array + ;; CHECK: (func $i8-bad-shared-none (type $4) (result (ref string)) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref (shared none))) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (string.new_lossy_utf8_array + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $i8-ok-shared-none (result (ref string)) - ;; Shared bottom references are also ok. + (func $i8-bad-shared-none (result (ref string)) + ;; Shared bottom references also do not work. block (result (ref (shared none))) unreachable end @@ -225,16 +236,22 @@ string.new_wtf16_array ) - ;; CHECK: (func $i16-ok-shared (type $4) (result (ref string)) - ;; CHECK-NEXT: (string.new_wtf16_array + ;; CHECK: (func $i16-bad-shared (type $4) (result (ref string)) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref $shared-array16)) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (string.new_wtf16_array + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $i16-ok-shared (result (ref string)) + (func $i16-bad-shared (result (ref string)) block (result (ref $shared-array16)) unreachable end @@ -243,16 +260,22 @@ string.new_wtf16_array ) - ;; CHECK: (func $i16-ok-shared-none (type $4) (result (ref string)) - ;; CHECK-NEXT: (string.new_wtf16_array + ;; CHECK: (func $i16-bad-shared-none (type $4) (result (ref string)) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref (shared none))) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (string.new_wtf16_array + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $i16-ok-shared-none (result (ref string)) + (func $i16-bad-shared-none (result (ref string)) block (result (ref (shared none))) unreachable end diff --git a/test/lit/passes/precompute-strings.wast b/test/lit/passes/precompute-strings.wast index 4649eb194fc..514fbd6379f 100644 --- a/test/lit/passes/precompute-strings.wast +++ b/test/lit/passes/precompute-strings.wast @@ -263,20 +263,10 @@ ;; CHECK: (func $string.new-mutable (type $3) (result externref) - ;; CHECK-NEXT: (string.new_wtf16_array - ;; CHECK-NEXT: (array.new_fixed $array16 4 - ;; CHECK-NEXT: (i32.const 65) - ;; CHECK-NEXT: (i32.const 66) - ;; CHECK-NEXT: (i32.const 67) - ;; CHECK-NEXT: (i32.const 68) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (i32.const 4) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (string.const "ABCD") ;; CHECK-NEXT: ) (func $string.new-mutable (result externref) - ;; We do not precompute this because the array is mutable, and we do not yet - ;; do an analysis to see that it does not "escape" into places that modify it. + ;; We can precompute this only because the allocation is the immediate child. (string.new_wtf16_array (array.new_fixed $array16 4 (i32.const 65) @@ -289,17 +279,31 @@ ) ) - ;; CHECK: (func $string.new-immutable (type $3) (result externref) - ;; CHECK-NEXT: (string.const "ABCD") + ;; CHECK: (func $string.new-mutable-indirect (type $3) (result externref) + ;; CHECK-NEXT: (string.new_wtf16_array + ;; CHECK-NEXT: (block (result (ref (exact $array16))) + ;; CHECK-NEXT: (array.new_fixed $array16 4 + ;; CHECK-NEXT: (i32.const 65) + ;; CHECK-NEXT: (i32.const 66) + ;; CHECK-NEXT: (i32.const 67) + ;; CHECK-NEXT: (i32.const 68) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $string.new-immutable (result externref) - ;; This array is immutable and we can optimize here. + (func $string.new-mutable-indirect (result externref) + ;; Now the allocation is not the immediate child, so we do not precompute. + ;; TODO: be smarter and optimize this. (string.new_wtf16_array - (array.new_fixed $array16-imm 4 - (i32.const 65) - (i32.const 66) - (i32.const 67) - (i32.const 68) + (block (result (ref $array16)) + (array.new_fixed $array16 4 + (i32.const 65) + (i32.const 66) + (i32.const 67) + (i32.const 68) + ) ) (i32.const 0) (i32.const 4) diff --git a/test/lit/passes/simplify-locals-strings.wast b/test/lit/passes/simplify-locals-strings.wast index b4b2adc88de..eea929b1289 100644 --- a/test/lit/passes/simplify-locals-strings.wast +++ b/test/lit/passes/simplify-locals-strings.wast @@ -5,10 +5,10 @@ (module (memory 10 10) - ;; CHECK: (type $array (sub (array (mut i8)))) - (type $array (sub (array (mut i8)))) - ;; CHECK: (type $array16 (sub (array (mut i16)))) - (type $array16 (sub (array (mut i16)))) + ;; CHECK: (type $array (array (mut i8))) + (type $array (array (mut i8))) + ;; CHECK: (type $array16 (array (mut i16))) + (type $array16 (array (mut i16))) ;; CHECK: (func $no-new-past-store (type $2) (param $array (ref $array)) (param $array16 (ref $array16)) ;; CHECK-NEXT: (local $temp stringref) diff --git a/test/lit/passes/string-lowering-instructions.wast b/test/lit/passes/string-lowering-instructions.wast index a3a59df0636..23303838d20 100644 --- a/test/lit/passes/string-lowering-instructions.wast +++ b/test/lit/passes/string-lowering-instructions.wast @@ -3,21 +3,11 @@ ;; RUN: wasm-opt %s -all --preserve-type-order --string-lowering -S -o - | filecheck %s (module - (rec - ;; CHECK: (type $0 (func)) - - ;; CHECK: (type $1 (func (param externref) (result i32))) - - ;; CHECK: (type $2 (array (mut i16))) + ;; CHECK: (type $array16 (array (mut i16))) + (type $array16 (array (mut i16))) ;; CHECK: (rec - ;; CHECK-NEXT: (type $struct-of-string (struct (field externref) (field i32) (field anyref))) - (type $struct-of-string (struct (field stringref) (field i32) (field anyref))) - - ;; CHECK: (type $struct-of-array (struct (field (ref $2)))) - (type $struct-of-array (struct (field (ref $array16)))) - - ;; CHECK: (type $array16-imm (array i32)) + ;; CHECK-NEXT: (type $array16-imm (array i32)) (type $array16-imm (array i32)) ;; CHECK: (type $array32 (array (mut i32))) @@ -29,69 +19,75 @@ ;; CHECK: (type $array16-child (sub $array16-open (array (mut i16)))) (type $array16-child (sub $array16-open (array (mut i16)))) - ;; CHECK: (type $array16 (array (mut i16))) - (type $array16 (array (mut i16))) - ) + ;; CHECK: (type $struct-of-string (struct (field externref) (field i32) (field anyref))) + (type $struct-of-string (struct (field stringref) (field i32) (field anyref))) + + ;; CHECK: (type $struct-of-array (struct (field (ref $array16)))) + (type $struct-of-array (struct (field (ref $array16)))) + + ;; CHECK: (type $7 (func (param (ref $array16)))) + + ;; CHECK: (type $8 (func (param externref) (result i32))) - ;; CHECK: (type $10 (func (param (ref $2)))) + ;; CHECK: (type $9 (func (param externref externref) (result (ref extern)))) - ;; CHECK: (type $11 (func (param externref) (result i32))) + ;; CHECK: (type $10 (func (param externref (ref $array16)) (result i32))) - ;; CHECK: (type $12 (func (param externref externref) (result (ref extern)))) + ;; CHECK: (type $11 (func (param externref externref) (result i32))) - ;; CHECK: (type $13 (func (param externref (ref $2)) (result i32))) + ;; CHECK: (type $12 (func (param externref) (result externref))) - ;; CHECK: (type $14 (func (param externref externref) (result i32))) + ;; CHECK: (type $13 (func (param externref))) - ;; CHECK: (type $15 (func (param externref) (result externref))) + ;; CHECK: (type $14 (func)) - ;; CHECK: (type $16 (func (param externref))) + ;; CHECK: (type $15 (func (param externref) (result i32))) - ;; CHECK: (type $17 (func (result externref))) + ;; CHECK: (type $16 (func (result externref))) - ;; CHECK: (type $18 (func (param externref externref) (result i32))) + ;; CHECK: (type $17 (func (param externref externref) (result i32))) - ;; CHECK: (type $19 (func (param externref i32 externref))) + ;; CHECK: (type $18 (func (param externref i32 externref))) - ;; CHECK: (type $20 (func (param (ref null $2) i32 i32) (result (ref extern)))) + ;; CHECK: (type $19 (func (param (ref null $array16) i32 i32) (result (ref extern)))) - ;; CHECK: (type $21 (func (param i32) (result (ref extern)))) + ;; CHECK: (type $20 (func (param i32) (result (ref extern)))) - ;; CHECK: (type $22 (func (param externref externref) (result (ref extern)))) + ;; CHECK: (type $21 (func (param externref externref) (result (ref extern)))) - ;; CHECK: (type $23 (func (param externref (ref null $2) i32) (result i32))) + ;; CHECK: (type $22 (func (param externref (ref null $array16) i32) (result i32))) - ;; CHECK: (type $24 (func (param externref i32) (result i32))) + ;; CHECK: (type $23 (func (param externref i32) (result i32))) - ;; CHECK: (type $25 (func (param externref i32 i32) (result (ref extern)))) + ;; CHECK: (type $24 (func (param externref i32 i32) (result (ref extern)))) ;; CHECK: (import "string.const" "0" (global $"string.const_\"exported\"" (ref extern))) ;; CHECK: (import "string.const" "1" (global $"string.const_\"value\"" (ref extern))) - ;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $0))) + ;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $14))) (import "colliding" "name" (func $fromCodePoint)) - ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $20) (param (ref null $2) i32 i32) (result (ref extern)))) + ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $19) (param (ref null $array16) i32 i32) (result (ref extern)))) - ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_19 (type $21) (param i32) (result (ref extern)))) + ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_19 (type $20) (param i32) (result (ref extern)))) - ;; CHECK: (import "wasm:js-string" "concat" (func $concat (type $22) (param externref externref) (result (ref extern)))) + ;; CHECK: (import "wasm:js-string" "concat" (func $concat (type $21) (param externref externref) (result (ref extern)))) - ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $23) (param externref (ref null $2) i32) (result i32))) + ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $22) (param externref (ref null $array16) i32) (result i32))) - ;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $18) (param externref externref) (result i32))) + ;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $17) (param externref externref) (result i32))) - ;; CHECK: (import "wasm:js-string" "test" (func $test (type $1) (param externref) (result i32))) + ;; CHECK: (import "wasm:js-string" "test" (func $test (type $15) (param externref) (result i32))) - ;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $18) (param externref externref) (result i32))) + ;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $17) (param externref externref) (result i32))) - ;; CHECK: (import "wasm:js-string" "length" (func $length (type $1) (param externref) (result i32))) + ;; CHECK: (import "wasm:js-string" "length" (func $length (type $15) (param externref) (result i32))) - ;; CHECK: (import "wasm:js-string" "charCodeAt" (func $charCodeAt (type $24) (param externref i32) (result i32))) + ;; CHECK: (import "wasm:js-string" "charCodeAt" (func $charCodeAt (type $23) (param externref i32) (result i32))) - ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $25) (param externref i32 i32) (result (ref extern)))) + ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $24) (param externref i32 i32) (result (ref extern)))) ;; CHECK: (global $string externref (ref.null noextern)) (global $string stringref (ref.null string)) ;; Test we update global nulls. @@ -100,7 +96,7 @@ ;; CHECK: (export "export.2" (func $exported-string-receiver)) - ;; CHECK: (func $string.new.gc (type $10) (param $array16 (ref $2)) + ;; CHECK: (func $string.new.gc (type $7) (param $array16 (ref $array16)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $fromCharCodeArray ;; CHECK-NEXT: (local.get $array16) @@ -119,7 +115,7 @@ ) ) - ;; CHECK: (func $string.from_code_point (type $17) (result externref) + ;; CHECK: (func $string.from_code_point (type $16) (result externref) ;; CHECK-NEXT: (call $fromCodePoint_19 ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) @@ -130,7 +126,7 @@ ) ) - ;; CHECK: (func $string.concat (type $12) (param $0 externref) (param $1 externref) (result (ref extern)) + ;; CHECK: (func $string.concat (type $9) (param $0 externref) (param $1 externref) (result (ref extern)) ;; CHECK-NEXT: (call $concat ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) @@ -143,7 +139,7 @@ ) ) - ;; CHECK: (func $string.encode (type $13) (param $ref externref) (param $array16 (ref $2)) (result i32) + ;; CHECK: (func $string.encode (type $10) (param $ref externref) (param $array16 (ref $array16)) (result i32) ;; CHECK-NEXT: (call $intoCharCodeArray ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: (local.get $array16) @@ -158,7 +154,7 @@ ) ) - ;; CHECK: (func $string.eq (type $14) (param $a externref) (param $b externref) (result i32) + ;; CHECK: (func $string.eq (type $11) (param $a externref) (param $b externref) (result i32) ;; CHECK-NEXT: (call $equals ;; CHECK-NEXT: (local.get $a) ;; CHECK-NEXT: (local.get $b) @@ -171,7 +167,7 @@ ) ) - ;; CHECK: (func $string.compare (type $14) (param $a externref) (param $b externref) (result i32) + ;; CHECK: (func $string.compare (type $11) (param $a externref) (param $b externref) (result i32) ;; CHECK-NEXT: (call $compare ;; CHECK-NEXT: (local.get $a) ;; CHECK-NEXT: (local.get $b) @@ -184,7 +180,7 @@ ) ) - ;; CHECK: (func $string-test (type $11) (param $str externref) (result i32) + ;; CHECK: (func $string-test (type $8) (param $str externref) (result i32) ;; CHECK-NEXT: (call $test ;; CHECK-NEXT: (local.get $str) ;; CHECK-NEXT: ) @@ -195,7 +191,7 @@ ) ) - ;; CHECK: (func $string.length (type $11) (param $ref externref) (result i32) + ;; CHECK: (func $string.length (type $8) (param $ref externref) (result i32) ;; CHECK-NEXT: (call $length ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) @@ -206,7 +202,7 @@ ) ) - ;; CHECK: (func $string.get_codeunit (type $11) (param $ref externref) (result i32) + ;; CHECK: (func $string.get_codeunit (type $8) (param $ref externref) (result i32) ;; CHECK-NEXT: (call $charCodeAt ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: (i32.const 2) @@ -219,7 +215,7 @@ ) ) - ;; CHECK: (func $string.slice (type $15) (param $ref externref) (result externref) + ;; CHECK: (func $string.slice (type $12) (param $ref externref) (result externref) ;; CHECK-NEXT: (call $substring ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: (i32.const 2) @@ -234,7 +230,7 @@ ) ) - ;; CHECK: (func $if.string (type $15) (param $ref externref) (result externref) + ;; CHECK: (func $if.string (type $12) (param $ref externref) (result externref) ;; CHECK-NEXT: (if (result externref) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then @@ -258,7 +254,7 @@ ) ) - ;; CHECK: (func $if.string.flip (type $15) (param $ref externref) (result externref) + ;; CHECK: (func $if.string.flip (type $12) (param $ref externref) (result externref) ;; CHECK-NEXT: (if (result externref) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (then @@ -282,7 +278,7 @@ ) ) - ;; CHECK: (func $exported-string-returner (type $17) (result externref) + ;; CHECK: (func $exported-string-returner (type $16) (result externref) ;; CHECK-NEXT: (global.get $"string.const_\"exported\"") ;; CHECK-NEXT: ) (func $exported-string-returner (export "export.1") (result stringref) @@ -291,7 +287,7 @@ (string.const "exported") ) - ;; CHECK: (func $exported-string-receiver (type $19) (param $x externref) (param $y i32) (param $z externref) + ;; CHECK: (func $exported-string-receiver (type $18) (param $x externref) (param $y i32) (param $z externref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) @@ -316,8 +312,8 @@ ) ) - ;; CHECK: (func $use-struct-of-array (type $0) - ;; CHECK-NEXT: (local $array16 (ref $2)) + ;; CHECK: (func $use-struct-of-array (type $14) + ;; CHECK-NEXT: (local $array16 (ref $array16)) ;; CHECK-NEXT: (local $open (ref $array16-open)) ;; CHECK-NEXT: (local $child (ref $array16-child)) ;; CHECK-NEXT: (local $32 (ref $array32)) @@ -326,7 +322,7 @@ ;; CHECK-NEXT: (call $fromCharCodeArray ;; CHECK-NEXT: (struct.get $struct-of-array 0 ;; CHECK-NEXT: (struct.new $struct-of-array - ;; CHECK-NEXT: (array.new_fixed $2 2 + ;; CHECK-NEXT: (array.new_fixed $array16 2 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) @@ -372,7 +368,7 @@ ) ) - ;; CHECK: (func $struct-of-string (type $0) + ;; CHECK: (func $struct-of-string (type $14) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct-of-string ;; CHECK-NEXT: (ref.null noextern) @@ -415,7 +411,7 @@ ) ) - ;; CHECK: (func $call-param-null (type $16) (param $str externref) + ;; CHECK: (func $call-param-null (type $13) (param $str externref) ;; CHECK-NEXT: (call $call-param-null ;; CHECK-NEXT: (ref.null noextern) ;; CHECK-NEXT: ) diff --git a/test/lit/strings.wast b/test/lit/strings.wast index 1f392aa2bc8..63473b0b1a6 100644 --- a/test/lit/strings.wast +++ b/test/lit/strings.wast @@ -14,9 +14,10 @@ (module ;; CHECK: (type $0 (func (param stringref stringref))) - ;; CHECK: (type $array (sub (array (mut i8)))) - - ;; CHECK: (type $array16 (sub (array (mut i16)))) + ;; CHECK: (type $array (array (mut i8))) + (type $array (array (mut i8))) + ;; CHECK: (type $array16 (array (mut i16))) + (type $array16 (array (mut i16))) ;; CHECK: (type $3 (func)) @@ -33,15 +34,11 @@ ;; CHECK: (import "env" "get-string-ref" (func $get-string-ref (type $4) (result externref))) (import "env" "get-string-ref" (func $get-string-ref (result externref))) - (memory 10 10) - - (type $array (sub (array (mut i8)))) - (type $array16 (sub (array (mut i16)))) - ;; CHECK: (global $string-const stringref (string.const "string in a global \c2\a3_\e2\82\ac_\f0\90\8d\88 \01\00\t\t\n\n\r\r\"\"\'\'\\\\ ")) (global $string-const stringref (string.const "string in a global \C2\A3_\E2\82\AC_\F0\90\8D\88 \01\00\t\t\n\n\r\r\"\"\'\'\\\\ ")) ;; CHECK: (memory $0 10 10) + (memory $0 10 10) ;; CHECK: (func $string.const (type $5) (param $param (ref string)) ;; CHECK-NEXT: (call $string.const diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index 9f85b526fc2..47ac2a5e448 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -42,15 +42,15 @@ (rec) + ;; CHECK: (type $many (sub (func (param i32 i64 f32 f64) (result anyref (ref func))))) + ;; CHECK: (type $packed-i8 (array (mut i8))) - ;; CHECK: (type $many (sub (func (param i32 i64 f32 f64) (result anyref (ref func))))) + ;; CHECK: (type $packed-i16 (array (mut i16))) ;; CHECK: (type $a0 (array i32)) - ;; CHECK: (type $18 (func (param i32))) - - ;; CHECK: (type $packed-i16 (array (mut i16))) + ;; CHECK: (type $19 (func (param i32))) ;; CHECK: (type $any-array (array (mut anyref))) @@ -214,7 +214,7 @@ ;; CHECK: (type $87 (func (param stringref))) - ;; CHECK: (type $88 (func (param stringref (ref $packed-i8) i32) (result i32))) + ;; CHECK: (type $88 (func (param stringref (ref $packed-i16) i32) (result i32))) ;; CHECK: (type $89 (func (param stringref stringref) (result (ref string)))) @@ -418,7 +418,7 @@ ;; CHECK: (tag $empty (type $0)) (tag $empty) - ;; CHECK: (tag $tag-i32 (type $18) (param i32)) + ;; CHECK: (tag $tag-i32 (type $19) (param i32)) (tag $tag-i32 (param $x i32)) ;; CHECK: (tag $tag-pair (type $7) (param i32 i64)) @@ -477,10 +477,10 @@ ;; CHECK: (func $2 (type $0) ;; CHECK-NEXT: ) - ;; CHECK: (func $f1 (type $18) (param $0 i32) + ;; CHECK: (func $f1 (type $19) (param $0 i32) ;; CHECK-NEXT: ) (func $f1 (param i32)) - ;; CHECK: (func $f2 (type $18) (param $x i32) + ;; CHECK: (func $f2 (type $19) (param $x i32) ;; CHECK-NEXT: ) (func $f2 (param $x i32)) ;; CHECK: (func $f3 (type $1) (result i32) @@ -4580,14 +4580,14 @@ drop ) - ;; CHECK: (func $string-encode-gc (type $88) (param $0 stringref) (param $1 (ref $packed-i8)) (param $2 i32) (result i32) + ;; CHECK: (func $string-encode-gc (type $88) (param $0 stringref) (param $1 (ref $packed-i16)) (param $2 i32) (result i32) ;; CHECK-NEXT: (string.encode_wtf16_array ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $string-encode-gc (param stringref (ref $packed-i8) i32) (result i32) + (func $string-encode-gc (param stringref (ref $packed-i16) i32) (result i32) local.get 0 local.get 1 local.get 2