Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 18a62c689bd3c5bea3ee9733923bbf4e46367205..b70a7fab698ebe19eac1b6aae49b54e09c652783 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2639,10 +2639,14 @@ void HGraphBuilder::SetUpScope(Scope* scope) { |
if (!scope->arguments()->IsStackAllocated()) { |
return Bailout("context-allocated arguments"); |
} |
- HArgumentsObject* object = new(zone()) HArgumentsObject; |
- AddInstruction(object); |
- graph()->SetArgumentsObject(object); |
- environment()->Bind(scope->arguments(), object); |
+ |
+ if (!graph()->HasArgumentsObject()) { |
+ HArgumentsObject* object = new(zone()) HArgumentsObject; |
+ AddInstruction(object); |
+ graph()->SetArgumentsObject(object); |
+ } |
+ environment()->Bind(scope->arguments(), |
+ graph()->GetArgumentsObject()); |
} |
} |
@@ -5226,10 +5230,20 @@ bool HGraphBuilder::TryInline(CallKind call_kind, |
return false; |
} |
- // Don't inline functions that uses the arguments object. |
+ // If the function uses arguments object check that inlining of functions |
+ // with arguments object is enabled and variable arguments is stack allocated. |
if (function->scope()->arguments() != NULL) { |
- TraceInline(target, caller, "target requires special argument handling"); |
- return false; |
+ if (!FLAG_inline_arguments) { |
+ TraceInline(target, caller, "target uses arguments object"); |
+ return false; |
+ } |
+ |
+ if (!function->scope()->arguments()->IsStackAllocated()) { |
+ TraceInline(target, |
+ caller, |
+ "target uses non-stackallocated arguments object"); |
+ return false; |
+ } |
} |
// All declarations must be inlineable. |
@@ -5307,6 +5321,17 @@ bool HGraphBuilder::TryInline(CallKind call_kind, |
function, |
call_kind, |
function_state()->is_construct())); |
+ // If the function uses arguments object create and bind one. |
+ if (function->scope()->arguments() != NULL) { |
+ ASSERT(function->scope()->arguments()->IsStackAllocated()); |
+ if (!graph()->HasArgumentsObject()) { |
+ HArgumentsObject* object = new(zone()) HArgumentsObject; |
+ AddInstruction(object); |
+ graph()->SetArgumentsObject(object); |
+ } |
+ environment()->Bind(function->scope()->arguments(), |
+ graph()->GetArgumentsObject()); |
+ } |
VisitDeclarations(target_info.scope()->declarations()); |
VisitStatements(function->body()); |
if (HasStackOverflow()) { |
@@ -5645,13 +5670,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) { |
HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
- // Our implementation of arguments (based on this stack frame or an |
- // adapter below it) does not work for inlined functions. |
- if (function_state()->outer() != NULL) { |
- Bailout("Function.prototype.apply optimization in inlined function"); |
- return true; |
- } |
- |
// Found pattern f.apply(receiver, arguments). |
VisitForValue(prop->obj()); |
if (HasStackOverflow() || current_block() == NULL) return true; |
@@ -5662,13 +5680,61 @@ bool HGraphBuilder::TryCallApply(Call* expr) { |
VisitForValue(args->at(0)); |
if (HasStackOverflow() || current_block() == NULL) return true; |
HValue* receiver = Pop(); |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
- HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
- HInstruction* result = |
- new(zone()) HApplyArguments(function, receiver, length, elements); |
- result->set_position(expr->position()); |
- ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
+ |
+ if (function_state()->outer() == NULL) { |
+ HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
+ HInstruction* length = |
+ AddInstruction(new(zone()) HArgumentsLength(elements)); |
+ HValue* wrapped_receiver = receiver; |
+ if (!receiver->IsAllocateObject()) { |
+ wrapped_receiver = |
+ AddInstruction(new(zone()) HWrapReceiver(receiver, function)); |
+ } |
+ HInstruction* result = |
+ new(zone()) HApplyArguments(function, |
+ wrapped_receiver, |
+ length, |
+ elements); |
+ result->set_position(expr->position()); |
+ ast_context()->ReturnInstruction(result, expr->id()); |
+ return true; |
+ } else { |
+ // We are inside inlined function and we know exactly what is inside |
+ // arguments object. |
+ HValue* context = environment()->LookupContext(); |
+ |
+ HValue* wrapped_receiver = receiver; |
+ if (!receiver->IsAllocateObject()) { |
+ wrapped_receiver = |
+ AddInstruction(new(zone()) HWrapReceiver(receiver, function)); |
+ } |
+ PushAndAdd(new(zone()) HPushArgument(wrapped_receiver)); |
+ |
+ int parameter_count = environment()->parameter_count(); |
+ for (int i = 1; i < environment()->parameter_count(); i++) { |
+ PushAndAdd(new(zone()) HPushArgument(environment()->Lookup(i))); |
+ } |
+ |
+ if (environment()->outer()->frame_type() == ARGUMENTS_ADAPTOR) { |
+ HEnvironment* adaptor = environment()->outer(); |
+ parameter_count = adaptor->parameter_count(); |
+ |
+ for (int i = environment()->parameter_count(); |
+ i < adaptor->parameter_count(); |
+ i++) { |
+ PushAndAdd(new(zone()) HPushArgument(adaptor->Lookup(i))); |
+ } |
+ } |
+ |
+ HInvokeFunction* call = new(zone()) HInvokeFunction( |
+ context, |
+ function, |
+ parameter_count); |
+ Drop(parameter_count); |
+ call->set_position(expr->position()); |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+ return true; |
+ } |
} |