Commit 7664dc27 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[csa][builtins] Port ArrayConstructorImpl builtin to CSA.

Bug: v8:5269, v8:7703
Change-Id: I3e1f8a7892192a06ce6a71563cc16a47c51f9d89
Reviewed-on: https://chromium-review.googlesource.com/1097487
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53740}
parent f8502357
......@@ -2657,175 +2657,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmp(r3, Operand(kind));
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// r2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// r3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// r0 - number of arguments
// r1 - constructor?
// sp[0] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ tst(r3, Operand(1));
__ b(ne, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ add(r3, r3, Operand(1));
if (FLAG_debug_code) {
__ ldr(r5, FieldMemOperand(r2, 0));
__ CompareInstanceType(r5, r6, ALLOCATION_SITE_TYPE);
__ Assert(eq, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store r3
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ ldr(r4, FieldMemOperand(
r2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ add(r4, r4, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
__ str(r4, FieldMemOperand(
r2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmp(r3, Operand(kind));
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ tst(r0, r0);
__ b(ne, &not_zero_case);
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ cmp(r0, Operand(1));
__ b(gt, &not_one_case);
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : argc (only if argument_count() == ANY)
// -- r1 : constructor
// -- r2 : AllocationSite or undefined
// -- r3 : new target
// -- sp[0] : return address
// -- sp[4] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ ldr(r4, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ tst(r4, Operand(kSmiTagMask));
__ Assert(ne, AbortReason::kUnexpectedInitialMapForArrayFunction);
__ CompareObjectType(r4, r4, r5, MAP_TYPE);
__ Assert(eq, AbortReason::kUnexpectedInitialMapForArrayFunction);
// We should either have undefined in r2 or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(r2, r4);
}
// Enter the context of the Array function.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
Label subclassing;
__ cmp(r3, r1);
__ b(ne, &subclassing);
Label no_info;
// Get the elements kind and case on that.
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ b(eq, &no_info);
__ ldr(r3, FieldMemOperand(
r2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(r3);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ and_(r3, r3, Operand(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
__ bind(&subclassing);
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ add(r0, r0, Operand(3));
__ Push(r3, r2);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
__ cmp(r0, Operand(1));
......
......@@ -3163,201 +3163,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
ASM_LOCATION("CreateArrayDispatch");
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
Register kind = x3;
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
// TODO(jbramley): Is this the best way to handle this? Can we make the
// tail calls conditional, rather than hopping over each one?
__ CompareAndBranch(kind, candidate_kind, ne, &next);
__ Jump(CodeFactory::ArrayNoArgumentConstructor(masm->isolate(),
candidate_kind, mode)
.code(),
RelocInfo::CODE_TARGET);
__ Bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
ASM_LOCATION("CreateArrayDispatchOneArgument");
// x0 - argc
// x1 - constructor?
// x2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// x3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// sp[0] - last argument
Register allocation_site = x2;
Register kind = x3;
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// Is the low bit set? If so, the array is holey.
Label normal_sequence;
__ Tbnz(kind, 0, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ Orr(kind, kind, 1);
if (FLAG_debug_code) {
__ Ldr(x10, FieldMemOperand(allocation_site, 0));
__ CompareInstanceType(x10, x11, ALLOCATION_SITE_TYPE);
__ Assert(eq, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store 'kind'
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field; upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ Ldr(x11,
FieldMemOperand(allocation_site,
AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ Add(x11, x11, Smi::FromInt(kFastElementsKindPackedToHoley));
__ Str(x11,
FieldMemOperand(allocation_site,
AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ Bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
__ CompareAndBranch(kind, candidate_kind, ne, &next);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), candidate_kind, DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET);
__ Bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Register argc = x0;
Label zero_case, n_case;
__ Cbz(argc, &zero_case);
__ Cmp(argc, 1);
__ B(ne, &n_case);
// One argument.
CreateArrayDispatchOneArgument(masm, mode);
__ Bind(&zero_case);
// No arguments.
CreateArrayDispatchNoArgument(masm, mode);
__ Bind(&n_case);
// N arguments.
Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
ASM_LOCATION("ArrayConstructorStub::Generate");
// ----------- S t a t e -------------
// -- x0 : argc (only if argument_count() is ANY or MORE_THAN_ONE)
// -- x1 : constructor
// -- x2 : AllocationSite or undefined
// -- x3 : new target
// -- sp[0] : last argument
// -----------------------------------
Register constructor = x1;
Register allocation_site = x2;
Register new_target = x3;
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
Label unexpected_map, map_ok;
// Initial map for the builtin Array function should be a map.
__ Ldr(x10, FieldMemOperand(constructor,
JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ JumpIfSmi(x10, &unexpected_map);
__ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok);
__ Bind(&unexpected_map);
__ Abort(AbortReason::kUnexpectedInitialMapForArrayFunction);
__ Bind(&map_ok);
// We should either have undefined in the allocation_site register or a
// valid AllocationSite.
__ AssertUndefinedOrAllocationSite(allocation_site);
}
// Enter the context of the Array function.
__ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
Label subclassing;
__ Cmp(new_target, constructor);
__ B(ne, &subclassing);
Register kind = x3;
Label no_info;
// Get the elements kind and case on that.
__ JumpIfRoot(allocation_site, Heap::kUndefinedValueRootIndex, &no_info);
__ SmiUntag(kind, FieldMemOperand(
allocation_site,
AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ And(kind, kind, AllocationSite::ElementsKindBits::kMask);
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ Bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
// Subclassing support.
__ Bind(&subclassing);
__ Poke(constructor, Operand(x0, LSL, kPointerSizeLog2));
__ Add(x0, x0, Operand(3));
__ Push(new_target, allocation_site);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
Label zero_case, n_case;
......
......@@ -4032,13 +4032,194 @@ TF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) {
SelectConstant<Object>(IsUndefined(new_target), function, new_target);
// Run the native code for the Array function called as a normal function.
TNode<Code> code =
HeapConstant(BUILTIN_CODE(isolate(), ArrayConstructorImpl));
ArrayConstructorDescriptor descriptor(isolate());
TNode<Object> no_allocation_site = UndefinedConstant();
// TODO(ishell): Use TailCallBuiltin once ArrayConstructorImpl is ported.
TailCallStub(descriptor, code, context, function, new_target, argc,
no_allocation_site);
TailCallBuiltin(Builtins::kArrayConstructorImpl, context, function,
new_target, argc, no_allocation_site);
}
void ArrayBuiltinsAssembler::TailCallArrayConstructorStub(
const Callable& callable, TNode<Context> context, TNode<JSFunction> target,
TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc) {
TNode<Code> code = HeapConstant(callable.code());
// We are going to call here ArrayNoArgumentsConstructor or
// ArraySingleArgumentsConstructor which in addition to the register arguments
// also expect some number of arguments on the expression stack.
// Since
// 1) incoming JS arguments are still on the stack,
// 2) the ArrayNoArgumentsConstructor, ArraySingleArgumentsConstructor and
// ArrayNArgumentsConstructor are defined so that the register arguments
// are passed on the same registers,
// in order to be able to generate a tail call to those builtins we do the
// following trick here: we tail call to the constructor builtin using
// ArrayNArgumentsConstructorDescriptor, so the tail call instruction
// pops the current frame but leaves all the incoming JS arguments on the
// expression stack so that the target builtin can still find them where it
// expects.
ArrayNArgumentsConstructorDescriptor descriptor(isolate());
TailCallStub(descriptor, code, context, target, allocation_site_or_undefined,
argc);
}
void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
if (mode == DISABLE_ALLOCATION_SITES) {
Callable callable = CodeFactory::ArrayNoArgumentConstructor(
isolate(), GetInitialFastElementsKind(), mode);
TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
argc);
} else {
DCHECK_EQ(mode, DONT_OVERRIDE);
TNode<Int32T> elements_kind = LoadElementsKind(allocation_site);
// TODO(ishell): Compute the builtin index dynamically instead of
// iterating over all expected elements kinds.
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next(this);
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
GotoIfNot(Word32Equal(elements_kind, Int32Constant(kind)), &next);
Callable callable =
CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode);
TailCallArrayConstructorStub(callable, context, target, allocation_site,
argc);
BIND(&next);
}
// If we reached this point there is a problem.
Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
}
}
void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
Callable callable = CodeFactory::ArraySingleArgumentConstructor(
isolate(), holey_initial, mode);
TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
argc);
} else {
DCHECK_EQ(mode, DONT_OVERRIDE);
TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
// Least significant bit in fast array elements kind means holeyness.
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
Label normal_sequence(this);
TVARIABLE(Int32T, var_elements_kind,
Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
SmiToInt32(transition_info))));
// Is the low bit set? If so, we are holey and that is good.
int fast_elements_kind_holey_mask =
AllocationSite::ElementsKindBits::encode(static_cast<ElementsKind>(1));
GotoIf(IsSetSmi(transition_info, fast_elements_kind_holey_mask),
&normal_sequence);
{
// Make elements kind holey and update elements kind in the type info.
var_elements_kind =
Signed(Word32Or(var_elements_kind.value(), Int32Constant(1)));
StoreObjectFieldNoWriteBarrier(
allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset,
SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask)));
Goto(&normal_sequence);
}
BIND(&normal_sequence);
// TODO(ishell): Compute the builtin index dynamically instead of
// iterating over all expected elements kinds.
// TODO(ishell): Given that the code above ensures that the elements kind
// is holey we can skip checking with non-holey elements kinds.
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next(this);
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
GotoIfNot(Word32Equal(var_elements_kind.value(), Int32Constant(kind)),
&next);
Callable callable =
CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode);
TailCallArrayConstructorStub(callable, context, target, allocation_site,
argc);
BIND(&next);
}
// If we reached this point there is a problem.
Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
}
}
void ArrayBuiltinsAssembler::GenerateDispatchToArrayStub(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
Label check_one_case(this), fallthrough(this);
GotoIfNot(Word32Equal(argc, Int32Constant(0)), &check_one_case);
CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site);
BIND(&check_one_case);
GotoIfNot(Word32Equal(argc, Int32Constant(1)), &fallthrough);
CreateArrayDispatchSingleArgument(context, target, argc, mode,
allocation_site);
BIND(&fallthrough);
}
TF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) {
TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
TNode<Int32T> argc =
UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
TNode<HeapObject> maybe_allocation_site =
CAST(Parameter(Descriptor::kAllocationSite));
// Initial map for the builtin Array functions should be Map.
CSA_ASSERT(this, IsMap(CAST(LoadObjectField(
target, JSFunction::kPrototypeOrInitialMapOffset))));
// We should either have undefined or a valid AllocationSite
CSA_ASSERT(this, Word32Or(IsUndefined(maybe_allocation_site),
IsAllocationSite(maybe_allocation_site)));
// "Enter" the context of the Array function.
TNode<Context> context =
CAST(LoadObjectField(target, JSFunction::kContextOffset));
Label runtime(this, Label::kDeferred);
GotoIf(WordNotEqual(target, new_target), &runtime);
Label no_info(this);
// If the feedback vector is the undefined value call an array constructor
// that doesn't use AllocationSites.
GotoIf(IsUndefined(maybe_allocation_site), &no_info);
GenerateDispatchToArrayStub(context, target, argc, DONT_OVERRIDE,
CAST(maybe_allocation_site));
Goto(&runtime);
BIND(&no_info);
GenerateDispatchToArrayStub(context, target, argc, DISABLE_ALLOCATION_SITES);
Goto(&runtime);
BIND(&runtime);
GenerateArrayNArgumentsConstructor(context, target, new_target, argc,
maybe_allocation_site);
}
void ArrayBuiltinsAssembler::GenerateConstructor(
......
......@@ -115,6 +115,26 @@ class ArrayBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
MissingPropertyMode missing_property_mode,
ForEachDirection direction = ForEachDirection::kForward);
void TailCallArrayConstructorStub(
const Callable& callable, TNode<Context> context,
TNode<JSFunction> target, TNode<HeapObject> allocation_site_or_undefined,
TNode<Int32T> argc);
void GenerateDispatchToArrayStub(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode,
TNode<AllocationSite> allocation_site = TNode<AllocationSite>());
void CreateArrayDispatchNoArgument(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode,
TNode<AllocationSite> allocation_site = TNode<AllocationSite>());
void CreateArrayDispatchSingleArgument(
TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
AllocationSiteOverrideMode mode,
TNode<AllocationSite> allocation_site = TNode<AllocationSite>());
void GenerateConstructor(Node* context, Node* array_function, Node* array_map,
Node* array_size, Node* allocation_site,
ElementsKind elements_kind, AllocationSiteMode mode);
......
......@@ -63,16 +63,6 @@ TF_BUILTIN(ConstructWithSpread, CallOrConstructBuiltinsAssembler) {
typedef compiler::Node Node;
Node* ConstructorBuiltinsAssembler::NotHasBoilerplate(Node* literal_site) {
return TaggedIsSmi(literal_site);
}
Node* ConstructorBuiltinsAssembler::LoadAllocationSiteBoilerplate(Node* site) {
CSA_ASSERT(this, IsAllocationSite(site));
return LoadObjectField(site,
AllocationSite::kTransitionInfoOrBoilerplateOffset);
}
TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
Node* shared_function_info = Parameter(Descriptor::kSharedFunctionInfo);
Node* feedback_cell = Parameter(Descriptor::kFeedbackCell);
......@@ -361,13 +351,13 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowArrayLiteral(
return_result(this);
VARIABLE(result, MachineRepresentation::kTagged);
TNode<Object> allocation_site =
TNode<Object> maybe_allocation_site =
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
GotoIf(NotHasBoilerplate(allocation_site), call_runtime);
GotoIf(NotHasBoilerplate(maybe_allocation_site), call_runtime);
Node* boilerplate = LoadAllocationSiteBoilerplate(allocation_site);
TNode<AllocationSite> allocation_site = CAST(maybe_allocation_site);
TNode<JSArray> boilerplate = CAST(LoadBoilerplate(allocation_site));
CSA_ASSERT(this, IsJSArrayMap(LoadMap(boilerplate)));
ParameterMode mode = OptimalParameterMode();
if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
return CloneFastJSArray(context, boilerplate, mode, allocation_site);
......@@ -400,15 +390,17 @@ Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
Node* feedback_vector, Node* slot, Node* context) {
// Array literals always have a valid AllocationSite to properly track
// elements transitions.
TVARIABLE(Object, allocation_site,
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0,
INTPTR_PARAMETERS)));
TNode<Object> maybe_allocation_site =
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
TVARIABLE(AllocationSite, allocation_site);
Label create_empty_array(this),
initialize_allocation_site(this, Label::kDeferred), done(this);
Branch(TaggedIsSmi(allocation_site.value()), &initialize_allocation_site,
&create_empty_array);
GotoIf(TaggedIsSmi(maybe_allocation_site), &initialize_allocation_site);
{
allocation_site = CAST(maybe_allocation_site);
Goto(&create_empty_array);
}
// TODO(cbruni): create the AllocationSite in CSA.
BIND(&initialize_allocation_site);
{
......@@ -418,12 +410,8 @@ Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
}
BIND(&create_empty_array);
CSA_ASSERT(this, IsAllocationSite(CAST(allocation_site.value())));
Node* kind = SmiToInt32(CAST(
LoadObjectField(CAST(allocation_site.value()),
AllocationSite::kTransitionInfoOrBoilerplateOffset)));
CSA_ASSERT(this, IsFastElementsKind(kind));
Node* native_context = LoadNativeContext(context);
TNode<Int32T> kind = LoadElementsKind(allocation_site.value());
TNode<Context> native_context = LoadNativeContext(context);
Comment("LoadJSArrayElementsMap");
Node* array_map = LoadJSArrayElementsMap(kind, native_context);
Node* zero = SmiConstant(0);
......@@ -448,12 +436,13 @@ TF_BUILTIN(CreateEmptyArrayLiteral, ConstructorBuiltinsAssembler) {
Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
Node* feedback_vector, Node* slot, Label* call_runtime) {
TNode<Object> allocation_site =
TNode<Object> maybe_allocation_site =
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
GotoIf(NotHasBoilerplate(allocation_site), call_runtime);
GotoIf(NotHasBoilerplate(maybe_allocation_site), call_runtime);
Node* boilerplate = LoadAllocationSiteBoilerplate(allocation_site);
Node* boilerplate_map = LoadMap(boilerplate);
TNode<AllocationSite> allocation_site = CAST(maybe_allocation_site);
TNode<JSObject> boilerplate = LoadBoilerplate(allocation_site);
TNode<Map> boilerplate_map = LoadMap(boilerplate);
CSA_ASSERT(this, IsJSObjectMap(boilerplate_map));
VARIABLE(var_properties, MachineRepresentation::kTagged);
......
......@@ -35,10 +35,6 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target,
Label* call_runtime);
private:
Node* NotHasBoilerplate(Node* literal_site);
Node* LoadAllocationSiteBoilerplate(Node* allocation_site);
};
} // namespace internal
......
......@@ -236,7 +236,7 @@ namespace internal {
\
/* Array */ \
TFC(ArrayConstructor, ConstructTrampoline, 1) \
ASM(ArrayConstructorImpl) \
TFC(ArrayConstructorImpl, ArrayConstructor, 1) \
TFC(ArrayNoArgumentConstructor_PackedSmi_DontOverride, \
ArrayNoArgumentConstructor, 1) \
TFC(ArrayNoArgumentConstructor_HoleySmi_DontOverride, \
......
......@@ -2890,187 +2890,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmp(edx, kind);
__ j(not_equal, &next);
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET);
__ bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// edx - kind (if mode != DISABLE_ALLOCATION_SITES)
// eax - number of arguments
// edi - constructor?
// esp[0] - return address
// esp[4] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ test_b(edx, Immediate(1));
__ j(not_zero, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry.
__ inc(edx);
if (FLAG_debug_code) {
Handle<Map> allocation_site_map =
masm->isolate()->factory()->allocation_site_map();
__ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
__ Assert(equal, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store r3
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ add(
FieldOperand(ebx, AllocationSite::kTransitionInfoOrBoilerplateOffset),
Immediate(Smi::FromInt(kFastElementsKindPackedToHoley)));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmp(edx, kind);
__ j(not_equal, &next);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET);
__ bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ test(eax, eax);
__ j(not_zero, &not_zero_case);
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ cmp(eax, 1);
__ j(greater, &not_one_case);
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc (only if argument_count() is ANY or MORE_THAN_ONE)
// -- ebx : AllocationSite or undefined
// -- edi : constructor
// -- edx : Original constructor
// -- esp[0] : return address
// -- esp[4] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ test(ecx, Immediate(kSmiTagMask));
__ Assert(not_zero, AbortReason::kUnexpectedInitialMapForArrayFunction);
__ CmpObjectType(ecx, MAP_TYPE, ecx);
__ Assert(equal, AbortReason::kUnexpectedInitialMapForArrayFunction);
// We should either have undefined in ebx or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(ebx);
}
Label subclassing;
// Enter the context of the Array function.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ cmp(edx, edi);
__ j(not_equal, &subclassing);
Label no_info;
// If the feedback vector is the undefined value call an array constructor
// that doesn't use AllocationSites.
__ cmp(ebx, masm->isolate()->factory()->undefined_value());
__ j(equal, &no_info);
// Only look at the lower 16 bits of the transition info.
__ mov(edx,
FieldOperand(ebx, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(edx);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
// Subclassing.
__ bind(&subclassing);
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
__ add(eax, Immediate(3));
__ PopReturnAddressTo(ecx);
__ Push(edx);
__ Push(ebx);
__ PushReturnAddressFrom(ecx);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
Label not_zero_case, not_one_case;
......
......@@ -2782,176 +2782,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET, eq, a3, Operand(kind));
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// a2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// a3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// a0 - number of arguments
// a1 - constructor?
// sp[0] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ And(kScratchReg, a3, Operand(1));
__ Branch(&normal_sequence, ne, kScratchReg, Operand(zero_reg));
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ Addu(a3, a3, Operand(1));
if (FLAG_debug_code) {
__ lw(t1, FieldMemOperand(a2, 0));
__ lhu(kScratchReg, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Assert(eq, AbortReason::kExpectedAllocationSite, kScratchReg,
Operand(ALLOCATION_SITE_TYPE));
}
// Save the resulting elements kind in type info. We can't just store a3
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ lw(t0, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ Addu(t0, t0, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
__ sw(t0, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET, eq, a3, Operand(kind));
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ And(kScratchReg, a0, a0);
__ Branch(&not_zero_case, ne, kScratchReg, Operand(zero_reg));
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ Branch(&not_one_case, gt, a0, Operand(1));
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
__ Jump(BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor),
RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : argc (only if argument_count() is ANY or MORE_THAN_ONE)
// -- a1 : constructor
// -- a2 : AllocationSite or undefined
// -- a3 : Original constructor
// -- sp[0] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ lw(t0, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ SmiTst(t0, kScratchReg);
__ Assert(ne, AbortReason::kUnexpectedInitialMapForArrayFunction,
kScratchReg, Operand(zero_reg));
__ GetObjectType(t0, t0, t1);
__ Assert(eq, AbortReason::kUnexpectedInitialMapForArrayFunction, t1,
Operand(MAP_TYPE));
// We should either have undefined in a2 or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(a2, t0);
}
// Enter the context of the Array function.
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
Label subclassing;
__ Branch(&subclassing, ne, a1, Operand(a3));
Label no_info;
// Get the elements kind and case on that.
__ LoadRoot(kScratchReg, Heap::kUndefinedValueRootIndex);
__ Branch(&no_info, eq, a2, Operand(kScratchReg));
__ lw(a3, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(a3);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ And(a3, a3, Operand(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
// Subclassing.
__ bind(&subclassing);
__ Lsa(kScratchReg, sp, a0, kPointerSizeLog2);
__ sw(a1, MemOperand(kScratchReg));
__ li(kScratchReg, Operand(3));
__ addu(a0, a0, kScratchReg);
__ Push(a3, a2);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
__ Jump(CodeFactory::InternalArrayNoArgumentConstructor(masm->isolate(), kind)
......
......@@ -2801,176 +2801,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET, eq, a3, Operand(kind));
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// a2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// a3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// a0 - number of arguments
// a1 - constructor?
// sp[0] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ And(kScratchReg, a3, Operand(1));
__ Branch(&normal_sequence, ne, kScratchReg, Operand(zero_reg));
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ Daddu(a3, a3, Operand(1));
if (FLAG_debug_code) {
__ Ld(a5, FieldMemOperand(a2, 0));
__ Lhu(kScratchReg, FieldMemOperand(a5, Map::kInstanceTypeOffset));
__ Assert(eq, AbortReason::kExpectedAllocationSite, kScratchReg,
Operand(ALLOCATION_SITE_TYPE));
}
// Save the resulting elements kind in type info. We can't just store a3
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ Ld(a4, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ Daddu(a4, a4, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
__ Sd(a4, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET, eq, a3, Operand(kind));
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ And(kScratchReg, a0, a0);
__ Branch(&not_zero_case, ne, kScratchReg, Operand(zero_reg));
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ Branch(&not_one_case, gt, a0, Operand(1));
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
__ Jump(BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor),
RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : argc (only if argument_count() == ANY)
// -- a1 : constructor
// -- a2 : AllocationSite or undefined
// -- a3 : new target
// -- sp[0] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ Ld(a4, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ SmiTst(a4, kScratchReg);
__ Assert(ne, AbortReason::kUnexpectedInitialMapForArrayFunction,
kScratchReg, Operand(zero_reg));
__ GetObjectType(a4, a4, a5);
__ Assert(eq, AbortReason::kUnexpectedInitialMapForArrayFunction, a5,
Operand(MAP_TYPE));
// We should either have undefined in a2 or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(a2, a4);
}
// Enter the context of the Array function.
__ Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
Label subclassing;
__ Branch(&subclassing, ne, a1, Operand(a3));
Label no_info;
// Get the elements kind and case on that.
__ LoadRoot(kScratchReg, Heap::kUndefinedValueRootIndex);
__ Branch(&no_info, eq, a2, Operand(kScratchReg));
__ Ld(a3, FieldMemOperand(
a2, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(a3);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ And(a3, a3, Operand(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
// Subclassing.
__ bind(&subclassing);
__ Dlsa(kScratchReg, sp, a0, kPointerSizeLog2);
__ Sd(a1, MemOperand(kScratchReg));
__ li(kScratchReg, Operand(3));
__ Daddu(a0, a0, kScratchReg);
__ Push(a3, a2);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
__ Jump(CodeFactory::InternalArrayNoArgumentConstructor(masm->isolate(), kind)
......
......@@ -2808,179 +2808,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ Cmpi(r6, Operand(kind), r0);
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// r5 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// r6 - kind (if mode != DISABLE_ALLOCATION_SITES)
// r3 - number of arguments
// r4 - constructor?
// sp[0] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ andi(r0, r6, Operand(1));
__ bne(&normal_sequence, cr0);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ addi(r6, r6, Operand(1));
if (FLAG_debug_code) {
__ LoadP(r8, FieldMemOperand(r5, 0));
__ CompareInstanceType(r8, r9, ALLOCATION_SITE_TYPE);
__ Assert(eq, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store r6
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ LoadP(r7, FieldMemOperand(
r5, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ AddSmiLiteral(r7, r7, Smi::FromInt(kFastElementsKindPackedToHoley), r0);
__ StoreP(
r7,
FieldMemOperand(r5, AllocationSite::kTransitionInfoOrBoilerplateOffset),
r0);
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ mov(r0, Operand(kind));
__ cmp(r6, r0);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(
MacroAssembler* masm, AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ cmpi(r3, Operand::Zero());
__ bne(&not_zero_case);
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ cmpi(r3, Operand(1));
__ bgt(&not_one_case);
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
__ Jump(BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor),
RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : argc (only if argument_count() == ANY)
// -- r4 : constructor
// -- r5 : AllocationSite or undefined
// -- r6 : new target
// -- sp[0] : return address
// -- sp[4] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ LoadP(r7, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ TestIfSmi(r7, r0);
__ Assert(ne, AbortReason::kUnexpectedInitialMapForArrayFunction, cr0);
__ CompareObjectType(r7, r7, r8, MAP_TYPE);
__ Assert(eq, AbortReason::kUnexpectedInitialMapForArrayFunction);
// We should either have undefined in r5 or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(r5, r7);
}
// Enter the context of the Array function.
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
Label subclassing;
__ cmp(r6, r4);
__ bne(&subclassing);
Label no_info;
// Get the elements kind and case on that.
__ CompareRoot(r5, Heap::kUndefinedValueRootIndex);
__ beq(&no_info);
__ LoadP(r6, FieldMemOperand(
r5, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(r6);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ And(r6, r6, Operand(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
__ bind(&subclassing);
__ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2));
__ StorePX(r4, MemOperand(sp, r0));
__ addi(r3, r3, Operand(3));
__ Push(r6, r5);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
__ cmpli(r3, Operand(1));
......
......@@ -2794,175 +2794,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ CmpP(r5, Operand(kind));
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// r4 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// r5 - kind (if mode != DISABLE_ALLOCATION_SITES)
// r2 - number of arguments
// r3 - constructor?
// sp[0] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
Label normal_sequence;
// is the low bit set? If so, we are holey and that is good.
__ AndP(r0, r5, Operand(1));
__ bne(&normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ AddP(r5, r5, Operand(1));
if (FLAG_debug_code) {
__ LoadP(r7, FieldMemOperand(r4, 0));
__ CompareInstanceType(r7, r8, ALLOCATION_SITE_TYPE);
__ Assert(eq, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store r5
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ LoadP(r6, FieldMemOperand(
r4, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ AddSmiLiteral(r6, r6, Smi::FromInt(kFastElementsKindPackedToHoley), r0);
__ StoreP(r6, FieldMemOperand(
r4, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ CmpP(r5, Operand(kind));
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET, eq);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(
MacroAssembler* masm, AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ CmpP(r2, Operand::Zero());
__ bne(&not_zero_case);
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ CmpP(r2, Operand(1));
__ bgt(&not_one_case);
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
__ Jump(BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor),
RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : argc (only if argument_count() == ANY)
// -- r3 : constructor
// -- r4 : AllocationSite or undefined
// -- r5 : new target
// -- sp[0] : return address
// -- sp[4] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ LoadP(r6, FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
__ TestIfSmi(r6);
__ Assert(ne, AbortReason::kUnexpectedInitialMapForArrayFunction, cr0);
__ CompareObjectType(r6, r6, r7, MAP_TYPE);
__ Assert(eq, AbortReason::kUnexpectedInitialMapForArrayFunction);
// We should either have undefined in r4 or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(r4, r6);
}
// Enter the context of the Array function.
__ LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
Label subclassing;
__ CmpP(r5, r3);
__ bne(&subclassing, Label::kNear);
Label no_info;
// Get the elements kind and case on that.
__ CompareRoot(r4, Heap::kUndefinedValueRootIndex);
__ beq(&no_info);
__ LoadP(r5, FieldMemOperand(
r4, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(r5);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ AndP(r5, Operand(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
__ bind(&subclassing);
__ ShiftLeftP(r1, r2, Operand(kPointerSizeLog2));
__ StoreP(r3, MemOperand(sp, r1));
__ AddP(r2, r2, Operand(3));
__ Push(r5, r4);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
__ CmpLogicalP(r2, Operand(1));
......
......@@ -2835,189 +2835,6 @@ void Builtins::Generate_MathPowInternal(MacroAssembler* masm) {
namespace {
void CreateArrayDispatchNoArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
if (mode == DISABLE_ALLOCATION_SITES) {
__ Jump(CodeFactory::ArrayNoArgumentConstructor(
masm->isolate(), GetInitialFastElementsKind(), mode)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmpl(rdx, Immediate(kind));
__ j(not_equal, &next);
__ Jump(
CodeFactory::ArrayNoArgumentConstructor(masm->isolate(), kind, mode)
.code(),
RelocInfo::CODE_TARGET);
__ bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void CreateArrayDispatchOneArgument(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
// rbx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
// rdx - kind (if mode != DISABLE_ALLOCATION_SITES)
// rax - number of arguments
// rdi - constructor?
// rsp[0] - return address
// rsp[8] - last argument
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
STATIC_ASSERT(HOLEY_ELEMENTS == 3);
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(
masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES)
.code(),
RelocInfo::CODE_TARGET);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ testb(rdx, Immediate(1));
__ j(not_zero, &normal_sequence);
// We are going to create a holey array, but our kind is non-holey.
// Fix kind and retry (only if we have an allocation site in the slot).
__ incl(rdx);
if (FLAG_debug_code) {
Handle<Map> allocation_site_map =
masm->isolate()->factory()->allocation_site_map();
__ Cmp(FieldOperand(rbx, 0), allocation_site_map);
__ Assert(equal, AbortReason::kExpectedAllocationSite);
}
// Save the resulting elements kind in type info. We can't just store r3
// in the AllocationSite::transition_info field because elements kind is
// restricted to a portion of the field...upper bits need to be left alone.
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ SmiAddConstant(
FieldOperand(rbx, AllocationSite::kTransitionInfoOrBoilerplateOffset),
Smi::FromInt(kFastElementsKindPackedToHoley));
__ bind(&normal_sequence);
int last_index =
GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= last_index; ++i) {
Label next;
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
__ cmpl(rdx, Immediate(kind));
__ j(not_equal, &next);
__ Jump(CodeFactory::ArraySingleArgumentConstructor(masm->isolate(), kind,
DONT_OVERRIDE)
.code(),
RelocInfo::CODE_TARGET);
__ bind(&next);
}
// If we reached this point there is a problem.
__ Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
} else {
UNREACHABLE();
}
}
void GenerateDispatchToArrayStub(MacroAssembler* masm,
AllocationSiteOverrideMode mode) {
Label not_zero_case, not_one_case;
__ testp(rax, rax);
__ j(not_zero, &not_zero_case);
CreateArrayDispatchNoArgument(masm, mode);
__ bind(&not_zero_case);
__ cmpl(rax, Immediate(1));
__ j(greater, &not_one_case);
CreateArrayDispatchOneArgument(masm, mode);
__ bind(&not_one_case);
Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
void Builtins::Generate_ArrayConstructorImpl(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : argc
// -- rbx : AllocationSite or undefined
// -- rdi : constructor
// -- rdx : new target
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -----------------------------------
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
__ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a nullptr and a Smi.
STATIC_ASSERT(kSmiTag == 0);
Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
__ Check(not_smi, AbortReason::kUnexpectedInitialMapForArrayFunction);
__ CmpObjectType(rcx, MAP_TYPE, rcx);
__ Check(equal, AbortReason::kUnexpectedInitialMapForArrayFunction);
// We should either have undefined in rbx or a valid AllocationSite
__ AssertUndefinedOrAllocationSite(rbx);
}
// Enter the context of the Array function.
__ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Label subclassing;
__ cmpp(rdi, rdx);
__ j(not_equal, &subclassing);
Label no_info;
// If the feedback vector is the undefined value call an array constructor
// that doesn't use AllocationSites.
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
__ j(equal, &no_info);
// Only look at the lower 16 bits of the transition info.
__ movp(rdx, FieldOperand(
rbx, AllocationSite::kTransitionInfoOrBoilerplateOffset));
__ SmiUntag(rdx, rdx);
STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
__ andp(rdx, Immediate(AllocationSite::ElementsKindBits::kMask));
GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
__ bind(&no_info);
GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
// Subclassing
__ bind(&subclassing);
StackArgumentsAccessor args(rsp, rax);
__ movp(args.GetReceiverOperand(), rdi);
__ addp(rax, Immediate(3));
__ PopReturnAddressTo(rcx);
__ Push(rdx);
__ Push(rbx);
__ PushReturnAddressFrom(rcx);
__ JumpToExternalReference(ExternalReference::Create(Runtime::kNewArray));
}
namespace {
void GenerateInternalArrayConstructorCase(MacroAssembler* masm,
ElementsKind kind) {
Label not_zero_case, not_one_case;
......
......@@ -9400,6 +9400,35 @@ TNode<MaybeObject> CodeStubAssembler::StoreWeakReferenceInFeedbackVector(
return weak_value;
}
TNode<BoolT> CodeStubAssembler::NotHasBoilerplate(
TNode<Object> maybe_literal_site) {
return TaggedIsSmi(maybe_literal_site);
}
TNode<Smi> CodeStubAssembler::LoadTransitionInfo(
TNode<AllocationSite> allocation_site) {
TNode<Smi> transition_info = CAST(LoadObjectField(
allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset));
return transition_info;
}
TNode<JSObject> CodeStubAssembler::LoadBoilerplate(
TNode<AllocationSite> allocation_site) {
TNode<JSObject> boilerplate = CAST(LoadObjectField(
allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset));
return boilerplate;
}
TNode<Int32T> CodeStubAssembler::LoadElementsKind(
TNode<AllocationSite> allocation_site) {
TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
TNode<Int32T> elements_kind =
Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
SmiToInt32(transition_info)));
CSA_ASSERT(this, IsFastElementsKind(elements_kind));
return elements_kind;
}
Node* CodeStubAssembler::BuildFastLoop(
const CodeStubAssembler::VariableList& vars, Node* start_index,
Node* end_index, const FastLoopBody& body, int increment,
......
......@@ -2395,6 +2395,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<AllocationSite> CreateAllocationSiteInFeedbackVector(
SloppyTNode<FeedbackVector> feedback_vector, TNode<Smi> slot);
// TODO(ishell, cbruni): Change to HasBoilerplate.
TNode<BoolT> NotHasBoilerplate(TNode<Object> maybe_literal_site);
TNode<Smi> LoadTransitionInfo(TNode<AllocationSite> allocation_site);
TNode<JSObject> LoadBoilerplate(TNode<AllocationSite> allocation_site);
TNode<Int32T> LoadElementsKind(TNode<AllocationSite> allocation_site);
enum class IndexAdvanceMode { kPre, kPost };
typedef std::function<void(Node* index)> FastLoopBody;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment