[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/565721
Reviewed-by: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46538}
This commit is contained in:
Benedikt Meurer 2017-07-10 20:50:09 +02:00 committed by Commit Bot
parent be8983da7b
commit 1edb46cc04
15 changed files with 145 additions and 304 deletions

View File

@ -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));

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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));
}

View File

@ -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()));

View File

@ -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,

View File

@ -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());

View File

@ -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);

View File

@ -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));

View File

@ -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));

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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);