[stringrefs] Implement string.concat

Bug: v8:12868
Change-Id: I7f5487dc01b006caef582f792e007d3a3cabb324
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3702435
Commit-Queue: Andy Wingo <wingo@igalia.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81151}
This commit is contained in:
Andy Wingo 2022-06-14 08:37:22 +02:00 committed by V8 LUCI CQ
parent 2eea0da9f1
commit 163ed720c7
7 changed files with 83 additions and 2 deletions

View File

@ -829,6 +829,10 @@ builtin WasmStringEncodeWtf16(
LoadContextFromInstance(instance), instance, memory, string,
WasmUint32ToNumber(offset), SmiConstant(0), SmiFromInt32(string.length));
}
builtin WasmStringConcat(a: String, b: String): String {
const context = LoadContextFromFrame();
return a + b;
}
transitioning builtin WasmStringViewWtf16GetCodeUnit(
string: String, offset: uint32): uint32 {
try {

View File

@ -5809,6 +5809,15 @@ Node* WasmGraphBuilder::StringEncodeWtf16(uint32_t memory, Node* string,
string, offset, gasm_->SmiConstant(memory));
}
Node* WasmGraphBuilder::StringConcat(Node* head, CheckForNull head_null_check,
Node* tail, CheckForNull tail_null_check,
wasm::WasmCodePosition position) {
if (head_null_check == kWithNullCheck) head = AssertNotNull(head, position);
if (tail_null_check == kWithNullCheck) tail = AssertNotNull(tail, position);
return gasm_->CallBuiltin(Builtin::kWasmStringConcat, Operator::kNoDeopt,
head, tail);
}
Node* WasmGraphBuilder::StringViewWtf16GetCodeUnit(
Node* string, CheckForNull null_check, Node* offset,
wasm::WasmCodePosition position) {

View File

@ -553,6 +553,9 @@ class WasmGraphBuilder {
Node* StringEncodeWtf16(uint32_t memory, Node* string,
CheckForNull null_check, Node* offset,
wasm::WasmCodePosition position);
Node* StringConcat(Node* head, CheckForNull head_null_check, Node* tail,
CheckForNull tail_null_check,
wasm::WasmCodePosition position);
Node* StringViewWtf16GetCodeUnit(Node* string, CheckForNull null_check,
Node* offset,
wasm::WasmCodePosition position);

View File

@ -6198,7 +6198,27 @@ class LiftoffCompiler {
void StringConcat(FullDecoder* decoder, const Value& head, const Value& tail,
Value* result) {
UNIMPLEMENTED();
LiftoffRegList pinned;
LiftoffRegister tail_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, tail_reg.gp(), pinned, tail.type);
LiftoffAssembler::VarState tail_var(kRef, tail_reg, 0);
LiftoffRegister head_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, head_reg.gp(), pinned, head.type);
LiftoffAssembler::VarState head_var(kRef, head_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringConcat,
MakeSig::Returns(kRef).Params(kRef, kRef),
{
head_var,
tail_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kRef, result_reg);
}
void StringEq(FullDecoder* decoder, const Value& a, const Value& b,

View File

@ -1448,7 +1448,9 @@ class WasmGraphBuildingInterface {
void StringConcat(FullDecoder* decoder, const Value& head, const Value& tail,
Value* result) {
UNIMPLEMENTED();
result->node =
builder_->StringConcat(head.node, NullCheckFor(head.type), tail.node,
NullCheckFor(tail.type), decoder->position());
}
void StringEq(FullDecoder* decoder, const Value& a, const Value& b,

View File

@ -130,6 +130,7 @@ struct WasmModule;
V(WasmStringMeasureWtf8) \
V(WasmStringEncodeWtf8) \
V(WasmStringEncodeWtf16) \
V(WasmStringConcat) \
V(WasmStringViewWtf16GetCodeUnit) \
V(WasmStringViewWtf16Encode) \
V(WasmStringViewWtf16Slice)

View File

@ -15,6 +15,8 @@ let kSig_w_wii = makeSig([kWasmStringRef, kWasmI32, kWasmI32],
let kSig_v_wi = makeSig([kWasmStringRef, kWasmI32], []);
let kSig_v_wiii = makeSig([kWasmStringRef, kWasmI32, kWasmI32, kWasmI32],
[]);
let kSig_w_ww = makeSig([kWasmStringRef, kWasmStringRef], [kWasmStringRef]);
let kSig_w_w = makeSig([kWasmStringRef], [kWasmStringRef]);
function encodeWtf8(str) {
// String iterator coalesces surrogate pairs.
@ -433,6 +435,46 @@ function HasIsolatedSurrogate(str) {
}
})();
(function TestStringConcat() {
let builder = new WasmModuleBuilder();
builder.addFunction("concat", kSig_w_ww)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kGCPrefix, kExprStringConcat
]);
builder.addFunction("concat_null_head", kSig_w_w)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
kExprLocalGet, 0,
kGCPrefix, kExprStringConcat
]);
builder.addFunction("concat_null_tail", kSig_w_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprRefNull, kStringRefCode,
kGCPrefix, kExprStringConcat
]);
let instance = builder.instantiate();
for (let head of interestingStrings) {
for (let tail of interestingStrings) {
assertEquals(head + tail, instance.exports.concat(head, tail));
}
}
assertThrows(() => instance.exports.concat_null_head("hey"),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.concat_null_tail("hey"),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
(function TestStringViewWtf16() {
let builder = new WasmModuleBuilder();