diff options
author | Alon Zakai <azakai@google.com> | 2022-07-13 14:38:10 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-13 14:38:10 -0700 |
commit | 9671e95adbfcf0984a7e9800a7ea2ed33e1670ad (patch) | |
tree | d7273e64ed26429d18568439cdfb7b1fb6369645 /src | |
parent | 7b9c18b98c020f887aa9cb1750543751ebe5c530 (diff) | |
download | binaryen-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.inc | 368 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 6 | ||||
-rw-r--r-- | src/ir/cost.h | 12 | ||||
-rw-r--r-- | src/ir/effects.h | 26 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 16 | ||||
-rw-r--r-- | src/passes/Print.cpp | 21 | ||||
-rw-r--r-- | src/wasm-binary.h | 9 | ||||
-rw-r--r-- | src/wasm-builder.h | 32 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 29 | ||||
-rw-r--r-- | src/wasm-delegations.def | 4 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 12 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 4 | ||||
-rw-r--r-- | src/wasm.h | 55 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 61 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 20 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 29 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 33 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 30 | ||||
-rw-r--r-- | src/wasm2js.h | 16 |
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"); |