Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 8e0858dca7ea91be64f320d0f83392c592cbf8d9..6059a2a65317b2d9dfba4505ad2ca835e339523e 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2474,14 +2474,14 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, |
} |
// Special loop unfolding case |
- STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= |
- kElementLoopUnrollThreshold); |
+ static const int kLoopUnfoldLimit = 8; |
+ STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
int initial_capacity = -1; |
if (from->IsInteger32Constant() && to->IsInteger32Constant()) { |
int constant_from = from->GetInteger32Constant(); |
int constant_to = to->GetInteger32Constant(); |
- if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) { |
+ if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) { |
initial_capacity = constant_to; |
} |
} |
@@ -8234,56 +8234,6 @@ HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
} |
-void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression, |
- int arguments_count, |
- HValue* function, |
- Handle<AllocationSite> site) { |
- Add<HCheckValue>(function, array_function()); |
- |
- if (IsCallArrayInlineable(arguments_count, site)) { |
- BuildInlinedCallArray(expression, arguments_count, site); |
- return; |
- } |
- |
- HInstruction* call = PreProcessCall(New<HCallNewArray>( |
- function, arguments_count + 1, site->GetElementsKind())); |
- if (expression->IsCall()) { |
- Drop(1); |
- } |
- ast_context()->ReturnInstruction(call, expression->id()); |
-} |
- |
- |
-bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) { |
- if (!array_function().is_identical_to(expr->target())) { |
- return false; |
- } |
- |
- Handle<AllocationSite> site = expr->allocation_site(); |
- if (site.is_null()) return false; |
- |
- BuildArrayCall(expr, |
- expr->arguments()->length(), |
- function, |
- site); |
- return true; |
-} |
- |
- |
-bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr, |
- HValue* function) { |
- if (!array_function().is_identical_to(expr->target())) { |
- return false; |
- } |
- |
- BuildArrayCall(expr, |
- expr->arguments()->length(), |
- function, |
- expr->allocation_site()); |
- return true; |
-} |
- |
- |
void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
ASSERT(!HasStackOverflow()); |
ASSERT(current_block() != NULL); |
@@ -8378,7 +8328,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
// evaluation of the arguments. |
CHECK_ALIVE(VisitForValue(expr->expression())); |
HValue* function = Top(); |
- if (expr->global_call()) { |
+ bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
+ if (global_call) { |
Variable* var = proxy->var(); |
bool known_global_function = false; |
// If there is a global property cell for the name at compile time and |
@@ -8412,7 +8363,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
return; |
} |
if (TryInlineApiFunctionCall(expr, receiver)) return; |
- if (TryHandleArrayCall(expr, function)) return; |
if (TryInlineCall(expr)) return; |
PushArgumentsFromEnvironment(argument_count); |
@@ -8462,21 +8412,20 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
-void HOptimizedGraphBuilder::BuildInlinedCallArray( |
- Expression* expression, |
- int argument_count, |
- Handle<AllocationSite> site) { |
- ASSERT(!site.is_null()); |
- ASSERT(argument_count >= 0 && argument_count <= 1); |
+void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
NoObservableSideEffectsScope no_effects(this); |
+ int argument_count = expr->arguments()->length(); |
// We should at least have the constructor on the expression stack. |
HValue* constructor = environment()->ExpressionStackAt(argument_count); |
+ ElementsKind kind = expr->elements_kind(); |
+ Handle<AllocationSite> site = expr->allocation_site(); |
+ ASSERT(!site.is_null()); |
+ |
// Register on the site for deoptimization if the transition feedback changes. |
AllocationSite::AddDependentCompilationInfo( |
site, AllocationSite::TRANSITIONS, top_info()); |
- ElementsKind kind = site->GetElementsKind(); |
HInstruction* site_instruction = Add<HConstant>(site); |
// In the single constant argument case, we may have to adjust elements kind |
@@ -8499,12 +8448,32 @@ void HOptimizedGraphBuilder::BuildInlinedCallArray( |
site_instruction, |
constructor, |
DISABLE_ALLOCATION_SITES); |
- HValue* new_object = argument_count == 0 |
- ? array_builder.AllocateEmptyArray() |
- : BuildAllocateArrayFromLength(&array_builder, Top()); |
- |
- int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); |
- Drop(args_to_drop); |
+ HValue* new_object; |
+ if (argument_count == 0) { |
+ new_object = array_builder.AllocateEmptyArray(); |
+ } else if (argument_count == 1) { |
+ HValue* argument = environment()->Top(); |
+ new_object = BuildAllocateArrayFromLength(&array_builder, argument); |
+ } else { |
+ HValue* length = Add<HConstant>(argument_count); |
+ // Smi arrays need to initialize array elements with the hole because |
+ // bailout could occur if the arguments don't fit in a smi. |
+ // |
+ // TODO(mvstanton): If all the arguments are constants in smi range, then |
+ // we could set fill_with_hole to false and save a few instructions. |
+ JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) |
+ ? JSArrayBuilder::FILL_WITH_HOLE |
+ : JSArrayBuilder::DONT_FILL_WITH_HOLE; |
+ new_object = array_builder.AllocateArray(length, length, fill_mode); |
+ HValue* elements = array_builder.GetElementsLocation(); |
+ for (int i = 0; i < argument_count; i++) { |
+ HValue* value = environment()->ExpressionStackAt(argument_count - i - 1); |
+ HValue* constant_i = Add<HConstant>(i); |
+ Add<HStoreKeyed>(elements, constant_i, value, kind); |
+ } |
+ } |
+ |
+ Drop(argument_count + 1); // drop constructor and args. |
ast_context()->ReturnValue(new_object); |
} |
@@ -8518,13 +8487,14 @@ static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
} |
-bool HOptimizedGraphBuilder::IsCallArrayInlineable( |
- int argument_count, |
- Handle<AllocationSite> site) { |
+bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
Handle<JSFunction> caller = current_info()->closure(); |
- Handle<JSFunction> target = array_function(); |
+ Handle<JSFunction> target(isolate()->native_context()->array_function(), |
+ isolate()); |
+ int argument_count = expr->arguments()->length(); |
// We should have the function plus array arguments on the environment stack. |
ASSERT(environment()->length() >= (argument_count + 1)); |
+ Handle<AllocationSite> site = expr->allocation_site(); |
ASSERT(!site.is_null()); |
bool inline_ok = false; |
@@ -8534,24 +8504,22 @@ bool HOptimizedGraphBuilder::IsCallArrayInlineable( |
HValue* argument = Top(); |
if (argument->IsConstant()) { |
// Do not inline if the constant length argument is not a smi or |
- // outside the valid range for unrolled loop initialization. |
+ // outside the valid range for a fast array. |
HConstant* constant_argument = HConstant::cast(argument); |
if (constant_argument->HasSmiValue()) { |
int value = constant_argument->Integer32Value(); |
- inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold; |
+ inline_ok = value >= 0 && |
+ value < JSObject::kInitialMaxFastElementArray; |
if (!inline_ok) { |
TraceInline(target, caller, |
- "Constant length outside of valid inlining range."); |
+ "Length outside of valid array range"); |
} |
} |
} else { |
- TraceInline(target, caller, |
- "Dont inline [new] Array(n) where n isn't constant."); |
+ inline_ok = true; |
} |
- } else if (argument_count == 0) { |
- inline_ok = true; |
} else { |
- TraceInline(target, caller, "Too many arguments to inline."); |
+ inline_ok = true; |
} |
} else { |
TraceInline(target, caller, "AllocationSite requested no inlining."); |
@@ -8676,10 +8644,25 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
} else { |
// The constructor function is both an operand to the instruction and an |
// argument to the construct call. |
- if (TryHandleArrayCallNew(expr, function)) return; |
+ Handle<JSFunction> array_function( |
+ isolate()->native_context()->array_function(), isolate()); |
+ bool use_call_new_array = expr->target().is_identical_to(array_function); |
+ if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
+ // Verify we are still calling the array function for our native context. |
+ Add<HCheckValue>(function, array_function); |
+ BuildInlinedCallNewArray(expr); |
+ return; |
+ } |
- HInstruction* call = |
- PreProcessCall(New<HCallNew>(function, argument_count)); |
+ HBinaryCall* call; |
+ if (use_call_new_array) { |
+ Add<HCheckValue>(function, array_function); |
+ call = New<HCallNewArray>(function, argument_count, |
+ expr->elements_kind()); |
+ } else { |
+ call = New<HCallNew>(function, argument_count); |
+ } |
+ PreProcessCall(call); |
return ast_context()->ReturnInstruction(call, expr->id()); |
} |
} |