| // 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); |
| } |
| } |