[stringrefs] Implement stringview_wtf16.get_codeunit

Bug: v8:12868
Change-Id: I5fb5dccb5ff6b691348a519253de338fa91e8be1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3695269
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andy Wingo <wingo@igalia.com>
Cr-Commit-Position: refs/heads/main@{#81082}
This commit is contained in:
Andy Wingo 2022-06-10 16:10:21 +02:00 committed by V8 LUCI CQ
parent 659d106af0
commit ea6bedaeb1
9 changed files with 79 additions and 7 deletions

View File

@ -434,6 +434,7 @@ extern enum MessageTemplate {
kWasmTrapIllegalCast,
kWasmTrapArrayOutOfBounds,
kWasmTrapArrayTooLarge,
kWasmTrapStringOffsetOutOfBounds,
kWeakRefsRegisterTargetAndHoldingsMustNotBeSame,
kWeakRefsRegisterTargetMustBeObject,
kWeakRefsUnregisterTokenMustBeObject,

View File

@ -811,4 +811,16 @@ builtin WasmStringMeasureWtf8(string: String): int32 {
const result = runtime::WasmStringMeasureWtf8(LoadContextFromFrame(), string);
return Signed(ChangeNumberToUint32(result));
}
transitioning builtin WasmStringViewWtf16GetCodeUnit(
string: String, offset: uint32): uint32 {
try {
if (Unsigned(string.length) <= offset) goto OffsetOutOfRange;
const code: char16 = StringCharCodeAt(string, Convert<uintptr>(offset));
return Convert<uint32>(code);
} label OffsetOutOfRange deferred {
const error = MessageTemplate::kWasmTrapStringOffsetOutOfBounds;
runtime::ThrowWasmError(LoadContextFromFrame(), SmiConstant(error));
unreachable;
}
}
}

View File

@ -645,6 +645,7 @@ namespace internal {
T(WasmTrapArrayOutOfBounds, "array element access out of bounds") \
T(WasmTrapArrayTooLarge, "requested new array is too large") \
T(WasmTrapStringInvalidWtf8, "invalid WTF-8 string") \
T(WasmTrapStringOffsetOutOfBounds, "string offset out of bounds") \
T(WasmExceptionError, "wasm exception") \
/* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \

View File

@ -5786,6 +5786,16 @@ Node* WasmGraphBuilder::StringMeasureWtf16(Node* string,
wasm::ObjectAccess::ToTagged(String::kLengthOffset));
}
Node* WasmGraphBuilder::StringViewWtf16GetCodeUnit(
Node* string, CheckForNull null_check, Node* offset,
wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) {
string = AssertNotNull(string, position);
}
return gasm_->CallBuiltin(Builtin::kWasmStringViewWtf16GetCodeUnit,
Operator::kNoDeopt, string, offset);
}
// 1 bit V8 Smi tag, 31 bits V8 Smi shift, 1 bit i31ref high-bit truncation.
constexpr int kI31To32BitSmiShift = 33;

View File

@ -547,6 +547,9 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* StringMeasureWtf16(Node* string, CheckForNull null_check,
wasm::WasmCodePosition position);
Node* StringViewWtf16GetCodeUnit(Node* string, CheckForNull null_check,
Node* offset,
wasm::WasmCodePosition position);
Node* IsNull(Node* object);
Node* TypeGuard(Node* value, wasm::ValueType type);

View File

@ -6178,7 +6178,24 @@ class LiftoffCompiler {
void StringViewWtf16GetCodeUnit(FullDecoder* decoder, const Value& view,
const Value& pos, Value* result) {
UNIMPLEMENTED();
LiftoffRegList pinned;
LiftoffRegister pos_reg = pinned.set(__ PopToRegister(pinned));
LiftoffRegister view_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, view_reg.gp(), pinned, view.type);
LiftoffAssembler::VarState view_var(kRef, view_reg, 0);
LiftoffAssembler::VarState pos_var(kI32, pos_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringViewWtf16GetCodeUnit,
MakeSig::Returns(kI32).Params(kRef, kI32),
{
view_var,
pos_var,
},
decoder->position());
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
LiftoffRegister result_reg(kReturnRegister0);
__ PushRegister(kI32, result_reg);
}
void StringViewWtf16Encode(FullDecoder* decoder,

View File

@ -1479,7 +1479,8 @@ class WasmGraphBuildingInterface {
void StringViewWtf16GetCodeUnit(FullDecoder* decoder, const Value& view,
const Value& pos, Value* result) {
UNIMPLEMENTED();
result->node = builder_->StringViewWtf16GetCodeUnit(
view.node, NullCheckFor(view.type), pos.node, decoder->position());
}
void StringViewWtf16Encode(FullDecoder* decoder,

View File

@ -127,7 +127,8 @@ struct WasmModule;
V(WasmStringNewWtf16) \
V(WasmStringConst) \
V(WasmStringMeasureUtf8) \
V(WasmStringMeasureWtf8)
V(WasmStringMeasureWtf8) \
V(WasmStringViewWtf16GetCodeUnit)
// Sorted, disjoint and non-overlapping memory regions. A region is of the
// form [start, end). So there's no [start, end), [end, other_end),

View File

@ -9,6 +9,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
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]);
function encodeWtf8(str) {
// String iterator coalesces surrogate pairs.
@ -245,7 +246,7 @@ function makeWtf16TestDataSegment() {
(function TestStringViewWtf16() {
let builder = new WasmModuleBuilder();
builder.addFunction("string_measure_wtf16", kSig_i_w)
builder.addFunction("string_view_wtf16_length", kSig_i_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
@ -253,18 +254,43 @@ function makeWtf16TestDataSegment() {
kGCPrefix, kExprStringViewWtf16Length
]);
builder.addFunction("string_measure_wtf16_null", kSig_i_v)
builder.addFunction("string_view_wtf16_length_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringViewWtf16Code,
kGCPrefix, kExprStringViewWtf16Length
]);
builder.addFunction("string_view_wtf16_get_codeunit", kSig_i_wi)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStringAsWtf16,
kExprLocalGet, 1,
kGCPrefix, kExprStringViewWtf16GetCodeunit
]);
builder.addFunction("string_view_wtf16_get_codeunit_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringViewWtf16Code,
kExprI32Const, 0,
kGCPrefix, kExprStringViewWtf16GetCodeunit
]);
let instance = builder.instantiate();
for (let str of interestingStrings) {
assertEquals(str.length, instance.exports.string_measure_wtf16(str));
assertEquals(str.length, instance.exports.string_view_wtf16_length(str));
for (let i = 0; i < str.length; i++) {
assertEquals(str.charCodeAt(i),
instance.exports.string_view_wtf16_get_codeunit(str, i));
}
}
assertThrows(() => instance.exports.string_measure_wtf16_null(),
assertThrows(() => instance.exports.string_view_wtf16_length_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.string_view_wtf16_get_codeunit_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.string_view_wtf16_get_codeunit("", 0),
WebAssembly.RuntimeError, "string offset out of bounds");
})();