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 5namespace array { 6macro LoadWithHoleCheck<Elements : type extends FixedArrayBase>( 7 elements: FixedArrayBase, index: Smi): JSAny 8 labels IfHole; 9 10LoadWithHoleCheck<FixedArray>(implicit context: Context)( 11 elements: FixedArrayBase, index: Smi): JSAny 12 labels IfHole { 13 const elements: FixedArray = UnsafeCast<FixedArray>(elements); 14 const element: Object = elements.objects[index]; 15 if (element == TheHole) goto IfHole; 16 return UnsafeCast<JSAny>(element); 17} 18 19LoadWithHoleCheck<FixedDoubleArray>(implicit context: Context)( 20 elements: FixedArrayBase, index: Smi): JSAny 21 labels IfHole { 22 const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements); 23 const element: float64 = elements.floats[index].Value() otherwise IfHole; 24 return AllocateHeapNumberWithValue(element); 25} 26 27macro FastArrayLastIndexOf<Elements : type extends FixedArrayBase>( 28 context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi { 29 const elements: FixedArrayBase = array.elements; 30 let k: Smi = from; 31 32 // Bug(898785): Due to side-effects in the evaluation of `fromIndex` 33 // the {from} can be out-of-bounds here, so we need to clamp {k} to 34 // the {elements} length. We might be reading holes / hole NaNs still 35 // due to that, but those will be ignored below. 36 if (k >= elements.length) { 37 k = elements.length - 1; 38 } 39 40 while (k >= 0) { 41 try { 42 const element: JSAny = LoadWithHoleCheck<Elements>(elements, k) 43 otherwise Hole; 44 45 const same: Boolean = StrictEqual(searchElement, element); 46 if (same == True) { 47 assert(Is<FastJSArray>(array)); 48 return k; 49 } 50 } label Hole {} // Do nothing for holes. 51 52 --k; 53 } 54 55 assert(Is<FastJSArray>(array)); 56 return -1; 57} 58 59transitioning macro 60GetFromIndex(context: Context, length: Number, arguments: Arguments): Number { 61 // 4. If fromIndex is present, let n be ? ToInteger(fromIndex); 62 // else let n be len - 1. 63 const n: Number = 64 arguments.length < 2 ? length - 1 : ToInteger_Inline(arguments[1]); 65 66 // 5. If n >= 0, then. 67 let k: Number = SmiConstant(0); 68 if (n >= 0) { 69 // a. If n is -0, let k be +0; else let k be min(n, len - 1). 70 // If n was -0 it got truncated to 0.0, so taking the minimum is fine. 71 k = Min(n, length - 1); 72 } else { 73 // a. Let k be len + n. 74 k = length + n; 75 } 76 return k; 77} 78 79macro TryFastArrayLastIndexOf( 80 context: Context, receiver: JSReceiver, searchElement: JSAny, 81 from: Number): JSAny 82 labels Slow { 83 const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow; 84 const length: Smi = array.length; 85 if (length == 0) return SmiConstant(-1); 86 87 const fromSmi: Smi = Cast<Smi>(from) otherwise Slow; 88 const kind: ElementsKind = array.map.elements_kind; 89 if (IsFastSmiOrTaggedElementsKind(kind)) { 90 return FastArrayLastIndexOf<FixedArray>( 91 context, array, fromSmi, searchElement); 92 } 93 assert(IsDoubleElementsKind(kind)); 94 return FastArrayLastIndexOf<FixedDoubleArray>( 95 context, array, fromSmi, searchElement); 96} 97 98transitioning macro GenericArrayLastIndexOf( 99 context: Context, object: JSReceiver, searchElement: JSAny, 100 from: Number): JSAny { 101 let k: Number = from; 102 103 // 7. Repeat, while k >= 0. 104 while (k >= 0) { 105 // a. Let kPresent be ? HasProperty(O, ! ToString(k)). 106 const kPresent: Boolean = HasProperty(object, k); 107 108 // b. If kPresent is true, then. 109 if (kPresent == True) { 110 // i. Let elementK be ? Get(O, ! ToString(k)). 111 const element: JSAny = GetProperty(object, k); 112 113 // ii. Let same be the result of performing Strict Equality Comparison 114 // searchElement === elementK. 115 const same: Boolean = StrictEqual(searchElement, element); 116 117 // iii. If same is true, return k. 118 if (same == True) return k; 119 } 120 121 // c. Decrease k by 1. 122 --k; 123 } 124 125 // 8. Return -1. 126 return SmiConstant(-1); 127} 128 129// https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf 130transitioning javascript builtin ArrayPrototypeLastIndexOf( 131 js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { 132 // 1. Let O be ? ToObject(this value). 133 const object: JSReceiver = ToObject_Inline(context, receiver); 134 135 // 2. Let len be ? ToLength(? Get(O, "length")). 136 const length: Number = GetLengthProperty(object); 137 138 // 3. If len is 0, return -1. 139 if (length == SmiConstant(0)) return SmiConstant(-1); 140 141 // Step 4 - 6. 142 const from: Number = GetFromIndex(context, length, arguments); 143 144 const searchElement: JSAny = arguments[0]; 145 146 try { 147 return TryFastArrayLastIndexOf(context, object, searchElement, from) 148 otherwise Baseline; 149 } label Baseline { 150 return GenericArrayLastIndexOf(context, object, searchElement, from); 151 } 152} 153} 154