%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/array-join.tq |
// Copyright 2018 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.
namespace array {
type LoadJoinElementFn = builtin(Context, JSReceiver, uintptr) => JSAny;
const kMaxArrayLength:
constexpr uint32 generates 'JSArray::kMaxArrayLength';
// Fast C call to write a fixed array (see Buffer.fixedArray) to a single
// string.
extern macro
ArrayBuiltinsAssembler::CallJSArrayArrayJoinConcatToSequentialString(
FixedArray, intptr, String, String): String;
transitioning builtin LoadJoinElement<T : type extends ElementsKind>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
return GetProperty(receiver, Convert<Number>(k));
}
transitioning LoadJoinElement<array::DictionaryElements>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const dict: NumberDictionary = UnsafeCast<NumberDictionary>(array.elements);
try {
return BasicLoadNumberDictionaryElement(dict, Signed(k))
otherwise IfNoData, IfHole;
} label IfNoData deferred {
return GetProperty(receiver, Convert<Number>(k));
} label IfHole {
return kEmptyString;
}
}
LoadJoinElement<array::FastSmiOrObjectElements>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const fixedArray: FixedArray = UnsafeCast<FixedArray>(array.elements);
const element: Object = fixedArray.objects[k];
return element == TheHole ? kEmptyString : UnsafeCast<JSAny>(element);
}
LoadJoinElement<array::FastDoubleElements>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const fixedDoubleArray: FixedDoubleArray =
UnsafeCast<FixedDoubleArray>(array.elements);
const element: float64 =
fixedDoubleArray.floats[k].Value() otherwise return kEmptyString;
return AllocateHeapNumberWithValue(element);
}
builtin LoadJoinTypedElement<T : type extends ElementsKind>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
dcheck(!typed_array::IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(
typedArray));
return typed_array::LoadFixedTypedArrayElementAsTagged(
typedArray.data_ptr, k, typed_array::KindForArrayType<T>());
}
transitioning builtin ConvertToLocaleString(
context: Context, element: JSAny, locales: JSAny, options: JSAny): String {
if (IsNullOrUndefined(element)) return kEmptyString;
const prop: JSAny = GetProperty(element, 'toLocaleString');
try {
const callable: Callable = Cast<Callable>(prop) otherwise TypeError;
let result: JSAny;
// According to the ECMA-402 specification, the optional arguments locales
// and options must be passed.
@if(V8_INTL_SUPPORT) {
result = Call(context, callable, element, locales, options);
}
// Without the ECMA-402 internationalization API, the optional arguments
// must not be passed.
// See: https://tc39.es/ecma262/#sec-array.prototype.tolocalestring
@ifnot(V8_INTL_SUPPORT) {
result = Call(context, callable, element);
// Use the remaining parameters.
const _locales = locales;
const _options = options;
}
return ToString_Inline(result);
} label TypeError {
ThrowCalledNonCallable(prop);
}
}
// Verifies the current element JSArray accessor can still be safely used
// (see LoadJoinElement<ElementsAccessor>).
macro CannotUseSameArrayAccessor<T: type>(
implicit context: Context)(loadFn: LoadJoinElementFn, receiver: JSReceiver,
originalMap: Map, originalLen: Number): bool;
CannotUseSameArrayAccessor<JSArray>(
implicit context: Context)(loadFn: LoadJoinElementFn, receiver: JSReceiver,
originalMap: Map, originalLen: Number): bool {
if (loadFn == LoadJoinElement<array::GenericElementsAccessor>) return false;
const array: JSArray = UnsafeCast<JSArray>(receiver);
if (originalMap != array.map) return true;
if (originalLen != array.length) return true;
if (IsNoElementsProtectorCellInvalid()) return true;
return false;
}
CannotUseSameArrayAccessor<JSTypedArray>(
implicit context: Context)(_loadFn: LoadJoinElementFn,
receiver: JSReceiver, _initialMap: Map, _initialLen: Number): bool {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
// When this is called from toLocaleString(), the underlying buffer might get
// detached / resized (in the case of RAB / GSAB) during iterating the
// elements. When this is called from join(), it can happen only before the
// first element (during parameter conversion). The code below doesn't
// differentiate between these two cases, but does the checks in both cases.
if (IsDetachedBuffer(typedArray.buffer)) {
return true;
}
if (IsVariableLengthJSArrayBufferView(typedArray)) {
// TODO(v8:11111): Add a fast(er) path here.
return true;
}
return false;
}
// Calculates the running total length of the resulting string. If the
// calculated length exceeds the maximum string length (see
// String::kMaxLength), throws a range error.
macro AddStringLength(
implicit context: Context)(lenA: intptr, lenB: intptr): intptr {
try {
const length: intptr = TryIntPtrAdd(lenA, lenB) otherwise IfOverflow;
if (length > kStringMaxLength) goto IfOverflow;
return length;
} label IfOverflow deferred {
ThrowInvalidStringLength(context);
}
}
// Stores an element to a fixed array and return the fixed array. If the fixed
// array is not large enough, create and return a new, larger fixed array that
// contains all previously elements and the new element.
macro StoreAndGrowFixedArray<T: type>(
fixedArray: FixedArray, index: intptr, element: T): FixedArray {
const length: intptr = fixedArray.length_intptr;
dcheck(index <= length);
if (index < length) {
fixedArray.objects[index] = element;
return fixedArray;
} else
deferred {
const newLength: intptr = CalculateNewElementsCapacity(length);
dcheck(index < newLength);
const newfixedArray: FixedArray =
ExtractFixedArray(fixedArray, 0, length, newLength);
newfixedArray.objects[index] = element;
return newfixedArray;
}
}
// Contains the information necessary to create a single, separator delimited,
// flattened one or two byte string.
// The buffer is maintained and updated by Buffer.constructor, Buffer.Add(),
// Buffer.AddSeparators().
struct Buffer {
macro Add(
implicit context: Context)(str: String, nofSeparators: intptr,
separatorLength: intptr): void {
// Add separators if necessary (at the beginning or more than one)
const writeSeparators: bool = this.index == 0 | nofSeparators > 1;
this.AddSeparators(nofSeparators, separatorLength, writeSeparators);
this.totalStringLength =
AddStringLength(this.totalStringLength, str.length_intptr);
// String comparison is expensive, so we only check for pointer equality
// (i.e. only works for internalized strings).
if (TaggedEqual(str, this.lastString)) {
this.RepeatLast();
} else {
this.fixedArray =
StoreAndGrowFixedArray(this.fixedArray, this.index++, str);
this.lastString = str;
}
this.isOneByte =
IsOneByteStringInstanceType(str.instanceType) & this.isOneByte;
}
macro AddSeparators(
implicit context: Context)(nofSeparators: intptr,
separatorLength: intptr, write: bool): void {
if (nofSeparators == 0 || separatorLength == 0) return;
const nofSeparatorsInt: intptr = nofSeparators;
const sepsLen: intptr = separatorLength * nofSeparatorsInt;
// Detect integer overflow
// TODO(turbofan): Replace with overflow-checked multiplication.
if (sepsLen / separatorLength != nofSeparatorsInt) deferred {
ThrowInvalidStringLength(context);
}
this.totalStringLength = AddStringLength(this.totalStringLength, sepsLen);
if (write) deferred {
this.fixedArray = StoreAndGrowFixedArray(
this.fixedArray, this.index++, Convert<Smi>(nofSeparatorsInt));
this.lastString = Null;
}
}
macro RepeatLast(): void {
dcheck(this.index > 0);
typeswitch (this.fixedArray.objects[this.index - 1]) {
case (String): {
this.fixedArray = StoreAndGrowFixedArray(
this.fixedArray, this.index++, SmiConstant(-1));
}
case (count: Smi): {
dcheck(count < 0);
dcheck(count - 1 < 0); // Check that there is no overflow.
this.fixedArray.objects[this.index - 1] = count - 1;
}
case (Object): {
unreachable;
}
}
}
// Fixed array holding elements that are either:
// 1) String result of `ToString(next)`.
// 2) Smi representing either
// - the number of consecutive separators (positive smi).
// - the number to repeat the last stored string (negative smi).
// `BufferJoin()` will iterate and writes these entries to a flat string.
//
// To save space, reduce reads and writes, only separators at the beginning,
// end, or more than one are written.
//
// No hole example
// receiver: ['hello', 'world']
// fixedArray: ['hello', 'world']
//
// Hole example
// receiver: [<hole>, 'hello', <hole>, 'world', <hole>]
// fixedArray: [1, 'hello', 2, 'world', 1]
//
// Repeat example
// receiver: ['hello', 'hello', hello', 'world']
// fixedArray: ['hello', -2, 'world']
fixedArray: FixedArray;
// Index to insert a new entry into `fixedArray`.
index: intptr;
// Running total of the resulting string length.
totalStringLength: intptr;
// `true` if the separator and all strings in the buffer are one-byte,
// otherwise `false`.
isOneByte: bool;
lastString: PrimitiveHeapObject;
}
macro NewBuffer(len: uintptr, sep: String): Buffer {
const cappedBufferSize: intptr = len > kMaxNewSpaceFixedArrayElements ?
kMaxNewSpaceFixedArrayElements :
Signed(len);
dcheck(cappedBufferSize > 0);
return Buffer{
fixedArray: AllocateZeroedFixedArray(cappedBufferSize),
index: 0,
totalStringLength: 0,
isOneByte: IsOneByteStringInstanceType(sep.instanceType),
lastString: Null
};
}
macro BufferJoin(implicit context: Context)(buffer: Buffer, sep: String):
String {
dcheck(IsValidPositiveSmi(buffer.totalStringLength));
if (buffer.totalStringLength == 0) return kEmptyString;
// Fast path when there's only one buffer element.
if (buffer.index == 1) {
const fixedArray: FixedArray = buffer.fixedArray;
typeswitch (fixedArray.objects[0]) {
// When the element is a string, just return it and completely avoid
// allocating another string.
case (str: String): {
return str;
}
// When the element is a smi, use StringRepeat to quickly build a memory
// efficient separator repeated string.
case (nofSeparators: Smi): {
dcheck(nofSeparators > 0);
return StringRepeat(context, sep, nofSeparators);
}
case (Object): {
unreachable;
}
}
}
const length: uint32 = Convert<uint32>(Unsigned(buffer.totalStringLength));
const r: String = buffer.isOneByte ? AllocateSeqOneByteString(length) :
AllocateSeqTwoByteString(length);
return CallJSArrayArrayJoinConcatToSequentialString(
buffer.fixedArray, buffer.index, sep, r);
}
transitioning macro ArrayJoinImpl<T: type>(
implicit context: Context)(receiver: JSReceiver, sep: String,
lengthNumber: Number, useToLocaleString: constexpr bool, locales: JSAny,
options: JSAny, initialLoadFn: LoadJoinElementFn): String {
const initialMap: Map = receiver.map;
const len: uintptr = Convert<uintptr>(lengthNumber);
const separatorLength: intptr = sep.length_intptr;
let nofSeparators: intptr = 0;
let loadFn: LoadJoinElementFn = initialLoadFn;
let buffer: Buffer = NewBuffer(len, sep);
// 6. Let k be 0.
let k: uintptr = 0;
// 7. Repeat, while k < len
while (k < len) {
if (CannotUseSameArrayAccessor<T>(
loadFn, receiver, initialMap, lengthNumber))
deferred {
loadFn = LoadJoinElement<array::GenericElementsAccessor>;
}
if (k > 0) {
// a. If k > 0, let R be the string-concatenation of R and sep.
nofSeparators = nofSeparators + 1;
}
// b. Let element be ? Get(O, ! ToString(k)).
const element: JSAny = loadFn(context, receiver, k++);
// c. If element is undefined or null, let next be the empty String;
// otherwise, let next be ? ToString(element).
let next: String;
if constexpr (useToLocaleString) {
next = ConvertToLocaleString(context, element, locales, options);
if (next == kEmptyString) continue;
} else {
typeswitch (element) {
case (str: String): {
if (str == kEmptyString) continue;
next = str;
}
case (num: Number): {
next = NumberToString(num);
}
case (obj: JSAny): {
if (IsNullOrUndefined(obj)) continue;
const str = string::ToString_Inline(context, obj);
if (str == kEmptyString) continue;
next = str;
}
}
}
// d. Set R to the string-concatenation of R and next.
buffer.Add(next, nofSeparators, separatorLength);
nofSeparators = 0;
}
// Add any separators at the end.
buffer.AddSeparators(nofSeparators, separatorLength, true);
// 8. Return R.
return BufferJoin(buffer, sep);
}
transitioning macro ArrayJoin<T: type>(
implicit context: Context)(useToLocaleString: constexpr bool,
receiver: JSReceiver, sep: String, lenNumber: Number, locales: JSAny,
options: JSAny): JSAny;
transitioning ArrayJoin<JSArray>(
implicit context: Context)(useToLocaleString: constexpr bool,
receiver: JSReceiver, sep: String, lenNumber: Number, locales: JSAny,
options: JSAny): JSAny {
const map: Map = receiver.map;
const kind: ElementsKind = map.elements_kind;
let loadFn: LoadJoinElementFn;
try {
const array: JSArray = Cast<JSArray>(receiver) otherwise IfSlowPath;
if (array.length != lenNumber) goto IfSlowPath;
if (!IsPrototypeInitialArrayPrototype(map)) goto IfSlowPath;
if (IsNoElementsProtectorCellInvalid()) goto IfSlowPath;
if (IsElementsKindLessThanOrEqual(kind, ElementsKind::HOLEY_ELEMENTS)) {
loadFn = LoadJoinElement<array::FastSmiOrObjectElements>;
} else if (IsElementsKindLessThanOrEqual(
kind, ElementsKind::HOLEY_DOUBLE_ELEMENTS)) {
loadFn = LoadJoinElement<array::FastDoubleElements>;
} else if (kind == ElementsKind::DICTIONARY_ELEMENTS)
deferred {
const dict: NumberDictionary =
UnsafeCast<NumberDictionary>(array.elements);
const nofElements: Smi = GetNumberDictionaryNumberOfElements(dict);
if (nofElements == 0) {
if (sep == kEmptyString) return kEmptyString;
try {
const nofSeparators: Smi =
Cast<Smi>(lenNumber - 1) otherwise IfNotSmi;
return StringRepeat(context, sep, nofSeparators);
} label IfNotSmi {
ThrowInvalidStringLength(context);
}
} else {
loadFn = LoadJoinElement<array::DictionaryElements>;
}
}
else {
goto IfSlowPath;
}
} label IfSlowPath {
loadFn = LoadJoinElement<array::GenericElementsAccessor>;
}
return ArrayJoinImpl<JSArray>(
receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn);
}
transitioning ArrayJoin<JSTypedArray>(
implicit context: Context)(useToLocaleString: constexpr bool,
receiver: JSReceiver, sep: String, lenNumber: Number, locales: JSAny,
options: JSAny): JSAny {
const map: Map = receiver.map;
const kind: ElementsKind = map.elements_kind;
let loadFn: LoadJoinElementFn;
if (IsElementsKindGreaterThan(kind, ElementsKind::UINT32_ELEMENTS)) {
if (kind == ElementsKind::INT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int32Elements>;
} else if (kind == ElementsKind::FLOAT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Float32Elements>;
} else if (kind == ElementsKind::FLOAT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Float64Elements>;
} else if (kind == ElementsKind::UINT8_CLAMPED_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint8ClampedElements>;
} else if (kind == ElementsKind::BIGUINT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::BigUint64Elements>;
} else if (kind == ElementsKind::BIGINT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::BigInt64Elements>;
} else if (kind == ElementsKind::RAB_GSAB_UINT8_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint8Elements>;
} else if (kind == ElementsKind::RAB_GSAB_INT8_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int8Elements>;
} else if (kind == ElementsKind::RAB_GSAB_UINT16_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint16Elements>;
} else if (kind == ElementsKind::RAB_GSAB_INT16_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int16Elements>;
} else if (kind == ElementsKind::RAB_GSAB_UINT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint32Elements>;
} else if (kind == ElementsKind::RAB_GSAB_INT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int32Elements>;
} else if (kind == ElementsKind::RAB_GSAB_FLOAT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Float32Elements>;
} else if (kind == ElementsKind::RAB_GSAB_FLOAT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Float64Elements>;
} else if (kind == ElementsKind::RAB_GSAB_UINT8_CLAMPED_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint8ClampedElements>;
} else if (kind == ElementsKind::RAB_GSAB_BIGUINT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::BigUint64Elements>;
} else if (kind == ElementsKind::RAB_GSAB_BIGINT64_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::BigInt64Elements>;
} else {
unreachable;
}
} else {
if (kind == ElementsKind::UINT8_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint8Elements>;
} else if (kind == ElementsKind::INT8_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int8Elements>;
} else if (kind == ElementsKind::UINT16_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint16Elements>;
} else if (kind == ElementsKind::INT16_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Int16Elements>;
} else if (kind == ElementsKind::UINT32_ELEMENTS) {
loadFn = LoadJoinTypedElement<typed_array::Uint32Elements>;
} else {
unreachable;
}
}
return ArrayJoinImpl<JSTypedArray>(
receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn);
}
// The Join Stack detects cyclical calls to Array Join builtins
// (Array.p.join(), Array.p.toString(), Array.p.toLocaleString()). This
// FixedArray holds a stack of receivers to the current call.
// CycleProtectedArrayJoin() is responsible for calling JoinStackPush and
// JoinStackPop when visiting and leaving a receiver, respectively.
const kMinJoinStackSize:
constexpr int31 generates 'JSArray::kMinJoinStackSize';
macro LoadJoinStack(implicit context: Context)(): FixedArray
labels IfUninitialized {
typeswitch (*NativeContextSlot(ContextSlot::ARRAY_JOIN_STACK_INDEX)) {
case (Undefined): {
goto IfUninitialized;
}
case (stack: FixedArray): {
return stack;
}
}
}
macro SetJoinStack(implicit context: Context)(stack: FixedArray): void {
*NativeContextSlot(ContextSlot::ARRAY_JOIN_STACK_INDEX) = stack;
}
// Adds a receiver to the stack. The FixedArray will automatically grow to
// accommodate the receiver. If the receiver already exists on the stack,
// this indicates a cyclical call and False is returned.
builtin JoinStackPush(
implicit context: Context)(stack: FixedArray,
receiver: JSReceiver): Boolean {
const capacity: intptr = stack.length_intptr;
for (let i: intptr = 0; i < capacity; i++) {
const previouslyVisited: Object = stack.objects[i];
// Add `receiver` to the first open slot
if (previouslyVisited == TheHole) {
stack.objects[i] = receiver;
return True;
}
// Detect cycles
if (receiver == previouslyVisited) return False;
}
// If no open slots were found, grow the stack and add receiver to the end.
const newStack: FixedArray =
StoreAndGrowFixedArray(stack, capacity, receiver);
SetJoinStack(newStack);
return True;
}
// Fast path the common non-nested calls. If the receiver is not already on
// the stack, add it to the stack and return true. Otherwise return false.
macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver):
bool {
try {
const stack: FixedArray = LoadJoinStack()
otherwise IfUninitialized;
if (stack.objects[0] == TheHole) {
stack.objects[0] = receiver;
} else if (JoinStackPush(stack, receiver) == False)
deferred {
return false;
}
} label IfUninitialized {
const stack: FixedArray =
AllocateFixedArrayWithHoles(kMinJoinStackSize, AllocationFlag::kNone);
stack.objects[0] = receiver;
SetJoinStack(stack);
}
return true;
}
// Removes a receiver from the stack. The FixedArray will automatically shrink
// to Heap::kMinJoinStackSize once the stack becomes empty.
builtin JoinStackPop(
implicit context: Context)(stack: FixedArray,
receiver: JSReceiver): JSAny {
const len: intptr = stack.length_intptr;
for (let i: intptr = 0; i < len; i++) {
if (stack.objects[i] == receiver) {
// Shrink the Join Stack if the stack will be empty and is larger than
// the minimum size.
if (i == 0 && len > kMinJoinStackSize) deferred {
const newStack: FixedArray = AllocateFixedArrayWithHoles(
kMinJoinStackSize, AllocationFlag::kNone);
SetJoinStack(newStack);
}
else {
stack.objects[i] = TheHole;
}
return Undefined;
}
}
unreachable;
}
// Fast path the common non-nested calls.
macro JoinStackPopInline(implicit context: Context)(receiver: JSReceiver):
void {
const stack: FixedArray = LoadJoinStack()
otherwise unreachable;
const len: intptr = stack.length_intptr;
// Builtin call was not nested (receiver is the first entry) and
// did not contain other nested arrays that expanded the stack.
if (stack.objects[0] == receiver && len == kMinJoinStackSize) {
stack.objects[0] = TheHole;
} else
deferred {
JoinStackPop(stack, receiver);
}
}
// Main entry point for all builtins using Array Join functionality.
transitioning macro CycleProtectedArrayJoin<T: type>(
implicit context: Context)(useToLocaleString: constexpr bool,
o: JSReceiver, len: Number, sepObj: JSAny, locales: JSAny,
options: JSAny): JSAny {
// 3. If separator is undefined, let sep be the single-element String ",".
// 4. Else, let sep be ? ToString(separator).
const sep: String = sepObj == Undefined ? ',' : ToString_Inline(sepObj);
// If the receiver is not empty and not already being joined, continue with
// the normal join algorithm.
if (len > 0 && JoinStackPushInline(o)) {
try {
const result: JSAny =
ArrayJoin<T>(useToLocaleString, o, sep, len, locales, options);
JoinStackPopInline(o);
return result;
} catch (e, message) deferred {
JoinStackPopInline(o);
ReThrowWithMessage(context, e, message);
}
} else {
return kEmptyString;
}
}
// https://tc39.github.io/ecma262/#sec-array.prototype.join
transitioning javascript builtin ArrayPrototypeJoin(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
const separator: JSAny = arguments[0];
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
const len: Number = GetLengthProperty(o);
// Only handle valid array lengths. Although the spec allows larger
// values, this matches historical V8 behavior.
if (len > kMaxArrayLength) {
ThrowTypeError(MessageTemplate::kInvalidArrayLength);
}
return CycleProtectedArrayJoin<JSArray>(
false, o, len, separator, Undefined, Undefined);
}
// https://tc39.github.io/ecma262/#sec-array.prototype.tolocalestring
transitioning javascript builtin ArrayPrototypeToLocaleString(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
const locales: JSAny = arguments[0];
const options: JSAny = arguments[1];
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
const len: Number = GetLengthProperty(o);
// Only handle valid array lengths. Although the spec allows larger
// values, this matches historical V8 behavior.
if (len > kMaxArrayLength) {
ThrowTypeError(MessageTemplate::kInvalidArrayLength);
}
return CycleProtectedArrayJoin<JSArray>(true, o, len, ',', locales, options);
}
// https://tc39.github.io/ecma262/#sec-array.prototype.tostring
transitioning javascript builtin ArrayPrototypeToString(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
// 1. Let array be ? ToObject(this value).
const array: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let func be ? Get(array, "join").
const prop: JSAny = GetProperty(array, 'join');
try {
// 3. If IsCallable(func) is false, let func be the intrinsic function
// %ObjProto_toString%.
const func: Callable = Cast<Callable>(prop) otherwise NotCallable;
// 4. Return ? Call(func, array).
return Call(context, func, array);
} label NotCallable {
return ObjectToString(context, array);
}
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
transitioning javascript builtin TypedArrayPrototypeJoin(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
const separator: JSAny = arguments[0];
// Spec: ValidateTypedArray is applied to the this value prior to evaluating
// the algorithm.
const length = typed_array::ValidateTypedArrayAndGetLength(
context, receiver, '%TypedArray%.prototype.join');
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
return CycleProtectedArrayJoin<JSTypedArray>(
false, typedArray, Convert<Number>(length), separator, Undefined,
Undefined);
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring
transitioning javascript builtin TypedArrayPrototypeToLocaleString(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
const locales: JSAny = arguments[0];
const options: JSAny = arguments[1];
// Spec: ValidateTypedArray is applied to the this value prior to evaluating
// the algorithm.
const length = typed_array::ValidateTypedArrayAndGetLength(
context, receiver, '%TypedArray%.prototype.toLocaleString');
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
return CycleProtectedArrayJoin<JSTypedArray>(
true, typedArray, Convert<Number>(length), ',', locales, options);
}
}