// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. module array { macro ArrayForEachTorqueContinuation( context: Context, o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object, initialK: Number): Object { // 5. Let k be 0. // 6. Repeat, while k < len for (let k: Number = initialK; k < len; k = k + 1) { // 6a. Let Pk be ! ToString(k). // k is guaranteed to be a positive integer, hence ToString is // side-effect free and HasProperty/GetProperty do the conversion inline. // 6b. Let kPresent be ? HasProperty(O, Pk). const kPresent: Boolean = HasProperty_Inline(context, o, k); // 6c. If kPresent is true, then if (kPresent == True) { // 6c. i. Let kValue be ? Get(O, Pk). const kValue: Object = GetProperty(context, o, k); // 6c. ii. Perform ? Call(callbackfn, T, ). Call(context, callbackfn, thisArg, kValue, k, o); } // 6d. Increase k by 1. (done by the loop). } return Undefined; } javascript builtin ArrayForEachLoopEagerDeoptContinuation( context: Context, receiver: Object, callback: Object, thisArg: Object, initialK: Object, length: Object): Object { // The unsafe Cast is safe because all continuation points in forEach are // after the ToObject(O) call that ensures we are dealing with a // JSReceiver. const jsreceiver: JSReceiver = UnsafeCast(receiver); return ArrayForEachLoopContinuation( context, jsreceiver, callback, thisArg, Undefined, jsreceiver, initialK, length, Undefined); } javascript builtin ArrayForEachLoopLazyDeoptContinuation( context: Context, receiver: Object, callback: Object, thisArg: Object, initialK: Object, length: Object, result: Object): Object { // The unsafe Cast is safe because all continuation points in forEach are // after the ToObject(O) call that ensures we are dealing with a // JSReceiver. const jsreceiver: JSReceiver = UnsafeCast(receiver); return ArrayForEachLoopContinuation( context, jsreceiver, callback, thisArg, Undefined, jsreceiver, initialK, length, Undefined); } builtin ArrayForEachLoopContinuation( context: Context, receiver: JSReceiver, callback: Object, thisArg: Object, array: Object, object: Object, initialK: Object, length: Object, to: Object): Object { try { const callbackfn: Callable = Cast(callback) otherwise Unexpected; const k: Number = Cast(initialK) otherwise Unexpected; const numberLength: Number = Cast(length) otherwise Unexpected; return ArrayForEachTorqueContinuation( context, receiver, numberLength, callbackfn, thisArg, k); } label Unexpected deferred { unreachable; } } macro VisitAllElements( context: Context, a: JSArray, len: Smi, callbackfn: Callable, thisArg: Object): void labels Bailout(Smi) { let k: Smi = 0; const map: Map = a.map; try { // Build a fast loop over the smi array. for (; k < len; k = k + 1) { // Ensure that the map didn't change. if (map != a.map) goto Slow; // Ensure that we haven't walked beyond a possibly updated length. if (k >= a.length) goto Slow; try { const value: Object = LoadElementNoHole(a, k) otherwise FoundHole; Call(context, callbackfn, thisArg, value, k, a); } label FoundHole { // If we found the hole, we need to bail out if the initial // array prototype has had elements inserted. This is preferable // to walking the prototype chain looking for elements. if (IsNoElementsProtectorCellInvalid()) goto Bailout(k); } } } label Slow deferred { goto Bailout(k); } } macro FastArrayForEach( context: Context, o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object labels Bailout(Smi) { let k: Smi = 0; try { const smiLen: Smi = Cast(len) otherwise Slow; const a: JSArray = Cast(o) otherwise Slow; const map: Map = a.map; if (!IsPrototypeInitialArrayPrototype(context, map)) goto Slow; const elementsKind: ElementsKind = map.elements_kind; if (!IsFastElementsKind(elementsKind)) goto Slow; if (IsElementsKindGreaterThan(elementsKind, HOLEY_ELEMENTS)) { VisitAllElements( context, a, smiLen, callbackfn, thisArg) otherwise Bailout; } else { VisitAllElements(context, a, smiLen, callbackfn, thisArg) otherwise Bailout; } } label Slow deferred { goto Bailout(k); } return Undefined; } // https://tc39.github.io/ecma262/#sec-array.prototype.foreach javascript builtin ArrayForEach( context: Context, receiver: Object, ...arguments): Object { try { if (IsNullOrUndefined(receiver)) { goto NullOrUndefinedError; } // 1. Let O be ? ToObject(this value). const o: JSReceiver = ToObject_Inline(context, receiver); // 2. Let len be ? ToLength(? Get(O, "length")). const len: Number = GetLengthProperty(context, o); // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. if (arguments.length == 0) { goto TypeError; } const callbackfn: Callable = Cast(arguments[0]) otherwise TypeError; // 4. If thisArg is present, let T be thisArg; else let T be undefined. const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined; // Special cases. let k: Number = 0; try { return FastArrayForEach(context, o, len, callbackfn, thisArg) otherwise Bailout; } label Bailout(kValue: Smi) deferred { k = kValue; } return ArrayForEachTorqueContinuation( context, o, len, callbackfn, thisArg, k); } label TypeError deferred { ThrowTypeError(context, kCalledNonCallable, arguments[0]); } label NullOrUndefinedError deferred { ThrowTypeError( context, kCalledOnNullOrUndefined, 'Array.prototype.forEach'); } } }