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 7ArrayFindLoopEagerDeoptContinuation( 8 js-implicit context: NativeContext, receiver: JSAny)( 9 callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny { 10 // All continuation points in the optimized find 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 numberK = Cast<Number>(initialK) otherwise unreachable; 20 const numberLength = Cast<Number>(length) otherwise unreachable; 21 22 return ArrayFindLoopContinuation( 23 jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); 24} 25 26transitioning javascript builtin 27ArrayFindLoopLazyDeoptContinuation( 28 js-implicit context: NativeContext, receiver: JSAny)( 29 _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny, 30 _result: JSAny): JSAny { 31 // This deopt continuation point is never actually called, it just 32 // exists to make stack traces correct from a ThrowTypeError if the 33 // callback was found to be non-callable. 34 unreachable; 35} 36 37// Continuation that is called after a lazy deoptimization from TF that 38// happens right after the callback and it's returned value must be handled 39// before iteration continues. 40transitioning javascript builtin 41ArrayFindLoopAfterCallbackLazyDeoptContinuation( 42 js-implicit context: NativeContext, receiver: JSAny)( 43 callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny, 44 foundValue: JSAny, isFound: JSAny): JSAny { 45 // All continuation points in the optimized find implementation are 46 // after the ToObject(O) call that ensures we are dealing with a 47 // JSReceiver. 48 const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; 49 const callbackfn = Cast<Callable>(callback) otherwise unreachable; 50 const numberK = Cast<Number>(initialK) otherwise unreachable; 51 const numberLength = Cast<Number>(length) otherwise unreachable; 52 53 // This custom lazy deopt point is right after the callback. find() needs 54 // to pick up at the next step, which is returning the element if the 55 // callback value is truthy. Otherwise, continue the search by calling the 56 // continuation. 57 58 if (ToBoolean(isFound)) { 59 return foundValue; 60 } 61 62 return ArrayFindLoopContinuation( 63 jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength); 64} 65 66transitioning builtin ArrayFindLoopContinuation(implicit context: Context)( 67 _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny, o: JSReceiver, 68 initialK: Number, length: Number): JSAny { 69 // 5. Let k be 0. 70 // 6. Repeat, while k < len 71 for (let k: Number = initialK; k < length; k++) { 72 // 6a. Let Pk be ! ToString(k). 73 // k is guaranteed to be a positive integer, hence ToString is 74 // side-effect free and HasProperty/GetProperty do the conversion inline. 75 76 // 6b. i. Let kValue be ? Get(O, Pk). 77 const value: JSAny = GetProperty(o, k); 78 79 // 6c. Let testResult be ToBoolean(? Call(predicate, T, <<kValue, k, 80 // O>>)). 81 const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o); 82 83 // 6d. If testResult is true, return kValue. 84 if (ToBoolean(testResult)) { 85 return value; 86 } 87 88 // 6e. Increase k by 1. (done by the loop). 89 } 90 return Undefined; 91} 92 93transitioning macro FastArrayFind(implicit context: Context)( 94 o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny 95 labels Bailout(Smi) { 96 let k: Smi = 0; 97 const smiLen = Cast<Smi>(len) otherwise goto Bailout(k); 98 const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k); 99 let fastOW = NewFastJSArrayWitness(fastO); 100 101 // Build a fast loop over the smi array. 102 for (; k < smiLen; k++) { 103 fastOW.Recheck() otherwise goto Bailout(k); 104 105 // Ensure that we haven't walked beyond a possibly updated length. 106 if (k >= fastOW.Get().length) goto Bailout(k); 107 108 const value: JSAny = fastOW.LoadElementOrUndefined(k); 109 const testResult: JSAny = 110 Call(context, callbackfn, thisArg, value, k, fastOW.Get()); 111 if (ToBoolean(testResult)) { 112 return value; 113 } 114 } 115 return Undefined; 116} 117 118// https://tc39.github.io/ecma262/#sec-array.prototype.find 119transitioning javascript builtin 120ArrayPrototypeFind( 121 js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { 122 try { 123 RequireObjectCoercible(receiver, 'Array.prototype.find'); 124 125 // 1. Let O be ? ToObject(this value). 126 const o: JSReceiver = ToObject_Inline(context, receiver); 127 128 // 2. Let len be ? ToLength(? Get(O, "length")). 129 const len: Number = GetLengthProperty(o); 130 131 // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 132 if (arguments.length == 0) { 133 goto NotCallableError; 134 } 135 const callbackfn = Cast<Callable>(arguments[0]) otherwise NotCallableError; 136 137 // 4. If thisArg is present, let T be thisArg; else let T be undefined. 138 const thisArg: JSAny = arguments[1]; 139 140 // Special cases. 141 try { 142 return FastArrayFind(o, len, callbackfn, thisArg) 143 otherwise Bailout; 144 } label Bailout(k: Smi) deferred { 145 return ArrayFindLoopContinuation(o, callbackfn, thisArg, o, k, len); 146 } 147 } label NotCallableError deferred { 148 ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); 149 } 150} 151} 152