blob: fded2afce6f71975b4ced9d9b72c47c884d53a49 [file] [log] [blame]
// 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 {
macro LoadElement<Elements : type extends FixedArrayBase, T: type>(
elements: FixedArrayBase, index: Smi): T;
LoadElement<FixedArray, Object>(
implicit context: Context)(elements: FixedArrayBase, index: Smi): Object {
const elements: FixedArray = UnsafeCast<FixedArray>(elements);
return elements.objects[index];
}
LoadElement<FixedDoubleArray, float64_or_undefined_or_hole>(
implicit context: Context)(elements: FixedArrayBase,
index: Smi): float64_or_undefined_or_hole {
const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
return elements.values[index];
}
macro StoreElement<Elements : type extends FixedArrayBase, T: type>(
implicit context: Context)(elements: FixedArrayBase, index: Smi,
value: T): void;
StoreElement<FixedArray, Object>(
implicit context: Context)(elements: FixedArrayBase, index: Smi,
value: Object): void {
const elements: FixedArray = UnsafeCast<FixedArray>(elements);
elements.objects[index] = value;
}
StoreElement<FixedDoubleArray, float64_or_undefined_or_hole>(
implicit context: Context)(elements: FixedArrayBase, index: Smi,
value: float64_or_undefined_or_hole): void {
const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
elems.values[index] = value;
}
// Fast-path for all PACKED_* elements kinds. These do not need to check
// whether a property is present, so we can simply swap them using fast
// FixedArray loads/stores.
macro FastArrayReverse<Elements : type extends FixedArrayBase, T: type>(
implicit context: Context)(elements: FixedArrayBase, length: Smi): void {
let lower: Smi = 0;
let upper: Smi = length - 1;
while (lower < upper) {
const lowerValue: T = LoadElement<Elements, T>(elements, lower);
const upperValue: T = LoadElement<Elements, T>(elements, upper);
StoreElement<Elements>(elements, lower, upperValue);
StoreElement<Elements>(elements, upper, lowerValue);
++lower;
--upper;
}
}
transitioning macro GenericArrayReverse(context: Context, receiver: JSAny):
JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let len be ? ToLength(? Get(O, "length")).
const length: Number = GetLengthProperty(object);
// 3. Let middle be floor(len / 2).
// 4. Let lower be 0.
// 5. Repeat, while lower != middle.
// a. Let upper be len - lower - 1.
// Instead of calculating the middle value, we simply initialize upper
// with len - 1 and decrement it after each iteration.
let lower: Number = 0;
let upper: Number = length - 1;
while (lower < upper) {
let lowerValue: JSAny = Undefined;
let upperValue: JSAny = Undefined;
// b. Let upperP be ! ToString(upper).
// c. Let lowerP be ! ToString(lower).
// d. Let lowerExists be ? HasProperty(O, lowerP).
const lowerExists: Boolean = HasProperty(object, lower);
// e. If lowerExists is true, then.
if (lowerExists == True) {
// i. Let lowerValue be ? Get(O, lowerP).
lowerValue = GetProperty(object, lower);
}
// f. Let upperExists be ? HasProperty(O, upperP).
const upperExists: Boolean = HasProperty(object, upper);
// g. If upperExists is true, then.
if (upperExists == True) {
// i. Let upperValue be ? Get(O, upperP).
upperValue = GetProperty(object, upper);
}
// h. If lowerExists is true and upperExists is true, then
if (lowerExists == True && upperExists == True) {
// i. Perform ? Set(O, lowerP, upperValue, true).
SetProperty(object, lower, upperValue);
// ii. Perform ? Set(O, upperP, lowerValue, true).
SetProperty(object, upper, lowerValue);
} else if (lowerExists == False && upperExists == True) {
// i. Perform ? Set(O, lowerP, upperValue, true).
SetProperty(object, lower, upperValue);
// ii. Perform ? DeletePropertyOrThrow(O, upperP).
DeleteProperty(object, upper, LanguageMode::kStrict);
} else if (lowerExists == True && upperExists == False) {
// i. Perform ? DeletePropertyOrThrow(O, lowerP).
DeleteProperty(object, lower, LanguageMode::kStrict);
// ii. Perform ? Set(O, upperP, lowerValue, true).
SetProperty(object, upper, lowerValue);
}
// l. Increase lower by 1.
++lower;
--upper;
}
// 6. Return O.
return object;
}
macro TryFastPackedArrayReverse(implicit context: Context)(
receiver: JSAny): void labels Slow {
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
const kind: ElementsKind = array.map.elements_kind;
if (kind == ElementsKind::PACKED_SMI_ELEMENTS ||
kind == ElementsKind::PACKED_ELEMENTS) {
array::EnsureWriteableFastElements(array);
FastArrayReverse<FixedArray, Object>(array.elements, array.length);
} else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
FastArrayReverse<FixedDoubleArray, float64_or_undefined_or_hole>(
array.elements, array.length);
} else {
if (!IsPrototypeInitialArrayPrototype(array.map)) goto Slow;
if (IsNoElementsProtectorCellInvalid()) goto Slow;
if (kind == ElementsKind::HOLEY_SMI_ELEMENTS ||
kind == ElementsKind::HOLEY_ELEMENTS) {
array::EnsureWriteableFastElements(array);
FastArrayReverse<FixedArray, Object>(array.elements, array.length);
} else if (kind == ElementsKind::HOLEY_DOUBLE_ELEMENTS) {
FastArrayReverse<FixedDoubleArray, float64_or_undefined_or_hole>(
array.elements, array.length);
} else {
goto Slow;
}
}
}
// https://tc39.github.io/ecma262/#sec-array.prototype.reverse
transitioning javascript builtin ArrayPrototypeReverse(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
try {
TryFastPackedArrayReverse(receiver) otherwise Baseline;
return receiver;
} label Baseline {
return GenericArrayReverse(context, receiver);
}
}
}