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 HandleSimpleArgumentsSlice( 7 context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, 8 count: Smi): JSArray 9 labels Bailout { 10 // If the resulting array doesn't fit in new space, use the slow path. 11 if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; 12 13 const end: Smi = start + count; 14 const sourceElements: FixedArray = 15 Cast<FixedArray>(args.elements) otherwise Bailout; 16 if (SmiAbove(end, sourceElements.length)) goto Bailout; 17 18 const arrayMap: Map = 19 LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); 20 const result: JSArray = 21 AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); 22 const newElements: FixedArray = 23 Cast<FixedArray>(result.elements) otherwise Bailout; 24 CopyElements( 25 ElementsKind::PACKED_ELEMENTS, newElements, 0, sourceElements, 26 Convert<intptr>(start), Convert<intptr>(count)); 27 return result; 28} 29 30macro HandleFastAliasedSloppyArgumentsSlice( 31 context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi, 32 count: Smi): JSArray 33 labels Bailout { 34 // If the resulting array doesn't fit in new space, use the slow path. 35 if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout; 36 37 const sloppyElements: SloppyArgumentsElements = 38 Cast<SloppyArgumentsElements>(args.elements) otherwise Bailout; 39 const parameterMapLength: Smi = sloppyElements.length; 40 41 // Check to make sure that the extraction will not access outside the 42 // defined arguments 43 const end: Smi = start + count; 44 const unmappedElements: FixedArray = 45 Cast<FixedArray>(sloppyElements.arguments) 46 otherwise Bailout; 47 const unmappedElementsLength: Smi = unmappedElements.length; 48 if (SmiAbove(end, unmappedElementsLength)) goto Bailout; 49 50 const argumentsContext: Context = sloppyElements.context; 51 52 const arrayMap: Map = 53 LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context); 54 const result: JSArray = 55 AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count); 56 57 let indexOut: Smi = 0; 58 const resultElements: FixedArray = UnsafeCast<FixedArray>(result.elements); 59 const to: Smi = SmiMin(parameterMapLength, end); 60 61 // Fill in the part of the result that map to context-mapped parameters. 62 for (let current: Smi = start; current < to; ++current) { 63 const e: Object = sloppyElements.mapped_entries[current]; 64 const newElement = UnsafeCast<(JSAny | TheHole)>( 65 e != TheHole ? argumentsContext.elements[UnsafeCast<Smi>(e)] : 66 unmappedElements.objects[current]); 67 // It is safe to skip the write barrier here because resultElements was 68 // allocated together with result in a folded allocation. 69 // TODO(tebbi): The verification of this fails at the moment due to 70 // missing load elimination. 71 StoreFixedArrayElement( 72 resultElements, indexOut++, newElement, UNSAFE_SKIP_WRITE_BARRIER); 73 } 74 75 // Fill in the rest of the result that contains the unmapped parameters 76 // above the formal parameters. 77 const unmappedFrom: Smi = SmiMin(SmiMax(parameterMapLength, start), end); 78 const restCount: Smi = end - unmappedFrom; 79 CopyElements( 80 ElementsKind::PACKED_ELEMENTS, resultElements, Convert<intptr>(indexOut), 81 unmappedElements, Convert<intptr>(unmappedFrom), 82 Convert<intptr>(restCount)); 83 return result; 84} 85 86macro HandleFastSlice( 87 context: NativeContext, o: JSAny, startNumber: Number, 88 countNumber: Number): JSArray 89 labels Bailout { 90 const start: Smi = Cast<Smi>(startNumber) otherwise Bailout; 91 const count: Smi = Cast<Smi>(countNumber) otherwise Bailout; 92 assert(start >= 0); 93 94 try { 95 typeswitch (o) { 96 case (a: FastJSArrayForCopy): { 97 // It's possible to modify the array length from a valueOf 98 // callback between the original array length read and this 99 // point. That can change the length of the array backing store, 100 // in the worst case, making it smaller than the region that needs 101 // to be copied out. Therefore, re-check the length before calling 102 // the appropriate fast path. See regress-785804.js 103 if (SmiAbove(start + count, a.length)) goto Bailout; 104 return ExtractFastJSArray(context, a, start, count); 105 } 106 case (a: JSStrictArgumentsObject): { 107 goto HandleSimpleArgumentsSlice(a); 108 } 109 case (a: JSSloppyArgumentsObject): { 110 const map: Map = a.map; 111 if (IsFastAliasedArgumentsMap(map)) { 112 return HandleFastAliasedSloppyArgumentsSlice(context, a, start, count) 113 otherwise Bailout; 114 } else if (IsSloppyArgumentsMap(map)) { 115 goto HandleSimpleArgumentsSlice(a); 116 } 117 goto Bailout; 118 } 119 case (JSAny): { 120 goto Bailout; 121 } 122 } 123 } label HandleSimpleArgumentsSlice(a: JSArgumentsObjectWithLength) { 124 return HandleSimpleArgumentsSlice(context, a, start, count) 125 otherwise Bailout; 126 } 127} 128 129// https://tc39.github.io/ecma262/#sec-array.prototype.slice 130transitioning javascript builtin 131ArrayPrototypeSlice( 132 js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { 133 // Handle array cloning case if the receiver is a fast array. 134 if (arguments.length == 0) { 135 typeswitch (receiver) { 136 case (a: FastJSArrayForCopy): { 137 return CloneFastJSArray(context, a); 138 } 139 case (JSAny): { 140 } 141 } 142 } 143 144 // 1. Let O be ? ToObject(this value). 145 const o: JSReceiver = ToObject_Inline(context, receiver); 146 147 // 2. Let len be ? ToLength(? Get(O, "length")). 148 const len: Number = GetLengthProperty(o); 149 150 // 3. Let relativeStart be ? ToInteger(start). 151 const start: JSAny = arguments[0]; 152 const relativeStart: Number = ToInteger_Inline(start); 153 154 // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); 155 // else let k be min(relativeStart, len). 156 let k: Number = relativeStart < 0 ? Max((len + relativeStart), 0) : 157 Min(relativeStart, len); 158 159 // 5. If end is undefined, let relativeEnd be len; 160 // else let relativeEnd be ? ToInteger(end). 161 const end: JSAny = arguments[1]; 162 const relativeEnd: Number = end == Undefined ? len : ToInteger_Inline(end); 163 164 // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); 165 // else let final be min(relativeEnd, len). 166 const final: Number = 167 relativeEnd < 0 ? Max((len + relativeEnd), 0) : Min(relativeEnd, len); 168 169 // 7. Let count be max(final - k, 0). 170 const count: Number = Max(final - k, 0); 171 172 assert(0 <= k); 173 assert(k <= len); 174 assert(0 <= final); 175 assert(final <= len); 176 assert(0 <= count); 177 assert(count <= len); 178 179 try { 180 return HandleFastSlice(context, o, k, count) 181 otherwise Slow; 182 } label Slow {} 183 184 // 8. Let A be ? ArraySpeciesCreate(O, count). 185 const a: JSReceiver = ArraySpeciesCreate(context, o, count); 186 187 // 9. Let n be 0. 188 let n: Number = 0; 189 190 // 10. Repeat, while k < final 191 while (k < final) { 192 // a. Let Pk be ! ToString(k). 193 const pK: Number = k; 194 195 // b. Let kPresent be ? HasProperty(O, Pk). 196 const fromPresent: Boolean = HasProperty(o, pK); 197 198 // c. If kPresent is true, then 199 if (fromPresent == True) { 200 // i. Let kValue be ? Get(O, Pk). 201 const kValue: JSAny = GetProperty(o, pK); 202 203 // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue). 204 FastCreateDataProperty(a, n, kValue); 205 } 206 207 // d. Increase k by 1. 208 k++; 209 210 // e. Increase n by 1. 211 n++; 212 } 213 214 // 11. Perform ? Set(A, "length", n, true). 215 SetProperty(a, kLengthString, n); 216 217 // 12. Return A. 218 return a; 219} 220} 221