[Torque] Implement Array.prototype.every and some in Torque
Just a straightforward port. bug:v8:7672 Change-Id: Ie2511cda23d7b61775e3619d61dde43c8ae48c7f Reviewed-on: https://chromium-review.googlesource.com/c/1425916 Commit-Queue: Michael Stanton <mvstanton@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#59638}
This commit is contained in:
parent
9542fd8fa0
commit
9bf0c69674
2
BUILD.gn
2
BUILD.gn
@ -900,6 +900,7 @@ torque_files = [
|
||||
"src/builtins/arguments.tq",
|
||||
"src/builtins/array.tq",
|
||||
"src/builtins/array-copywithin.tq",
|
||||
"src/builtins/array-every.tq",
|
||||
"src/builtins/array-filter.tq",
|
||||
"src/builtins/array-foreach.tq",
|
||||
"src/builtins/array-join.tq",
|
||||
@ -908,6 +909,7 @@ torque_files = [
|
||||
"src/builtins/array-map.tq",
|
||||
"src/builtins/array-reverse.tq",
|
||||
"src/builtins/array-slice.tq",
|
||||
"src/builtins/array-some.tq",
|
||||
"src/builtins/array-splice.tq",
|
||||
"src/builtins/array-unshift.tq",
|
||||
"src/builtins/collections.tq",
|
||||
|
172
src/builtins/array-every.tq
Normal file
172
src/builtins/array-every.tq
Normal file
@ -0,0 +1,172 @@
|
||||
// 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.
|
||||
|
||||
namespace array {
|
||||
transitioning javascript builtin
|
||||
ArrayEveryLoopEagerDeoptContinuation(implicit context: Context)(
|
||||
receiver: Object, callback: Object, thisArg: Object, initialK: Object,
|
||||
length: Object): Object {
|
||||
// All continuation points in the optimized every implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
//
|
||||
// Also, this great mass of casts is necessary because the signature
|
||||
// of Torque javascript builtins requires Object type for all parameters
|
||||
// other than {context}.
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArrayEveryLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
numberLength, Undefined);
|
||||
}
|
||||
|
||||
transitioning javascript builtin
|
||||
ArrayEveryLoopLazyDeoptContinuation(implicit context: Context)(
|
||||
receiver: Object, callback: Object, thisArg: Object, initialK: Object,
|
||||
length: Object, result: Object): Object {
|
||||
// All continuation points in the optimized every implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
let numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
// This custom lazy deopt point is right after the callback. every() needs
|
||||
// to pick up at the next step, which is either continuing to the next
|
||||
// array element or returning false if {result} is false.
|
||||
if (!ToBoolean(result)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
numberK = numberK + 1;
|
||||
|
||||
return ArrayEveryLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
numberLength, Undefined);
|
||||
}
|
||||
|
||||
transitioning builtin ArrayEveryLoopContinuation(implicit context: Context)(
|
||||
receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
|
||||
array: Object, o: JSReceiver, initialK: Number, length: Number,
|
||||
initialTo: Object): Object {
|
||||
// 5. Let k be 0.
|
||||
// 6. Repeat, while k < len
|
||||
for (let k: Number = initialK; k < length; k++) {
|
||||
// 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(o, k);
|
||||
|
||||
// 6c. If kPresent is true, then
|
||||
if (kPresent == True) {
|
||||
// 6c. i. Let kValue be ? Get(O, Pk).
|
||||
const kValue: Object = GetProperty(o, k);
|
||||
|
||||
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
|
||||
const result: Object = Call(context, callbackfn, thisArg, kValue, k, o);
|
||||
|
||||
// iii. If selected is true, then...
|
||||
if (!ToBoolean(result)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
// 6d. Increase k by 1. (done by the loop).
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
transitioning macro
|
||||
EveryVisitAllElements<FixedArrayType: type>(implicit context: Context)(
|
||||
o: FastJSArray, len: Smi, callbackfn: Callable,
|
||||
thisArg: Object): Boolean labels Bailout(Smi) {
|
||||
let k: Smi = 0;
|
||||
let fastO = FastJSArrayWitness{o};
|
||||
|
||||
// Build a fast loop over the smi array.
|
||||
for (; k < len; k++) {
|
||||
// Ensure that we haven't walked beyond a possibly updated length.
|
||||
if (k >= fastO.Get().length) goto Bailout(k);
|
||||
|
||||
try {
|
||||
const value: Object = LoadElementNoHole<FixedArrayType>(fastO.Get(), k)
|
||||
otherwise FoundHole;
|
||||
const result: Object =
|
||||
Call(context, callbackfn, thisArg, value, k, fastO.Get());
|
||||
if (!ToBoolean(result)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
label FoundHole {}
|
||||
fastO.Recheck() otherwise goto Bailout(k + 1);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
transitioning macro FastArrayEvery(implicit context: Context)(
|
||||
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
|
||||
labels Bailout(Smi) {
|
||||
let k: Smi = 0;
|
||||
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
|
||||
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
|
||||
const elementsKind: ElementsKind = fastO.map.elements_kind;
|
||||
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_ELEMENTS)) {
|
||||
return EveryVisitAllElements<FixedArray>(
|
||||
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
|
||||
}
|
||||
|
||||
assert(IsDoubleElementsKind(elementsKind));
|
||||
return EveryVisitAllElements<FixedDoubleArray>(
|
||||
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.every
|
||||
transitioning javascript builtin
|
||||
ArrayEvery(implicit 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(o);
|
||||
|
||||
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (arguments.length == 0) {
|
||||
goto TypeError;
|
||||
}
|
||||
const callbackfn = Cast<Callable>(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.
|
||||
try {
|
||||
return FastArrayEvery(o, len, callbackfn, thisArg)
|
||||
otherwise Bailout;
|
||||
}
|
||||
label Bailout(kValue: Smi) deferred {
|
||||
return ArrayEveryLoopContinuation(
|
||||
o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined);
|
||||
}
|
||||
}
|
||||
label TypeError deferred {
|
||||
ThrowTypeError(context, kCalledNonCallable, arguments[0]);
|
||||
}
|
||||
label NullOrUndefinedError deferred {
|
||||
ThrowTypeError(
|
||||
context, kCalledOnNullOrUndefined, 'Array.prototype.every');
|
||||
}
|
||||
}
|
||||
}
|
@ -14,14 +14,12 @@ namespace array_filter {
|
||||
// Also, this great mass of casts is necessary because the signature
|
||||
// of Torque javascript builtins requires Object type for all parameters
|
||||
// other than {context}.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray: JSReceiver =
|
||||
Cast<JSReceiver>(array) otherwise unreachable;
|
||||
const numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberTo: Number = Cast<Number>(initialTo) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberTo = Cast<Number>(initialTo) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArrayFilterLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
|
||||
@ -36,14 +34,12 @@ namespace array_filter {
|
||||
// All continuation points in the optimized filter implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray: JSReceiver =
|
||||
Cast<JSReceiver>(array) otherwise unreachable;
|
||||
let numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
let numberTo: Number = Cast<Number>(initialTo) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
|
||||
let numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
let numberTo = Cast<Number>(initialTo) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
// This custom lazy deopt point is right after the callback. filter() needs
|
||||
// to pick up at the next step, which is setting the callback result in
|
||||
@ -142,10 +138,9 @@ namespace array_filter {
|
||||
labels Bailout(Smi, Smi) {
|
||||
let k: Smi = 0;
|
||||
let to: Smi = 0;
|
||||
const smiLen: Smi = Cast<Smi>(len) otherwise goto Bailout(k, to);
|
||||
const fastArray: FastJSArray =
|
||||
Cast<FastJSArray>(array) otherwise goto Bailout(k, to);
|
||||
let fastO: FastJSArray = Cast<FastJSArray>(o) otherwise goto Bailout(k, to);
|
||||
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k, to);
|
||||
const fastArray = Cast<FastJSArray>(array) otherwise goto Bailout(k, to);
|
||||
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k, to);
|
||||
EnsureArrayPushable(fastArray.map) otherwise goto Bailout(k, to);
|
||||
const elementsKind: ElementsKind = fastO.map.elements_kind;
|
||||
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_SMI_ELEMENTS)) {
|
||||
@ -172,7 +167,7 @@ namespace array_filter {
|
||||
receiver: JSReceiver): JSReceiver labels Slow {
|
||||
const len: Smi = 0;
|
||||
if (IsArraySpeciesProtectorCellInvalid()) goto Slow;
|
||||
const o: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||
const o = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||
const newMap: Map =
|
||||
LoadJSArrayElementsMap(o.map.elements_kind, LoadNativeContext(context));
|
||||
return AllocateJSArray(PACKED_SMI_ELEMENTS, newMap, len, len);
|
||||
@ -197,8 +192,7 @@ namespace array_filter {
|
||||
if (arguments.length == 0) {
|
||||
goto TypeError;
|
||||
}
|
||||
const callbackfn: Callable =
|
||||
Cast<Callable>(arguments[0]) otherwise TypeError;
|
||||
const callbackfn = Cast<Callable>(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;
|
||||
|
@ -10,11 +10,10 @@ namespace array_foreach {
|
||||
// All continuation points in the optimized forEach implemntation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArrayForEachLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
@ -28,11 +27,10 @@ namespace array_foreach {
|
||||
// All continuation points in the optimized forEach implemntation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArrayForEachLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
@ -92,8 +90,8 @@ namespace array_foreach {
|
||||
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
|
||||
labels Bailout(Smi) {
|
||||
let k: Smi = 0;
|
||||
const smiLen: Smi = Cast<Smi>(len) otherwise goto Bailout(k);
|
||||
let fastO: FastJSArray = Cast<FastJSArray>(o) otherwise goto Bailout(k);
|
||||
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
|
||||
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
|
||||
const elementsKind: ElementsKind = fastO.map.elements_kind;
|
||||
if (IsElementsKindGreaterThan(elementsKind, HOLEY_ELEMENTS)) {
|
||||
VisitAllElements<FixedDoubleArray>(fastO, smiLen, callbackfn, thisArg)
|
||||
@ -123,8 +121,7 @@ namespace array_foreach {
|
||||
if (arguments.length == 0) {
|
||||
goto TypeError;
|
||||
}
|
||||
const callbackfn: Callable =
|
||||
Cast<Callable>(arguments[0]) otherwise TypeError;
|
||||
const callbackfn = Cast<Callable>(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;
|
||||
|
@ -14,13 +14,11 @@ namespace array_map {
|
||||
// Also, this great mass of casts is necessary because the signature
|
||||
// of Torque javascript builtins requires Object type for all parameters
|
||||
// other than {context}.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray: JSReceiver =
|
||||
Cast<JSReceiver>(array) otherwise unreachable;
|
||||
const numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArrayMapLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
|
||||
@ -34,13 +32,11 @@ namespace array_map {
|
||||
// All continuation points in the optimized filter implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver: JSReceiver =
|
||||
Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn: Callable = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray: JSReceiver =
|
||||
Cast<JSReceiver>(array) otherwise unreachable;
|
||||
let numberK: Number = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength: Number = Cast<Number>(length) otherwise unreachable;
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
|
||||
let numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
// This custom lazy deopt point is right after the callback. map() needs
|
||||
// to pick up at the next step, which is setting the callback result in
|
||||
@ -220,7 +216,7 @@ namespace array_map {
|
||||
o: JSReceiver, len: Smi, callbackfn: Callable, thisArg: Object): JSArray
|
||||
labels Bailout(JSArray, Smi) {
|
||||
let k: Smi = 0;
|
||||
let fastO: FastJSArray = Cast<FastJSArray>(o) otherwise unreachable;
|
||||
let fastO = Cast<FastJSArray>(o) otherwise unreachable;
|
||||
let vector = Vector{len};
|
||||
const elementsKind: ElementsKind = fastO.map.elements_kind;
|
||||
try {
|
||||
@ -254,8 +250,8 @@ namespace array_map {
|
||||
macro FastMapSpeciesCreate(implicit context: Context)(
|
||||
receiver: JSReceiver, length: Number): JSArray labels Bailout {
|
||||
if (IsArraySpeciesProtectorCellInvalid()) goto Bailout;
|
||||
const o: FastJSArray = Cast<FastJSArray>(receiver) otherwise Bailout;
|
||||
const smiLength: Smi = Cast<Smi>(length) otherwise Bailout;
|
||||
const o = Cast<FastJSArray>(receiver) otherwise Bailout;
|
||||
const smiLength = Cast<Smi>(length) otherwise Bailout;
|
||||
const newMap: Map =
|
||||
LoadJSArrayElementsMap(PACKED_SMI_ELEMENTS, LoadNativeContext(context));
|
||||
return AllocateJSArray(PACKED_SMI_ELEMENTS, newMap, smiLength, smiLength);
|
||||
@ -276,8 +272,7 @@ namespace array_map {
|
||||
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (arguments.length == 0) goto TypeError;
|
||||
|
||||
const callbackfn: Callable =
|
||||
Cast<Callable>(arguments[0]) otherwise TypeError;
|
||||
const callbackfn = Cast<Callable>(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;
|
||||
|
171
src/builtins/array-some.tq
Normal file
171
src/builtins/array-some.tq
Normal file
@ -0,0 +1,171 @@
|
||||
// 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.
|
||||
|
||||
namespace array {
|
||||
transitioning javascript builtin
|
||||
ArraySomeLoopEagerDeoptContinuation(implicit context: Context)(
|
||||
receiver: Object, callback: Object, thisArg: Object, initialK: Object,
|
||||
length: Object): Object {
|
||||
// All continuation points in the optimized some implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
//
|
||||
// Also, this great mass of casts is necessary because the signature
|
||||
// of Torque javascript builtins requires Object type for all parameters
|
||||
// other than {context}.
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
const numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
return ArraySomeLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
numberLength, Undefined);
|
||||
}
|
||||
|
||||
transitioning javascript builtin
|
||||
ArraySomeLoopLazyDeoptContinuation(implicit context: Context)(
|
||||
receiver: Object, callback: Object, thisArg: Object, initialK: Object,
|
||||
length: Object, result: Object): Object {
|
||||
// All continuation points in the optimized some implementation are
|
||||
// after the ToObject(O) call that ensures we are dealing with a
|
||||
// JSReceiver.
|
||||
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
|
||||
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
|
||||
let numberK = Cast<Number>(initialK) otherwise unreachable;
|
||||
const numberLength = Cast<Number>(length) otherwise unreachable;
|
||||
|
||||
// This custom lazy deopt point is right after the callback. some() needs
|
||||
// to pick up at the next step: if the result is true, then return,
|
||||
// otherwise, keep going through the array starting from k + 1.
|
||||
if (ToBoolean(result)) {
|
||||
return True;
|
||||
}
|
||||
|
||||
numberK = numberK + 1;
|
||||
|
||||
return ArraySomeLoopContinuation(
|
||||
jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
|
||||
numberLength, Undefined);
|
||||
}
|
||||
|
||||
transitioning builtin ArraySomeLoopContinuation(implicit context: Context)(
|
||||
receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
|
||||
array: Object, o: JSReceiver, initialK: Number, length: Number,
|
||||
initialTo: Object): Object {
|
||||
// 5. Let k be 0.
|
||||
// 6. Repeat, while k < len
|
||||
for (let k: Number = initialK; k < length; k++) {
|
||||
// 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(o, k);
|
||||
|
||||
// 6c. If kPresent is true, then
|
||||
if (kPresent == True) {
|
||||
// 6c. i. Let kValue be ? Get(O, Pk).
|
||||
const kValue: Object = GetProperty(o, k);
|
||||
|
||||
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
|
||||
const result: Object = Call(context, callbackfn, thisArg, kValue, k, o);
|
||||
|
||||
// iii. If selected is true, then...
|
||||
if (ToBoolean(result)) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
// 6d. Increase k by 1. (done by the loop).
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
transitioning macro
|
||||
SomeVisitAllElements<FixedArrayType: type>(implicit context: Context)(
|
||||
o: FastJSArray, len: Smi, callbackfn: Callable, thisArg: Object): Boolean
|
||||
labels Bailout(Smi) {
|
||||
let k: Smi = 0;
|
||||
let fastO = FastJSArrayWitness{o};
|
||||
|
||||
// Build a fast loop over the smi array.
|
||||
for (; k < len; k++) {
|
||||
// Ensure that we haven't walked beyond a possibly updated length.
|
||||
if (k >= fastO.Get().length) goto Bailout(k);
|
||||
|
||||
try {
|
||||
const value: Object = LoadElementNoHole<FixedArrayType>(fastO.Get(), k)
|
||||
otherwise FoundHole;
|
||||
const result: Object =
|
||||
Call(context, callbackfn, thisArg, value, k, fastO.Get());
|
||||
if (ToBoolean(result)) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
label FoundHole {}
|
||||
fastO.Recheck() otherwise goto Bailout(k + 1);
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
transitioning macro FastArraySome(implicit context: Context)(
|
||||
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
|
||||
labels Bailout(Smi) {
|
||||
let k: Smi = 0;
|
||||
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
|
||||
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
|
||||
const elementsKind: ElementsKind = fastO.map.elements_kind;
|
||||
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_ELEMENTS)) {
|
||||
return SomeVisitAllElements<FixedArray>(
|
||||
fastO, smiLen, callbackfn, thisArg)
|
||||
otherwise Bailout;
|
||||
}
|
||||
|
||||
assert(IsDoubleElementsKind(elementsKind));
|
||||
return SomeVisitAllElements<FixedDoubleArray>(
|
||||
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.some
|
||||
transitioning javascript builtin
|
||||
ArraySome(implicit 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(o);
|
||||
|
||||
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (arguments.length == 0) {
|
||||
goto TypeError;
|
||||
}
|
||||
const callbackfn = Cast<Callable>(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.
|
||||
try {
|
||||
return FastArraySome(o, len, callbackfn, thisArg)
|
||||
otherwise Bailout;
|
||||
}
|
||||
label Bailout(kValue: Smi) deferred {
|
||||
return ArraySomeLoopContinuation(
|
||||
o, callbackfn, thisArg, Undefined, o, kValue, len, Undefined);
|
||||
}
|
||||
}
|
||||
label TypeError deferred {
|
||||
ThrowTypeError(context, kCalledNonCallable, arguments[0]);
|
||||
}
|
||||
label NullOrUndefinedError deferred {
|
||||
ThrowTypeError(context, kCalledOnNullOrUndefined, 'Array.prototype.some');
|
||||
}
|
||||
}
|
||||
}
|
@ -1609,87 +1609,6 @@ TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinsAssembler) {
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArraySomeLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
Node* result = Parameter(Descriptor::kResult);
|
||||
|
||||
// This custom lazy deopt point is right after the callback. every() needs
|
||||
// to pick up at the next step, which is either continuing to the next
|
||||
// array element or returning false if {result} is false.
|
||||
Label true_continue(this), false_continue(this);
|
||||
|
||||
// iii. If selected is true, then...
|
||||
BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
|
||||
BIND(&true_continue);
|
||||
{ Return(TrueConstant()); }
|
||||
BIND(&false_continue);
|
||||
{
|
||||
// Increment k.
|
||||
initial_k = NumberInc(initial_k);
|
||||
|
||||
Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
|
||||
callbackfn, this_arg, FalseConstant(), receiver,
|
||||
initial_k, len, UndefinedConstant()));
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArraySomeLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
|
||||
Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
|
||||
callbackfn, this_arg, FalseConstant(), receiver, initial_k,
|
||||
len, UndefinedConstant()));
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* array = Parameter(Descriptor::kArray);
|
||||
TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
Node* to = Parameter(Descriptor::kTo);
|
||||
|
||||
InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
|
||||
this_arg, array, object, initial_k,
|
||||
len, to);
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinsAssembler::SomeProcessor,
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArraySome, ArrayBuiltinsAssembler) {
|
||||
TNode<IntPtrT> argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
Node* callbackfn = args.GetOptionalArgumentValue(0);
|
||||
Node* this_arg = args.GetOptionalArgumentValue(1);
|
||||
|
||||
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
|
||||
|
||||
GenerateIteratingArrayBuiltinBody(
|
||||
"Array.prototype.some", &ArrayBuiltinsAssembler::SomeResultGenerator,
|
||||
&ArrayBuiltinsAssembler::SomeProcessor,
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
|
||||
TNode<IntPtrT> argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
@ -1708,87 +1627,6 @@ TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayEveryLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
Node* result = Parameter(Descriptor::kResult);
|
||||
|
||||
// This custom lazy deopt point is right after the callback. every() needs
|
||||
// to pick up at the next step, which is either continuing to the next
|
||||
// array element or returning false if {result} is false.
|
||||
Label true_continue(this), false_continue(this);
|
||||
|
||||
// iii. If selected is true, then...
|
||||
BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
|
||||
BIND(&true_continue);
|
||||
{
|
||||
// Increment k.
|
||||
initial_k = NumberInc(initial_k);
|
||||
|
||||
Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
|
||||
callbackfn, this_arg, TrueConstant(), receiver,
|
||||
initial_k, len, UndefinedConstant()));
|
||||
}
|
||||
BIND(&false_continue);
|
||||
{ Return(FalseConstant()); }
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayEveryLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
|
||||
Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
|
||||
callbackfn, this_arg, TrueConstant(), receiver, initial_k,
|
||||
len, UndefinedConstant()));
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* array = Parameter(Descriptor::kArray);
|
||||
TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
|
||||
Node* initial_k = Parameter(Descriptor::kInitialK);
|
||||
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
|
||||
Node* to = Parameter(Descriptor::kTo);
|
||||
|
||||
InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
|
||||
this_arg, array, object, initial_k,
|
||||
len, to);
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinsAssembler::EveryProcessor,
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayEvery, ArrayBuiltinsAssembler) {
|
||||
TNode<IntPtrT> argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
Node* callbackfn = args.GetOptionalArgumentValue(0);
|
||||
Node* this_arg = args.GetOptionalArgumentValue(1);
|
||||
|
||||
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
|
||||
|
||||
GenerateIteratingArrayBuiltinBody(
|
||||
"Array.prototype.every", &ArrayBuiltinsAssembler::EveryResultGenerator,
|
||||
&ArrayBuiltinsAssembler::EveryProcessor,
|
||||
&ArrayBuiltinsAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) {
|
||||
TNode<IntPtrT> argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
|
@ -350,22 +350,6 @@ namespace internal {
|
||||
TFS(CloneFastJSArray, kSource) \
|
||||
TFS(CloneFastJSArrayFillingHoles, kSource) \
|
||||
TFS(ExtractFastJSArray, kSource, kBegin, kCount) \
|
||||
/* ES6 #sec-array.prototype.every */ \
|
||||
TFS(ArrayEveryLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
|
||||
kObject, kInitialK, kLength, kTo) \
|
||||
TFJ(ArrayEveryLoopEagerDeoptContinuation, 4, kReceiver, kCallbackFn, \
|
||||
kThisArg, kInitialK, kLength) \
|
||||
TFJ(ArrayEveryLoopLazyDeoptContinuation, 5, kReceiver, kCallbackFn, \
|
||||
kThisArg, kInitialK, kLength, kResult) \
|
||||
TFJ(ArrayEvery, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.some */ \
|
||||
TFS(ArraySomeLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
|
||||
kObject, kInitialK, kLength, kTo) \
|
||||
TFJ(ArraySomeLoopEagerDeoptContinuation, 4, kReceiver, kCallbackFn, \
|
||||
kThisArg, kInitialK, kLength) \
|
||||
TFJ(ArraySomeLoopLazyDeoptContinuation, 5, kReceiver, kCallbackFn, kThisArg, \
|
||||
kInitialK, kLength, kResult) \
|
||||
TFJ(ArraySome, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.reduce */ \
|
||||
TFS(ArrayReduceLoopContinuation, kReceiver, kCallbackFn, kThisArg, \
|
||||
kAccumulator, kObject, kInitialK, kLength, kTo) \
|
||||
|
Loading…
Reference in New Issue
Block a user