Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index ba0fcab3114ca4628d3b354b172c74e4b1a4c73f..7ab4ec98cfb6411b307aa0ee2c1d5168844cc528 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -2468,7 +2468,6 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, |
| } |
| // Special loop unfolding case |
| - static const int kLoopUnfoldLimit = 8; |
| STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit); |
| int initial_capacity = -1; |
| if (from->IsInteger32Constant() && to->IsInteger32Constant()) { |
| @@ -8232,6 +8231,59 @@ 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; |
| + } |
| + |
| + AllocationSiteInfo* site_info = |
| + reinterpret_cast<AllocationSiteInfo*>(expr->extra_info()); |
| + if (site_info == NULL) return false; |
| + Handle<AllocationSite> site = site_info->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); |
| @@ -8326,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 |
| @@ -8361,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); |
| @@ -8410,20 +8462,20 @@ 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()); |
| 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 |
| @@ -8446,32 +8498,18 @@ void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
| site_instruction, |
| constructor, |
| DISABLE_ALLOCATION_SITES); |
| - HValue* new_object; |
| + HValue* new_object = NULL; |
| if (argument_count == 0) { |
|
danno
2014/05/16 16:34:11
ASSERT(argument_count == 0); and remove the if.
mvstanton
2014/05/19 13:45:24
I do need to support the 1 argument case too thoug
|
| 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. |
| + UNREACHABLE(); |
| + } |
| + |
| + int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); |
| + Drop(args_to_drop); |
| ast_context()->ReturnValue(new_object); |
| } |
| @@ -8485,14 +8523,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; |
| @@ -8502,22 +8539,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 <= kLoopUnfoldLimit; |
| 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."); |
| @@ -8647,25 +8686,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()); |
| } |
| } |