Commit 1edb46cc authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Widen the fast-path for JSCreateArray.

This improves the general Array constructor call performance (w/o
usable AllocationSite feedback) in TurboFan by ~2x, i.e. for example
invoking the Array constructor like this

  var a = Array.call(undefined, n);

instead of

  var a = Array(n);

such that the CallIC doesn't know that it's eventually calling the
Array constructor.

It also thus changes the single argument Array constructor to always
return holey arrays. Previously the single argument case for the Array
constructor was somehow trying to dynamically detect 0 and in that case
returned a packed array instead of a holey one. That adds quite a lot
of churn, and doesn't seem to be very useful, especially since this
might lead to unnecessary feedback pollution later.

R=mvstanton@chromium.org

Bug: v8:2229, v8:5269, v8:6399
Change-Id: I3d7cb9bd975ec0e491e3cdbcf1230185cfd1e3de
Reviewed-on: https://chromium-review.googlesource.com/565721Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46538}
parent be8983da
......@@ -2316,24 +2316,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
// r0 - number of arguments
// r1 - constructor?
// sp[0] - last argument
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
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);
// is the low bit set? If so, we are holey and that is good.
__ tst(r3, Operand(1));
__ b(ne, &normal_sequence);
}
// look at the first argument
__ ldr(r5, MemOperand(sp, 0));
__ cmp(r5, Operand::Zero());
__ b(eq, &normal_sequence);
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();
......@@ -2343,13 +2331,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} 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));
......
......@@ -2486,23 +2486,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
Register allocation_site = x2;
Register kind = x3;
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
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);
// Is the low bit set? If so, the array is holey.
__ Tbnz(kind, 0, &normal_sequence);
}
// Look at the last argument.
// TODO(jbramley): What does a 0 argument represent?
__ Peek(x10, 0);
__ Cbz(x10, &normal_sequence);
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();
......@@ -2512,13 +2501,11 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ Bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} 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);
......
......@@ -731,11 +731,15 @@ Reduction JSCreateLowering::ReduceNewArrayToStubCall(
Node* target = NodeProperties::GetValueInput(node, 0);
Node* new_target = NodeProperties::GetValueInput(node, 1);
Type* new_target_type = NodeProperties::GetType(new_target);
Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
: jsgraph()->HeapConstant(site);
ElementsKind elements_kind = site->GetElementsKind();
ElementsKind elements_kind =
site.is_null() ? GetInitialFastElementsKind() : site->GetElementsKind();
AllocationSiteOverrideMode override_mode =
AllocationSite::ShouldTrack(elements_kind) ? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
(site.is_null() || AllocationSite::ShouldTrack(elements_kind))
? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
// The Array constructor can only trigger an observable side-effect
// if the new.target may be a proxy.
......@@ -748,137 +752,37 @@ Reduction JSCreateLowering::ReduceNewArrayToStubCall(
ArrayNoArgumentConstructorStub stub(isolate(), elements_kind,
override_mode);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1,
CallDescriptor::kNeedsFrameState, properties);
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
arity + 1, CallDescriptor::kNeedsFrameState, properties);
node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(0));
node->InsertInput(graph()->zone(), 2, type_info);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc));
return Changed(node);
} else if (arity == 1) {
AllocationSiteOverrideMode override_mode =
AllocationSite::ShouldTrack(elements_kind) ? DISABLE_ALLOCATION_SITES
: DONT_OVERRIDE;
if (IsHoleyOrDictionaryElementsKind(elements_kind)) {
ArraySingleArgumentConstructorStub stub(isolate(), elements_kind,
override_mode);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
CallDescriptor::kNeedsFrameState, properties);
node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(1));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc));
return Changed(node);
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* length = NodeProperties::GetValueInput(node, 2);
Node* equal = graph()->NewNode(simplified()->ReferenceEqual(), length,
jsgraph()->ZeroConstant());
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), equal, control);
Node* call_holey;
Node* call_packed;
Node* success_holey;
Node* success_packed;
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* if_equal = graph()->NewNode(common()->IfTrue(), branch);
{
ArraySingleArgumentConstructorStub stub(isolate(), elements_kind,
override_mode);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
CallDescriptor::kNeedsFrameState, properties);
Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()),
node->InputAt(1),
jsgraph()->HeapConstant(site),
jsgraph()->Constant(1),
jsgraph()->UndefinedConstant(),
length,
context,
frame_state,
effect,
if_equal};
success_holey = call_holey =
graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs);
}
Node* if_not_equal = graph()->NewNode(common()->IfFalse(), branch);
{
// Require elements kind to "go holey."
ArraySingleArgumentConstructorStub stub(
isolate(), GetHoleyElementsKind(elements_kind), override_mode);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
CallDescriptor::kNeedsFrameState, properties);
Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()),
node->InputAt(1),
jsgraph()->HeapConstant(site),
jsgraph()->Constant(1),
jsgraph()->UndefinedConstant(),
length,
context,
frame_state,
effect,
if_not_equal};
success_packed = call_packed =
graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs);
}
// Update potential {IfException} uses of {node} to point to the above two
// stub call nodes instead, by introducing a merge of two exception cases.
Node* on_exception = nullptr;
if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
Node* exception_holey =
graph()->NewNode(common()->IfException(), call_holey, call_holey);
Node* exception_packed =
graph()->NewNode(common()->IfException(), call_packed, call_packed);
Node* exception_merge = graph()->NewNode(
common()->Merge(2), exception_holey, exception_packed);
Node* exception_effect =
graph()->NewNode(common()->EffectPhi(2), exception_holey,
exception_packed, exception_merge);
Node* exception_value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
exception_holey, exception_packed, exception_merge);
ReplaceWithValue(on_exception, exception_value, exception_effect,
exception_merge);
success_holey = graph()->NewNode(common()->IfSuccess(), call_holey);
success_packed = graph()->NewNode(common()->IfSuccess(), call_packed);
}
Node* merge =
graph()->NewNode(common()->Merge(2), success_holey, success_packed);
Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), call_holey,
call_packed, merge);
Node* phi =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
call_holey, call_packed, merge);
ReplaceWithValue(node, phi, effect_phi, merge);
return Changed(node);
// Require elements kind to "go holey".
ArraySingleArgumentConstructorStub stub(
isolate(), GetHoleyElementsKind(elements_kind), override_mode);
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
arity + 1, CallDescriptor::kNeedsFrameState, properties);
node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
node->InsertInput(graph()->zone(), 2, type_info);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc));
} else {
DCHECK_GT(arity, 1);
ArrayNArgumentsConstructorStub stub(isolate());
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
arity + 1, CallDescriptor::kNeedsFrameState);
node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
node->InsertInput(graph()->zone(), 2, type_info);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc));
}
DCHECK(arity > 1);
ArrayNArgumentsConstructorStub stub(isolate());
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), arity + 1,
CallDescriptor::kNeedsFrameState);
node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(node, common()->Call(desc));
return Changed(node);
}
......@@ -893,38 +797,38 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
// Check if we have a feedback {site} on the {node}.
Handle<AllocationSite> site = p.site();
if (p.site().is_null()) return NoChange();
// Attempt to inline calls to the Array constructor for the relevant cases
// where either no arguments are provided, or exactly one unsigned number
// argument is given.
if (site->CanInlineCall()) {
if (p.arity() == 0) {
Node* length = jsgraph()->ZeroConstant();
int capacity = JSArray::kPreallocatedArrayElements;
return ReduceNewArray(node, length, capacity, site);
} else if (p.arity() == 1) {
Node* length = NodeProperties::GetValueInput(node, 2);
Type* length_type = NodeProperties::GetType(length);
if (!length_type->Maybe(Type::Number())) {
// Handle the single argument case, where we know that the value
// cannot be a valid Array length.
return ReduceNewArray(node, {length}, site);
}
if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 &&
length_type->Max() <= kElementLoopUnrollLimit &&
length_type->Min() == length_type->Max()) {
int capacity = static_cast<int>(length_type->Max());
if (!site.is_null()) {
// Attempt to inline calls to the Array constructor for the relevant cases
// where either no arguments are provided, or exactly one unsigned number
// argument is given.
if (site->CanInlineCall()) {
if (p.arity() == 0) {
Node* length = jsgraph()->ZeroConstant();
int capacity = JSArray::kPreallocatedArrayElements;
return ReduceNewArray(node, length, capacity, site);
} else if (p.arity() == 1) {
Node* length = NodeProperties::GetValueInput(node, 2);
Type* length_type = NodeProperties::GetType(length);
if (!length_type->Maybe(Type::Number())) {
// Handle the single argument case, where we know that the value
// cannot be a valid Array length.
return ReduceNewArray(node, {length}, site);
}
if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 &&
length_type->Max() <= kElementLoopUnrollLimit &&
length_type->Min() == length_type->Max()) {
int capacity = static_cast<int>(length_type->Max());
return ReduceNewArray(node, length, capacity, site);
}
} else if (p.arity() <= JSArray::kInitialMaxFastElementArray) {
std::vector<Node*> values;
values.reserve(p.arity());
for (size_t i = 0; i < p.arity(); ++i) {
values.push_back(
NodeProperties::GetValueInput(node, static_cast<int>(2 + i)));
}
return ReduceNewArray(node, values, site);
}
} else if (p.arity() <= JSArray::kInitialMaxFastElementArray) {
std::vector<Node*> values;
values.reserve(p.arity());
for (size_t i = 0; i < p.arity(); ++i) {
values.push_back(
NodeProperties::GetValueInput(node, static_cast<int>(2 + i)));
}
return ReduceNewArray(node, values, site);
}
}
......
......@@ -393,13 +393,21 @@ void JSGenericLowering::LowerJSCreateArray(Node* node) {
CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
int const arity = static_cast<int>(p.arity());
Handle<AllocationSite> const site = p.site();
Node* new_target = node->InputAt(1);
ArrayConstructorDescriptor descriptor(isolate());
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), descriptor, arity + 1,
CallDescriptor::kNeedsFrameState, node->op()->properties(),
MachineType::AnyTagged());
Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
Node* stub_arity = jsgraph()->Int32Constant(arity);
Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
: jsgraph()->HeapConstant(site);
node->RemoveInput(1);
node->InsertInput(zone(), 1 + arity, new_target);
node->InsertInput(zone(), 2 + arity, type_info);
ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3);
Node* receiver = jsgraph()->UndefinedConstant();
node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, type_info);
node->InsertInput(zone(), 5, receiver);
NodeProperties::ChangeOp(node, common()->Call(desc));
}
......
......@@ -26,6 +26,11 @@ Node* JSGraph::AllocateInOldSpaceStubConstant() {
HeapConstant(isolate()->builtins()->AllocateInOldSpace()));
}
Node* JSGraph::ArrayConstructorStubConstant() {
return CACHED(kArrayConstructorStubConstant,
HeapConstant(ArrayConstructorStub(isolate()).GetCode()));
}
Node* JSGraph::ToNumberBuiltinConstant() {
return CACHED(kToNumberBuiltinConstant,
HeapConstant(isolate()->builtins()->ToNumber()));
......
......@@ -43,6 +43,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
// Canonicalized global constants.
Node* AllocateInNewSpaceStubConstant();
Node* AllocateInOldSpaceStubConstant();
Node* ArrayConstructorStubConstant();
Node* ToNumberBuiltinConstant();
Node* CEntryStubConstant(int result_size,
SaveFPRegsMode save_doubles = kDontSaveFPRegs,
......@@ -165,6 +166,7 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
enum CachedNode {
kAllocateInNewSpaceStubConstant,
kAllocateInOldSpaceStubConstant,
kArrayConstructorStubConstant,
kToNumberBuiltinConstant,
kCEntryStub1Constant,
kCEntryStub2Constant,
......
......@@ -1145,6 +1145,10 @@ struct ConcurrentOptimizationPrepPhase {
data->jsgraph()->CEntryStubConstant(2);
data->jsgraph()->CEntryStubConstant(3);
// TODO(turbofan): Remove this line once the Array constructor code
// is a proper builtin and no longer a CodeStub.
data->jsgraph()->ArrayConstructorStubConstant();
// This is needed for escape analysis.
NodeProperties::SetType(data->jsgraph()->FalseConstant(), Type::Boolean());
NodeProperties::SetType(data->jsgraph()->TrueConstant(), Type::Boolean());
......
......@@ -2223,24 +2223,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
// edi - constructor?
// esp[0] - return address
// esp[4] - last argument
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
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);
// is the low bit set? If so, we are holey and that is good.
__ test_b(edx, Immediate(1));
__ j(not_zero, &normal_sequence);
}
// look at the first argument
__ mov(ecx, Operand(esp, kPointerSize));
__ test(ecx, ecx);
__ j(zero, &normal_sequence);
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();
......@@ -2250,13 +2238,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} 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);
......
......@@ -2482,8 +2482,6 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
// a0 - number of arguments
// a1 - constructor?
// sp[0] - last argument
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
......@@ -2491,15 +2489,6 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
// is the low bit set? If so, we are holey and that is good.
__ And(at, a3, Operand(1));
__ Branch(&normal_sequence, ne, at, Operand(zero_reg));
}
// look at the first argument
__ lw(t1, MemOperand(sp, 0));
__ Branch(&normal_sequence, eq, t1, Operand(zero_reg));
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
......@@ -2508,13 +2497,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ And(at, a3, Operand(1));
__ Branch(&normal_sequence, ne, at, 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));
......
......@@ -2486,8 +2486,6 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
// a0 - number of arguments
// a1 - constructor?
// sp[0] - last argument
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
......@@ -2495,14 +2493,6 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
// is the low bit set? If so, we are holey and that is good.
__ And(at, a3, Operand(1));
__ Branch(&normal_sequence, ne, at, Operand(zero_reg));
}
// look at the first argument
__ Ld(a5, MemOperand(sp, 0));
__ Branch(&normal_sequence, eq, a5, Operand(zero_reg));
if (mode == DISABLE_ALLOCATION_SITES) {
ElementsKind initial = GetInitialFastElementsKind();
ElementsKind holey_initial = GetHoleyElementsKind(initial);
......@@ -2511,13 +2501,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} else if (mode == DONT_OVERRIDE) {
// is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
__ And(at, a3, Operand(1));
__ Branch(&normal_sequence, ne, at, 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));
......
......@@ -2181,25 +2181,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
// rsp[0] - return address
// rsp[8] - last argument
Label normal_sequence;
if (mode == DONT_OVERRIDE) {
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);
// is the low bit set? If so, we are holey and that is good.
__ testb(rdx, Immediate(1));
__ j(not_zero, &normal_sequence);
}
// look at the first argument
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movp(rcx, args.GetArgumentOperand(0));
__ testp(rcx, rcx);
__ j(zero, &normal_sequence);
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();
......@@ -2209,13 +2196,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
holey_initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub_holey);
__ bind(&normal_sequence);
ArraySingleArgumentConstructorStub stub(masm->isolate(),
initial,
DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
} 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);
......
......@@ -81,7 +81,7 @@ assertNotHoley(obj);
assertKind(elements_kind.fast_smi_only, obj);
obj = new Array(0);
assertNotHoley(obj);
assertHoley(obj);
assertKind(elements_kind.fast_smi_only, obj);
obj = new Array(2);
......
......@@ -180,7 +180,7 @@ function assertKind(expected, obj, name_opt) {
%OptimizeFunctionOnNextCall(bar);
a = bar(0);
assertOptimized(bar);
assertFalse(isHoley(a));
assertTrue(isHoley(a));
a = bar(1); // ouch!
assertOptimized(bar);
assertTrue(isHoley(a));
......@@ -188,9 +188,7 @@ function assertKind(expected, obj, name_opt) {
assertTrue(isHoley(a));
a = bar(0);
assertOptimized(bar);
// Crankshafted functions don't use mementos, so feedback still
// indicates a packed array is desired.
assertFalse(isHoley(a));
assertTrue(isHoley(a));
})();
// Test: Make sure that crankshaft continues with feedback for large arrays.
......
......@@ -84,7 +84,7 @@ function assertKind(expected, obj, name_opt) {
create1(0);
create1(0);
a = create1(0);
assertFalse(isHoley(a));
assertTrue(isHoley(a));
assertKind(elements_kind.fast_smi_only, a);
a[0] = "hello";
b = create1(10);
......
......@@ -36,16 +36,12 @@ function assertHoley(obj, name_opt) {
assertEquals(true, isHoley(obj), name_opt);
}
function assertNotHoley(obj, name_opt) {
assertEquals(false, isHoley(obj), name_opt);
}
function create_array(arg) {
return new Array(arg);
}
obj = create_array(0);
assertNotHoley(obj);
assertHoley(obj);
create_array(0);
%OptimizeFunctionOnNextCall(create_array);
obj = create_array(10);
......
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