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 { 6transitioning javascript builtin 7ArrayReducePreLoopEagerDeoptContinuation( 8 js-implicit context: NativeContext, receiver: JSAny)( 9 callback: JSAny, length: JSAny): JSAny { 10 // All continuation points in the optimized every implementation are 11 // after the ToObject(O) call that ensures we are dealing with a 12 // JSReceiver. 13 // 14 // Also, this great mass of casts is necessary because the signature 15 // of Torque javascript builtins requires JSAny type for all parameters 16 // other than {context}. 17 const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; 18 const callbackfn = Cast<Callable>(callback) otherwise unreachable; 19 const numberLength = Cast<Number>(length) otherwise unreachable; 20 21 // Simulate starting the loop at 0, but ensuring that the accumulator is 22 // the hole. The continuation stub will search for the initial non-hole 23 // element, rightly throwing an exception if not found. 24 return ArrayReduceLoopContinuation( 25 jsreceiver, callbackfn, TheHole, jsreceiver, 0, numberLength); 26} 27 28transitioning javascript builtin 29ArrayReduceLoopEagerDeoptContinuation( 30 js-implicit context: NativeContext, receiver: JSAny)( 31 callback: JSAny, initialK: JSAny, length: JSAny, 32 accumulator: JSAny): JSAny { 33 // All continuation points in the optimized every implementation are 34 // after the ToObject(O) call that ensures we are dealing with a 35 // JSReceiver. 36 // 37 // Also, this great mass of casts is necessary because the signature 38 // of Torque javascript builtins requires JSAny type for all parameters 39 // other than {context}. 40 const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; 41 const callbackfn = Cast<Callable>(callback) otherwise unreachable; 42 const numberK = Cast<Number>(initialK) otherwise unreachable; 43 const numberLength = Cast<Number>(length) otherwise unreachable; 44 45 return ArrayReduceLoopContinuation( 46 jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength); 47} 48 49transitioning javascript builtin 50ArrayReduceLoopLazyDeoptContinuation( 51 js-implicit context: NativeContext, receiver: JSAny)( 52 callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny { 53 // All continuation points in the optimized every implementation are 54 // after the ToObject(O) call that ensures we are dealing with a 55 // JSReceiver. 56 const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; 57 const callbackfn = Cast<Callable>(callback) otherwise unreachable; 58 const numberK = Cast<Number>(initialK) otherwise unreachable; 59 const numberLength = Cast<Number>(length) otherwise unreachable; 60 61 // The accumulator is the result from the callback call which just occured. 62 const r = ArrayReduceLoopContinuation( 63 jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); 64 return r; 65} 66 67transitioning builtin ArrayReduceLoopContinuation(implicit context: Context)( 68 _receiver: JSReceiver, callbackfn: Callable, 69 initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number, 70 length: Number): JSAny { 71 let accumulator = initialAccumulator; 72 73 // 8b and 9. Repeat, while k < len 74 for (let k: Number = initialK; k < length; k++) { 75 // 8b i and 9a. Let Pk be ! ToString(k). 76 // k is guaranteed to be a positive integer, hence ToString is 77 // side-effect free and HasProperty/GetProperty do the conversion inline. 78 79 // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk). 80 const present: Boolean = HasProperty_Inline(o, k); 81 82 // 6c. If kPresent is true, then 83 if (present == True) { 84 // 6c. i. Let kValue be ? Get(O, Pk). 85 const value: JSAny = GetProperty(o, k); 86 87 typeswitch (accumulator) { 88 case (TheHole): { 89 // 8b. 90 accumulator = value; 91 } 92 case (accumulatorNotHole: JSAny): { 93 // 9c. ii. Set accumulator to ? Call(callbackfn, undefined, 94 // <accumulator, kValue, k, O>). 95 accumulator = Call( 96 context, callbackfn, Undefined, accumulatorNotHole, value, k, o); 97 } 98 } 99 } 100 101 // 8b iv and 9d. Increase k by 1. (done by the loop). 102 } 103 104 // 8c. if kPresent is false, throw a TypeError exception. 105 // If the accumulator is discovered with the sentinel hole value, 106 // this means kPresent is false. 107 typeswitch (accumulator) { 108 case (TheHole): { 109 ThrowTypeError( 110 MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); 111 } 112 case (accumulator: JSAny): { 113 return accumulator; 114 } 115 } 116} 117 118transitioning macro FastArrayReduce(implicit context: Context)( 119 o: JSReceiver, len: Number, callbackfn: Callable, 120 initialAccumulator: JSAny|TheHole): JSAny 121 labels Bailout(Number, JSAny | TheHole) { 122 const k = 0; 123 let accumulator = initialAccumulator; 124 Cast<Smi>(len) otherwise goto Bailout(k, accumulator); 125 const fastO = 126 Cast<FastJSArrayForRead>(o) otherwise goto Bailout(k, accumulator); 127 let fastOW = NewFastJSArrayForReadWitness(fastO); 128 129 // Build a fast loop over the array. 130 for (let k: Smi = 0; k < len; k++) { 131 fastOW.Recheck() otherwise goto Bailout(k, accumulator); 132 133 // Ensure that we haven't walked beyond a possibly updated length. 134 if (k >= fastOW.Get().length) goto Bailout(k, accumulator); 135 136 const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue; 137 typeswitch (accumulator) { 138 case (TheHole): { 139 accumulator = value; 140 } 141 case (accumulatorNotHole: JSAny): { 142 accumulator = Call( 143 context, callbackfn, Undefined, accumulatorNotHole, value, k, 144 fastOW.Get()); 145 } 146 } 147 } 148 typeswitch (accumulator) { 149 case (TheHole): { 150 ThrowTypeError( 151 MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); 152 } 153 case (accumulator: JSAny): { 154 return accumulator; 155 } 156 } 157} 158 159// https://tc39.github.io/ecma262/#sec-array.prototype.reduce 160transitioning javascript builtin 161ArrayReduce( 162 js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { 163 try { 164 RequireObjectCoercible(receiver, 'Array.prototype.reduce'); 165 166 // 1. Let O be ? ToObject(this value). 167 const o: JSReceiver = ToObject_Inline(context, receiver); 168 169 // 2. Let len be ? ToLength(? Get(O, "length")). 170 const len: Number = GetLengthProperty(o); 171 172 // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 173 if (arguments.length == 0) { 174 goto NoCallableError; 175 } 176 const callbackfn = Cast<Callable>(arguments[0]) otherwise NoCallableError; 177 178 // 4. If len is 0 and initialValue is not present, throw a TypeError 179 // exception. (This case is handled at the end of 180 // ArrayReduceLoopContinuation). 181 182 const initialValue: JSAny|TheHole = 183 arguments.length > 1 ? arguments[1] : TheHole; 184 185 try { 186 return FastArrayReduce(o, len, callbackfn, initialValue) 187 otherwise Bailout; 188 } label Bailout(value: Number, accumulator: JSAny|TheHole) { 189 return ArrayReduceLoopContinuation( 190 o, callbackfn, accumulator, o, value, len); 191 } 192 } label NoCallableError deferred { 193 ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); 194 } 195} 196} 197