Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 2b999cb768dd2239e69a527c3e50a2f423887992..4e8c1e6a04955e21f0c75586616ecacdc904c6d7 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -113,7 +113,6 @@ void HBasicBlock::AddInstruction(HInstruction* instr) { |
first_ = last_ = entry; |
} |
instr->InsertAfter(last_); |
- last_ = instr; |
} |
@@ -165,11 +164,15 @@ void HBasicBlock::Finish(HControlInstruction* end) { |
} |
-void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
+void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { |
+ bool drop_extra = state != NULL && state->drop_extra(); |
+ bool arguments_pushed = state != NULL && state->arguments_pushed(); |
+ |
if (block->IsInlineReturnTarget()) { |
- AddInstruction(new(zone()) HLeaveInlined); |
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
last_environment_ = last_environment()->DiscardInlined(drop_extra); |
} |
+ |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(block); |
Finish(instr); |
@@ -178,10 +181,13 @@ void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
void HBasicBlock::AddLeaveInlined(HValue* return_value, |
HBasicBlock* target, |
- bool drop_extra) { |
+ FunctionState* state) { |
+ bool drop_extra = state != NULL && state->drop_extra(); |
+ bool arguments_pushed = state != NULL && state->arguments_pushed(); |
+ |
ASSERT(target->IsInlineReturnTarget()); |
ASSERT(return_value != NULL); |
- AddInstruction(new(zone()) HLeaveInlined); |
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); |
last_environment_ = last_environment()->DiscardInlined(drop_extra); |
last_environment()->Push(return_value); |
AddSimulate(AstNode::kNoNumber); |
@@ -2178,6 +2184,8 @@ FunctionState::FunctionState(HGraphBuilder* owner, |
return_handling_(return_handling), |
function_return_(NULL), |
test_context_(NULL), |
+ entry_(NULL), |
+ arguments_elements_(NULL), |
outer_(owner->function_state()) { |
if (outer_ != NULL) { |
// State for an inline function. |
@@ -2337,8 +2345,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
instr->SetSuccessorAt(0, empty_true); |
instr->SetSuccessorAt(1, empty_false); |
owner()->current_block()->Finish(instr); |
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
+ empty_true->Goto(if_true(), owner()->function_state()); |
+ empty_false->Goto(if_false(), owner()->function_state()); |
owner()->set_current_block(NULL); |
} |
@@ -2359,8 +2367,8 @@ void TestContext::BuildBranch(HValue* value) { |
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
builder->current_block()->Finish(test); |
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
+ empty_true->Goto(if_true(), owner()->function_state()); |
+ empty_false->Goto(if_false(), owner()->function_state()); |
builder->set_current_block(NULL); |
} |
@@ -2855,10 +2863,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
if (context->IsTest()) { |
TestContext* test = TestContext::cast(context); |
CHECK_ALIVE(VisitForEffect(stmt->expression())); |
- current_block()->Goto(test->if_true(), function_state()->drop_extra()); |
+ current_block()->Goto(test->if_true(), function_state()); |
} else if (context->IsEffect()) { |
CHECK_ALIVE(VisitForEffect(stmt->expression())); |
- current_block()->Goto(function_return(), function_state()->drop_extra()); |
+ current_block()->Goto(function_return(), function_state()); |
} else { |
ASSERT(context->IsValue()); |
CHECK_ALIVE(VisitForValue(stmt->expression())); |
@@ -2875,10 +2883,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
current_block()->Finish(typecheck); |
if_spec_object->AddLeaveInlined(return_value, |
function_return(), |
- function_state()->drop_extra()); |
+ function_state()); |
not_spec_object->AddLeaveInlined(receiver, |
function_return(), |
- function_state()->drop_extra()); |
+ function_state()); |
} |
} else { |
// Return from an inlined function, visit the subexpression in the |
@@ -2890,14 +2898,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
test->if_false()); |
} else if (context->IsEffect()) { |
CHECK_ALIVE(VisitForEffect(stmt->expression())); |
- current_block()->Goto(function_return(), function_state()->drop_extra()); |
+ current_block()->Goto(function_return(), function_state()); |
} else { |
ASSERT(context->IsValue()); |
CHECK_ALIVE(VisitForValue(stmt->expression())); |
HValue* return_value = Pop(); |
current_block()->AddLeaveInlined(return_value, |
function_return(), |
- function_state()->drop_extra()); |
+ function_state()); |
} |
} |
set_current_block(NULL); |
@@ -4984,6 +4992,34 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
function_strict_mode_flag()); |
} |
+ |
+void HGraphBuilder::EnsureArgumentsArePushedForAccess() { |
+ // Outermost function already has arguments on the stack. |
+ if (function_state()->outer() == NULL) return; |
+ |
+ if (function_state()->arguments_pushed()) return; |
+ |
+ // Push arguments when entering inlined function. |
+ HEnterInlined* entry = function_state()->entry(); |
+ |
+ ZoneList<HValue*>* arguments_values = entry->arguments_values(); |
+ |
+ HInstruction* insert_after = entry; |
+ for (int i = 0; i < arguments_values->length(); i++) { |
+ HValue* argument = arguments_values->at(i); |
+ HInstruction* push_argument = new(zone()) HPushArgument(argument); |
+ push_argument->InsertAfter(insert_after); |
+ insert_after = push_argument; |
+ } |
+ |
+ HArgumentsElements* arguments_elements = |
+ new(zone()) HArgumentsElements(true); |
+ arguments_elements->ClearFlag(HValue::kUseGVN); |
+ arguments_elements->InsertAfter(insert_after); |
+ function_state()->set_arguments_elements(arguments_elements); |
+} |
+ |
+ |
bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
if (proxy == NULL) return false; |
@@ -4992,31 +5028,51 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
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("arguments access in inlined function"); |
- return true; |
- } |
- |
HInstruction* result = NULL; |
if (expr->key()->IsPropertyName()) { |
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
if (!name->IsEqualTo(CStrVector("length"))) return false; |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
- result = new(zone()) HArgumentsLength(elements); |
+ |
+ if (function_state()->outer() == NULL) { |
+ HInstruction* elements = AddInstruction( |
+ new(zone()) HArgumentsElements(false)); |
+ result = new(zone()) HArgumentsLength(elements); |
+ } else { |
+ // Number of arguments without receiver. |
+ int argument_count = environment()-> |
+ arguments_environment()->parameter_count() - 1; |
+ result = new(zone()) HConstant( |
+ Handle<Object>(Smi::FromInt(argument_count)), |
+ Representation::Integer32()); |
+ } |
} else { |
Push(graph()->GetArgumentsObject()); |
VisitForValue(expr->key()); |
if (HasStackOverflow() || current_block() == NULL) return true; |
HValue* key = Pop(); |
Drop(1); // Arguments object. |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
- HInstruction* length = AddInstruction( |
- new(zone()) HArgumentsLength(elements)); |
- HInstruction* checked_key = |
- AddInstruction(new(zone()) HBoundsCheck(key, length)); |
- result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
+ if (function_state()->outer() == NULL) { |
+ HInstruction* elements = AddInstruction( |
+ new(zone()) HArgumentsElements(false)); |
+ HInstruction* length = AddInstruction( |
+ new(zone()) HArgumentsLength(elements)); |
+ HInstruction* checked_key = |
+ AddInstruction(new(zone()) HBoundsCheck(key, length)); |
+ result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
+ } else { |
+ EnsureArgumentsArePushedForAccess(); |
+ |
+ // Number of arguments without receiver. |
+ HInstruction* elements = function_state()->arguments_elements(); |
+ int argument_count = environment()-> |
+ arguments_environment()->parameter_count() - 1; |
+ HInstruction* length = AddInstruction(new(zone()) HConstant( |
+ Handle<Object>(Smi::FromInt(argument_count)), |
+ Representation::Integer32())); |
+ HInstruction* checked_key = |
+ AddInstruction(new(zone()) HBoundsCheck(key, length)); |
+ result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
+ } |
} |
ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
@@ -5423,20 +5479,42 @@ bool HGraphBuilder::TryInline(CallKind call_kind, |
AddInstruction(context); |
inner_env->BindContext(context); |
#endif |
+ |
AddSimulate(return_id); |
current_block()->UpdateEnvironment(inner_env); |
- AddInstruction(new(zone()) HEnterInlined(target, |
- arguments->length(), |
- function, |
- call_kind, |
- function_state()->is_construct(), |
- function->scope()->arguments())); |
+ |
+ ZoneList<HValue*>* arguments_values = NULL; |
+ |
+ // If the function uses arguments copy current arguments values |
+ // to use them for materialization. |
+ if (function->scope()->arguments() != NULL) { |
+ HEnvironment* arguments_env = inner_env->arguments_environment(); |
+ int arguments_count = arguments_env->parameter_count(); |
+ arguments_values = new(zone()) ZoneList<HValue*>(arguments_count); |
+ for (int i = 0; i < arguments_count; i++) { |
+ arguments_values->Add(arguments_env->Lookup(i)); |
+ } |
+ } |
+ |
+ HEnterInlined* enter_inlined = |
+ new(zone()) HEnterInlined(target, |
+ arguments->length(), |
+ function, |
+ call_kind, |
+ function_state()->is_construct(), |
+ function->scope()->arguments(), |
+ arguments_values); |
+ function_state()->set_entry(enter_inlined); |
+ AddInstruction(enter_inlined); |
+ |
// If the function uses arguments object create and bind one. |
if (function->scope()->arguments() != NULL) { |
ASSERT(function->scope()->arguments()->IsStackAllocated()); |
- environment()->Bind(function->scope()->arguments(), |
- graph()->GetArgumentsObject()); |
+ inner_env->Bind(function->scope()->arguments(), |
+ graph()->GetArgumentsObject()); |
} |
+ |
+ |
VisitDeclarations(target_info.scope()->declarations()); |
VisitStatements(function->body()); |
if (HasStackOverflow()) { |
@@ -5465,17 +5543,17 @@ bool HGraphBuilder::TryInline(CallKind call_kind, |
: undefined; |
current_block()->AddLeaveInlined(return_value, |
function_return(), |
- function_state()->drop_extra()); |
+ function_state()); |
} else if (call_context()->IsEffect()) { |
ASSERT(function_return() != NULL); |
- current_block()->Goto(function_return(), function_state()->drop_extra()); |
+ current_block()->Goto(function_return(), function_state()); |
} else { |
ASSERT(call_context()->IsTest()); |
ASSERT(inlined_test_context() != NULL); |
HBasicBlock* target = function_state()->is_construct() |
? inlined_test_context()->if_true() |
: inlined_test_context()->if_false(); |
- current_block()->Goto(target, function_state()->drop_extra()); |
+ current_block()->Goto(target, function_state()); |
} |
} |
@@ -5493,12 +5571,12 @@ bool HGraphBuilder::TryInline(CallKind call_kind, |
if (if_true->HasPredecessor()) { |
if_true->SetJoinId(ast_id); |
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
- if_true->Goto(true_target, function_state()->drop_extra()); |
+ if_true->Goto(true_target, function_state()); |
} |
if (if_false->HasPredecessor()) { |
if_false->SetJoinId(ast_id); |
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
- if_false->Goto(false_target, function_state()->drop_extra()); |
+ if_false->Goto(false_target, function_state()); |
} |
set_current_block(NULL); |
return true; |
@@ -5807,7 +5885,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) { |
HValue* receiver = Pop(); |
if (function_state()->outer() == NULL) { |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
+ HInstruction* elements = AddInstruction( |
+ new(zone()) HArgumentsElements(false)); |
HInstruction* length = |
AddInstruction(new(zone()) HArgumentsLength(elements)); |
HValue* wrapped_receiver = |
@@ -7277,7 +7356,8 @@ void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { |
// function is blacklisted by AstNode::IsInlineable. |
ASSERT(function_state()->outer() == NULL); |
ASSERT(call->arguments()->length() == 0); |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
+ HInstruction* elements = AddInstruction( |
+ new(zone()) HArgumentsElements(false)); |
HArgumentsLength* result = new(zone()) HArgumentsLength(elements); |
return ast_context()->ReturnInstruction(result, call->id()); |
} |
@@ -7291,7 +7371,8 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) { |
ASSERT(call->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
HValue* index = Pop(); |
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); |
+ HInstruction* elements = AddInstruction( |
+ new(zone()) HArgumentsElements(false)); |
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); |
HAccessArgumentsAt* result = |
new(zone()) HAccessArgumentsAt(elements, length, index); |