Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index 2b999cb768dd2239e69a527c3e50a2f423887992..d7a8027c08d9e4a73a0f945034b7401bda3b6cc4 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); |
| @@ -4992,31 +5000,70 @@ 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; |
| + // Push arguments when entering inlined function. |
| + if (!function_state()->arguments_pushed()) { |
|
Kevin Millikin (Chromium)
2012/04/11 11:49:18
I'd move this after all possible "return false", s
Vyacheslav Egorov (Chromium)
2012/04/11 12:47:28
Done.
|
| + HInstruction* insert_after = function_state()->entry(); |
| + ASSERT(insert_after->IsEnterInlined()); |
| + |
| + ZoneList<HValue*>* arguments_values = |
| + HEnterInlined::cast(insert_after)->arguments_values(); |
| + |
| + 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; |
| + } |
| + |
| + HInstruction* arguments_elements = new(zone()) HArgumentsElements(); |
| + arguments_elements->ClearFlag(HValue::kUseGVN); |
| + arguments_elements->InsertAfter(insert_after); |
| + function_state()->set_arguments_elements(arguments_elements); |
| + } |
| } |
| 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); |
| + 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); |
| + 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 { |
| + // 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 +5470,41 @@ 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)); |
| + } |
| + } |
| + |
| + HInstruction* enter_inlined = |
| + AddInstruction(new(zone()) HEnterInlined(target, |
| + arguments->length(), |
| + function, |
| + call_kind, |
| + function_state()->is_construct(), |
| + function->scope()->arguments(), |
| + arguments_values)); |
| + function_state()->set_entry(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 +5533,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 +5561,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; |