1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5module array { 6 macro LoadElement<ElementsAccessor : type, T : type>( 7 elements: FixedArrayBase, index: Smi): T; 8 9 LoadElement<FastPackedSmiElements, Smi>( 10 elements: FixedArrayBase, index: Smi): Smi { 11 const elems: FixedArray = unsafe_cast<FixedArray>(elements); 12 return unsafe_cast<Smi>(elems[index]); 13 } 14 15 LoadElement<FastPackedObjectElements, Object>( 16 elements: FixedArrayBase, index: Smi): Object { 17 const elems: FixedArray = unsafe_cast<FixedArray>(elements); 18 return elems[index]; 19 } 20 21 LoadElement<FastPackedDoubleElements, float64>( 22 elements: FixedArrayBase, index: Smi): float64 { 23 try { 24 const elems: FixedDoubleArray = unsafe_cast<FixedDoubleArray>(elements); 25 return LoadDoubleWithHoleCheck(elems, index) otherwise Hole; 26 } 27 label Hole { 28 // This macro is only used for PACKED_DOUBLE, loading the hole should 29 // be impossible. 30 unreachable; 31 } 32 } 33 34 macro StoreElement<ElementsAccessor : type, T : type>( 35 elements: FixedArrayBase, index: Smi, value: T); 36 37 StoreElement<FastPackedSmiElements, Smi>( 38 elements: FixedArrayBase, index: Smi, value: Smi) { 39 const elems: FixedArray = unsafe_cast<FixedArray>(elements); 40 StoreFixedArrayElementSmi(elems, index, value, SKIP_WRITE_BARRIER); 41 } 42 43 StoreElement<FastPackedObjectElements, Object>( 44 elements: FixedArrayBase, index: Smi, value: Object) { 45 const elems: FixedArray = unsafe_cast<FixedArray>(elements); 46 elems[index] = value; 47 } 48 49 StoreElement<FastPackedDoubleElements, float64>( 50 elements: FixedArrayBase, index: Smi, value: float64) { 51 const elems: FixedDoubleArray = unsafe_cast<FixedDoubleArray>(elements); 52 53 assert(value == Float64SilenceNaN(value)); 54 StoreFixedDoubleArrayElementWithSmiIndex(elems, index, value); 55 } 56 57 // Fast-path for all PACKED_* elements kinds. These do not need to check 58 // whether a property is present, so we can simply swap them using fast 59 // FixedArray loads/stores. 60 macro FastPackedArrayReverse<Accessor : type, T : type>( 61 elements: FixedArrayBase, length: Smi) { 62 let lower: Smi = 0; 63 let upper: Smi = length - 1; 64 65 while (lower < upper) { 66 const lower_value: T = LoadElement<Accessor, T>(elements, lower); 67 const upper_value: T = LoadElement<Accessor, T>(elements, upper); 68 StoreElement<Accessor, T>(elements, lower, upper_value); 69 StoreElement<Accessor, T>(elements, upper, lower_value); 70 ++lower; 71 --upper; 72 } 73 } 74 75 macro GenericArrayReverse(context: Context, receiver: Object): Object { 76 // 1. Let O be ? ToObject(this value). 77 const object: JSReceiver = ToObject_Inline(context, receiver); 78 79 // 2. Let len be ? ToLength(? Get(O, "length")). 80 const length: Number = GetLengthProperty(context, object); 81 82 // 3. Let middle be floor(len / 2). 83 // 4. Let lower be 0. 84 // 5. Repeat, while lower != middle. 85 // a. Let upper be len - lower - 1. 86 87 // Instead of calculating the middle value, we simply initialize upper 88 // with len - 1 and decrement it after each iteration. 89 let lower: Number = 0; 90 let upper: Number = length - 1; 91 92 while (lower < upper) { 93 let lower_value: Object = Undefined; 94 let upper_value: Object = Undefined; 95 96 // b. Let upperP be ! ToString(upper). 97 // c. Let lowerP be ! ToString(lower). 98 // d. Let lowerExists be ? HasProperty(O, lowerP). 99 const lower_exists: Boolean = HasProperty(context, object, lower); 100 101 // e. If lowerExists is true, then. 102 if (lower_exists == True) { 103 // i. Let lowerValue be ? Get(O, lowerP). 104 lower_value = GetProperty(context, object, lower); 105 } 106 107 // f. Let upperExists be ? HasProperty(O, upperP). 108 const upper_exists: Boolean = HasProperty(context, object, upper); 109 110 // g. If upperExists is true, then. 111 if (upper_exists == True) { 112 // i. Let upperValue be ? Get(O, upperP). 113 upper_value = GetProperty(context, object, upper); 114 } 115 116 // h. If lowerExists is true and upperExists is true, then 117 if (lower_exists == True && upper_exists == True) { 118 // i. Perform ? Set(O, lowerP, upperValue, true). 119 SetProperty(context, object, lower, upper_value); 120 121 // ii. Perform ? Set(O, upperP, lowerValue, true). 122 SetProperty(context, object, upper, lower_value); 123 } else if (lower_exists == False && upper_exists == True) { 124 // i. Perform ? Set(O, lowerP, upperValue, true). 125 SetProperty(context, object, lower, upper_value); 126 127 // ii. Perform ? DeletePropertyOrThrow(O, upperP). 128 DeleteProperty(context, object, upper, kStrict); 129 } else if (lower_exists == True && upper_exists == False) { 130 // i. Perform ? DeletePropertyOrThrow(O, lowerP). 131 DeleteProperty(context, object, lower, kStrict); 132 133 // ii. Perform ? Set(O, upperP, lowerValue, true). 134 SetProperty(context, object, upper, lower_value); 135 } 136 137 // l. Increase lower by 1. 138 ++lower; 139 --upper; 140 } 141 142 // 6. Return O. 143 return object; 144 } 145 146 macro EnsureWriteableFastElements(array: JSArray) { 147 const elements: FixedArrayBase = array.elements; 148 if (elements.map != kCOWMap) return; 149 150 // There are no COW *_DOUBLE_ELEMENTS arrays, so we are allowed to always 151 // extract FixedArrays and don't have to worry about FixedDoubleArrays. 152 assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind)); 153 154 const length: Smi = array.length_fast; 155 array.elements = ExtractFixedArray( 156 unsafe_cast<FixedArray>(elements), 0, length, length, kFixedArrays); 157 } 158 159 macro TryFastPackedArrayReverse(receiver: Object) labels Slow { 160 const array: JSArray = cast<JSArray>(receiver) otherwise Slow; 161 EnsureWriteableFastElements(array); 162 assert(array.elements.map != kCOWMap); 163 164 const kind: ElementsKind = array.map.elements_kind; 165 if (kind == PACKED_SMI_ELEMENTS) { 166 FastPackedArrayReverse<FastPackedSmiElements, Smi>( 167 array.elements, array.length_fast); 168 } else if (kind == PACKED_ELEMENTS) { 169 FastPackedArrayReverse<FastPackedObjectElements, Object>( 170 array.elements, array.length_fast); 171 } else if (kind == PACKED_DOUBLE_ELEMENTS) { 172 FastPackedArrayReverse<FastPackedDoubleElements, float64>( 173 array.elements, array.length_fast); 174 } else { 175 goto Slow; 176 } 177 } 178 179 // https://tc39.github.io/ecma262/#sec-array.prototype.reverse 180 javascript builtin ArrayPrototypeReverse( 181 context: Context, receiver: Object, ...arguments): Object { 182 try { 183 TryFastPackedArrayReverse(receiver) otherwise Baseline; 184 return receiver; 185 } 186 label Baseline { 187 return GenericArrayReverse(context, receiver); 188 } 189 } 190} 191