| // 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<ElementsAccessor : type extends ElementsKind, T: type>( |
| elements: FixedArrayBase, index: Smi): T; |
| |
| LoadElement<array::FastPackedSmiElements, Smi>(implicit context: Context)( |
| elements: FixedArrayBase, index: Smi): Smi { |
| const elements: FixedArray = UnsafeCast<FixedArray>(elements); |
| return UnsafeCast<Smi>(elements.objects[index]); |
| } |
| |
| LoadElement<array::FastPackedObjectElements, JSAny>(implicit context: Context)( |
| elements: FixedArrayBase, index: Smi): JSAny { |
| const elements: FixedArray = UnsafeCast<FixedArray>(elements); |
| return UnsafeCast<JSAny>(elements.objects[index]); |
| } |
| |
| LoadElement<array::FastPackedDoubleElements, float64>( |
| implicit context: Context)(elements: FixedArrayBase, index: Smi): float64 { |
| const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements); |
| // This macro is only used for PACKED_DOUBLE, loading the hole should |
| // be impossible. |
| return elements.floats[index].Value() otherwise unreachable; |
| } |
| |
| macro StoreElement<ElementsAccessor : type extends ElementsKind, T: type>( |
| implicit context: Context)(elements: FixedArrayBase, index: Smi, value: T); |
| |
| StoreElement<array::FastPackedSmiElements, Smi>(implicit context: Context)( |
| elements: FixedArrayBase, index: Smi, value: Smi) { |
| const elems: FixedArray = UnsafeCast<FixedArray>(elements); |
| StoreFixedArrayElement(elems, index, value, SKIP_WRITE_BARRIER); |
| } |
| |
| StoreElement<array::FastPackedObjectElements, JSAny>(implicit context: Context)( |
| elements: FixedArrayBase, index: Smi, value: JSAny) { |
| const elements: FixedArray = UnsafeCast<FixedArray>(elements); |
| elements.objects[index] = value; |
| } |
| |
| StoreElement<array::FastPackedDoubleElements, float64>( |
| implicit context: Context)( |
| elements: FixedArrayBase, index: Smi, value: float64) { |
| const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements); |
| StoreFixedDoubleArrayElement(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>( |
| implicit context: Context)(elements: FixedArrayBase, length: Smi) { |
| let lower: Smi = 0; |
| let upper: Smi = length - 1; |
| |
| while (lower < upper) { |
| const lowerValue: T = LoadElement<Accessor, T>(elements, lower); |
| const upperValue: T = LoadElement<Accessor, T>(elements, upper); |
| StoreElement<Accessor>(elements, lower, upperValue); |
| StoreElement<Accessor>(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) |
| labels Slow { |
| const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow; |
| |
| const kind: ElementsKind = array.map.elements_kind; |
| if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { |
| array::EnsureWriteableFastElements(array); |
| FastPackedArrayReverse<array::FastPackedSmiElements, Smi>( |
| array.elements, array.length); |
| } else if (kind == ElementsKind::PACKED_ELEMENTS) { |
| array::EnsureWriteableFastElements(array); |
| FastPackedArrayReverse<array::FastPackedObjectElements, JSAny>( |
| array.elements, array.length); |
| } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) { |
| FastPackedArrayReverse<array::FastPackedDoubleElements, float64>( |
| 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); |
| } |
| } |
| } |