Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 6059a2a65317b2d9dfba4505ad2ca835e339523e..8e0858dca7ea91be64f320d0f83392c592cbf8d9 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2474,14 +2474,14 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, |
} |
// Special loop unfolding case |
- static const int kLoopUnfoldLimit = 8; |
- STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
+ STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= |
+ kElementLoopUnrollThreshold); |
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 <= kLoopUnfoldLimit) { |
+ if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) { |
initial_capacity = constant_to; |
} |
} |
@@ -8234,6 +8234,56 @@ 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); |
@@ -8328,8 +8378,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
// evaluation of the arguments. |
CHECK_ALIVE(VisitForValue(expr->expression())); |
HValue* function = Top(); |
- bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
- if (global_call) { |
+ if (expr->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 |
@@ -8363,6 +8412,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
return; |
} |
if (TryInlineApiFunctionCall(expr, receiver)) return; |
+ if (TryHandleArrayCall(expr, function)) return; |
if (TryInlineCall(expr)) return; |
PushArgumentsFromEnvironment(argument_count); |
@@ -8412,20 +8462,21 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
-void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
+void HOptimizedGraphBuilder::BuildInlinedCallArray( |
+ Expression* expression, |
+ int argument_count, |
+ Handle<AllocationSite> site) { |
+ ASSERT(!site.is_null()); |
+ ASSERT(argument_count >= 0 && argument_count <= 1); |
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 |
@@ -8448,32 +8499,12 @@ void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
site_instruction, |
constructor, |
DISABLE_ALLOCATION_SITES); |
- 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. |
+ 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); |
ast_context()->ReturnValue(new_object); |
} |
@@ -8487,14 +8518,13 @@ static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
} |
-bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
+bool HOptimizedGraphBuilder::IsCallArrayInlineable( |
+ int argument_count, |
+ Handle<AllocationSite> site) { |
Handle<JSFunction> caller = current_info()->closure(); |
- Handle<JSFunction> target(isolate()->native_context()->array_function(), |
- isolate()); |
- int argument_count = expr->arguments()->length(); |
+ Handle<JSFunction> target = array_function(); |
// 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; |
@@ -8504,22 +8534,24 @@ bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
HValue* argument = Top(); |
if (argument->IsConstant()) { |
// Do not inline if the constant length argument is not a smi or |
- // outside the valid range for a fast array. |
+ // outside the valid range for unrolled loop initialization. |
HConstant* constant_argument = HConstant::cast(argument); |
if (constant_argument->HasSmiValue()) { |
int value = constant_argument->Integer32Value(); |
- inline_ok = value >= 0 && |
- value < JSObject::kInitialMaxFastElementArray; |
+ inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold; |
if (!inline_ok) { |
TraceInline(target, caller, |
- "Length outside of valid array range"); |
+ "Constant length outside of valid inlining range."); |
} |
} |
} else { |
- inline_ok = true; |
+ TraceInline(target, caller, |
+ "Dont inline [new] Array(n) where n isn't constant."); |
} |
- } else { |
+ } else if (argument_count == 0) { |
inline_ok = true; |
+ } else { |
+ TraceInline(target, caller, "Too many arguments to inline."); |
} |
} else { |
TraceInline(target, caller, "AllocationSite requested no inlining."); |
@@ -8644,25 +8676,10 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
} else { |
// The constructor function is both an operand to the instruction and an |
// argument to the construct call. |
- 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; |
- } |
+ if (TryHandleArrayCallNew(expr, function)) return; |
- 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); |
+ HInstruction* call = |
+ PreProcessCall(New<HCallNew>(function, argument_count)); |
return ast_context()->ReturnInstruction(call, expr->id()); |
} |
} |