[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:
parent
659d106af0
commit
ea6bedaeb1
@ -434,6 +434,7 @@ extern enum MessageTemplate {
|
||||
kWasmTrapIllegalCast,
|
||||
kWasmTrapArrayOutOfBounds,
|
||||
kWasmTrapArrayTooLarge,
|
||||
kWasmTrapStringOffsetOutOfBounds,
|
||||
kWeakRefsRegisterTargetAndHoldingsMustNotBeSame,
|
||||
kWeakRefsRegisterTargetMustBeObject,
|
||||
kWeakRefsUnregisterTokenMustBeObject,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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: %") \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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");
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user