Commit 994b6414 authored by Andy Wingo's avatar Andy Wingo Committed by V8 LUCI CQ

[stringrefs] Implement string.as_iter, stringview_iter.next

Bug: v8:12868
Change-Id: Ice7134d0ad5efddb85420543ea785253791d0258
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3757885Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andy Wingo <wingo@igalia.com>
Cr-Commit-Position: refs/heads/main@{#81692}
parent b580e58f
......@@ -1052,4 +1052,43 @@ transitioning builtin WasmStringViewWtf16Slice(
const clampedEnd = Convert<uintptr>(end <= length ? end : length);
return string::SubString(string, Convert<uintptr>(start), clampedEnd);
}
builtin WasmStringAsIter(string: String): WasmStringViewIter {
return new WasmStringViewIter{string: string, offset: 0};
}
macro IsLeadSurrogate(code: char16): bool {
return (code & 0xfc00) == 0xd800;
}
macro IsTrailSurrogate(code: char16): bool {
return (code & 0xfc00) == 0xdc00;
}
macro CombineSurrogatePair(lead: char16, trail: char16): int32 {
const lead32 = Convert<uint32>(lead);
const trail32 = Convert<uint32>(trail);
// Surrogate pairs encode codepoints in the range
// [0x010000, 0x10FFFF]. Each surrogate has 10 bits of information in
// the low bits. We can combine them together with a shift-and-add,
// then add a bias of 0x010000 - 0xD800<<10 - 0xDC00 = 0xFCA02400.
const surrogateBias: uint32 = 0xFCA02400;
return Signed((lead32 << 10) + trail32 + surrogateBias);
}
builtin WasmStringViewIterNext(view: WasmStringViewIter): int32 {
const string = view.string;
const offset = view.offset;
if (offset >= Unsigned(string.length)) return -1;
const code: char16 = StringCharCodeAt(string, Convert<uintptr>(offset));
try {
if (IsLeadSurrogate(code) && offset + 1 < Unsigned(string.length)) {
goto CheckForSurrogatePair;
}
} label CheckForSurrogatePair deferred {
const code2: char16 =
StringCharCodeAt(string, Convert<uintptr>(offset + 1));
if (IsTrailSurrogate(code2)) {
view.offset = offset + 2;
return CombineSurrogatePair(code, code2);
}
}
view.offset = offset + 1;
return Signed(Convert<uint32>(code));
}
}
......@@ -5971,6 +5971,22 @@ Node* WasmGraphBuilder::StringViewWtf16Slice(Node* string,
Operator::kNoDeopt, string, start, end);
}
Node* WasmGraphBuilder::StringAsIter(Node* str, CheckForNull null_check,
wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) str = AssertNotNull(str, position);
return gasm_->CallBuiltin(Builtin::kWasmStringAsIter, Operator::kNoDeopt,
str);
}
Node* WasmGraphBuilder::StringViewIterNext(Node* view, CheckForNull null_check,
wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) view = AssertNotNull(view, position);
return gasm_->CallBuiltin(Builtin::kWasmStringViewIterNext,
Operator::kNoDeopt, view);
}
// 1 bit V8 Smi tag, 31 bits V8 Smi shift, 1 bit i31ref high-bit truncation.
constexpr int kI31To32BitSmiShift = 33;
......
......@@ -587,6 +587,10 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* StringViewWtf16Slice(Node* string, CheckForNull null_check, Node* start,
Node* end, wasm::WasmCodePosition position);
Node* StringAsIter(Node* str, CheckForNull null_check,
wasm::WasmCodePosition position);
Node* StringViewIterNext(Node* view, CheckForNull null_check,
wasm::WasmCodePosition position);
Node* IsNull(Node* object);
Node* TypeGuard(Node* value, wasm::ValueType type);
......
......@@ -6828,12 +6828,42 @@ class LiftoffCompiler {
}
void StringAsIter(FullDecoder* decoder, const Value& str, Value* result) {
UNIMPLEMENTED();
LiftoffRegList pinned;
LiftoffRegister str_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, str_reg.gp(), pinned, str.type);
LiftoffAssembler::VarState str_var(kRef, str_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringAsIter,
MakeSig::Returns(kRef).Params(kRef),
{
str_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kRef, result_reg);
}
void StringViewIterNext(FullDecoder* decoder, const Value& view,
Value* result) {
UNIMPLEMENTED();
LiftoffRegList pinned;
LiftoffRegister view_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, view_reg.gp(), pinned, view.type);
LiftoffAssembler::VarState view_var(kRef, view_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringViewIterNext,
MakeSig::Returns(kI32).Params(kRef),
{
view_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kI32, result_reg);
}
void StringViewIterAdvance(FullDecoder* decoder, const Value& view,
......
......@@ -1548,12 +1548,15 @@ class WasmGraphBuildingInterface {
}
void StringAsIter(FullDecoder* decoder, const Value& str, Value* result) {
UNIMPLEMENTED();
SetAndTypeNode(result,
builder_->StringAsIter(str.node, NullCheckFor(str.type),
decoder->position()));
}
void StringViewIterNext(FullDecoder* decoder, const Value& view,
Value* result) {
UNIMPLEMENTED();
result->node = builder_->StringViewIterNext(
view.node, NullCheckFor(view.type), decoder->position());
}
void StringViewIterAdvance(FullDecoder* decoder, const Value& view,
......
......@@ -143,7 +143,9 @@ struct WasmModule;
V(WasmStringAsWtf8) \
V(WasmStringViewWtf8Advance) \
V(WasmStringViewWtf8Encode) \
V(WasmStringViewWtf8Slice)
V(WasmStringViewWtf8Slice) \
V(WasmStringAsIter) \
V(WasmStringViewIterNext)
// Sorted, disjoint and non-overlapping memory regions. A region is of the
// form [start, end). So there's no [start, end), [end, other_end),
......
......@@ -206,3 +206,8 @@ extern class WasmArray extends WasmObject {
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
}
class WasmStringViewIter extends HeapObject {
string: String;
offset: uint32; // Index into string.
}
......@@ -16,6 +16,7 @@ let kSig_i_wiii = makeSig([kWasmStringRef, kWasmI32, kWasmI32, kWasmI32],
[kWasmI32]);
let kSig_ii_wiii = makeSig([kWasmStringRef, kWasmI32, kWasmI32, kWasmI32],
[kWasmI32, kWasmI32]);
let kSig_v_w = makeSig([kWasmStringRef], []);
let kSig_w_wii = makeSig([kWasmStringRef, kWasmI32, kWasmI32],
[kWasmStringRef]);
let kSig_w_ww = makeSig([kWasmStringRef, kWasmStringRef], [kWasmStringRef]);
......@@ -1032,3 +1033,55 @@ function makeWtf16TestDataSegment() {
assertThrows(() => instance.exports.slice_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
(function TestStringViewIter() {
let builder = new WasmModuleBuilder();
let global = builder.addGlobal(kWasmStringViewIter, true);
builder.addFunction("iterate", kSig_v_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStringAsIter,
kExprGlobalSet, global.index
]);
builder.addFunction("iterate_null", kSig_v_v)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
kGCPrefix, kExprStringAsIter,
kExprDrop
]);
builder.addFunction("next", kSig_i_v)
.exportFunc()
.addBody([
kExprGlobalGet, global.index,
kGCPrefix, kExprStringViewIterNext
]);
builder.addFunction("next_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringViewIterCode,
kGCPrefix, kExprStringViewIterNext
]);
let instance = builder.instantiate();
for (let str of interestingStrings) {
instance.exports.iterate(str);
for (let codepoint of str) {
assertEquals(codepoint.codePointAt(0), instance.exports.next());
}
assertEquals(-1, instance.exports.next());
assertEquals(-1, instance.exports.next());
}
assertThrows(() => instance.exports.iterate_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.next_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
......@@ -168,15 +168,16 @@ INSTANCE_TYPES = {
261: "SWISS_NAME_DICTIONARY_TYPE",
262: "WASM_API_FUNCTION_REF_TYPE",
263: "WASM_RESUME_DATA_TYPE",
264: "WEAK_ARRAY_LIST_TYPE",
265: "WEAK_CELL_TYPE",
266: "WASM_ARRAY_TYPE",
267: "WASM_STRUCT_TYPE",
268: "JS_PROXY_TYPE",
264: "WASM_STRING_VIEW_ITER_TYPE",
265: "WEAK_ARRAY_LIST_TYPE",
266: "WEAK_CELL_TYPE",
267: "WASM_ARRAY_TYPE",
268: "WASM_STRUCT_TYPE",
269: "JS_PROXY_TYPE",
1057: "JS_OBJECT_TYPE",
269: "JS_GLOBAL_OBJECT_TYPE",
270: "JS_GLOBAL_PROXY_TYPE",
271: "JS_MODULE_NAMESPACE_TYPE",
270: "JS_GLOBAL_OBJECT_TYPE",
271: "JS_GLOBAL_PROXY_TYPE",
272: "JS_MODULE_NAMESPACE_TYPE",
1040: "JS_SPECIAL_API_OBJECT_TYPE",
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
1058: "JS_API_OBJECT_TYPE",
......@@ -281,7 +282,7 @@ KNOWN_MAPS = {
("read_only_space", 0x02139): (250, "MetaMap"),
("read_only_space", 0x02161): (131, "NullMap"),
("read_only_space", 0x02189): (232, "StrongDescriptorArrayMap"),
("read_only_space", 0x021b1): (264, "WeakArrayListMap"),
("read_only_space", 0x021b1): (265, "WeakArrayListMap"),
("read_only_space", 0x021f5): (155, "EnumCacheMap"),
("read_only_space", 0x02229): (177, "FixedArrayMap"),
("read_only_space", 0x02275): (8, "OneByteInternalizedStringMap"),
......@@ -358,7 +359,7 @@ KNOWN_MAPS = {
("read_only_space", 0x03009): (235, "WeakFixedArrayMap"),
("read_only_space", 0x03031): (179, "EphemeronHashTableMap"),
("read_only_space", 0x03059): (243, "EmbedderDataArrayMap"),
("read_only_space", 0x03081): (265, "WeakCellMap"),
("read_only_space", 0x03081): (266, "WeakCellMap"),
("read_only_space", 0x030a9): (32, "StringMap"),
("read_only_space", 0x030d1): (41, "ConsOneByteStringMap"),
("read_only_space", 0x030f9): (33, "ConsStringMap"),
......@@ -443,15 +444,16 @@ KNOWN_MAPS = {
("read_only_space", 0x06869): (249, "InternalClassWithStructElementsMap"),
("read_only_space", 0x06891): (227, "ExportedSubClass2Map"),
("read_only_space", 0x068b9): (260, "SortStateMap"),
("read_only_space", 0x068e1): (145, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x06909): (145, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x069d5): (137, "LoadHandler1Map"),
("read_only_space", 0x069fd): (137, "LoadHandler2Map"),
("read_only_space", 0x06a25): (137, "LoadHandler3Map"),
("read_only_space", 0x06a4d): (138, "StoreHandler0Map"),
("read_only_space", 0x06a75): (138, "StoreHandler1Map"),
("read_only_space", 0x06a9d): (138, "StoreHandler2Map"),
("read_only_space", 0x06ac5): (138, "StoreHandler3Map"),
("read_only_space", 0x068e1): (264, "WasmStringViewIterMap"),
("read_only_space", 0x06909): (145, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x06931): (145, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x069fd): (137, "LoadHandler1Map"),
("read_only_space", 0x06a25): (137, "LoadHandler2Map"),
("read_only_space", 0x06a4d): (137, "LoadHandler3Map"),
("read_only_space", 0x06a75): (138, "StoreHandler0Map"),
("read_only_space", 0x06a9d): (138, "StoreHandler1Map"),
("read_only_space", 0x06ac5): (138, "StoreHandler2Map"),
("read_only_space", 0x06aed): (138, "StoreHandler3Map"),
("map_space", 0x02139): (2114, "ExternalMap"),
("map_space", 0x02161): (2118, "JSMessageObjectMap"),
}
......
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