Index: src/hydrogen.cc |
=================================================================== |
--- src/hydrogen.cc (revision 9754) |
+++ src/hydrogen.cc (working copy) |
@@ -164,10 +164,11 @@ |
} |
-void HBasicBlock::Goto(HBasicBlock* block) { |
+void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
if (block->IsInlineReturnTarget()) { |
AddInstruction(new(zone()) HLeaveInlined); |
last_environment_ = last_environment()->outer(); |
+ if (drop_extra) last_environment_->Drop(1); |
} |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(block); |
@@ -175,11 +176,14 @@ |
} |
-void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
+void HBasicBlock::AddLeaveInlined(HValue* return_value, |
+ HBasicBlock* target, |
+ bool drop_extra) { |
ASSERT(target->IsInlineReturnTarget()); |
ASSERT(return_value != NULL); |
AddInstruction(new(zone()) HLeaveInlined); |
last_environment_ = last_environment()->outer(); |
+ if (drop_extra) last_environment_->Drop(1); |
last_environment()->Push(return_value); |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(target); |
@@ -541,7 +545,7 @@ |
HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
TypeFeedbackOracle* oracle) |
: function_state_(NULL), |
- initial_function_state_(this, info, oracle), |
+ initial_function_state_(this, info, oracle, false), |
ast_context_(NULL), |
break_scope_(NULL), |
graph_(NULL), |
@@ -2005,11 +2009,13 @@ |
// a (possibly inlined) function. |
FunctionState::FunctionState(HGraphBuilder* owner, |
CompilationInfo* info, |
- TypeFeedbackOracle* oracle) |
+ TypeFeedbackOracle* oracle, |
+ bool drop_extra) |
: owner_(owner), |
compilation_info_(info), |
oracle_(oracle), |
call_context_(NULL), |
+ drop_extra_(drop_extra), |
function_return_(NULL), |
test_context_(NULL), |
outer_(owner->function_state()) { |
@@ -2168,8 +2174,8 @@ |
instr->SetSuccessorAt(0, empty_true); |
instr->SetSuccessorAt(1, empty_false); |
owner()->current_block()->Finish(instr); |
- empty_true->Goto(if_true()); |
- empty_false->Goto(if_false()); |
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
owner()->set_current_block(NULL); |
} |
@@ -2190,8 +2196,8 @@ |
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
builder->current_block()->Finish(test); |
- empty_true->Goto(if_true()); |
- empty_false->Goto(if_false()); |
+ empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
+ empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
builder->set_current_block(NULL); |
} |
@@ -2652,12 +2658,14 @@ |
test->if_false()); |
} else if (context->IsEffect()) { |
CHECK_ALIVE(VisitForEffect(stmt->expression())); |
- current_block()->Goto(function_return()); |
+ current_block()->Goto(function_return(), function_state()->drop_extra()); |
} else { |
ASSERT(context->IsValue()); |
CHECK_ALIVE(VisitForValue(stmt->expression())); |
HValue* return_value = environment()->Pop(); |
- current_block()->AddLeaveInlined(return_value, function_return()); |
+ current_block()->AddLeaveInlined(return_value, |
+ function_return(), |
+ function_state()->drop_extra()); |
} |
set_current_block(NULL); |
} |
@@ -4546,7 +4554,7 @@ |
} |
-bool HGraphBuilder::TryInline(Call* expr) { |
+bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
if (!FLAG_use_inlining) return false; |
// The function call we are inlining is a method call if the call |
@@ -4574,9 +4582,9 @@ |
return false; |
} |
- CompilationInfo* outer_info = info(); |
#if !defined(V8_TARGET_ARCH_IA32) |
// Target must be able to use caller's context. |
+ CompilationInfo* outer_info = info(); |
if (target->context() != outer_info->closure()->context() || |
outer_info->scope()->contains_with() || |
outer_info->scope()->num_heap_slots() > 0) { |
@@ -4599,9 +4607,13 @@ |
} |
// Don't inline recursive functions. |
- if (*target_shared == outer_info->closure()->shared()) { |
- TraceInline(target, caller, "target is recursive"); |
- return false; |
+ for (FunctionState* state = function_state(); |
+ state != NULL; |
+ state = state->outer()) { |
+ if (state->compilation_info()->closure()->shared() == *target_shared) { |
+ TraceInline(target, caller, "target is recursive"); |
+ return false; |
+ } |
} |
// We don't want to add more than a certain number of nodes from inlining. |
@@ -4698,7 +4710,7 @@ |
Handle<Code>(target_shared->code()), |
Handle<Context>(target->context()->global_context()), |
isolate()); |
- FunctionState target_state(this, &target_info, &target_oracle); |
+ FunctionState target_state(this, &target_info, &target_oracle, drop_extra); |
HConstant* undefined = graph()->GetConstantUndefined(); |
HEnvironment* inner_env = |
@@ -4747,9 +4759,11 @@ |
ASSERT(function_return() != NULL); |
ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
if (call_context()->IsEffect()) { |
- current_block()->Goto(function_return()); |
+ current_block()->Goto(function_return(), drop_extra); |
} else { |
- current_block()->AddLeaveInlined(undefined, function_return()); |
+ current_block()->AddLeaveInlined(undefined, |
+ function_return(), |
+ drop_extra); |
} |
} else { |
// The graph builder assumes control can reach both branches of a |
@@ -4757,13 +4771,14 @@ |
// simply jumping to the false target. |
// |
// TODO(3168478): refactor to avoid this. |
+ ASSERT(call_context()->IsTest()); |
HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); |
current_block()->Finish(test); |
- empty_true->Goto(inlined_test_context()->if_true()); |
- empty_false->Goto(inlined_test_context()->if_false()); |
+ empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
+ empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
} |
} |
@@ -4780,12 +4795,12 @@ |
if (if_true->HasPredecessor()) { |
if_true->SetJoinId(expr->id()); |
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
- if_true->Goto(true_target); |
+ if_true->Goto(true_target, drop_extra); |
} |
if (if_false->HasPredecessor()) { |
if_false->SetJoinId(expr->id()); |
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
- if_false->Goto(false_target); |
+ if_false->Goto(false_target, drop_extra); |
} |
set_current_block(NULL); |
@@ -5102,26 +5117,7 @@ |
PushAndAdd(receiver); |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
- if (TryInline(expr)) { |
- // The function is lingering in the deoptimization environment. |
- // Handle it by case analysis on the AST context. |
- if (ast_context()->IsEffect()) { |
- Drop(1); |
- } else if (ast_context()->IsValue()) { |
- HValue* result = Pop(); |
- Drop(1); |
- Push(result); |
- } else if (ast_context()->IsTest()) { |
- TestContext* context = TestContext::cast(ast_context()); |
- if (context->if_true()->HasPredecessor()) { |
- context->if_true()->last_environment()->Drop(1); |
- } |
- if (context->if_false()->HasPredecessor()) { |
- context->if_true()->last_environment()->Drop(1); |
- } |
- } else { |
- UNREACHABLE(); |
- } |
+ if (TryInline(expr, true)) { // Drop function from environment. |
return; |
} else { |
call = PreProcessCall(new(zone()) HInvokeFunction(context, |
@@ -5337,7 +5333,6 @@ |
void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
- // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. |
if (ast_context()->IsTest()) { |
TestContext* context = TestContext::cast(ast_context()); |
VisitForControl(expr->expression(), |