[stringrefs] Implement stringview_iter.slice
Feature complete! Bug: v8:12868 Change-Id: I7727071bdd062a6dae26206a65080f675ef7ee93 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3758226 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Andy Wingo <wingo@igalia.com> Cr-Commit-Position: refs/heads/main@{#81694}
This commit is contained in:
parent
77425d0a3e
commit
74289c46bb
@ -1133,4 +1133,25 @@ builtin WasmStringViewIterRewind(
|
||||
view.offset = offset;
|
||||
return rewound;
|
||||
}
|
||||
builtin WasmStringViewIterSlice(
|
||||
view: WasmStringViewIter, codepoints: uint32): String {
|
||||
const string = view.string;
|
||||
const start = view.offset;
|
||||
let end = view.offset;
|
||||
let advanced: uint32 = 0;
|
||||
while (advanced < codepoints) {
|
||||
if (end == Unsigned(string.length)) break;
|
||||
advanced = advanced + 1;
|
||||
if (end + 1 < Unsigned(string.length) &&
|
||||
IsLeadSurrogate(StringCharCodeAt(string, Convert<uintptr>(end))) &&
|
||||
IsTrailSurrogate(StringCharCodeAt(string, Convert<uintptr>(end + 1)))) {
|
||||
end = end + 2;
|
||||
} else {
|
||||
end = end + 1;
|
||||
}
|
||||
}
|
||||
return (start == end) ?
|
||||
kEmptyString :
|
||||
string::SubString(string, Convert<uintptr>(start), Convert<uintptr>(end));
|
||||
}
|
||||
}
|
||||
|
@ -6007,6 +6007,15 @@ Node* WasmGraphBuilder::StringViewIterRewind(Node* view,
|
||||
Operator::kNoDeopt, view, codepoints);
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::StringViewIterSlice(Node* view, CheckForNull null_check,
|
||||
Node* codepoints,
|
||||
wasm::WasmCodePosition position) {
|
||||
if (null_check == kWithNullCheck) view = AssertNotNull(view, position);
|
||||
|
||||
return gasm_->CallBuiltin(Builtin::kWasmStringViewIterSlice,
|
||||
Operator::kNoDeopt, view, codepoints);
|
||||
}
|
||||
|
||||
// 1 bit V8 Smi tag, 31 bits V8 Smi shift, 1 bit i31ref high-bit truncation.
|
||||
constexpr int kI31To32BitSmiShift = 33;
|
||||
|
||||
|
@ -596,6 +596,8 @@ class WasmGraphBuilder {
|
||||
wasm::WasmCodePosition position);
|
||||
Node* StringViewIterRewind(Node* view, CheckForNull null_check,
|
||||
Node* codepoints, wasm::WasmCodePosition position);
|
||||
Node* StringViewIterSlice(Node* view, CheckForNull null_check,
|
||||
Node* codepoints, wasm::WasmCodePosition position);
|
||||
Node* IsNull(Node* object);
|
||||
Node* TypeGuard(Node* value, wasm::ValueType type);
|
||||
|
||||
|
@ -6918,7 +6918,27 @@ class LiftoffCompiler {
|
||||
|
||||
void StringViewIterSlice(FullDecoder* decoder, const Value& view,
|
||||
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::kWasmStringViewIterSlice,
|
||||
MakeSig::Returns(kRef).Params(kRef, kI32),
|
||||
{
|
||||
view_var,
|
||||
codepoints_var,
|
||||
},
|
||||
decoder->position());
|
||||
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
|
||||
|
||||
LiftoffRegister result_reg(kReturnRegister0);
|
||||
__ PushRegister(kRef, result_reg);
|
||||
}
|
||||
|
||||
void Forward(FullDecoder* decoder, const Value& from, Value* to) {
|
||||
|
@ -1575,7 +1575,9 @@ class WasmGraphBuildingInterface {
|
||||
|
||||
void StringViewIterSlice(FullDecoder* decoder, const Value& view,
|
||||
const Value& codepoints, Value* result) {
|
||||
UNIMPLEMENTED();
|
||||
SetAndTypeNode(result, builder_->StringViewIterSlice(
|
||||
view.node, NullCheckFor(view.type),
|
||||
codepoints.node, decoder->position()));
|
||||
}
|
||||
|
||||
void Forward(FullDecoder* decoder, const Value& from, Value* to) {
|
||||
|
@ -147,7 +147,8 @@ struct WasmModule;
|
||||
V(WasmStringAsIter) \
|
||||
V(WasmStringViewIterNext) \
|
||||
V(WasmStringViewIterAdvance) \
|
||||
V(WasmStringViewIterRewind)
|
||||
V(WasmStringViewIterRewind) \
|
||||
V(WasmStringViewIterSlice)
|
||||
|
||||
// Sorted, disjoint and non-overlapping memory regions. A region is of the
|
||||
// form [start, end). So there's no [start, end), [end, other_end),
|
||||
|
@ -17,6 +17,7 @@ let kSig_i_wiii = makeSig([kWasmStringRef, kWasmI32, kWasmI32, kWasmI32],
|
||||
let kSig_ii_wiii = makeSig([kWasmStringRef, kWasmI32, kWasmI32, kWasmI32],
|
||||
[kWasmI32, kWasmI32]);
|
||||
let kSig_v_w = makeSig([kWasmStringRef], []);
|
||||
let kSig_w_i = makeSig([kWasmI32], [kWasmStringRef]);
|
||||
let kSig_w_wii = makeSig([kWasmStringRef, kWasmI32, kWasmI32],
|
||||
[kWasmStringRef]);
|
||||
let kSig_w_ww = makeSig([kWasmStringRef, kWasmStringRef], [kWasmStringRef]);
|
||||
@ -1101,6 +1102,22 @@ function makeWtf16TestDataSegment() {
|
||||
kGCPrefix, kExprStringViewIterRewind
|
||||
]);
|
||||
|
||||
builder.addFunction("slice", kSig_w_i)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, global.index,
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStringViewIterSlice
|
||||
]);
|
||||
|
||||
builder.addFunction("slice_null", kSig_w_i)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprRefNull, kStringViewIterCode,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprStringViewIterSlice
|
||||
]);
|
||||
|
||||
let instance = builder.instantiate();
|
||||
|
||||
for (let str of interestingStrings) {
|
||||
@ -1131,6 +1148,22 @@ function makeWtf16TestDataSegment() {
|
||||
assertEquals(0, instance.exports.rewind(-1));
|
||||
assertEquals(codepoints.length, instance.exports.advance(-1));
|
||||
assertEquals(0, instance.exports.advance(-1));
|
||||
|
||||
for (let start = 0; start <= codepoints.length; start++) {
|
||||
for (let end = start; end <= codepoints.length; end++) {
|
||||
let expected_slice =
|
||||
String.fromCodePoint(...codepoints.slice(start, end));
|
||||
instance.exports.iterate(str);
|
||||
assertEquals(start, instance.exports.advance(start));
|
||||
assertEquals(expected_slice, instance.exports.slice(end - start));
|
||||
}
|
||||
}
|
||||
instance.exports.iterate(str);
|
||||
assertEquals(str, instance.exports.slice(codepoints.length));
|
||||
assertEquals(str, instance.exports.slice(-1));
|
||||
assertEquals("", instance.exports.slice(0));
|
||||
assertEquals(codepoints.length, instance.exports.advance(-1));
|
||||
assertEquals("", instance.exports.slice(-1));
|
||||
}
|
||||
|
||||
assertThrows(() => instance.exports.iterate_null(),
|
||||
@ -1141,4 +1174,6 @@ function makeWtf16TestDataSegment() {
|
||||
WebAssembly.RuntimeError, "dereferencing a null pointer");
|
||||
assertThrows(() => instance.exports.rewind_null(),
|
||||
WebAssembly.RuntimeError, "dereferencing a null pointer");
|
||||
assertThrows(() => instance.exports.slice_null(),
|
||||
WebAssembly.RuntimeError, "dereferencing a null pointer");
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user