Commit 77425d0a authored by Andy Wingo's avatar Andy Wingo Committed by V8 LUCI CQ

[stringrefs] Implement stringview_iter.advance, stringview_iter.rewind

Bug: v8:12868
Change-Id: I2e4a1733876a817dca36e0134ba4b7549f0cf4b8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3757886
Commit-Queue: Andy Wingo <wingo@igalia.com>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81693}
parent 994b6414
...@@ -1091,4 +1091,46 @@ builtin WasmStringViewIterNext(view: WasmStringViewIter): int32 { ...@@ -1091,4 +1091,46 @@ builtin WasmStringViewIterNext(view: WasmStringViewIter): int32 {
view.offset = offset + 1; view.offset = offset + 1;
return Signed(Convert<uint32>(code)); return Signed(Convert<uint32>(code));
} }
builtin WasmStringViewIterAdvance(
view: WasmStringViewIter, codepoints: uint32): uint32 {
const string = view.string;
let offset = view.offset;
let advanced: uint32 = 0;
while (advanced < codepoints) {
if (offset == Unsigned(string.length)) break;
advanced = advanced + 1;
if (offset + 1 < Unsigned(string.length) &&
IsLeadSurrogate(StringCharCodeAt(string, Convert<uintptr>(offset))) &&
IsTrailSurrogate(
StringCharCodeAt(string, Convert<uintptr>(offset + 1)))) {
offset = offset + 2;
} else {
offset = offset + 1;
}
}
view.offset = offset;
return advanced;
}
builtin WasmStringViewIterRewind(
view: WasmStringViewIter, codepoints: uint32): uint32 {
const string = view.string;
let offset = view.offset;
let rewound: uint32 = 0;
if (string.length == 0) return 0;
while (rewound < codepoints) {
if (offset == 0) break;
rewound = rewound + 1;
if (offset >= 2 &&
IsTrailSurrogate(
StringCharCodeAt(string, Convert<uintptr>(offset - 1))) &&
IsLeadSurrogate(
StringCharCodeAt(string, Convert<uintptr>(offset - 2)))) {
offset = offset - 2;
} else {
offset = offset - 1;
}
}
view.offset = offset;
return rewound;
}
} }
...@@ -5987,6 +5987,26 @@ Node* WasmGraphBuilder::StringViewIterNext(Node* view, CheckForNull null_check, ...@@ -5987,6 +5987,26 @@ Node* WasmGraphBuilder::StringViewIterNext(Node* view, CheckForNull null_check,
Operator::kNoDeopt, view); Operator::kNoDeopt, view);
} }
Node* WasmGraphBuilder::StringViewIterAdvance(Node* view,
CheckForNull null_check,
Node* codepoints,
wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) view = AssertNotNull(view, position);
return gasm_->CallBuiltin(Builtin::kWasmStringViewIterAdvance,
Operator::kNoDeopt, view, codepoints);
}
Node* WasmGraphBuilder::StringViewIterRewind(Node* view,
CheckForNull null_check,
Node* codepoints,
wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) view = AssertNotNull(view, position);
return gasm_->CallBuiltin(Builtin::kWasmStringViewIterRewind,
Operator::kNoDeopt, view, codepoints);
}
// 1 bit V8 Smi tag, 31 bits V8 Smi shift, 1 bit i31ref high-bit truncation. // 1 bit V8 Smi tag, 31 bits V8 Smi shift, 1 bit i31ref high-bit truncation.
constexpr int kI31To32BitSmiShift = 33; constexpr int kI31To32BitSmiShift = 33;
......
...@@ -591,6 +591,11 @@ class WasmGraphBuilder { ...@@ -591,6 +591,11 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
Node* StringViewIterNext(Node* view, CheckForNull null_check, Node* StringViewIterNext(Node* view, CheckForNull null_check,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
Node* StringViewIterAdvance(Node* view, CheckForNull null_check,
Node* codepoints,
wasm::WasmCodePosition position);
Node* StringViewIterRewind(Node* view, CheckForNull null_check,
Node* codepoints, wasm::WasmCodePosition position);
Node* IsNull(Node* object); Node* IsNull(Node* object);
Node* TypeGuard(Node* value, wasm::ValueType type); Node* TypeGuard(Node* value, wasm::ValueType type);
......
...@@ -6868,12 +6868,52 @@ class LiftoffCompiler { ...@@ -6868,12 +6868,52 @@ class LiftoffCompiler {
void StringViewIterAdvance(FullDecoder* decoder, const Value& view, void StringViewIterAdvance(FullDecoder* decoder, const Value& view,
const Value& codepoints, Value* result) { const Value& codepoints, Value* result) {
UNIMPLEMENTED(); LiftoffRegList pinned;
LiftoffAssembler::VarState& codepoints_var =
__ cache_state()->stack_state.end()[-1];
LiftoffRegister view_reg = pinned.set(
__ LoadToRegister(__ cache_state()->stack_state.end()[-2], pinned));
MaybeEmitNullCheck(decoder, view_reg.gp(), pinned, view.type);
LiftoffAssembler::VarState view_var(kRef, view_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringViewIterAdvance,
MakeSig::Returns(kI32).Params(kRef, kI32),
{
view_var,
codepoints_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kI32, result_reg);
} }
void StringViewIterRewind(FullDecoder* decoder, const Value& view, void StringViewIterRewind(FullDecoder* decoder, const Value& view,
const Value& codepoints, Value* result) { const Value& codepoints, Value* result) {
UNIMPLEMENTED(); LiftoffRegList pinned;
LiftoffAssembler::VarState& codepoints_var =
__ cache_state()->stack_state.end()[-1];
LiftoffRegister view_reg = pinned.set(
__ LoadToRegister(__ cache_state()->stack_state.end()[-2], pinned));
MaybeEmitNullCheck(decoder, view_reg.gp(), pinned, view.type);
LiftoffAssembler::VarState view_var(kRef, view_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringViewIterRewind,
MakeSig::Returns(kI32).Params(kRef, kI32),
{
view_var,
codepoints_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kI32, result_reg);
} }
void StringViewIterSlice(FullDecoder* decoder, const Value& view, void StringViewIterSlice(FullDecoder* decoder, const Value& view,
......
...@@ -1561,12 +1561,16 @@ class WasmGraphBuildingInterface { ...@@ -1561,12 +1561,16 @@ class WasmGraphBuildingInterface {
void StringViewIterAdvance(FullDecoder* decoder, const Value& view, void StringViewIterAdvance(FullDecoder* decoder, const Value& view,
const Value& codepoints, Value* result) { const Value& codepoints, Value* result) {
UNIMPLEMENTED(); result->node =
builder_->StringViewIterAdvance(view.node, NullCheckFor(view.type),
codepoints.node, decoder->position());
} }
void StringViewIterRewind(FullDecoder* decoder, const Value& view, void StringViewIterRewind(FullDecoder* decoder, const Value& view,
const Value& codepoints, Value* result) { const Value& codepoints, Value* result) {
UNIMPLEMENTED(); result->node =
builder_->StringViewIterRewind(view.node, NullCheckFor(view.type),
codepoints.node, decoder->position());
} }
void StringViewIterSlice(FullDecoder* decoder, const Value& view, void StringViewIterSlice(FullDecoder* decoder, const Value& view,
......
...@@ -145,7 +145,9 @@ struct WasmModule; ...@@ -145,7 +145,9 @@ struct WasmModule;
V(WasmStringViewWtf8Encode) \ V(WasmStringViewWtf8Encode) \
V(WasmStringViewWtf8Slice) \ V(WasmStringViewWtf8Slice) \
V(WasmStringAsIter) \ V(WasmStringAsIter) \
V(WasmStringViewIterNext) V(WasmStringViewIterNext) \
V(WasmStringViewIterAdvance) \
V(WasmStringViewIterRewind)
// Sorted, disjoint and non-overlapping memory regions. A region is of the // Sorted, disjoint and non-overlapping memory regions. A region is of the
// form [start, end). So there's no [start, end), [end, other_end), // form [start, end). So there's no [start, end), [end, other_end),
......
...@@ -1069,19 +1069,76 @@ function makeWtf16TestDataSegment() { ...@@ -1069,19 +1069,76 @@ function makeWtf16TestDataSegment() {
kGCPrefix, kExprStringViewIterNext kGCPrefix, kExprStringViewIterNext
]); ]);
builder.addFunction("advance", kSig_i_i)
.exportFunc()
.addBody([
kExprGlobalGet, global.index,
kExprLocalGet, 0,
kGCPrefix, kExprStringViewIterAdvance
]);
builder.addFunction("advance_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringViewIterCode,
kExprI32Const, 0,
kGCPrefix, kExprStringViewIterAdvance
]);
builder.addFunction("rewind", kSig_i_i)
.exportFunc()
.addBody([
kExprGlobalGet, global.index,
kExprLocalGet, 0,
kGCPrefix, kExprStringViewIterRewind
]);
builder.addFunction("rewind_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringViewIterCode,
kExprI32Const, 0,
kGCPrefix, kExprStringViewIterRewind
]);
let instance = builder.instantiate(); let instance = builder.instantiate();
for (let str of interestingStrings) { for (let str of interestingStrings) {
instance.exports.iterate(str); let codepoints = [];
for (let codepoint of str) { for (let codepoint of str) {
assertEquals(codepoint.codePointAt(0), instance.exports.next()); codepoints.push(codepoint.codePointAt(0));
}
instance.exports.iterate(str);
for (let codepoint of codepoints) {
assertEquals(codepoint, instance.exports.next());
} }
assertEquals(-1, instance.exports.next()); assertEquals(-1, instance.exports.next());
assertEquals(-1, instance.exports.next()); assertEquals(-1, instance.exports.next());
for (let i = 1; i <= codepoints.length; i++) {
assertEquals(i, instance.exports.rewind(i));
assertEquals(codepoints[codepoints.length - i], instance.exports.next());
assertEquals(i - 1, instance.exports.advance(-1));
}
for (let i = 0; i < codepoints.length; i++) {
instance.exports.rewind(-1);
assertEquals(i, instance.exports.advance(i));
assertEquals(codepoints[i], instance.exports.next());
}
assertEquals(codepoints.length, instance.exports.rewind(-1));
assertEquals(0, instance.exports.rewind(-1));
assertEquals(codepoints.length, instance.exports.advance(-1));
assertEquals(0, instance.exports.advance(-1));
} }
assertThrows(() => instance.exports.iterate_null(), assertThrows(() => instance.exports.iterate_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer"); WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.next_null(), assertThrows(() => instance.exports.next_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer"); WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.advance_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.rewind_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})(); })();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment