blob: 43c30d9b352bd8f2cc6139b2644b762ad9765ea1 [file] [log] [blame]
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file defines the builtins that are used as the non-optimized versions
// of the "JS String Builtins", i.e. from Liftoff code, and for exported
// functions.
macro Trap(context: Context, error: constexpr MessageTemplate): never {
runtime::ThrowWasmError(context, SmiConstant(error));
}
transitioning javascript builtin WebAssemblyStringCast(
js-implicit context: Context)(arg: JSAny): String {
try {
return Cast<String>(arg) otherwise goto IllegalCast;
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringTest(
js-implicit context: Context)(arg: JSAny): Smi {
return Is<String>(arg) ? SmiConstant(1) : SmiConstant(0);
}
extern runtime WasmCastToSpecialPrimitiveArray(Context, Object, Smi): WasmArray;
transitioning javascript builtin WebAssemblyStringFromWtf16Array(
js-implicit context: Context)(arrayArg: JSAny, startArg: JSAny,
endArg: JSAny): JSAny {
const array =
WasmCastToSpecialPrimitiveArray(context, arrayArg, SmiConstant(16));
const start = NumberToUint32(ToNumber_Inline(startArg));
const end = NumberToUint32(ToNumber_Inline(endArg));
return wasm::WasmStringNewWtf16Array(array, start, end);
}
const kLossyUtf8:
constexpr int31 generates 'unibrow::Utf8Variant::kLossyUtf8';
transitioning javascript builtin WebAssemblyStringFromUtf8Array(
js-implicit context: Context)(arrayArg: JSAny, startArg: JSAny,
endArg: JSAny): JSAny {
const array =
WasmCastToSpecialPrimitiveArray(context, arrayArg, SmiConstant(8));
const start = NumberToUint32(ToNumber_Inline(startArg));
const end = NumberToUint32(ToNumber_Inline(endArg));
const result =
wasm::WasmStringNewWtf8Array(start, end, array, SmiConstant(kLossyUtf8));
dcheck(Is<String>(result));
return %RawDownCast<String>(result);
}
transitioning javascript builtin WebAssemblyStringIntoUtf8Array(
js-implicit context: Context)(stringArg: JSAny, arrayArg: JSAny,
startArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
const array =
WasmCastToSpecialPrimitiveArray(context, arrayArg, SmiConstant(8));
const start = NumberToUint32(ToNumber_Inline(startArg));
return runtime::WasmStringEncodeWtf8Array(
context, SmiConstant(kLossyUtf8), string, array,
ChangeUint32ToTagged(start));
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringToUtf8Array(
js-implicit context: Context)(stringArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
return runtime::WasmStringToUtf8Array(context, string);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringToWtf16Array(
js-implicit context: Context)(stringArg: JSAny, arrayArg: JSAny,
startArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
const array =
WasmCastToSpecialPrimitiveArray(context, arrayArg, SmiConstant(16));
const start = NumberToUint32(ToNumber_Inline(startArg));
const written = wasm::WasmStringEncodeWtf16Array(string, array, start);
return Convert<Smi>(written);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringFromCharCode(
js-implicit context: Context)(codeArg: JSAny): JSAny {
const code = NumberToUint32(ToNumber_Inline(codeArg));
return StringFromSingleCharCode(%RawDownCast<char16>(code & 0xFFFF));
}
transitioning javascript builtin WebAssemblyStringFromCodePoint(
js-implicit context: Context)(codeArg: JSAny): JSAny {
const code = ToNumber_Inline(codeArg);
const codeUint = NumberToUint32(code);
if (codeUint <= 0xFFFF) {
return StringFromSingleCharCode(%RawDownCast<char16>(codeUint));
}
return runtime::WasmStringFromCodePoint(context, code);
}
transitioning javascript builtin WebAssemblyStringCodePointAt(
js-implicit context: Context)(stringArg: JSAny, indexArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
const index = NumberToUint32(ToNumber_Inline(indexArg));
if (index >= Unsigned(string.length)) goto OOB;
const code: int32 = string::LoadSurrogatePairAt(
string, string.length_intptr, Signed(Convert<uintptr>(index)),
UnicodeEncoding::UTF32);
return Convert<Smi>(code);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
} label OOB deferred {
Trap(context, MessageTemplate::kWasmTrapStringOffsetOutOfBounds);
}
}
transitioning javascript builtin WebAssemblyStringCharCodeAt(
js-implicit context: Context)(stringArg: JSAny, indexArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
const index = NumberToUint32(ToNumber_Inline(indexArg));
if (index >= Unsigned(string.length)) goto OOB;
const code: char16 = StringCharCodeAt(string, Convert<uintptr>(index));
return SmiTag(code);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
} label OOB deferred {
Trap(context, MessageTemplate::kWasmTrapStringOffsetOutOfBounds);
}
}
transitioning javascript builtin WebAssemblyStringLength(
js-implicit context: Context)(stringArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
return string.length_smi;
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringMeasureUtf8(
js-implicit context: Context)(stringArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
// WTF-8 length equals Lossy-UTF-8 length.
return runtime::WasmStringMeasureWtf8(context, string);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringConcat(
js-implicit context: Context)(firstArg: JSAny, secondArg: JSAny): JSAny {
try {
const first = Cast<String>(firstArg) otherwise goto IllegalCast;
const second = Cast<String>(secondArg) otherwise goto IllegalCast;
return StringAdd_CheckNone(first, second);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringSubstring(
js-implicit context: Context)(stringArg: JSAny, startArg: JSAny,
endArg: JSAny): JSAny {
try {
const string = Cast<String>(stringArg) otherwise goto IllegalCast;
const start = NumberToUint32(ToNumber_Inline(startArg));
const end = NumberToUint32(ToNumber_Inline(endArg));
return wasm::WasmStringViewWtf16Slice(string, start, end);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringEquals(
js-implicit context: Context)(a: JSAny, b: JSAny): JSAny {
try {
if (a == Null) {
typeswitch (b) {
case (Null): {
return SmiConstant(1);
}
case (String): {
return SmiConstant(0);
}
case (JSAny): {
goto IllegalCast;
}
}
}
const left = Cast<String>(a) otherwise goto IllegalCast;
if (b == Null) return SmiConstant(0);
const right = Cast<String>(b) otherwise goto IllegalCast;
if (TaggedEqual(a, b)) return SmiConstant(1);
if (left.length != right.length) return SmiConstant(0);
if (wasm::StringEqual(kNoContext, left, right, left.length_intptr) ==
True) {
return SmiConstant(1);
}
return SmiConstant(0);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringCompare(
js-implicit context: Context)(firstArg: JSAny, secondArg: JSAny): JSAny {
try {
const first = Cast<String>(firstArg) otherwise goto IllegalCast;
const second = Cast<String>(secondArg) otherwise goto IllegalCast;
return StringCompare(first, second);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}