[Torque] Array.prototype.map implemented in Torque

Change-Id: I3a60be25b9c7daadcad6078447348b790b249e1c
Reviewed-on: https://chromium-review.googlesource.com/c/1402774
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59042}
This commit is contained in:
Mike Stanton 2019-01-23 16:01:19 +01:00 committed by Commit Bot
parent 7e616f2b6e
commit 304e74c8b3
6 changed files with 360 additions and 213 deletions

View File

@ -865,6 +865,7 @@ torque_files = [
"src/builtins/array-join.tq",
"src/builtins/array-lastindexof.tq",
"src/builtins/array-of.tq",
"src/builtins/array-map.tq",
"src/builtins/array-reverse.tq",
"src/builtins/array-slice.tq",
"src/builtins/array-splice.tq",

318
src/builtins/array-map.tq Normal file
View File

@ -0,0 +1,318 @@
// 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
ArrayMapLoopEagerDeoptContinuation(implicit context: Context)(
receiver: Object, callback: Object, thisArg: Object, array: Object,
initialK: Object, length: Object): Object {
// All continuation points in the optimized filter 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: 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;
return ArrayMapLoopContinuation(
jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
numberLength, Undefined);
}
transitioning javascript builtin
ArrayMapLoopLazyDeoptContinuation(implicit context: Context)(
receiver: Object, callback: Object, thisArg: Object, array: Object,
initialK: Object, length: Object, result: Object): Object {
// 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;
// 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
// the output array. After incrementing k, we can glide into the loop
// continuation builtin.
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
CreateDataProperty(outputArray, numberK, result);
// 7d. Increase k by 1.
numberK = numberK + 1;
return ArrayMapLoopContinuation(
jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
numberLength, Undefined);
}
transitioning builtin ArrayMapLoopContinuation(implicit context: Context)(
receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
array: JSReceiver, o: JSReceiver, initialK: Number, length: Number,
initialTo: Object): Object {
// {initialTo} is ignored.
// 6. Let k be 0.
// 7. Repeat, while k < len
for (let k: Number = initialK; k < length; k++) {
// 7a. 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.
// 7b. Let kPresent be ? HasProperty(O, Pk).
const kPresent: Boolean = HasProperty_Inline(o, k);
// 7c. If kPresent is true, then:
if (kPresent == True) {
// i. Let kValue be ? Get(O, Pk).
const kValue: Object = GetProperty(o, k);
// ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
const mappedValue: Object =
Call(context, callbackfn, thisArg, kValue, k, o);
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
CreateDataProperty(array, k, mappedValue);
}
// 7d. Increase k by 1. (done by the loop).
}
// 8. Return A.
return array;
}
struct Vector {
constructor(implicit context: Context)(length: Smi) {
this.fixedArray = length > 0 ?
AllocateFixedArrayWithHoles(
SmiUntag(length), kAllowLargeObjectAllocation) :
kEmptyFixedArray;
this.onlySmis = this.onlyNumbers = true;
this.skippedElements = false;
}
ReportSkippedElement() {
this.skippedElements = true;
}
CreateJSArray(implicit context: Context)(validLength: Smi): JSArray {
let length: Smi = this.fixedArray.length;
assert(validLength <= length);
let kind: ElementsKind = PACKED_SMI_ELEMENTS;
if (!this.onlySmis) {
if (this.onlyNumbers) {
kind = PACKED_DOUBLE_ELEMENTS;
} else {
kind = PACKED_ELEMENTS;
}
}
if (this.skippedElements || validLength < length) {
// We also need to create a holey output array if we are
// bailing out of the fast path partway through the array.
// This is indicated by {validLength} < {length}.
// Who knows if the bailout condition will continue to fill in
// every element?
kind = FastHoleyElementsKind(kind);
}
let map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context));
let a: JSArray;
if (IsDoubleElementsKind(kind)) {
// We need to allocate and copy.
// First, initialize the elements field before allocation to prevent
// heap corruption.
const elements: FixedDoubleArray =
AllocateFixedDoubleArrayWithHoles(SmiUntag(length), kNone);
a = new JSArray{map, this.fixedArray};
for (let i: Smi = 0; i < validLength; i++) {
typeswitch (this.fixedArray[i]) {
case (n: Number): {
elements[i] = Convert<float64>(n);
}
case (h: HeapObject): {
assert(h == Hole);
}
}
}
a.elements = elements;
} else {
// Simply install the given fixedArray in {vector}.
a = new JSArray{map, this.fixedArray};
}
// Paranoia. the FixedArray now "belongs" to JSArray {a}.
this.fixedArray = kEmptyFixedArray;
return a;
}
StoreResult(implicit context: Context)(index: Smi, result: Object) {
typeswitch (result) {
case (s: Smi): {
this.fixedArray[index] = s;
}
case (s: HeapNumber): {
this.onlySmis = false;
this.fixedArray[index] = s;
}
case (s: HeapObject): {
this.onlySmis = false;
this.onlyNumbers = false;
this.fixedArray[index] = s;
}
}
}
fixedArray: FixedArray;
onlySmis: bool; // initially true.
onlyNumbers: bool; // initially true.
skippedElements: bool; // initially false.
}
transitioning macro
MapVisitAllElements<FixedArrayType: type>(implicit context: Context)(
o: JSArray, len: Smi, callbackfn: Callable, thisArg: Object,
vector: Vector): Vector labels Bailout(Vector, Smi) {
let k: Smi = 0;
let v: Vector = vector;
const fastOWitness: FastJSArrayWitness =
MakeWitness(Cast<FastJSArray>(o) otherwise goto Bailout(v, k));
// Build a fast loop over the smi array.
// 7. Repeat, while k < len.
for (; k < len; k = k + 1) {
let fastO: FastJSArray =
Testify(fastOWitness) otherwise goto Bailout(v, k);
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastO.length) goto Bailout(v, k);
try {
const value: Object =
LoadElementNoHole<FixedArrayType>(fastO, k) otherwise FoundHole;
const result: Object =
Call(context, callbackfn, thisArg, value, k, fastO);
v.StoreResult(k, result);
}
label FoundHole {
// Our output array must necessarily be holey because of holes in
// the input array.
v.ReportSkippedElement();
}
}
return v;
}
transitioning macro FastArrayMap(implicit context: Context)(
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 vector: Vector = Vector{len};
const elementsKind: ElementsKind = fastO.map.elements_kind;
try {
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_SMI_ELEMENTS)) {
vector = MapVisitAllElements<FixedArray>(
fastO, len, callbackfn, thisArg, vector)
otherwise InnerBailout;
} else if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_ELEMENTS)) {
vector = MapVisitAllElements<FixedArray>(
fastO, len, callbackfn, thisArg, vector)
otherwise InnerBailout;
} else {
assert(IsDoubleElementsKind(elementsKind));
vector = MapVisitAllElements<FixedDoubleArray>(
fastO, len, callbackfn, thisArg, vector)
otherwise InnerBailout;
}
}
label InnerBailout(v: Vector, k: Smi) {
// Transform the Vector {v} into a JSArray and bail out.
let vector: Vector = v;
goto Bailout(vector.CreateJSArray(k), k);
}
return vector.CreateJSArray(len);
}
// Bails out if the slow path needs to be taken.
// It's useful to structure it this way, because the consequences of
// using the slow path on species creation are interesting to the caller.
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 newMap: Map =
LoadJSArrayElementsMap(PACKED_SMI_ELEMENTS, LoadNativeContext(context));
return AllocateJSArray(PACKED_SMI_ELEMENTS, newMap, smiLength, smiLength);
}
// https://tc39.github.io/ecma262/#sec-array.prototype.map
transitioning javascript builtin
ArrayMap(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: Callable =
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;
let array: JSReceiver;
let k: Number = 0;
try {
// 5. Let A be ? ArraySpeciesCreate(O, len).
if (IsArraySpeciesProtectorCellInvalid()) goto SlowSpeciesCreate;
const o: FastJSArray = Cast<FastJSArray>(receiver)
otherwise SlowSpeciesCreate;
const smiLength: Smi = Cast<Smi>(len)
otherwise SlowSpeciesCreate;
return FastArrayMap(o, smiLength, callbackfn, thisArg)
otherwise Bailout;
}
label SlowSpeciesCreate {
array = ArraySpeciesCreate(context, receiver, len);
}
label Bailout(output: JSArray, kValue: Smi) deferred {
array = output;
k = kValue;
}
return ArrayMapLoopContinuation(
o, callbackfn, thisArg, array, o, k, len, Undefined);
}
label TypeError deferred {
ThrowTypeError(context, kCalledNonCallable, arguments[0]);
}
label NullOrUndefinedError deferred {
ThrowTypeError(context, kCalledOnNullOrUndefined, 'Array.prototype.map');
}
}
}

View File

@ -93,6 +93,10 @@ class JSArray extends JSObject {
kEmptyFixedArray);
this.length = 0;
}
constructor(implicit context: Context)(map: Map, elements: FixedArrayBase) {
super(map, kEmptyFixedArray, elements);
this.length = elements.length;
}
IsEmpty(): bool {
return this.length == 0;
}
@ -232,11 +236,12 @@ const BIGINT64_ELEMENTS:
const kNone:
constexpr AllocationFlags generates 'CodeStubAssembler::kNone';
const kDoubleAlignment:
constexpr AllocationFlags generates 'kDoubleAlignment';
const kPretenured: constexpr AllocationFlags generates 'kPretenured';
const kAllowLargeObjectAllocation:
constexpr AllocationFlags generates 'kAllowLargeObjectAllocation';
const kDoubleAlignment: constexpr AllocationFlags
generates 'CodeStubAssembler::kDoubleAlignment';
const kPretenured:
constexpr AllocationFlags generates 'CodeStubAssembler::kPretenured';
const kAllowLargeObjectAllocation: constexpr AllocationFlags
generates 'CodeStubAssembler::kAllowLargeObjectAllocation';
type FixedUint8Array extends FixedTypedArray;
type FixedInt8Array extends FixedTypedArray;
@ -1072,8 +1077,8 @@ UnsafeCast<Object>(o: Object): Object {
}
const kCOWMap: Map = %RawObjectCast<Map>(LoadRoot(kFixedCOWArrayMapRootIndex));
const kEmptyFixedArray: FixedArrayBase =
%RawObjectCast<FixedArrayBase>(LoadRoot(kEmptyFixedArrayRootIndex));
const kEmptyFixedArray: FixedArray =
%RawObjectCast<FixedArray>(LoadRoot(kEmptyFixedArrayRootIndex));
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
bool;
@ -1105,6 +1110,7 @@ extern operator '[]' macro LoadFixedArrayElement(
FixedArray, constexpr int31): Object;
extern operator '[]=' macro StoreFixedArrayElement(
FixedArray, intptr, Smi): void;
extern operator '[]=' macro StoreFixedArrayElement(FixedArray, Smi, Smi): void;
extern operator '[]=' macro StoreFixedArrayElement(
FixedArray, intptr, HeapObject): void;
extern operator '[]=' macro StoreFixedArrayElement(
@ -1148,6 +1154,16 @@ extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool;
extern macro IsFastSmiElementsKind(ElementsKind): bool;
extern macro IsHoleyFastElementsKind(ElementsKind): bool;
macro FastHoleyElementsKind(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return HOLEY_SMI_ELEMENTS;
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
return HOLEY_DOUBLE_ELEMENTS;
}
assert(kind == PACKED_ELEMENTS);
return HOLEY_ELEMENTS;
}
macro AllowDoubleElements(kind: ElementsKind): ElementsKind {
if (kind == PACKED_SMI_ELEMENTS) {
return PACKED_DOUBLE_ELEMENTS;
@ -1177,6 +1193,8 @@ extern macro CalculateNewElementsCapacity(intptr): intptr;
extern macro AllocateFixedArrayWithHoles(
intptr, constexpr AllocationFlags): FixedArray;
extern macro AllocateFixedDoubleArrayWithHoles(
intptr, constexpr AllocationFlags): FixedDoubleArray;
extern macro CopyFixedArrayElements(
constexpr ElementsKind, FixedArray, constexpr ElementsKind, FixedArray,
intptr, intptr, intptr): void;
@ -1186,7 +1204,6 @@ extern macro CopyFixedArrayElements(
extern macro AllocateJSArray(constexpr ElementsKind, Map, intptr, Smi): JSArray;
extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro AllocateJSObjectFromMap(Map): JSObject;
extern operator '[]=' macro StoreFixedDoubleArrayElementSmi(
@ -1300,7 +1317,8 @@ LoadElementNoHole<FixedDoubleArray>(implicit context: Context)(
}
extern macro TransitionElementsKind(
JSObject, Map, ElementsKind, ElementsKind): void labels Bailout;
JSObject, Map, constexpr ElementsKind,
constexpr ElementsKind): void labels Bailout;
extern macro IsCallable(HeapObject): bool;
extern macro IsJSArray(HeapObject): bool;

View File

@ -126,10 +126,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
BIND(&ok);
}
void ArrayBuiltinsAssembler::MapResultGenerator() {
GenerateArraySpeciesCreate(len_);
}
void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
// 6. Let A be ? TypedArraySpeciesCreate(O, len).
TNode<JSTypedArray> original_array = CAST(o());
@ -148,120 +144,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
a_.Bind(a);
}
Node* ArrayBuiltinsAssembler::SpecCompliantMapProcessor(Node* k_value,
Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of
// SpecCompliantMapProcessor.
// ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mapped_value);
return a();
}
Node* ArrayBuiltinsAssembler::FastMapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of
// FastMapProcessor.
// ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
// mode is SMI_PARAMETERS because k has tagged representation.
ParameterMode mode = SMI_PARAMETERS;
Label runtime(this), finished(this);
Label transition_pre(this), transition_smi_fast(this),
transition_smi_double(this);
Label array_not_smi(this), array_fast(this), array_double(this);
TNode<Int32T> kind = LoadElementsKind(a());
Node* elements = LoadElements(a());
GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), &array_not_smi);
TryStoreArrayElement(HOLEY_SMI_ELEMENTS, mode, &transition_pre, elements, k,
mapped_value);
Goto(&finished);
BIND(&transition_pre);
{
// array is smi. Value is either tagged or a heap number.
CSA_ASSERT(this, TaggedIsNotSmi(mapped_value));
GotoIf(IsHeapNumberMap(LoadMap(mapped_value)), &transition_smi_double);
Goto(&transition_smi_fast);
}
BIND(&array_not_smi);
{
Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &array_double,
&array_fast);
}
BIND(&transition_smi_fast);
{
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
Node* const native_context = LoadNativeContext(context());
Node* const fast_map = LoadContextElement(
native_context, Context::JS_ARRAY_HOLEY_ELEMENTS_MAP_INDEX);
// Since this transition is only a map change, just do it right here.
// Since a() doesn't have an allocation site, it's safe to do the
// map store directly, otherwise I'd call TransitionElementsKind().
StoreMap(a(), fast_map);
Goto(&array_fast);
}
BIND(&array_fast);
{
TryStoreArrayElement(HOLEY_ELEMENTS, mode, &runtime, elements, k,
mapped_value);
Goto(&finished);
}
BIND(&transition_smi_double);
{
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
Node* const native_context = LoadNativeContext(context());
Node* const double_map = LoadContextElement(
native_context, Context::JS_ARRAY_HOLEY_DOUBLE_ELEMENTS_MAP_INDEX);
const ElementsKind kFromKind = HOLEY_SMI_ELEMENTS;
const ElementsKind kToKind = HOLEY_DOUBLE_ELEMENTS;
Label transition_in_runtime(this, Label::kDeferred);
TransitionElementsKind(a(), double_map, kFromKind, kToKind,
&transition_in_runtime);
Goto(&array_double);
BIND(&transition_in_runtime);
CallRuntime(Runtime::kTransitionElementsKind, context(), a(), double_map);
Goto(&array_double);
}
BIND(&array_double);
{
// TODO(mvstanton): If we use a variable for elements and bind it
// appropriately, we can avoid an extra load of elements by binding the
// value only after a transition from smi to double.
elements = LoadElements(a());
// If the mapped_value isn't a number, this will bail out to the runtime
// to make the transition.
TryStoreArrayElement(HOLEY_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
mapped_value);
Goto(&finished);
}
BIND(&runtime);
{
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
CallRuntime(Runtime::kCreateDataProperty, context(), a(), k,
mapped_value);
Goto(&finished);
}
BIND(&finished);
return a();
}
// See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
// 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
@ -2128,84 +2010,6 @@ TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinsAssembler) {
ForEachDirection::kReverse);
}
TF_BUILTIN(ArrayMapLoopContinuation, 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::SpecCompliantMapProcessor,
&ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
}
TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation, 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);
Node* initial_k = Parameter(Descriptor::kInitialK);
TNode<Number> len = CAST(Parameter(Descriptor::kLength));
Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
callbackfn, this_arg, array, receiver, initial_k, len,
UndefinedConstant()));
}
TF_BUILTIN(ArrayMapLoopLazyDeoptContinuation, 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);
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. map() needs
// to pick up at the next step, which is setting the callback result in
// the output array. After incrementing k, we can glide into the loop
// continuation builtin.
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
CallRuntime(Runtime::kCreateDataProperty, context, array, initial_k, result);
// Then we have to increment k before going on.
initial_k = NumberInc(initial_k);
Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
callbackfn, this_arg, array, receiver, initial_k, len,
UndefinedConstant()));
}
TF_BUILTIN(ArrayMap, 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.map", &ArrayBuiltinsAssembler::MapResultGenerator,
&ArrayBuiltinsAssembler::FastMapProcessor,
&ArrayBuiltinsAssembler::NullPostLoopAction,
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation),
MissingPropertyMode::kSkip);
}
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));

View File

@ -364,14 +364,6 @@ namespace internal {
TFJ(ArraySomeLoopLazyDeoptContinuation, 5, kReceiver, kCallbackFn, kThisArg, \
kInitialK, kLength, kResult) \
TFJ(ArraySome, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.foreach */ \
TFS(ArrayMapLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
kObject, kInitialK, kLength, kTo) \
TFJ(ArrayMapLoopEagerDeoptContinuation, 5, kReceiver, kCallbackFn, kThisArg, \
kArray, kInitialK, kLength) \
TFJ(ArrayMapLoopLazyDeoptContinuation, 6, kReceiver, kCallbackFn, kThisArg, \
kArray, kInitialK, kLength, kResult) \
TFJ(ArrayMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.reduce */ \
TFS(ArrayReduceLoopContinuation, kReceiver, kCallbackFn, kThisArg, \
kAccumulator, kObject, kInitialK, kLength, kTo) \

View File

@ -1262,6 +1262,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Smi> value) {
StoreFixedArrayElement(array, index, value, SKIP_WRITE_BARRIER, 0);
}
void StoreFixedArrayElement(TNode<FixedArray> array, TNode<Smi> index,
TNode<Smi> value) {
StoreFixedArrayElement(array, index, value, SKIP_WRITE_BARRIER, 0,
SMI_PARAMETERS);
}
void StoreFixedDoubleArrayElement(
TNode<FixedDoubleArray> object, Node* index, TNode<Float64T> value,
@ -1532,6 +1537,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return result;
}
TNode<FixedDoubleArray> AllocateFixedDoubleArrayWithHoles(
TNode<IntPtrT> capacity, AllocationFlags flags) {
TNode<FixedDoubleArray> result = UncheckedCast<FixedDoubleArray>(
AllocateFixedArray(PACKED_DOUBLE_ELEMENTS, capacity, flags));
FillFixedArrayWithValue(PACKED_DOUBLE_ELEMENTS, result, IntPtrConstant(0),
capacity, RootIndex::kTheHoleValue);
return result;
}
Node* AllocatePropertyArray(Node* capacity,
ParameterMode mode = INTPTR_PARAMETERS,
AllocationFlags flags = kNone);