summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/StringLowering.cpp34
-rw-r--r--test/lit/passes/string-lowering-instructions.wast161
2 files changed, 143 insertions, 52 deletions
diff --git a/src/passes/StringLowering.cpp b/src/passes/StringLowering.cpp
index 1a5610608..d0487f602 100644
--- a/src/passes/StringLowering.cpp
+++ b/src/passes/StringLowering.cpp
@@ -189,12 +189,12 @@ struct StringLowering : public StringGathering {
// First, run the gathering operation so all string.consts are in one place.
StringGathering::run(module);
- // Lower the string.const globals into imports.
- makeImports(module);
-
// Remove all HeapType::string etc. in favor of externref.
updateTypes(module);
+ // Lower the string.const globals into imports.
+ makeImports(module);
+
// Replace string.* etc. operations with imported ones.
replaceInstructions(module);
@@ -230,6 +230,11 @@ struct StringLowering : public StringGathering {
CustomSection{"string.consts", std::move(vec)});
}
+ // Common types used in imports.
+ Type nullArray16 = Type(Array(Field(Field::i16, Mutable)), Nullable);
+ Type nullExt = Type(HeapType::ext, Nullable);
+ Type nnExt = Type(HeapType::ext, NonNullable);
+
void updateTypes(Module* module) {
TypeMapper::TypeUpdates updates;
@@ -240,8 +245,24 @@ struct StringLowering : public StringGathering {
updates[HeapType::stringview_wtf16] = HeapType::ext;
updates[HeapType::stringview_iter] = 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;
+ }
+ }
+
// We consider all types that use strings as modifiable, which means we
- // mark them as non-private. That is, we are doing something TypeMapper
+ // mark them as non-public. That is, we are doing something TypeMapper
// normally does not, as we are changing the external interface/ABI of the
// module: we are changing that ABI from using strings to externs.
auto publicTypes = ModuleUtils::getPublicHeapTypes(*module);
@@ -268,11 +289,6 @@ struct StringLowering : public StringGathering {
// The name of the module to import string functions from.
Name WasmStringsModule = "wasm:js-string";
- // Common types used in imports.
- Type nullArray16 = Type(Array(Field(Field::i16, Mutable)), Nullable);
- Type nullExt = Type(HeapType::ext, Nullable);
- Type nnExt = Type(HeapType::ext, NonNullable);
-
// Creates an imported string function, returning its name (which is equal to
// the true name of the import, if there is no conflict).
Name addImport(Module* module, Name trueName, Type params, Type results) {
diff --git a/test/lit/passes/string-lowering-instructions.wast b/test/lit/passes/string-lowering-instructions.wast
index 9e2d78012..2feedcb39 100644
--- a/test/lit/passes/string-lowering-instructions.wast
+++ b/test/lit/passes/string-lowering-instructions.wast
@@ -3,70 +3,89 @@
;; RUN: foreach %s %t wasm-opt --string-lowering -all -S -o - | filecheck %s
(module
- ;; CHECK: (type $array16 (array (mut i16)))
- (type $array16 (array (mut i16)))
+ (rec
+ ;; CHECK: (type $0 (array (mut i16)))
- ;; CHECK: (type $1 (func (param externref externref) (result i32)))
+ ;; CHECK: (type $1 (func))
- ;; CHECK: (rec
- ;; CHECK-NEXT: (type $2 (func (param externref i32 externref)))
+ ;; CHECK: (type $2 (func (param externref externref) (result i32)))
- ;; CHECK: (type $3 (func (result externref)))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $3 (func (param externref i32 externref)))
- ;; CHECK: (type $4 (func (param externref) (result externref)))
+ ;; CHECK: (type $4 (func (result externref)))
- ;; CHECK: (type $5 (func (param externref) (result externref)))
+ ;; CHECK: (type $struct-of-array (struct (field (ref $0))))
+ (type $struct-of-array (struct (field (ref $array16))))
- ;; CHECK: (type $6 (func (param externref) (result i32)))
+ ;; CHECK: (type $array16-imm (array i32))
+ (type $array16-imm (array i32))
- ;; CHECK: (type $7 (func (param externref externref) (result i32)))
+ ;; CHECK: (type $array32 (array (mut i32)))
+ (type $array32 (array (mut i32)))
- ;; CHECK: (type $8 (func (param externref (ref $array16)) (result i32)))
+ ;; CHECK: (type $array16-open (sub (array (mut i16))))
+ (type $array16-open (sub (array (mut i16))))
- ;; CHECK: (type $9 (func (param (ref $array16))))
+ ;; CHECK: (type $array16-child (sub $array16-open (array (mut i16))))
+ (type $array16-child (sub $array16-open (array (mut i16))))
- ;; CHECK: (type $10 (func (param externref externref externref externref)))
+ ;; CHECK: (type $array16 (array (mut i16)))
+ (type $array16 (array (mut i16)))
+ )
+
+ ;; CHECK: (type $11 (func (param externref) (result externref)))
+
+ ;; CHECK: (type $12 (func (param externref) (result externref)))
+
+ ;; CHECK: (type $13 (func (param externref) (result i32)))
+
+ ;; CHECK: (type $14 (func (param externref externref) (result i32)))
+
+ ;; CHECK: (type $15 (func (param externref (ref $0)) (result i32)))
- ;; CHECK: (type $11 (func))
+ ;; CHECK: (type $16 (func (param (ref $0))))
- ;; CHECK: (type $12 (func (param (ref null $array16) i32 i32) (result (ref extern))))
+ ;; CHECK: (type $17 (func (param externref externref externref externref)))
- ;; CHECK: (type $13 (func (param i32) (result (ref extern))))
+ ;; CHECK: (type $18 (func (param (ref null $0) i32 i32) (result (ref extern))))
- ;; CHECK: (type $14 (func (param externref (ref null $array16) i32) (result i32)))
+ ;; CHECK: (type $19 (func (param i32) (result (ref extern))))
- ;; CHECK: (type $15 (func (param externref) (result i32)))
+ ;; CHECK: (type $20 (func (param externref (ref null $0) i32) (result i32)))
- ;; CHECK: (type $16 (func (param externref i32) (result i32)))
+ ;; CHECK: (type $21 (func (param externref) (result i32)))
- ;; CHECK: (type $17 (func (param externref i32 i32) (result (ref extern))))
+ ;; CHECK: (type $22 (func (param externref i32) (result i32)))
+
+ ;; CHECK: (type $23 (func (param externref i32 i32) (result (ref extern))))
;; CHECK: (import "string.const" "0" (global $string.const_exported (ref extern)))
- ;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $11)))
+ ;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $1)))
(import "colliding" "name" (func $fromCodePoint))
- ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $12) (param (ref null $array16) i32 i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $18) (param (ref null $0) i32 i32) (result (ref extern))))
- ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_15 (type $13) (param i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_16 (type $19) (param i32) (result (ref extern))))
- ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $14) (param externref (ref null $array16) i32) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $20) (param externref (ref null $0) i32) (result i32)))
- ;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $1) (param externref externref) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $2) (param externref externref) (result i32)))
- ;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $1) (param externref externref) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $2) (param externref externref) (result i32)))
- ;; CHECK: (import "wasm:js-string" "length" (func $length (type $15) (param externref) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "length" (func $length (type $21) (param externref) (result i32)))
- ;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $16) (param externref i32) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $22) (param externref i32) (result i32)))
- ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $17) (param externref i32 i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $23) (param externref i32 i32) (result (ref extern))))
;; CHECK: (export "export.1" (func $exported-string-returner))
;; CHECK: (export "export.2" (func $exported-string-receiver))
- ;; CHECK: (func $string.as (type $10) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
+ ;; CHECK: (func $string.as (type $17) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
;; CHECK-NEXT: (local.set $b
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
@@ -101,7 +120,7 @@
)
)
- ;; CHECK: (func $string.new.gc (type $9) (param $array16 (ref $array16))
+ ;; CHECK: (func $string.new.gc (type $16) (param $array16 (ref $0))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $fromCharCodeArray
;; CHECK-NEXT: (local.get $array16)
@@ -120,8 +139,8 @@
)
)
- ;; CHECK: (func $string.from_code_point (type $3) (result externref)
- ;; CHECK-NEXT: (call $fromCodePoint_15
+ ;; CHECK: (func $string.from_code_point (type $4) (result externref)
+ ;; CHECK-NEXT: (call $fromCodePoint_16
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -131,7 +150,7 @@
)
)
- ;; CHECK: (func $string.encode (type $8) (param $ref externref) (param $array16 (ref $array16)) (result i32)
+ ;; CHECK: (func $string.encode (type $15) (param $ref externref) (param $array16 (ref $0)) (result i32)
;; CHECK-NEXT: (call $intoCharCodeArray
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: (local.get $array16)
@@ -146,7 +165,7 @@
)
)
- ;; CHECK: (func $string.eq (type $7) (param $a externref) (param $b externref) (result i32)
+ ;; CHECK: (func $string.eq (type $14) (param $a externref) (param $b externref) (result i32)
;; CHECK-NEXT: (call $equals
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (local.get $b)
@@ -159,7 +178,7 @@
)
)
- ;; CHECK: (func $string.compare (type $7) (param $a externref) (param $b externref) (result i32)
+ ;; CHECK: (func $string.compare (type $14) (param $a externref) (param $b externref) (result i32)
;; CHECK-NEXT: (call $compare
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (local.get $b)
@@ -172,7 +191,7 @@
)
)
- ;; CHECK: (func $string.length (type $6) (param $ref externref) (result i32)
+ ;; CHECK: (func $string.length (type $13) (param $ref externref) (result i32)
;; CHECK-NEXT: (call $length
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: )
@@ -183,7 +202,7 @@
)
)
- ;; CHECK: (func $string.get_codeunit (type $6) (param $ref externref) (result i32)
+ ;; CHECK: (func $string.get_codeunit (type $13) (param $ref externref) (result i32)
;; CHECK-NEXT: (call $codePointAt
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: (i32.const 2)
@@ -196,7 +215,7 @@
)
)
- ;; CHECK: (func $string.slice (type $5) (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)
@@ -211,7 +230,7 @@
)
)
- ;; CHECK: (func $if.string (type $4) (param $ref externref) (result externref)
+ ;; CHECK: (func $if.string (type $11) (param $ref externref) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
@@ -234,7 +253,7 @@
)
)
- ;; CHECK: (func $if.string.flip (type $4) (param $ref externref) (result externref)
+ ;; CHECK: (func $if.string.flip (type $11) (param $ref externref) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
@@ -258,7 +277,7 @@
)
)
- ;; CHECK: (func $exported-string-returner (type $3) (result externref)
+ ;; CHECK: (func $exported-string-returner (type $4) (result externref)
;; CHECK-NEXT: (global.get $string.const_exported)
;; CHECK-NEXT: )
(func $exported-string-returner (export "export.1") (result stringref)
@@ -267,7 +286,7 @@
(string.const "exported")
)
- ;; CHECK: (func $exported-string-receiver (type $2) (param $x externref) (param $y i32) (param $z externref)
+ ;; CHECK: (func $exported-string-receiver (type $3) (param $x externref) (param $y i32) (param $z externref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
@@ -291,4 +310,60 @@
(local.get $z)
)
)
+
+ ;; CHECK: (func $use-struct-of-array (type $1)
+ ;; CHECK-NEXT: (local $array16 (ref $0))
+ ;; CHECK-NEXT: (local $open (ref $array16-open))
+ ;; CHECK-NEXT: (local $child (ref $array16-child))
+ ;; CHECK-NEXT: (local $32 (ref $array32))
+ ;; CHECK-NEXT: (local $imm (ref $array16-imm))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (call $fromCharCodeArray
+ ;; CHECK-NEXT: (struct.get $struct-of-array 0
+ ;; CHECK-NEXT: (struct.new $struct-of-array
+ ;; CHECK-NEXT: (array.new_fixed $0 2
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $use-struct-of-array
+ ;; The array type here should switch to the new 16-bit array type that we
+ ;; use for the new imports, so that it is compatible with them. Without
+ ;; that, calling the import as we do below will fail.
+ (local $array16 (ref $array16))
+
+ ;; In comparison, the array16-open param should remain as it is: it is an
+ ;; open type which is different then the one we care about.
+ (local $open (ref $array16-open))
+
+ ;; Likewise a child of that open type is also ignored.
+ (local $child (ref $array16-child))
+
+ ;; Another array size is also ignored.
+ (local $32 (ref $array32))
+
+ ;; An immutable array is also ignored.
+ (local $imm (ref $array16-imm))
+
+ (drop
+ (string.new_wtf16_array
+ (struct.get $struct-of-array 0
+ (struct.new $struct-of-array
+ (array.new_fixed $array16 2
+ (i32.const 10)
+ (i32.const 20)
+ )
+ )
+ )
+ (i32.const 0)
+ (i32.const 1)
+ )
+ )
+ )
)