OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 void HBasicBlock::Finish(HControlInstruction* end) { | 157 void HBasicBlock::Finish(HControlInstruction* end) { |
158 ASSERT(!IsFinished()); | 158 ASSERT(!IsFinished()); |
159 AddInstruction(end); | 159 AddInstruction(end); |
160 end_ = end; | 160 end_ = end; |
161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
162 it.Current()->RegisterPredecessor(this); | 162 it.Current()->RegisterPredecessor(this); |
163 } | 163 } |
164 } | 164 } |
165 | 165 |
166 | 166 |
167 void HBasicBlock::Goto(HBasicBlock* block) { | 167 void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
168 if (block->IsInlineReturnTarget()) { | 168 if (block->IsInlineReturnTarget()) { |
169 AddInstruction(new(zone()) HLeaveInlined); | 169 AddInstruction(new(zone()) HLeaveInlined); |
170 last_environment_ = last_environment()->outer(); | 170 last_environment_ = last_environment()->outer(); |
| 171 if (drop_extra) last_environment_->Drop(1); |
171 } | 172 } |
172 AddSimulate(AstNode::kNoNumber); | 173 AddSimulate(AstNode::kNoNumber); |
173 HGoto* instr = new(zone()) HGoto(block); | 174 HGoto* instr = new(zone()) HGoto(block); |
174 Finish(instr); | 175 Finish(instr); |
175 } | 176 } |
176 | 177 |
177 | 178 |
178 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 179 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 180 HBasicBlock* target, |
| 181 bool drop_extra) { |
179 ASSERT(target->IsInlineReturnTarget()); | 182 ASSERT(target->IsInlineReturnTarget()); |
180 ASSERT(return_value != NULL); | 183 ASSERT(return_value != NULL); |
181 AddInstruction(new(zone()) HLeaveInlined); | 184 AddInstruction(new(zone()) HLeaveInlined); |
182 last_environment_ = last_environment()->outer(); | 185 last_environment_ = last_environment()->outer(); |
| 186 if (drop_extra) last_environment_->Drop(1); |
183 last_environment()->Push(return_value); | 187 last_environment()->Push(return_value); |
184 AddSimulate(AstNode::kNoNumber); | 188 AddSimulate(AstNode::kNoNumber); |
185 HGoto* instr = new(zone()) HGoto(target); | 189 HGoto* instr = new(zone()) HGoto(target); |
186 Finish(instr); | 190 Finish(instr); |
187 } | 191 } |
188 | 192 |
189 | 193 |
190 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 194 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
191 ASSERT(!HasEnvironment()); | 195 ASSERT(!HasEnvironment()); |
192 ASSERT(first() == NULL); | 196 ASSERT(first() == NULL); |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 | 538 |
535 | 539 |
536 HConstant* HGraph::GetConstantHole() { | 540 HConstant* HGraph::GetConstantHole() { |
537 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); | 541 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); |
538 } | 542 } |
539 | 543 |
540 | 544 |
541 HGraphBuilder::HGraphBuilder(CompilationInfo* info, | 545 HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
542 TypeFeedbackOracle* oracle) | 546 TypeFeedbackOracle* oracle) |
543 : function_state_(NULL), | 547 : function_state_(NULL), |
544 initial_function_state_(this, info, oracle), | 548 initial_function_state_(this, info, oracle, false), |
545 ast_context_(NULL), | 549 ast_context_(NULL), |
546 break_scope_(NULL), | 550 break_scope_(NULL), |
547 graph_(NULL), | 551 graph_(NULL), |
548 current_block_(NULL), | 552 current_block_(NULL), |
549 inlined_count_(0), | 553 inlined_count_(0), |
550 zone_(info->isolate()->zone()), | 554 zone_(info->isolate()->zone()), |
551 inline_bailout_(false) { | 555 inline_bailout_(false) { |
552 // This is not initialized in the initializer list because the | 556 // This is not initialized in the initializer list because the |
553 // constructor for the initial state relies on function_state_ == NULL | 557 // constructor for the initial state relies on function_state_ == NULL |
554 // to know it's the initial state. | 558 // to know it's the initial state. |
(...skipping 1443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1998 } | 2002 } |
1999 } | 2003 } |
2000 } | 2004 } |
2001 } | 2005 } |
2002 | 2006 |
2003 | 2007 |
2004 // Implementation of utility class to encapsulate the translation state for | 2008 // Implementation of utility class to encapsulate the translation state for |
2005 // a (possibly inlined) function. | 2009 // a (possibly inlined) function. |
2006 FunctionState::FunctionState(HGraphBuilder* owner, | 2010 FunctionState::FunctionState(HGraphBuilder* owner, |
2007 CompilationInfo* info, | 2011 CompilationInfo* info, |
2008 TypeFeedbackOracle* oracle) | 2012 TypeFeedbackOracle* oracle, |
| 2013 bool drop_extra) |
2009 : owner_(owner), | 2014 : owner_(owner), |
2010 compilation_info_(info), | 2015 compilation_info_(info), |
2011 oracle_(oracle), | 2016 oracle_(oracle), |
2012 call_context_(NULL), | 2017 call_context_(NULL), |
| 2018 drop_extra_(drop_extra), |
2013 function_return_(NULL), | 2019 function_return_(NULL), |
2014 test_context_(NULL), | 2020 test_context_(NULL), |
2015 outer_(owner->function_state()) { | 2021 outer_(owner->function_state()) { |
2016 if (outer_ != NULL) { | 2022 if (outer_ != NULL) { |
2017 // State for an inline function. | 2023 // State for an inline function. |
2018 if (owner->ast_context()->IsTest()) { | 2024 if (owner->ast_context()->IsTest()) { |
2019 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2025 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
2020 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2026 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
2021 if_true->MarkAsInlineReturnTarget(); | 2027 if_true->MarkAsInlineReturnTarget(); |
2022 if_false->MarkAsInlineReturnTarget(); | 2028 if_false->MarkAsInlineReturnTarget(); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2161 } | 2167 } |
2162 | 2168 |
2163 | 2169 |
2164 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { | 2170 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
2165 ASSERT(!instr->HasSideEffects()); | 2171 ASSERT(!instr->HasSideEffects()); |
2166 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); | 2172 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); |
2167 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); | 2173 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); |
2168 instr->SetSuccessorAt(0, empty_true); | 2174 instr->SetSuccessorAt(0, empty_true); |
2169 instr->SetSuccessorAt(1, empty_false); | 2175 instr->SetSuccessorAt(1, empty_false); |
2170 owner()->current_block()->Finish(instr); | 2176 owner()->current_block()->Finish(instr); |
2171 empty_true->Goto(if_true()); | 2177 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
2172 empty_false->Goto(if_false()); | 2178 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
2173 owner()->set_current_block(NULL); | 2179 owner()->set_current_block(NULL); |
2174 } | 2180 } |
2175 | 2181 |
2176 | 2182 |
2177 void TestContext::BuildBranch(HValue* value) { | 2183 void TestContext::BuildBranch(HValue* value) { |
2178 // We expect the graph to be in edge-split form: there is no edge that | 2184 // We expect the graph to be in edge-split form: there is no edge that |
2179 // connects a branch node to a join node. We conservatively ensure that | 2185 // connects a branch node to a join node. We conservatively ensure that |
2180 // property by always adding an empty block on the outgoing edges of this | 2186 // property by always adding an empty block on the outgoing edges of this |
2181 // branch. | 2187 // branch. |
2182 HGraphBuilder* builder = owner(); | 2188 HGraphBuilder* builder = owner(); |
2183 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { | 2189 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
2184 builder->Bailout("arguments object value in a test context"); | 2190 builder->Bailout("arguments object value in a test context"); |
2185 } | 2191 } |
2186 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2192 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
2187 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2193 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
2188 unsigned test_id = condition()->test_id(); | 2194 unsigned test_id = condition()->test_id(); |
2189 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); | 2195 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); |
2190 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); | 2196 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
2191 builder->current_block()->Finish(test); | 2197 builder->current_block()->Finish(test); |
2192 | 2198 |
2193 empty_true->Goto(if_true()); | 2199 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
2194 empty_false->Goto(if_false()); | 2200 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
2195 builder->set_current_block(NULL); | 2201 builder->set_current_block(NULL); |
2196 } | 2202 } |
2197 | 2203 |
2198 | 2204 |
2199 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2205 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
2200 #define CHECK_BAILOUT(call) \ | 2206 #define CHECK_BAILOUT(call) \ |
2201 do { \ | 2207 do { \ |
2202 call; \ | 2208 call; \ |
2203 if (HasStackOverflow()) return; \ | 2209 if (HasStackOverflow()) return; \ |
2204 } while (false) | 2210 } while (false) |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2645 } else { | 2651 } else { |
2646 // Return from an inlined function, visit the subexpression in the | 2652 // Return from an inlined function, visit the subexpression in the |
2647 // expression context of the call. | 2653 // expression context of the call. |
2648 if (context->IsTest()) { | 2654 if (context->IsTest()) { |
2649 TestContext* test = TestContext::cast(context); | 2655 TestContext* test = TestContext::cast(context); |
2650 VisitForControl(stmt->expression(), | 2656 VisitForControl(stmt->expression(), |
2651 test->if_true(), | 2657 test->if_true(), |
2652 test->if_false()); | 2658 test->if_false()); |
2653 } else if (context->IsEffect()) { | 2659 } else if (context->IsEffect()) { |
2654 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2660 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2655 current_block()->Goto(function_return()); | 2661 current_block()->Goto(function_return(), function_state()->drop_extra()); |
2656 } else { | 2662 } else { |
2657 ASSERT(context->IsValue()); | 2663 ASSERT(context->IsValue()); |
2658 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2664 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2659 HValue* return_value = environment()->Pop(); | 2665 HValue* return_value = environment()->Pop(); |
2660 current_block()->AddLeaveInlined(return_value, function_return()); | 2666 current_block()->AddLeaveInlined(return_value, |
| 2667 function_return(), |
| 2668 function_state()->drop_extra()); |
2661 } | 2669 } |
2662 set_current_block(NULL); | 2670 set_current_block(NULL); |
2663 } | 2671 } |
2664 } | 2672 } |
2665 | 2673 |
2666 | 2674 |
2667 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2675 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
2668 ASSERT(!HasStackOverflow()); | 2676 ASSERT(!HasStackOverflow()); |
2669 ASSERT(current_block() != NULL); | 2677 ASSERT(current_block() != NULL); |
2670 ASSERT(current_block()->HasPredecessor()); | 2678 ASSERT(current_block()->HasPredecessor()); |
(...skipping 1868 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4539 if (reason == NULL) { | 4547 if (reason == NULL) { |
4540 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 4548 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
4541 } else { | 4549 } else { |
4542 PrintF("Did not inline %s called from %s (%s).\n", | 4550 PrintF("Did not inline %s called from %s (%s).\n", |
4543 *target_name, *caller_name, reason); | 4551 *target_name, *caller_name, reason); |
4544 } | 4552 } |
4545 } | 4553 } |
4546 } | 4554 } |
4547 | 4555 |
4548 | 4556 |
4549 bool HGraphBuilder::TryInline(Call* expr) { | 4557 bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
4550 if (!FLAG_use_inlining) return false; | 4558 if (!FLAG_use_inlining) return false; |
4551 | 4559 |
4552 // The function call we are inlining is a method call if the call | 4560 // The function call we are inlining is a method call if the call |
4553 // is a property call. | 4561 // is a property call. |
4554 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | 4562 CallKind call_kind = (expr->expression()->AsProperty() == NULL) |
4555 ? CALL_AS_FUNCTION | 4563 ? CALL_AS_FUNCTION |
4556 : CALL_AS_METHOD; | 4564 : CALL_AS_METHOD; |
4557 | 4565 |
4558 // Precondition: call is monomorphic and we have found a target with the | 4566 // Precondition: call is monomorphic and we have found a target with the |
4559 // appropriate arity. | 4567 // appropriate arity. |
4560 Handle<JSFunction> caller = info()->closure(); | 4568 Handle<JSFunction> caller = info()->closure(); |
4561 Handle<JSFunction> target = expr->target(); | 4569 Handle<JSFunction> target = expr->target(); |
4562 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4570 Handle<SharedFunctionInfo> target_shared(target->shared()); |
4563 | 4571 |
4564 // Do a quick check on source code length to avoid parsing large | 4572 // Do a quick check on source code length to avoid parsing large |
4565 // inlining candidates. | 4573 // inlining candidates. |
4566 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 4574 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
4567 TraceInline(target, caller, "target text too big"); | 4575 TraceInline(target, caller, "target text too big"); |
4568 return false; | 4576 return false; |
4569 } | 4577 } |
4570 | 4578 |
4571 // Target must be inlineable. | 4579 // Target must be inlineable. |
4572 if (!target->IsInlineable()) { | 4580 if (!target->IsInlineable()) { |
4573 TraceInline(target, caller, "target not inlineable"); | 4581 TraceInline(target, caller, "target not inlineable"); |
4574 return false; | 4582 return false; |
4575 } | 4583 } |
4576 | 4584 |
4577 CompilationInfo* outer_info = info(); | |
4578 #if !defined(V8_TARGET_ARCH_IA32) | 4585 #if !defined(V8_TARGET_ARCH_IA32) |
4579 // Target must be able to use caller's context. | 4586 // Target must be able to use caller's context. |
| 4587 CompilationInfo* outer_info = info(); |
4580 if (target->context() != outer_info->closure()->context() || | 4588 if (target->context() != outer_info->closure()->context() || |
4581 outer_info->scope()->contains_with() || | 4589 outer_info->scope()->contains_with() || |
4582 outer_info->scope()->num_heap_slots() > 0) { | 4590 outer_info->scope()->num_heap_slots() > 0) { |
4583 TraceInline(target, caller, "target requires context change"); | 4591 TraceInline(target, caller, "target requires context change"); |
4584 return false; | 4592 return false; |
4585 } | 4593 } |
4586 #endif | 4594 #endif |
4587 | 4595 |
4588 | 4596 |
4589 // Don't inline deeper than kMaxInliningLevels calls. | 4597 // Don't inline deeper than kMaxInliningLevels calls. |
4590 HEnvironment* env = environment(); | 4598 HEnvironment* env = environment(); |
4591 int current_level = 1; | 4599 int current_level = 1; |
4592 while (env->outer() != NULL) { | 4600 while (env->outer() != NULL) { |
4593 if (current_level == Compiler::kMaxInliningLevels) { | 4601 if (current_level == Compiler::kMaxInliningLevels) { |
4594 TraceInline(target, caller, "inline depth limit reached"); | 4602 TraceInline(target, caller, "inline depth limit reached"); |
4595 return false; | 4603 return false; |
4596 } | 4604 } |
4597 current_level++; | 4605 current_level++; |
4598 env = env->outer(); | 4606 env = env->outer(); |
4599 } | 4607 } |
4600 | 4608 |
4601 // Don't inline recursive functions. | 4609 // Don't inline recursive functions. |
4602 if (*target_shared == outer_info->closure()->shared()) { | 4610 for (FunctionState* state = function_state(); |
4603 TraceInline(target, caller, "target is recursive"); | 4611 state != NULL; |
4604 return false; | 4612 state = state->outer()) { |
| 4613 if (state->compilation_info()->closure()->shared() == *target_shared) { |
| 4614 TraceInline(target, caller, "target is recursive"); |
| 4615 return false; |
| 4616 } |
4605 } | 4617 } |
4606 | 4618 |
4607 // We don't want to add more than a certain number of nodes from inlining. | 4619 // We don't want to add more than a certain number of nodes from inlining. |
4608 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 4620 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
4609 TraceInline(target, caller, "cumulative AST node limit reached"); | 4621 TraceInline(target, caller, "cumulative AST node limit reached"); |
4610 return false; | 4622 return false; |
4611 } | 4623 } |
4612 | 4624 |
4613 int count_before = AstNode::Count(); | 4625 int count_before = AstNode::Count(); |
4614 | 4626 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4691 // After this point, we've made a decision to inline this function (so | 4703 // After this point, we've made a decision to inline this function (so |
4692 // TryInline should always return true). | 4704 // TryInline should always return true). |
4693 | 4705 |
4694 // Save the pending call context and type feedback oracle. Set up new ones | 4706 // Save the pending call context and type feedback oracle. Set up new ones |
4695 // for the inlined function. | 4707 // for the inlined function. |
4696 ASSERT(target_shared->has_deoptimization_support()); | 4708 ASSERT(target_shared->has_deoptimization_support()); |
4697 TypeFeedbackOracle target_oracle( | 4709 TypeFeedbackOracle target_oracle( |
4698 Handle<Code>(target_shared->code()), | 4710 Handle<Code>(target_shared->code()), |
4699 Handle<Context>(target->context()->global_context()), | 4711 Handle<Context>(target->context()->global_context()), |
4700 isolate()); | 4712 isolate()); |
4701 FunctionState target_state(this, &target_info, &target_oracle); | 4713 FunctionState target_state(this, &target_info, &target_oracle, drop_extra); |
4702 | 4714 |
4703 HConstant* undefined = graph()->GetConstantUndefined(); | 4715 HConstant* undefined = graph()->GetConstantUndefined(); |
4704 HEnvironment* inner_env = | 4716 HEnvironment* inner_env = |
4705 environment()->CopyForInlining(target, | 4717 environment()->CopyForInlining(target, |
4706 function, | 4718 function, |
4707 undefined, | 4719 undefined, |
4708 call_kind); | 4720 call_kind); |
4709 #ifdef V8_TARGET_ARCH_IA32 | 4721 #ifdef V8_TARGET_ARCH_IA32 |
4710 // IA32 only, overwrite the caller's context in the deoptimization | 4722 // IA32 only, overwrite the caller's context in the deoptimization |
4711 // environment with the correct one. | 4723 // environment with the correct one. |
(...skipping 28 matching lines...) Expand all Loading... |
4740 | 4752 |
4741 TraceInline(target, caller, NULL); | 4753 TraceInline(target, caller, NULL); |
4742 | 4754 |
4743 if (current_block() != NULL) { | 4755 if (current_block() != NULL) { |
4744 // Add a return of undefined if control can fall off the body. In a | 4756 // Add a return of undefined if control can fall off the body. In a |
4745 // test context, undefined is false. | 4757 // test context, undefined is false. |
4746 if (inlined_test_context() == NULL) { | 4758 if (inlined_test_context() == NULL) { |
4747 ASSERT(function_return() != NULL); | 4759 ASSERT(function_return() != NULL); |
4748 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 4760 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
4749 if (call_context()->IsEffect()) { | 4761 if (call_context()->IsEffect()) { |
4750 current_block()->Goto(function_return()); | 4762 current_block()->Goto(function_return(), drop_extra); |
4751 } else { | 4763 } else { |
4752 current_block()->AddLeaveInlined(undefined, function_return()); | 4764 current_block()->AddLeaveInlined(undefined, |
| 4765 function_return(), |
| 4766 drop_extra); |
4753 } | 4767 } |
4754 } else { | 4768 } else { |
4755 // The graph builder assumes control can reach both branches of a | 4769 // The graph builder assumes control can reach both branches of a |
4756 // test, so we materialize the undefined value and test it rather than | 4770 // test, so we materialize the undefined value and test it rather than |
4757 // simply jumping to the false target. | 4771 // simply jumping to the false target. |
4758 // | 4772 // |
4759 // TODO(3168478): refactor to avoid this. | 4773 // TODO(3168478): refactor to avoid this. |
| 4774 ASSERT(call_context()->IsTest()); |
4760 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4775 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
4761 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4776 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
4762 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); | 4777 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); |
4763 current_block()->Finish(test); | 4778 current_block()->Finish(test); |
4764 | 4779 |
4765 empty_true->Goto(inlined_test_context()->if_true()); | 4780 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
4766 empty_false->Goto(inlined_test_context()->if_false()); | 4781 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
4767 } | 4782 } |
4768 } | 4783 } |
4769 | 4784 |
4770 // Fix up the function exits. | 4785 // Fix up the function exits. |
4771 if (inlined_test_context() != NULL) { | 4786 if (inlined_test_context() != NULL) { |
4772 HBasicBlock* if_true = inlined_test_context()->if_true(); | 4787 HBasicBlock* if_true = inlined_test_context()->if_true(); |
4773 HBasicBlock* if_false = inlined_test_context()->if_false(); | 4788 HBasicBlock* if_false = inlined_test_context()->if_false(); |
4774 | 4789 |
4775 // Pop the return test context from the expression context stack. | 4790 // Pop the return test context from the expression context stack. |
4776 ASSERT(ast_context() == inlined_test_context()); | 4791 ASSERT(ast_context() == inlined_test_context()); |
4777 ClearInlinedTestContext(); | 4792 ClearInlinedTestContext(); |
4778 | 4793 |
4779 // Forward to the real test context. | 4794 // Forward to the real test context. |
4780 if (if_true->HasPredecessor()) { | 4795 if (if_true->HasPredecessor()) { |
4781 if_true->SetJoinId(expr->id()); | 4796 if_true->SetJoinId(expr->id()); |
4782 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4797 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
4783 if_true->Goto(true_target); | 4798 if_true->Goto(true_target, drop_extra); |
4784 } | 4799 } |
4785 if (if_false->HasPredecessor()) { | 4800 if (if_false->HasPredecessor()) { |
4786 if_false->SetJoinId(expr->id()); | 4801 if_false->SetJoinId(expr->id()); |
4787 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4802 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
4788 if_false->Goto(false_target); | 4803 if_false->Goto(false_target, drop_extra); |
4789 } | 4804 } |
4790 set_current_block(NULL); | 4805 set_current_block(NULL); |
4791 | 4806 |
4792 } else if (function_return()->HasPredecessor()) { | 4807 } else if (function_return()->HasPredecessor()) { |
4793 function_return()->SetJoinId(expr->id()); | 4808 function_return()->SetJoinId(expr->id()); |
4794 set_current_block(function_return()); | 4809 set_current_block(function_return()); |
4795 } else { | 4810 } else { |
4796 set_current_block(NULL); | 4811 set_current_block(NULL); |
4797 } | 4812 } |
4798 | 4813 |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5095 // evaluation of the arguments. | 5110 // evaluation of the arguments. |
5096 CHECK_ALIVE(VisitForValue(expr->expression())); | 5111 CHECK_ALIVE(VisitForValue(expr->expression())); |
5097 HValue* function = Top(); | 5112 HValue* function = Top(); |
5098 HValue* context = environment()->LookupContext(); | 5113 HValue* context = environment()->LookupContext(); |
5099 HGlobalObject* global = new(zone()) HGlobalObject(context); | 5114 HGlobalObject* global = new(zone()) HGlobalObject(context); |
5100 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); | 5115 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
5101 AddInstruction(global); | 5116 AddInstruction(global); |
5102 PushAndAdd(receiver); | 5117 PushAndAdd(receiver); |
5103 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 5118 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
5104 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 5119 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
5105 if (TryInline(expr)) { | 5120 if (TryInline(expr, true)) { // Drop function from environment. |
5106 // The function is lingering in the deoptimization environment. | |
5107 // Handle it by case analysis on the AST context. | |
5108 if (ast_context()->IsEffect()) { | |
5109 Drop(1); | |
5110 } else if (ast_context()->IsValue()) { | |
5111 HValue* result = Pop(); | |
5112 Drop(1); | |
5113 Push(result); | |
5114 } else if (ast_context()->IsTest()) { | |
5115 TestContext* context = TestContext::cast(ast_context()); | |
5116 if (context->if_true()->HasPredecessor()) { | |
5117 context->if_true()->last_environment()->Drop(1); | |
5118 } | |
5119 if (context->if_false()->HasPredecessor()) { | |
5120 context->if_true()->last_environment()->Drop(1); | |
5121 } | |
5122 } else { | |
5123 UNREACHABLE(); | |
5124 } | |
5125 return; | 5121 return; |
5126 } else { | 5122 } else { |
5127 call = PreProcessCall(new(zone()) HInvokeFunction(context, | 5123 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
5128 function, | 5124 function, |
5129 argument_count)); | 5125 argument_count)); |
5130 Drop(1); // The function. | 5126 Drop(1); // The function. |
5131 } | 5127 } |
5132 | 5128 |
5133 } else { | 5129 } else { |
5134 CHECK_ALIVE(VisitArgument(expr->expression())); | 5130 CHECK_ALIVE(VisitArgument(expr->expression())); |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5330 if (info.IsUninitialized()) { | 5326 if (info.IsUninitialized()) { |
5331 AddInstruction(new(zone()) HSoftDeoptimize); | 5327 AddInstruction(new(zone()) HSoftDeoptimize); |
5332 current_block()->MarkAsDeoptimizing(); | 5328 current_block()->MarkAsDeoptimizing(); |
5333 } | 5329 } |
5334 HInstruction* instr = new(zone()) HBitNot(value); | 5330 HInstruction* instr = new(zone()) HBitNot(value); |
5335 return ast_context()->ReturnInstruction(instr, expr->id()); | 5331 return ast_context()->ReturnInstruction(instr, expr->id()); |
5336 } | 5332 } |
5337 | 5333 |
5338 | 5334 |
5339 void HGraphBuilder::VisitNot(UnaryOperation* expr) { | 5335 void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
5340 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. | |
5341 if (ast_context()->IsTest()) { | 5336 if (ast_context()->IsTest()) { |
5342 TestContext* context = TestContext::cast(ast_context()); | 5337 TestContext* context = TestContext::cast(ast_context()); |
5343 VisitForControl(expr->expression(), | 5338 VisitForControl(expr->expression(), |
5344 context->if_false(), | 5339 context->if_false(), |
5345 context->if_true()); | 5340 context->if_true()); |
5346 return; | 5341 return; |
5347 } | 5342 } |
5348 | 5343 |
5349 if (ast_context()->IsEffect()) { | 5344 if (ast_context()->IsEffect()) { |
5350 VisitForEffect(expr->expression()); | 5345 VisitForEffect(expr->expression()); |
(...skipping 1662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7013 } | 7008 } |
7014 } | 7009 } |
7015 | 7010 |
7016 #ifdef DEBUG | 7011 #ifdef DEBUG |
7017 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7012 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
7018 if (allocator_ != NULL) allocator_->Verify(); | 7013 if (allocator_ != NULL) allocator_->Verify(); |
7019 #endif | 7014 #endif |
7020 } | 7015 } |
7021 | 7016 |
7022 } } // namespace v8::internal | 7017 } } // namespace v8::internal |
OLD | NEW |