summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/gen-s-parser.py2
-rw-r--r--src/gen-s-parser.inc76
-rw-r--r--src/passes/Print.cpp9
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-builder.h7
-rw-r--r--src/wasm-delegations-fields.def1
-rw-r--r--src/wasm.h10
-rw-r--r--src/wasm/wasm-binary.cpp19
-rw-r--r--src/wasm/wasm-s-parser.cpp15
-rw-r--r--src/wasm/wasm-stack.cpp11
-rw-r--r--src/wasm/wasm.cpp3
-rw-r--r--test/lit/strings.wast57
12 files changed, 187 insertions, 25 deletions
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py
index dbe24cbda..e36caf02e 100755
--- a/scripts/gen-s-parser.py
+++ b/scripts/gen-s-parser.py
@@ -624,6 +624,8 @@ instructions = [
("string.is_usv_sequence", "makeStringMeasure(s, StringMeasureIsUSV)"),
("string.encode_wtf8", "makeStringEncode(s, StringEncodeWTF8)"),
("string.encode_wtf16", "makeStringEncode(s, StringEncodeWTF16)"),
+ ("string.encode_wtf8_array", "makeStringEncode(s, StringEncodeWTF8Array)"),
+ ("string.encode_wtf16_array", "makeStringEncode(s, StringEncodeWTF16Array)"),
("string.concat", "makeStringConcat(s)"),
("string.eq", "makeStringEq(s)"),
("string.as_wtf8", "makeStringAs(s, StringAsWTF8)"),
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 59eee1070..301164f87 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -3165,12 +3165,28 @@ switch (op[0]) {
switch (op[8]) {
case 'n': {
switch (op[17]) {
- case '1':
- if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
- goto parse_error;
- case '8':
- if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
- goto parse_error;
+ case '1': {
+ switch (op[19]) {
+ case '\0':
+ if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
+ goto parse_error;
+ case '_':
+ if (strcmp(op, "string.encode_wtf16_array") == 0) { return makeStringEncode(s, StringEncodeWTF16Array); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case '8': {
+ switch (op[18]) {
+ case '\0':
+ if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
+ goto parse_error;
+ case '_':
+ if (strcmp(op, "string.encode_wtf8_array") == 0) { return makeStringEncode(s, StringEncodeWTF8Array); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
@@ -8879,20 +8895,44 @@ switch (op[0]) {
switch (op[8]) {
case 'n': {
switch (op[17]) {
- case '1':
- if (op == "string.encode_wtf16"sv) {
- auto ret = makeStringEncode(ctx, in, StringEncodeWTF16);
- CHECK_ERR(ret);
- return *ret;
+ case '1': {
+ switch (op[19]) {
+ case '\0':
+ if (op == "string.encode_wtf16"sv) {
+ auto ret = makeStringEncode(ctx, in, StringEncodeWTF16);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case '_':
+ if (op == "string.encode_wtf16_array"sv) {
+ auto ret = makeStringEncode(ctx, in, StringEncodeWTF16Array);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
}
- goto parse_error;
- case '8':
- if (op == "string.encode_wtf8"sv) {
- auto ret = makeStringEncode(ctx, in, StringEncodeWTF8);
- CHECK_ERR(ret);
- return *ret;
+ }
+ case '8': {
+ switch (op[18]) {
+ case '\0':
+ if (op == "string.encode_wtf8"sv) {
+ auto ret = makeStringEncode(ctx, in, StringEncodeWTF8);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case '_':
+ if (op == "string.encode_wtf8_array"sv) {
+ auto ret = makeStringEncode(ctx, in, StringEncodeWTF8Array);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
}
- goto parse_error;
+ }
default: goto parse_error;
}
}
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 440ff114f..a6a0f7919 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2330,6 +2330,15 @@ struct PrintExpressionContents
case StringEncodeWTF16:
printMedium(o, "string.encode_wtf16");
break;
+ case StringEncodeUTF8Array:
+ printMedium(o, "string.encode_wtf8_array utf8");
+ break;
+ case StringEncodeWTF8Array:
+ printMedium(o, "string.encode_wtf8_array wtf8");
+ break;
+ case StringEncodeWTF16Array:
+ printMedium(o, "string.encode_wtf16_array");
+ break;
default:
WASM_UNREACHABLE("invalid string.encode*");
}
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 8f44c6ecf..cf0428625 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1161,6 +1161,8 @@ enum ASTNodes {
StringViewIterSlice = 0xa4,
StringNewWTF8Array = 0xb0,
StringNewWTF16Array = 0xb1,
+ StringEncodeWTF8Array = 0xb2,
+ StringEncodeWTF16Array = 0xb3,
};
enum MemoryAccess {
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index d76d24b21..61227a811 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -1012,12 +1012,15 @@ public:
ret->finalize();
return ret;
}
- StringEncode*
- makeStringEncode(StringEncodeOp op, Expression* ref, Expression* ptr) {
+ StringEncode* makeStringEncode(StringEncodeOp op,
+ Expression* ref,
+ Expression* ptr,
+ Expression* start = nullptr) {
auto* ret = wasm.allocator.alloc<StringEncode>();
ret->op = op;
ret->ref = ref;
ret->ptr = ptr;
+ ret->start = start;
ret->finalize();
return ret;
}
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index a8dfcc750..55a9edd16 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -737,6 +737,7 @@ switch (DELEGATE_ID) {
case Expression::Id::StringEncodeId: {
DELEGATE_START(StringEncode);
DELEGATE_FIELD_INT(StringEncode, op);
+ DELEGATE_FIELD_OPTIONAL_CHILD(StringEncode, start);
DELEGATE_FIELD_CHILD(StringEncode, ptr);
DELEGATE_FIELD_CHILD(StringEncode, ref);
DELEGATE_END(StringEncode);
diff --git a/src/wasm.h b/src/wasm.h
index 99a2d9f94..8c0e48da2 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -608,6 +608,9 @@ enum StringEncodeOp {
StringEncodeUTF8,
StringEncodeWTF8,
StringEncodeWTF16,
+ StringEncodeUTF8Array,
+ StringEncodeWTF8Array,
+ StringEncodeWTF16Array,
};
enum StringAsOp {
@@ -1746,8 +1749,15 @@ public:
StringEncodeOp op;
Expression* ref;
+
+ // In linear memory variations this is the pointer in linear memory. In the
+ // GC variations this is an Array.
Expression* ptr;
+ // Used only in GC variations, where it is the index in |ptr| to start
+ // encoding from.
+ Expression* start = nullptr;
+
void finalize();
};
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 5427deea1..edcf5f7bf 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -7261,6 +7261,7 @@ bool WasmBinaryBuilder::maybeVisitStringMeasure(Expression*& out,
bool WasmBinaryBuilder::maybeVisitStringEncode(Expression*& out,
uint32_t code) {
StringEncodeOp op;
+ Expression* start = nullptr;
// TODO: share this code with string.measure?
if (code == BinaryConsts::StringEncodeWTF8) {
auto policy = getU32LEB();
@@ -7276,12 +7277,28 @@ bool WasmBinaryBuilder::maybeVisitStringEncode(Expression*& out,
}
} else if (code == BinaryConsts::StringEncodeWTF16) {
op = StringEncodeWTF16;
+ } else if (code == BinaryConsts::StringEncodeWTF8Array) {
+ auto policy = getU32LEB();
+ switch (policy) {
+ case BinaryConsts::StringPolicy::UTF8:
+ op = StringEncodeUTF8Array;
+ break;
+ case BinaryConsts::StringPolicy::WTF8:
+ op = StringEncodeWTF8Array;
+ break;
+ default:
+ throwError("bad policy for string.encode");
+ }
+ start = popNonVoidExpression();
+ } else if (code == BinaryConsts::StringEncodeWTF16Array) {
+ op = StringEncodeWTF16Array;
+ start = popNonVoidExpression();
} else {
return false;
}
auto* ptr = popNonVoidExpression();
auto* ref = popNonVoidExpression();
- out = Builder(wasm).makeStringEncode(op, ref, ptr);
+ out = Builder(wasm).makeStringEncode(op, ref, ptr, start);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 97a25d2c4..38ec788ba 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2985,6 +2985,7 @@ Expression* SExpressionWasmBuilder::makeStringMeasure(Element& s,
Expression* SExpressionWasmBuilder::makeStringEncode(Element& s,
StringEncodeOp op) {
size_t i = 1;
+ Expression* start = nullptr;
if (op == StringEncodeWTF8) {
const char* str = s[i++]->c_str();
if (strncmp(str, "utf8", 4) == 0) {
@@ -2994,9 +2995,21 @@ Expression* SExpressionWasmBuilder::makeStringEncode(Element& s,
} else {
throw ParseException("bad string.new op", s.line, s.col);
}
+ } else if (op == StringEncodeWTF8Array) {
+ const char* str = s[i++]->c_str();
+ if (strncmp(str, "utf8", 4) == 0) {
+ op = StringEncodeUTF8Array;
+ } else if (strncmp(str, "wtf8", 4) == 0) {
+ op = StringEncodeWTF8Array;
+ } else {
+ throw ParseException("bad string.new op", s.line, s.col);
+ }
+ start = parseExpression(s[i + 2]);
+ } else if (op == StringEncodeWTF16Array) {
+ start = parseExpression(s[i + 2]);
}
return Builder(wasm).makeStringEncode(
- op, parseExpression(s[i]), parseExpression(s[i + 1]));
+ op, parseExpression(s[i]), parseExpression(s[i + 1]), start);
}
Expression* SExpressionWasmBuilder::makeStringConcat(Element& s) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index c980d896b..2fc06b176 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2301,6 +2301,17 @@ void BinaryInstWriter::visitStringEncode(StringEncode* curr) {
case StringEncodeWTF16:
o << U32LEB(BinaryConsts::StringEncodeWTF16);
break;
+ case StringEncodeUTF8Array:
+ o << U32LEB(BinaryConsts::StringEncodeWTF8Array)
+ << U32LEB(BinaryConsts::StringPolicy::UTF8);
+ break;
+ case StringEncodeWTF8Array:
+ o << U32LEB(BinaryConsts::StringEncodeWTF8Array)
+ << U32LEB(BinaryConsts::StringPolicy::WTF8);
+ break;
+ case StringEncodeWTF16Array:
+ o << U32LEB(BinaryConsts::StringEncodeWTF16Array);
+ break;
default:
WASM_UNREACHABLE("invalid string.new*");
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index bd83d62ed..1a6acf5bd 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1194,7 +1194,8 @@ void StringMeasure::finalize() {
}
void StringEncode::finalize() {
- if (ref->type == Type::unreachable || ptr->type == Type::unreachable) {
+ if (ref->type == Type::unreachable || ptr->type == Type::unreachable ||
+ (start && start->type == Type::unreachable)) {
type = Type::unreachable;
} else {
type = Type::i32;
diff --git a/test/lit/strings.wast b/test/lit/strings.wast
index 03e87e562..e201b2bd7 100644
--- a/test/lit/strings.wast
+++ b/test/lit/strings.wast
@@ -11,6 +11,9 @@
;; CHECK: (type $stringref_stringref_=>_none (func (param stringref stringref)))
+ ;; CHECK: (type $array (array i32))
+ (type $array (array_subtype i32 data))
+
;; CHECK: (type $stringref_stringview_wtf8_stringview_wtf16_stringview_iter_stringref_stringview_wtf8_stringview_wtf16_stringview_iter_ref|string|_ref|stringview_wtf8|_ref|stringview_wtf16|_ref|stringview_iter|_=>_none (func (param stringref stringview_wtf8 stringview_wtf16 stringview_iter stringref stringview_wtf8 stringview_wtf16 stringview_iter (ref string) (ref stringview_wtf8) (ref stringview_wtf16) (ref stringview_iter))))
;; CHECK: (type $none_=>_none (func))
@@ -19,8 +22,7 @@
;; CHECK: (type $ref|$array|_=>_none (func (param (ref $array))))
- ;; CHECK: (type $array (array i32))
- (type $array (array_subtype i32 data))
+ ;; CHECK: (type $stringref_ref|$array|_=>_none (func (param stringref (ref $array))))
;; CHECK: (global $string-const stringref (string.const "string in a global"))
(global $string-const stringref (string.const "string in a global"))
@@ -475,4 +477,55 @@
)
)
)
+
+ ;; CHECK: (func $string.encode.gc (param $ref stringref) (param $array (ref $array))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (string.encode_wtf8_array wtf8
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $array)
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (string.encode_wtf8_array utf8
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $array)
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (string.encode_wtf16_array
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $array)
+ ;; CHECK-NEXT: (i32.const 30)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $string.encode.gc (param $ref stringref) (param $array (ref $array))
+ (drop
+ (i32.eqz ;; validate the output is i32
+ (string.encode_wtf8_array wtf8
+ (local.get $ref)
+ (local.get $array)
+ (i32.const 10)
+ )
+ )
+ )
+ (drop
+ (string.encode_wtf8_array utf8
+ (local.get $ref)
+ (local.get $array)
+ (i32.const 20)
+ )
+ )
+ (drop
+ (string.encode_wtf16_array
+ (local.get $ref)
+ (local.get $array)
+ (i32.const 30)
+ )
+ )
+ )
)