blob: e141d945e23b9abf293e4c53aca6a2b722868d21 [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.
module array {
macro LoadElement<ElementsAccessor : type, T : type>(
elements: FixedArrayBase, index: Smi): T;
LoadElement<FastPackedSmiElements, Smi>(
elements: FixedArrayBase, index: Smi): Smi {
const elems: FixedArray = unsafe_cast<FixedArray>(elements);
return unsafe_cast<Smi>(elems[index]);
}
LoadElement<FastPackedObjectElements, Object>(
elements: FixedArrayBase, index: Smi): Object {
const elems: FixedArray = unsafe_cast<FixedArray>(elements);
return elems[index];
}
LoadElement<FastPackedDoubleElements, float64>(
elements: FixedArrayBase, index: Smi): float64 {
try {
const elems: FixedDoubleArray = unsafe_cast<FixedDoubleArray>(elements);
return LoadDoubleWithHoleCheck(elems, index) otherwise Hole;
}
label Hole {
// This macro is only used for PACKED_DOUBLE, loading the hole should
// be impossible.
unreachable;
}
}
macro StoreElement<ElementsAccessor : type, T : type>(
elements: FixedArrayBase, index: Smi, value: T);
StoreElement<FastPackedSmiElements, Smi>(
elements: FixedArrayBase, index: Smi, value: Smi) {
const elems: FixedArray = unsafe_cast<FixedArray>(elements);
StoreFixedArrayElementSmi(elems, index, value, SKIP_WRITE_BARRIER);
}
StoreElement<FastPackedObjectElements, Object>(
elements: FixedArrayBase, index: Smi, value: Object) {
const elems: FixedArray = unsafe_cast<FixedArray>(elements);
elems[index] = value;
}
StoreElement<FastPackedDoubleElements, float64>(
elements: FixedArrayBase, index: Smi, value: float64) {
const elems: FixedDoubleArray = unsafe_cast<FixedDoubleArray>(elements);
assert(value == Float64SilenceNaN(value));
StoreFixedDoubleArrayElementWithSmiIndex(elems, 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 FastPackedArrayReverse<Accessor : type, T : type>(
elements: FixedArrayBase, length: Smi) {
let lower: Smi = 0;
let upper: Smi = length - 1;
while (lower < upper) {
const lower_value: T = LoadElement<Accessor, T>(elements, lower);
const upper_value: T = LoadElement<Accessor, T>(elements, upper);
StoreElement<Accessor, T>(elements, lower, upper_value);
StoreElement<Accessor, T>(elements, upper, lower_value);
++lower;
--upper;
}
}
macro GenericArrayReverse(context: Context, receiver: Object): Object {
// 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(context, 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 lower_value: Object = Undefined;
let upper_value: Object = Undefined;
// b. Let upperP be ! ToString(upper).
// c. Let lowerP be ! ToString(lower).
// d. Let lowerExists be ? HasProperty(O, lowerP).
const lower_exists: Boolean = HasProperty(context, object, lower);
// e. If lowerExists is true, then.
if (lower_exists == True) {
// i. Let lowerValue be ? Get(O, lowerP).
lower_value = GetProperty(context, object, lower);
}
// f. Let upperExists be ? HasProperty(O, upperP).
const upper_exists: Boolean = HasProperty(context, object, upper);
// g. If upperExists is true, then.
if (upper_exists == True) {
// i. Let upperValue be ? Get(O, upperP).
upper_value = GetProperty(context, object, upper);
}
// h. If lowerExists is true and upperExists is true, then
if (lower_exists == True && upper_exists == True) {
// i. Perform ? Set(O, lowerP, upperValue, true).
SetProperty(context, object, lower, upper_value);
// ii. Perform ? Set(O, upperP, lowerValue, true).
SetProperty(context, object, upper, lower_value);
} else if (lower_exists == False && upper_exists == True) {
// i. Perform ? Set(O, lowerP, upperValue, true).
SetProperty(context, object, lower, upper_value);
// ii. Perform ? DeletePropertyOrThrow(O, upperP).
DeleteProperty(context, object, upper, kStrict);
} else if (lower_exists == True && upper_exists == False) {
// i. Perform ? DeletePropertyOrThrow(O, lowerP).
DeleteProperty(context, object, lower, kStrict);
// ii. Perform ? Set(O, upperP, lowerValue, true).
SetProperty(context, object, upper, lower_value);
}
// l. Increase lower by 1.
++lower;
--upper;
}
// 6. Return O.
return object;
}
macro EnsureWriteableFastElements(array: JSArray) {
const elements: FixedArrayBase = array.elements;
if (elements.map != kCOWMap) return;
// There are no COW *_DOUBLE_ELEMENTS arrays, so we are allowed to always
// extract FixedArrays and don't have to worry about FixedDoubleArrays.
assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind));
const length: Smi = array.length_fast;
array.elements =
ExtractFixedArray(unsafe_cast<FixedArray>(elements), 0, length, length);
}
macro TryFastPackedArrayReverse(receiver: Object) labels Slow {
const array: JSArray = cast<JSArray>(receiver) otherwise Slow;
EnsureWriteableFastElements(array);
assert(array.elements.map != kCOWMap);
const kind: ElementsKind = array.map.elements_kind;
if (kind == PACKED_SMI_ELEMENTS) {
FastPackedArrayReverse<FastPackedSmiElements, Smi>(
array.elements, array.length_fast);
} else if (kind == PACKED_ELEMENTS) {
FastPackedArrayReverse<FastPackedObjectElements, Object>(
array.elements, array.length_fast);
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
FastPackedArrayReverse<FastPackedDoubleElements, float64>(
array.elements, array.length_fast);
} else {
goto Slow;
}
}
// https://tc39.github.io/ecma262/#sec-array.prototype.reverse
javascript builtin ArrayPrototypeReverse(
context: Context, receiver: Object, ...arguments): Object {
try {
TryFastPackedArrayReverse(receiver) otherwise Baseline;
return receiver;
}
label Baseline {
return GenericArrayReverse(context, receiver);
}
}
}