summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-07-13 14:38:10 -0700
committerGitHub <noreply@github.com>2022-07-13 14:38:10 -0700
commit9671e95adbfcf0984a7e9800a7ea2ed33e1670ad (patch)
treed7273e64ed26429d18568439cdfb7b1fb6369645 /src
parent7b9c18b98c020f887aa9cb1750543751ebe5c530 (diff)
downloadbinaryen-9671e95adbfcf0984a7e9800a7ea2ed33e1670ad.tar.gz
binaryen-9671e95adbfcf0984a7e9800a7ea2ed33e1670ad.tar.bz2
binaryen-9671e95adbfcf0984a7e9800a7ea2ed33e1670ad.zip
[Strings] stringview access operations (#4798)
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc368
-rw-r--r--src/ir/ReFinalize.cpp6
-rw-r--r--src/ir/cost.h12
-rw-r--r--src/ir/effects.h26
-rw-r--r--src/ir/possible-contents.cpp16
-rw-r--r--src/passes/Print.cpp21
-rw-r--r--src/wasm-binary.h9
-rw-r--r--src/wasm-builder.h32
-rw-r--r--src/wasm-delegations-fields.def29
-rw-r--r--src/wasm-delegations.def4
-rw-r--r--src/wasm-interpreter.h12
-rw-r--r--src/wasm-s-parser.h4
-rw-r--r--src/wasm.h55
-rw-r--r--src/wasm/wasm-binary.cpp61
-rw-r--r--src/wasm/wasm-s-parser.cpp20
-rw-r--r--src/wasm/wasm-stack.cpp29
-rw-r--r--src/wasm/wasm.cpp33
-rw-r--r--src/wasm/wat-parser.cpp30
-rw-r--r--src/wasm2js.h16
19 files changed, 644 insertions, 139 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index 8ab31afb9..5fcbd3943 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -3128,78 +3128,113 @@ switch (op[0]) {
case 't': {
switch (op[3]) {
case 'i': {
- switch (op[7]) {
- case 'a': {
- switch (op[10]) {
+ switch (op[6]) {
+ case '.': {
+ switch (op[7]) {
+ case 'a': {
+ switch (op[10]) {
+ case 'i':
+ if (strcmp(op, "string.as_iter") == 0) { return makeStringAs(s, StringAsIter); }
+ goto parse_error;
+ case 'w': {
+ switch (op[13]) {
+ case '1':
+ if (strcmp(op, "string.as_wtf16") == 0) { return makeStringAs(s, StringAsWTF16); }
+ goto parse_error;
+ case '8':
+ if (strcmp(op, "string.as_wtf8") == 0) { return makeStringAs(s, StringAsWTF8); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ default: goto parse_error;
+ }
+ }
+ case 'c': {
+ switch (op[10]) {
+ case 'c':
+ if (strcmp(op, "string.concat") == 0) { return makeStringConcat(s); }
+ goto parse_error;
+ case 's':
+ if (strcmp(op, "string.const") == 0) { return makeStringConst(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'e': {
+ 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;
+ default: goto parse_error;
+ }
+ }
+ case 'q':
+ if (strcmp(op, "string.eq") == 0) { return makeStringEq(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
case 'i':
- if (strcmp(op, "string.as_iter") == 0) { return makeStringAs(s, StringAsIter); }
+ if (strcmp(op, "string.is_usv_sequence") == 0) { return makeStringMeasure(s, StringMeasureIsUSV); }
goto parse_error;
- case 'w': {
- switch (op[13]) {
+ case 'm': {
+ switch (op[18]) {
case '1':
- if (strcmp(op, "string.as_wtf16") == 0) { return makeStringAs(s, StringAsWTF16); }
+ if (strcmp(op, "string.measure_wtf16") == 0) { return makeStringMeasure(s, StringMeasureWTF16); }
goto parse_error;
case '8':
- if (strcmp(op, "string.as_wtf8") == 0) { return makeStringAs(s, StringAsWTF8); }
+ if (strcmp(op, "string.measure_wtf8") == 0) { return makeStringMeasure(s, StringMeasureWTF8); }
goto parse_error;
default: goto parse_error;
}
}
- default: goto parse_error;
- }
- }
- case 'c': {
- switch (op[10]) {
- case 'c':
- if (strcmp(op, "string.concat") == 0) { return makeStringConcat(s); }
- goto parse_error;
- case 's':
- if (strcmp(op, "string.const") == 0) { return makeStringConst(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'e': {
- switch (op[8]) {
case 'n': {
- switch (op[17]) {
+ switch (op[14]) {
case '1':
- if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
+ if (strcmp(op, "string.new_wtf16") == 0) { return makeStringNew(s, StringNewWTF16); }
goto parse_error;
case '8':
- if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
+ if (strcmp(op, "string.new_wtf8") == 0) { return makeStringNew(s, StringNewWTF8); }
goto parse_error;
default: goto parse_error;
}
}
- case 'q':
- if (strcmp(op, "string.eq") == 0) { return makeStringEq(s); }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'i':
- if (strcmp(op, "string.is_usv_sequence") == 0) { return makeStringMeasure(s, StringMeasureIsUSV); }
- goto parse_error;
- case 'm': {
- switch (op[18]) {
- case '1':
- if (strcmp(op, "string.measure_wtf16") == 0) { return makeStringMeasure(s, StringMeasureWTF16); }
- goto parse_error;
- case '8':
- if (strcmp(op, "string.measure_wtf8") == 0) { return makeStringMeasure(s, StringMeasureWTF8); }
- goto parse_error;
default: goto parse_error;
}
}
- case 'n': {
- switch (op[14]) {
- case '1':
- if (strcmp(op, "string.new_wtf16") == 0) { return makeStringNew(s, StringNewWTF16); }
- goto parse_error;
- case '8':
- if (strcmp(op, "string.new_wtf8") == 0) { return makeStringNew(s, StringNewWTF8); }
- goto parse_error;
+ case 'v': {
+ switch (op[11]) {
+ case 'i': {
+ switch (op[16]) {
+ case 'a':
+ if (strcmp(op, "stringview_iter.advance") == 0) { return makeStringIterMove(s, StringIterMoveAdvance); }
+ goto parse_error;
+ case 'n':
+ if (strcmp(op, "stringview_iter.next") == 0) { return makeStringIterNext(s); }
+ goto parse_error;
+ case 'r':
+ if (strcmp(op, "stringview_iter.rewind") == 0) { return makeStringIterMove(s, StringIterMoveRewind); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'w': {
+ switch (op[14]) {
+ case '1':
+ if (strcmp(op, "stringview_wtf16.get_codeunit") == 0) { return makeStringWTF16Get(s); }
+ goto parse_error;
+ case '8':
+ if (strcmp(op, "stringview_wtf8.advance") == 0) { return makeStringWTF8Advance(s); }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
@@ -8749,28 +8784,109 @@ switch (op[0]) {
case 't': {
switch (op[3]) {
case 'i': {
- switch (op[7]) {
- case 'a': {
- switch (op[10]) {
+ switch (op[6]) {
+ case '.': {
+ switch (op[7]) {
+ case 'a': {
+ switch (op[10]) {
+ case 'i':
+ if (op == "string.as_iter"sv) {
+ auto ret = makeStringAs(ctx, in, StringAsIter);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'w': {
+ switch (op[13]) {
+ case '1':
+ if (op == "string.as_wtf16"sv) {
+ auto ret = makeStringAs(ctx, in, StringAsWTF16);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case '8':
+ if (op == "string.as_wtf8"sv) {
+ auto ret = makeStringAs(ctx, in, StringAsWTF8);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ default: goto parse_error;
+ }
+ }
+ case 'c': {
+ switch (op[10]) {
+ case 'c':
+ if (op == "string.concat"sv) {
+ auto ret = makeStringConcat(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 's':
+ if (op == "string.const"sv) {
+ auto ret = makeStringConst(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'e': {
+ 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;
+ }
+ goto parse_error;
+ case '8':
+ if (op == "string.encode_wtf8"sv) {
+ auto ret = makeStringEncode(ctx, in, StringEncodeWTF8);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ case 'q':
+ if (op == "string.eq"sv) {
+ auto ret = makeStringEq(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
case 'i':
- if (op == "string.as_iter"sv) {
- auto ret = makeStringAs(ctx, in, StringAsIter);
+ if (op == "string.is_usv_sequence"sv) {
+ auto ret = makeStringMeasure(ctx, in, StringMeasureIsUSV);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
- case 'w': {
- switch (op[13]) {
+ case 'm': {
+ switch (op[18]) {
case '1':
- if (op == "string.as_wtf16"sv) {
- auto ret = makeStringAs(ctx, in, StringAsWTF16);
+ if (op == "string.measure_wtf16"sv) {
+ auto ret = makeStringMeasure(ctx, in, StringMeasureWTF16);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case '8':
- if (op == "string.as_wtf8"sv) {
- auto ret = makeStringAs(ctx, in, StringAsWTF8);
+ if (op == "string.measure_wtf8"sv) {
+ auto ret = makeStringMeasure(ctx, in, StringMeasureWTF8);
CHECK_ERR(ret);
return *ret;
}
@@ -8778,42 +8894,18 @@ switch (op[0]) {
default: goto parse_error;
}
}
- default: goto parse_error;
- }
- }
- case 'c': {
- switch (op[10]) {
- case 'c':
- if (op == "string.concat"sv) {
- auto ret = makeStringConcat(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 's':
- if (op == "string.const"sv) {
- auto ret = makeStringConst(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'e': {
- switch (op[8]) {
case 'n': {
- switch (op[17]) {
+ switch (op[14]) {
case '1':
- if (op == "string.encode_wtf16"sv) {
- auto ret = makeStringEncode(ctx, in, StringEncodeWTF16);
+ if (op == "string.new_wtf16"sv) {
+ auto ret = makeStringNew(ctx, in, StringNewWTF16);
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case '8':
- if (op == "string.encode_wtf8"sv) {
- auto ret = makeStringEncode(ctx, in, StringEncodeWTF8);
+ if (op == "string.new_wtf8"sv) {
+ auto ret = makeStringNew(ctx, in, StringNewWTF8);
CHECK_ERR(ret);
return *ret;
}
@@ -8821,58 +8913,56 @@ switch (op[0]) {
default: goto parse_error;
}
}
- case 'q':
- if (op == "string.eq"sv) {
- auto ret = makeStringEq(ctx, in);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
default: goto parse_error;
}
}
- case 'i':
- if (op == "string.is_usv_sequence"sv) {
- auto ret = makeStringMeasure(ctx, in, StringMeasureIsUSV);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case 'm': {
- switch (op[18]) {
- case '1':
- if (op == "string.measure_wtf16"sv) {
- auto ret = makeStringMeasure(ctx, in, StringMeasureWTF16);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- case '8':
- if (op == "string.measure_wtf8"sv) {
- auto ret = makeStringMeasure(ctx, in, StringMeasureWTF8);
- CHECK_ERR(ret);
- return *ret;
- }
- goto parse_error;
- default: goto parse_error;
- }
- }
- case 'n': {
- switch (op[14]) {
- case '1':
- if (op == "string.new_wtf16"sv) {
- auto ret = makeStringNew(ctx, in, StringNewWTF16);
- CHECK_ERR(ret);
- return *ret;
+ case 'v': {
+ switch (op[11]) {
+ case 'i': {
+ switch (op[16]) {
+ case 'a':
+ if (op == "stringview_iter.advance"sv) {
+ auto ret = makeStringIterMove(ctx, in, StringIterMoveAdvance);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'n':
+ if (op == "stringview_iter.next"sv) {
+ auto ret = makeStringIterNext(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case 'r':
+ if (op == "stringview_iter.rewind"sv) {
+ auto ret = makeStringIterMove(ctx, in, StringIterMoveRewind);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
}
- goto parse_error;
- case '8':
- if (op == "string.new_wtf8"sv) {
- auto ret = makeStringNew(ctx, in, StringNewWTF8);
- CHECK_ERR(ret);
- return *ret;
+ }
+ case 'w': {
+ switch (op[14]) {
+ case '1':
+ if (op == "stringview_wtf16.get_codeunit"sv) {
+ auto ret = makeStringWTF16Get(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ case '8':
+ if (op == "stringview_wtf8.advance"sv) {
+ auto ret = makeStringWTF8Advance(ctx, in);
+ CHECK_ERR(ret);
+ return *ret;
+ }
+ goto parse_error;
+ default: goto parse_error;
}
- goto parse_error;
+ }
default: goto parse_error;
}
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index bdb04f2b4..2c3b6c1f0 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -179,6 +179,12 @@ void ReFinalize::visitStringEncode(StringEncode* curr) { curr->finalize(); }
void ReFinalize::visitStringConcat(StringConcat* curr) { curr->finalize(); }
void ReFinalize::visitStringEq(StringEq* curr) { curr->finalize(); }
void ReFinalize::visitStringAs(StringAs* curr) { curr->finalize(); }
+void ReFinalize::visitStringWTF8Advance(StringWTF8Advance* curr) {
+ curr->finalize();
+}
+void ReFinalize::visitStringWTF16Get(StringWTF16Get* curr) { curr->finalize(); }
+void ReFinalize::visitStringIterNext(StringIterNext* curr) { curr->finalize(); }
+void ReFinalize::visitStringIterMove(StringIterMove* curr) { curr->finalize(); }
void ReFinalize::visitFunction(Function* curr) {
// we may have changed the body from unreachable to none, which might be bad
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 6a508db2d..3ed37e297 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -689,6 +689,18 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 3 + visit(curr->left) + visit(curr->right);
}
CostType visitStringAs(StringAs* curr) { return 4 + visit(curr->ref); }
+ CostType visitStringWTF8Advance(StringWTF8Advance* curr) {
+ return 4 + visit(curr->ref) + visit(curr->pos) + visit(curr->bytes);
+ }
+ CostType visitStringWTF16Get(StringWTF16Get* curr) {
+ return 1 + visit(curr->ref) + visit(curr->pos);
+ }
+ CostType visitStringIterNext(StringIterNext* curr) {
+ return 2 + visit(curr->ref);
+ }
+ CostType visitStringIterMove(StringIterMove* curr) {
+ return 4 + visit(curr->ref) + visit(curr->num);
+ }
private:
CostType nullCheckCost(Expression* ref) {
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 393285924..7045d9382 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -751,6 +751,32 @@ private:
// traps when ref is null.
parent.implicitTrap = true;
}
+ void visitStringWTF8Advance(StringWTF8Advance* curr) {
+ // traps when ref is null.
+ parent.implicitTrap = true;
+ }
+ void visitStringWTF16Get(StringWTF16Get* curr) {
+ // traps when ref is null.
+ parent.implicitTrap = true;
+ }
+ void visitStringIterNext(StringIterNext* curr) {
+ // traps when ref is null.
+ parent.implicitTrap = true;
+ // modifies state in the iterator. we model that as accessing heap memory
+ // in an array atm TODO consider adding a new effect type for this (we
+ // added one for arrays because struct/array operations often interleave,
+ // say with vtable accesses, but it's not clear adding overhead to this
+ // class is worth it for string iters)
+ parent.readsArray = true;
+ parent.writesArray = true;
+ }
+ void visitStringIterMove(StringIterMove* curr) {
+ // traps when ref is null.
+ parent.implicitTrap = true;
+ // see StringIterNext.
+ parent.readsArray = true;
+ parent.writesArray = true;
+ }
};
public:
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index f2839347d..35a855614 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -701,6 +701,22 @@ struct InfoCollector
// TODO: optimize when possible
addRoot(curr);
}
+ void visitStringWTF8Advance(StringWTF8Advance* curr) {
+ // TODO: optimize when possible
+ addRoot(curr);
+ }
+ void visitStringWTF16Get(StringWTF16Get* curr) {
+ // TODO: optimize when possible
+ addRoot(curr);
+ }
+ void visitStringIterNext(StringIterNext* curr) {
+ // TODO: optimize when possible
+ addRoot(curr);
+ }
+ void visitStringIterMove(StringIterMove* curr) {
+ // TODO: optimize when possible
+ addRoot(curr);
+ }
// TODO: Model which throws can go to which catches. For now, anything thrown
// is sent to the location of that tag, and any catch of that tag can
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 781c72376..f41bdcd26 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2294,6 +2294,27 @@ struct PrintExpressionContents
WASM_UNREACHABLE("invalid string.as*");
}
}
+ void visitStringWTF8Advance(StringWTF8Advance* curr) {
+ printMedium(o, "stringview_wtf8.advance");
+ }
+ void visitStringWTF16Get(StringWTF16Get* curr) {
+ printMedium(o, "stringview_wtf16.get_codeunit");
+ }
+ void visitStringIterNext(StringIterNext* curr) {
+ printMedium(o, "stringview_iter.next");
+ }
+ void visitStringIterMove(StringIterMove* curr) {
+ switch (curr->op) {
+ case StringIterMoveAdvance:
+ printMedium(o, "stringview_iter.advance");
+ break;
+ case StringIterMoveRewind:
+ printMedium(o, "stringview_iter.rewind");
+ break;
+ default:
+ WASM_UNREACHABLE("invalid string.move*");
+ }
+ }
};
// Prints an expression in s-expr format, including both the
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 8a03cb8af..9c5d6cd98 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1148,8 +1148,13 @@ enum ASTNodes {
StringEq = 0x89,
StringIsUSV = 0x8a,
StringAsWTF8 = 0x90,
+ StringViewWTF8Advance = 0x91,
StringAsWTF16 = 0x98,
+ StringViewWTF16GetCodePoint = 0x9a,
StringAsIter = 0xa0,
+ StringViewIterNext = 0xa1,
+ StringViewIterAdvance = 0xa2,
+ StringViewIterRewind = 0xa3,
};
enum MemoryAccess {
@@ -1737,6 +1742,10 @@ public:
bool maybeVisitStringConcat(Expression*& out, uint32_t code);
bool maybeVisitStringEq(Expression*& out, uint32_t code);
bool maybeVisitStringAs(Expression*& out, uint32_t code);
+ bool maybeVisitStringWTF8Advance(Expression*& out, uint32_t code);
+ bool maybeVisitStringWTF16Get(Expression*& out, uint32_t code);
+ bool maybeVisitStringIterNext(Expression*& out, uint32_t code);
+ bool maybeVisitStringIterMove(Expression*& out, uint32_t code);
void visitSelect(Select* curr, uint8_t code);
void visitReturn(Return* curr);
void visitMemorySize(MemorySize* curr);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 9fe039af1..f636ea799 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -1041,6 +1041,38 @@ public:
ret->finalize();
return ret;
}
+ StringWTF8Advance*
+ makeStringWTF8Advance(Expression* ref, Expression* pos, Expression* bytes) {
+ auto* ret = wasm.allocator.alloc<StringWTF8Advance>();
+ ret->ref = ref;
+ ret->pos = pos;
+ ret->bytes = bytes;
+ ret->finalize();
+ return ret;
+ }
+ StringWTF16Get* makeStringWTF16Get(Expression* ref, Expression* pos) {
+ auto* ret = wasm.allocator.alloc<StringWTF16Get>();
+ ret->ref = ref;
+ ret->pos = pos;
+ ret->finalize();
+ return ret;
+ }
+ StringIterNext* makeStringIterNext(Expression* ref) {
+ auto* ret = wasm.allocator.alloc<StringIterNext>();
+ ret->ref = ref;
+ ret->finalize();
+ return ret;
+ }
+ StringIterMove* makeStringIterMove(StringIterMoveOp op,
+ Expression* ref,
+ Expression* num = nullptr) {
+ auto* ret = wasm.allocator.alloc<StringIterMove>();
+ ret->op = op;
+ ret->ref = ref;
+ ret->num = num;
+ ret->finalize();
+ return ret;
+ }
// Additional helpers
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index 83483fbf4..d474f007e 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -763,6 +763,35 @@ switch (DELEGATE_ID) {
DELEGATE_END(StringAs);
break;
}
+ case Expression::Id::StringWTF8AdvanceId: {
+ DELEGATE_START(StringWTF8Advance);
+ DELEGATE_FIELD_CHILD(StringWTF8Advance, bytes);
+ DELEGATE_FIELD_CHILD(StringWTF8Advance, pos);
+ DELEGATE_FIELD_CHILD(StringWTF8Advance, ref);
+ DELEGATE_END(StringWTF8Advance);
+ break;
+ }
+ case Expression::Id::StringWTF16GetId: {
+ DELEGATE_START(StringWTF16Get);
+ DELEGATE_FIELD_CHILD(StringWTF16Get, pos);
+ DELEGATE_FIELD_CHILD(StringWTF16Get, ref);
+ DELEGATE_END(StringWTF16Get);
+ break;
+ }
+ case Expression::Id::StringIterNextId: {
+ DELEGATE_START(StringIterNext);
+ DELEGATE_FIELD_CHILD(StringIterNext, ref);
+ DELEGATE_END(StringIterNext);
+ break;
+ }
+ case Expression::Id::StringIterMoveId: {
+ DELEGATE_START(StringIterMove);
+ DELEGATE_FIELD_INT(StringIterMove, op);
+ DELEGATE_FIELD_CHILD(StringIterMove, num);
+ DELEGATE_FIELD_CHILD(StringIterMove, ref);
+ DELEGATE_END(StringIterMove);
+ break;
+ }
}
#undef DELEGATE_ID
diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def
index ed4f056c5..5b508f080 100644
--- a/src/wasm-delegations.def
+++ b/src/wasm-delegations.def
@@ -92,5 +92,9 @@ DELEGATE(StringEncode);
DELEGATE(StringConcat);
DELEGATE(StringEq);
DELEGATE(StringAs);
+DELEGATE(StringWTF8Advance);
+DELEGATE(StringWTF16Get);
+DELEGATE(StringIterNext);
+DELEGATE(StringIterMove);
#undef DELEGATE
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 6921220c2..a07103dca 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1976,6 +1976,18 @@ public:
Flow visitStringAs(StringAs* curr) {
WASM_UNREACHABLE("unimplemented string.as");
}
+ Flow visitStringWTF8Advance(StringWTF8Advance* curr) {
+ WASM_UNREACHABLE("unimplemented stringview_adjust*");
+ }
+ Flow visitStringWTF16Get(StringWTF16Get* curr) {
+ WASM_UNREACHABLE("unimplemented stringview_adjust*");
+ }
+ Flow visitStringIterNext(StringIterNext* curr) {
+ WASM_UNREACHABLE("unimplemented stringview_adjust*");
+ }
+ Flow visitStringIterMove(StringIterMove* curr) {
+ WASM_UNREACHABLE("unimplemented stringview_adjust*");
+ }
virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index c85b8875c..6b2ddd711 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -310,6 +310,10 @@ private:
Expression* makeStringConcat(Element& s);
Expression* makeStringEq(Element& s);
Expression* makeStringAs(Element& s, StringAsOp op);
+ Expression* makeStringWTF8Advance(Element& s);
+ Expression* makeStringWTF16Get(Element& s);
+ Expression* makeStringIterNext(Element& s);
+ Expression* makeStringIterMove(Element& s, StringIterMoveOp op);
// Helper functions
Type parseOptionalResultType(Element& s, Index& i);
diff --git a/src/wasm.h b/src/wasm.h
index 41fffb2e9..5bfd151a1 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -609,6 +609,11 @@ enum StringAsOp {
StringAsIter,
};
+enum StringIterMoveOp {
+ StringIterMoveAdvance,
+ StringIterMoveRewind,
+};
+
//
// Expressions
//
@@ -711,6 +716,10 @@ public:
StringConcatId,
StringEqId,
StringAsId,
+ StringWTF8AdvanceId,
+ StringWTF16GetId,
+ StringIterNextId,
+ StringIterMoveId,
NumExpressionIds
};
Id _id;
@@ -1755,6 +1764,52 @@ public:
void finalize();
};
+class StringWTF8Advance
+ : public SpecificExpression<Expression::StringWTF8AdvanceId> {
+public:
+ StringWTF8Advance(MixedArena& allocator) {}
+
+ Expression* ref;
+ Expression* pos;
+ Expression* bytes;
+
+ void finalize();
+};
+
+class StringWTF16Get : public SpecificExpression<Expression::StringWTF16GetId> {
+public:
+ StringWTF16Get(MixedArena& allocator) {}
+
+ Expression* ref;
+ Expression* pos;
+
+ void finalize();
+};
+
+class StringIterNext : public SpecificExpression<Expression::StringIterNextId> {
+public:
+ StringIterNext(MixedArena& allocator) {}
+
+ Expression* ref;
+
+ void finalize();
+};
+
+class StringIterMove : public SpecificExpression<Expression::StringIterMoveId> {
+public:
+ StringIterMove(MixedArena& allocator) {}
+
+ // Whether the movement is to advance or reverse.
+ StringIterMoveOp op;
+
+ Expression* ref;
+
+ // How many codepoints to advance or reverse.
+ Expression* num;
+
+ void finalize();
+};
+
// Globals
struct Named {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index ee1f4929b..e61fd1e27 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -3939,6 +3939,18 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitStringAs(curr, opcode)) {
break;
}
+ if (maybeVisitStringWTF8Advance(curr, opcode)) {
+ break;
+ }
+ if (maybeVisitStringWTF16Get(curr, opcode)) {
+ break;
+ }
+ if (maybeVisitStringIterNext(curr, opcode)) {
+ break;
+ }
+ if (maybeVisitStringIterMove(curr, opcode)) {
+ break;
+ }
if (opcode == BinaryConsts::RefIsFunc ||
opcode == BinaryConsts::RefIsData ||
opcode == BinaryConsts::RefIsI31) {
@@ -7268,6 +7280,55 @@ bool WasmBinaryBuilder::maybeVisitStringAs(Expression*& out, uint32_t code) {
return true;
}
+bool WasmBinaryBuilder::maybeVisitStringWTF8Advance(Expression*& out,
+ uint32_t code) {
+ if (code != BinaryConsts::StringViewWTF8Advance) {
+ return false;
+ }
+ auto* bytes = popNonVoidExpression();
+ auto* pos = popNonVoidExpression();
+ auto* ref = popNonVoidExpression();
+ out = Builder(wasm).makeStringWTF8Advance(ref, pos, bytes);
+ return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStringWTF16Get(Expression*& out,
+ uint32_t code) {
+ if (code != BinaryConsts::StringViewWTF16GetCodePoint) {
+ return false;
+ }
+ auto* pos = popNonVoidExpression();
+ auto* ref = popNonVoidExpression();
+ out = Builder(wasm).makeStringWTF16Get(ref, pos);
+ return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStringIterNext(Expression*& out,
+ uint32_t code) {
+ if (code != BinaryConsts::StringViewIterNext) {
+ return false;
+ }
+ auto* ref = popNonVoidExpression();
+ out = Builder(wasm).makeStringIterNext(ref);
+ return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitStringIterMove(Expression*& out,
+ uint32_t code) {
+ StringIterMoveOp op;
+ if (code == BinaryConsts::StringViewIterAdvance) {
+ op = StringIterMoveAdvance;
+ } else if (code == BinaryConsts::StringViewIterRewind) {
+ op = StringIterMoveRewind;
+ } else {
+ return false;
+ }
+ auto* num = popNonVoidExpression();
+ auto* ref = popNonVoidExpression();
+ out = Builder(wasm).makeStringIterMove(op, ref, num);
+ return true;
+}
+
void WasmBinaryBuilder::visitRefAs(RefAs* curr, uint8_t code) {
BYN_TRACE("zz node: RefAs\n");
switch (code) {
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index b3779e5e5..905c77523 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -3004,6 +3004,26 @@ Expression* SExpressionWasmBuilder::makeStringAs(Element& s, StringAsOp op) {
return Builder(wasm).makeStringAs(op, parseExpression(s[1]));
}
+Expression* SExpressionWasmBuilder::makeStringWTF8Advance(Element& s) {
+ return Builder(wasm).makeStringWTF8Advance(
+ parseExpression(s[1]), parseExpression(s[2]), parseExpression(s[3]));
+}
+
+Expression* SExpressionWasmBuilder::makeStringWTF16Get(Element& s) {
+ return Builder(wasm).makeStringWTF16Get(parseExpression(s[1]),
+ parseExpression(s[2]));
+}
+
+Expression* SExpressionWasmBuilder::makeStringIterNext(Element& s) {
+ return Builder(wasm).makeStringIterNext(parseExpression(s[1]));
+}
+
+Expression* SExpressionWasmBuilder::makeStringIterMove(Element& s,
+ StringIterMoveOp op) {
+ return Builder(wasm).makeStringIterMove(
+ op, parseExpression(s[1]), parseExpression(s[2]));
+}
+
// converts an s-expression string representing binary data into an output
// sequence of raw bytes this appends to data, which may already contain
// content.
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 9c1933067..731f47568 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2328,6 +2328,35 @@ void BinaryInstWriter::visitStringAs(StringAs* curr) {
}
}
+void BinaryInstWriter::visitStringWTF8Advance(StringWTF8Advance* curr) {
+ o << int8_t(BinaryConsts::GCPrefix)
+ << U32LEB(BinaryConsts::StringViewWTF8Advance);
+}
+
+void BinaryInstWriter::visitStringWTF16Get(StringWTF16Get* curr) {
+ o << int8_t(BinaryConsts::GCPrefix)
+ << U32LEB(BinaryConsts::StringViewWTF16GetCodePoint);
+}
+
+void BinaryInstWriter::visitStringIterNext(StringIterNext* curr) {
+ o << int8_t(BinaryConsts::GCPrefix)
+ << U32LEB(BinaryConsts::StringViewIterNext);
+}
+
+void BinaryInstWriter::visitStringIterMove(StringIterMove* curr) {
+ o << int8_t(BinaryConsts::GCPrefix);
+ switch (curr->op) {
+ case StringIterMoveAdvance:
+ o << U32LEB(BinaryConsts::StringViewIterAdvance);
+ break;
+ case StringIterMoveRewind:
+ o << U32LEB(BinaryConsts::StringViewIterRewind);
+ break;
+ default:
+ WASM_UNREACHABLE("invalid string.move*");
+ }
+}
+
void BinaryInstWriter::emitScopeEnd(Expression* curr) {
assert(!breakStack.empty());
breakStack.pop_back();
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 6568c907e..c4a5f362a 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1236,6 +1236,39 @@ void StringAs::finalize() {
}
}
+void StringWTF8Advance::finalize() {
+ if (ref->type == Type::unreachable || pos->type == Type::unreachable ||
+ bytes->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::i32;
+ }
+}
+
+void StringWTF16Get::finalize() {
+ if (ref->type == Type::unreachable || pos->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::i32;
+ }
+}
+
+void StringIterNext::finalize() {
+ if (ref->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::i32;
+ }
+}
+
+void StringIterMove::finalize() {
+ if (ref->type == Type::unreachable || num->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::i32;
+ }
+}
+
size_t Function::getNumParams() { return getParams().size(); }
size_t Function::getNumVars() { return vars.size(); }
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index c6c07bb8f..07503974d 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -1018,6 +1018,15 @@ template<typename Ctx>
Result<typename Ctx::InstrT> makeStringEq(Ctx&, ParseInput&);
template<typename Ctx>
Result<typename Ctx::InstrT> makeStringAs(Ctx&, ParseInput&, StringAsOp op);
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringWTF8Advance(Ctx&, ParseInput&);
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringWTF16Get(Ctx&, ParseInput&);
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringIterNext(Ctx&, ParseInput&);
+template<typename Ctx>
+Result<typename Ctx::InstrT>
+makeStringIterMove(Ctx&, ParseInput&, StringIterMoveOp op);
// Modules
template<typename Ctx>
@@ -1894,6 +1903,27 @@ makeStringAs(Ctx& ctx, ParseInput& in, StringAsOp op) {
return in.err("unimplemented instruction");
}
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringWTF8Advance(Ctx& ctx, ParseInput& in) {
+ return in.err("unimplemented instruction");
+}
+
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringWTF16Get(Ctx& ctx, ParseInput& in) {
+ return in.err("unimplemented instruction");
+}
+
+template<typename Ctx>
+Result<typename Ctx::InstrT> makeStringIterNext(Ctx& ctx, ParseInput& in) {
+ return in.err("unimplemented instruction");
+}
+
+template<typename Ctx>
+Result<typename Ctx::InstrT>
+makeStringIterMove(Ctx& ctx, ParseInput& in, StringIterMoveOp op) {
+ return in.err("unimplemented instruction");
+}
+
// =======
// Modules
// =======
diff --git a/src/wasm2js.h b/src/wasm2js.h
index ba6832540..7762f525a 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -2331,6 +2331,22 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
+ Ref visitStringWTF8Advance(StringWTF8Advance* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE("unimp");
+ }
+ Ref visitStringWTF16Get(StringWTF16Get* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE("unimp");
+ }
+ Ref visitStringIterNext(StringIterNext* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE("unimp");
+ }
+ Ref visitStringIterMove(StringIterMove* curr) {
+ unimplemented(curr);
+ WASM_UNREACHABLE("unimp");
+ }
Ref visitRefAs(RefAs* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");