[stringrefs] Implement string.eq

Bug: v8:12868
Change-Id: I56ccab1a0cfacfae236c4f87c31a84d3afecafc8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3702437
Commit-Queue: Andy Wingo <wingo@igalia.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81153}
This commit is contained in:
Andy Wingo 2022-06-14 09:37:12 +02:00 committed by V8 LUCI CQ
parent 4ac5b2f6e0
commit 310fe8e61c
7 changed files with 91 additions and 2 deletions

View File

@ -833,6 +833,13 @@ builtin WasmStringConcat(a: String, b: String): String {
const context = LoadContextFromFrame();
return a + b;
}
builtin WasmStringEqual(a: String, b: String): int32 {
if (TaggedEqual(a, b)) return 1;
if (a.length != b.length) return 0;
const context = LoadContextFromFrame();
if (StringEqual(context, a, b) == True) return 1;
return 0;
}
transitioning builtin WasmStringViewWtf16GetCodeUnit(
string: String, offset: uint32): uint32 {
try {

View File

@ -5818,6 +5818,20 @@ Node* WasmGraphBuilder::StringConcat(Node* head, CheckForNull head_null_check,
head, tail);
}
Node* WasmGraphBuilder::StringEqual(Node* a, CheckForNull a_null_check, Node* b,
CheckForNull b_null_check,
wasm::WasmCodePosition position) {
if (a_null_check == kWithNullCheck) a = AssertNotNull(a, position);
if (b_null_check == kWithNullCheck) b = AssertNotNull(b, position);
auto done = gasm_->MakeLabel(MachineRepresentation::kWord32);
gasm_->GotoIf(gasm_->TaggedEqual(a, b), &done, Int32Constant(1));
gasm_->Goto(&done, gasm_->CallBuiltin(Builtin::kWasmStringEqual,
Operator::kNoDeopt, a, b));
gasm_->Bind(&done);
return done.PhiAt(0);
}
Node* WasmGraphBuilder::StringViewWtf16GetCodeUnit(
Node* string, CheckForNull null_check, Node* offset,
wasm::WasmCodePosition position) {

View File

@ -556,6 +556,8 @@ class WasmGraphBuilder {
Node* StringConcat(Node* head, CheckForNull head_null_check, Node* tail,
CheckForNull tail_null_check,
wasm::WasmCodePosition position);
Node* StringEqual(Node* a, CheckForNull a_null_check, Node* b,
CheckForNull b_null_check, wasm::WasmCodePosition position);
Node* StringViewWtf16GetCodeUnit(Node* string, CheckForNull null_check,
Node* offset,
wasm::WasmCodePosition position);

View File

@ -6223,7 +6223,27 @@ class LiftoffCompiler {
void StringEq(FullDecoder* decoder, const Value& a, const Value& b,
Value* result) {
UNIMPLEMENTED();
LiftoffRegList pinned;
LiftoffRegister b_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, b_reg.gp(), pinned, b.type);
LiftoffAssembler::VarState b_var(kRef, b_reg, 0);
LiftoffRegister a_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, a_reg.gp(), pinned, a.type);
LiftoffAssembler::VarState a_var(kRef, a_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringEqual,
MakeSig::Returns(kI32).Params(kRef, kRef),
{
a_var,
b_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kI32, result_reg);
}
void StringAsWtf8(FullDecoder* decoder, const Value& str, Value* result) {

View File

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

View File

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

View File

@ -10,6 +10,7 @@ let kSig_w_ii = makeSig([kWasmI32, kWasmI32], [kWasmStringRef]);
let kSig_w_v = makeSig([], [kWasmStringRef]);
let kSig_i_w = makeSig([kWasmStringRef], [kWasmI32]);
let kSig_i_wi = makeSig([kWasmStringRef, kWasmI32], [kWasmI32]);
let kSig_i_ww = makeSig([kWasmStringRef, kWasmStringRef], [kWasmI32]);
let kSig_w_wii = makeSig([kWasmStringRef, kWasmI32, kWasmI32],
[kWasmStringRef]);
let kSig_v_wi = makeSig([kWasmStringRef, kWasmI32], []);
@ -475,6 +476,48 @@ function HasIsolatedSurrogate(str) {
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
(function TestStringEq() {
let builder = new WasmModuleBuilder();
builder.addFunction("eq", kSig_i_ww)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kGCPrefix, kExprStringEq
]);
builder.addFunction("eq_null_a", kSig_i_w)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
kExprLocalGet, 0,
kGCPrefix, kExprStringEq
]);
builder.addFunction("eq_null_b", kSig_i_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprRefNull, kStringRefCode,
kGCPrefix, kExprStringEq
]);
let instance = builder.instantiate();
for (let head of interestingStrings) {
for (let tail of interestingStrings) {
let result = (head == tail)|0;
assertEquals(result, instance.exports.eq(head, tail));
assertEquals(result, instance.exports.eq(head + head, tail + tail));
}
}
assertThrows(() => instance.exports.eq_null_a("hey"),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.eq_null_b("hey"),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
(function TestStringViewWtf16() {
let builder = new WasmModuleBuilder();