OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 loop_information_(NULL), | 64 loop_information_(NULL), |
65 predecessors_(2, graph->zone()), | 65 predecessors_(2, graph->zone()), |
66 dominator_(NULL), | 66 dominator_(NULL), |
67 dominated_blocks_(4, graph->zone()), | 67 dominated_blocks_(4, graph->zone()), |
68 last_environment_(NULL), | 68 last_environment_(NULL), |
69 argument_count_(-1), | 69 argument_count_(-1), |
70 first_instruction_index_(-1), | 70 first_instruction_index_(-1), |
71 last_instruction_index_(-1), | 71 last_instruction_index_(-1), |
72 deleted_phis_(4, graph->zone()), | 72 deleted_phis_(4, graph->zone()), |
73 parent_loop_header_(NULL), | 73 parent_loop_header_(NULL), |
74 enter_inlined_block_(NULL), | |
74 is_inline_return_target_(false), | 75 is_inline_return_target_(false), |
75 is_deoptimizing_(false), | 76 is_deoptimizing_(false), |
76 dominates_loop_successors_(false), | 77 dominates_loop_successors_(false), |
77 is_osr_entry_(false) { } | 78 is_osr_entry_(false) { } |
78 | 79 |
79 | 80 |
80 Isolate* HBasicBlock::isolate() const { | 81 Isolate* HBasicBlock::isolate() const { |
81 return graph_->isolate(); | 82 return graph_->isolate(); |
82 } | 83 } |
83 | 84 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 first_ = last_ = entry; | 124 first_ = last_ = entry; |
124 } | 125 } |
125 instr->InsertAfter(last_); | 126 instr->InsertAfter(last_); |
126 } | 127 } |
127 | 128 |
128 | 129 |
129 HDeoptimize* HBasicBlock::CreateDeoptimize( | 130 HDeoptimize* HBasicBlock::CreateDeoptimize( |
130 HDeoptimize::UseEnvironment has_uses) { | 131 HDeoptimize::UseEnvironment has_uses) { |
131 ASSERT(HasEnvironment()); | 132 ASSERT(HasEnvironment()); |
132 if (has_uses == HDeoptimize::kNoUses) | 133 if (has_uses == HDeoptimize::kNoUses) |
133 return new(zone()) HDeoptimize(0, zone()); | 134 return new(zone()) HDeoptimize(0, 0, 0, zone()); |
134 | 135 |
135 HEnvironment* environment = last_environment(); | 136 HEnvironment* environment = last_environment(); |
136 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length(), zone()); | 137 int first_local_index = environment->first_local_index(); |
138 int first_expression_index = environment->first_expression_index(); | |
139 HDeoptimize* instr = new(zone()) HDeoptimize( | |
140 environment->length(), first_local_index, first_expression_index, zone()); | |
137 for (int i = 0; i < environment->length(); i++) { | 141 for (int i = 0; i < environment->length(); i++) { |
138 HValue* val = environment->values()->at(i); | 142 HValue* val = environment->values()->at(i); |
139 instr->AddEnvironmentValue(val, zone()); | 143 instr->AddEnvironmentValue(val, zone()); |
140 } | 144 } |
141 | 145 |
142 return instr; | 146 return instr; |
143 } | 147 } |
144 | 148 |
145 | 149 |
146 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, | 150 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 | 189 |
186 | 190 |
187 void HBasicBlock::Goto(HBasicBlock* block, | 191 void HBasicBlock::Goto(HBasicBlock* block, |
188 FunctionState* state, | 192 FunctionState* state, |
189 bool add_simulate) { | 193 bool add_simulate) { |
190 bool drop_extra = state != NULL && | 194 bool drop_extra = state != NULL && |
191 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 195 state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
192 | 196 |
193 if (block->IsInlineReturnTarget()) { | 197 if (block->IsInlineReturnTarget()) { |
194 AddInstruction(new(zone()) HLeaveInlined()); | 198 AddInstruction(new(zone()) HLeaveInlined()); |
195 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 199 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
196 } | 200 } |
197 | 201 |
198 if (add_simulate) AddSimulate(BailoutId::None()); | 202 if (add_simulate) AddSimulate(BailoutId::None()); |
199 HGoto* instr = new(zone()) HGoto(block); | 203 HGoto* instr = new(zone()) HGoto(block); |
200 Finish(instr); | 204 Finish(instr); |
201 } | 205 } |
202 | 206 |
203 | 207 |
204 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 208 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
205 FunctionState* state) { | 209 FunctionState* state) { |
206 HBasicBlock* target = state->function_return(); | 210 HBasicBlock* target = state->function_return(); |
207 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 211 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
208 | 212 |
209 ASSERT(target->IsInlineReturnTarget()); | 213 ASSERT(target->IsInlineReturnTarget()); |
210 ASSERT(return_value != NULL); | 214 ASSERT(return_value != NULL); |
211 AddInstruction(new(zone()) HLeaveInlined()); | 215 AddInstruction(new(zone()) HLeaveInlined()); |
212 last_environment_ = last_environment()->DiscardInlined(drop_extra); | 216 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
213 last_environment()->Push(return_value); | 217 last_environment()->Push(return_value); |
214 AddSimulate(BailoutId::None()); | 218 AddSimulate(BailoutId::None()); |
215 HGoto* instr = new(zone()) HGoto(target); | 219 HGoto* instr = new(zone()) HGoto(target); |
216 Finish(instr); | 220 Finish(instr); |
217 } | 221 } |
218 | 222 |
219 | 223 |
220 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 224 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
221 ASSERT(!HasEnvironment()); | 225 ASSERT(!HasEnvironment()); |
222 ASSERT(first() == NULL); | 226 ASSERT(first() == NULL); |
223 UpdateEnvironment(env); | 227 UpdateEnvironment(env); |
224 } | 228 } |
225 | 229 |
226 | 230 |
231 void HBasicBlock::UpdateEnvironment(HEnvironment* env) { | |
232 last_environment_ = env; | |
233 graph()->update_biggest_environment_ever(env->first_expression_index()); | |
234 } | |
235 | |
236 | |
227 void HBasicBlock::SetJoinId(BailoutId ast_id) { | 237 void HBasicBlock::SetJoinId(BailoutId ast_id) { |
228 int length = predecessors_.length(); | 238 int length = predecessors_.length(); |
229 ASSERT(length > 0); | 239 ASSERT(length > 0); |
230 for (int i = 0; i < length; i++) { | 240 for (int i = 0; i < length; i++) { |
231 HBasicBlock* predecessor = predecessors_[i]; | 241 HBasicBlock* predecessor = predecessors_[i]; |
232 ASSERT(predecessor->end()->IsGoto()); | 242 ASSERT(predecessor->end()->IsGoto()); |
233 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); | 243 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
234 ASSERT(i != 0 || | 244 ASSERT(i != 0 || |
235 (predecessor->last_environment()->closure().is_null() || | 245 (predecessor->last_environment()->closure().is_null() || |
236 predecessor->last_environment()->closure()->shared() | 246 predecessor->last_environment()->closure()->shared() |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
724 input_representation); | 734 input_representation); |
725 compare->AssumeRepresentation(input_representation); | 735 compare->AssumeRepresentation(input_representation); |
726 AddCompare(compare); | 736 AddCompare(compare); |
727 return compare; | 737 return compare; |
728 } | 738 } |
729 | 739 |
730 | 740 |
731 HInstruction* HGraphBuilder::IfBuilder::IfCompareMap(HValue* left, | 741 HInstruction* HGraphBuilder::IfBuilder::IfCompareMap(HValue* left, |
732 Handle<Map> map) { | 742 Handle<Map> map) { |
733 HCompareMap* compare = | 743 HCompareMap* compare = |
734 new(zone()) HCompareMap(left, map, | 744 new(zone()) HCompareMap(left, map, first_true_block_, first_false_block_); |
735 first_true_block_, first_false_block_); | |
736 AddCompare(compare); | 745 AddCompare(compare); |
737 return compare; | 746 return compare; |
738 } | 747 } |
739 | 748 |
740 | 749 |
741 void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) { | 750 void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) { |
742 if (split_edge_merge_block_ != NULL) { | 751 if (split_edge_merge_block_ != NULL) { |
743 HEnvironment* env = first_false_block_->last_environment(); | 752 HEnvironment* env = first_false_block_->last_environment(); |
744 HBasicBlock* split_edge = | 753 HBasicBlock* split_edge = |
745 builder_->CreateBasicBlock(env->Copy()); | 754 builder_->CreateBasicBlock(env->Copy()); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
804 End(); | 813 End(); |
805 } | 814 } |
806 | 815 |
807 | 816 |
808 void HGraphBuilder::IfBuilder::Then() { | 817 void HGraphBuilder::IfBuilder::Then() { |
809 ASSERT(!captured_); | 818 ASSERT(!captured_); |
810 ASSERT(!finished_); | 819 ASSERT(!finished_); |
811 did_then_ = true; | 820 did_then_ = true; |
812 if (needs_compare_) { | 821 if (needs_compare_) { |
813 // Handle if's without any expressions, they jump directly to the "else" | 822 // Handle if's without any expressions, they jump directly to the "else" |
814 // branch. | 823 // branch. However, we must pretend that the "then" branch is reachable. |
titzer
2013/05/23 12:34:55
Why must we pretend that it's reachable?
Jakob Kummerow
2013/05/24 09:49:35
So that the graph builder visits it and any enviro
| |
815 builder_->current_block()->GotoNoSimulate(first_false_block_); | 824 HConstant* constant_false = builder_->graph()->GetConstantFalse(); |
816 first_true_block_ = NULL; | 825 ToBooleanStub::Types boolean_type = ToBooleanStub::no_types(); |
826 boolean_type.Add(ToBooleanStub::BOOLEAN); | |
827 HBranch* branch = | |
828 new(zone()) HBranch(constant_false, first_true_block_, | |
829 first_false_block_, boolean_type); | |
830 builder_->current_block()->Finish(branch); | |
817 } | 831 } |
818 builder_->set_current_block(first_true_block_); | 832 builder_->set_current_block(first_true_block_); |
819 } | 833 } |
820 | 834 |
821 | 835 |
822 void HGraphBuilder::IfBuilder::Else() { | 836 void HGraphBuilder::IfBuilder::Else() { |
823 ASSERT(did_then_); | 837 ASSERT(did_then_); |
824 ASSERT(!captured_); | 838 ASSERT(!captured_); |
825 ASSERT(!finished_); | 839 ASSERT(!finished_); |
826 last_true_block_ = builder_->current_block(); | 840 last_true_block_ = builder_->current_block(); |
(...skipping 1269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2096 blocks_(8, info->zone()), | 2110 blocks_(8, info->zone()), |
2097 values_(16, info->zone()), | 2111 values_(16, info->zone()), |
2098 phi_list_(NULL), | 2112 phi_list_(NULL), |
2099 uint32_instructions_(NULL), | 2113 uint32_instructions_(NULL), |
2100 info_(info), | 2114 info_(info), |
2101 zone_(info->zone()), | 2115 zone_(info->zone()), |
2102 is_recursive_(false), | 2116 is_recursive_(false), |
2103 use_optimistic_licm_(false), | 2117 use_optimistic_licm_(false), |
2104 has_soft_deoptimize_(false), | 2118 has_soft_deoptimize_(false), |
2105 depends_on_empty_array_proto_elements_(false), | 2119 depends_on_empty_array_proto_elements_(false), |
2106 type_change_checksum_(0) { | 2120 type_change_checksum_(0), |
2121 biggest_environment_ever_(0) { | |
2107 if (info->IsStub()) { | 2122 if (info->IsStub()) { |
2108 HydrogenCodeStub* stub = info->code_stub(); | 2123 HydrogenCodeStub* stub = info->code_stub(); |
2109 CodeStubInterfaceDescriptor* descriptor = | 2124 CodeStubInterfaceDescriptor* descriptor = |
2110 stub->GetInterfaceDescriptor(isolate_); | 2125 stub->GetInterfaceDescriptor(isolate_); |
2111 start_environment_ = | 2126 start_environment_ = |
2112 new(zone_) HEnvironment(zone_, descriptor->environment_length()); | 2127 new(zone_) HEnvironment(zone_, descriptor->environment_length()); |
2113 } else { | 2128 } else { |
2114 start_environment_ = | 2129 start_environment_ = |
2115 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 2130 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
2116 } | 2131 } |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2479 block->AssignLoopSuccessorDominators(); | 2494 block->AssignLoopSuccessorDominators(); |
2480 } else { | 2495 } else { |
2481 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { | 2496 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { |
2482 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); | 2497 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); |
2483 } | 2498 } |
2484 } | 2499 } |
2485 } | 2500 } |
2486 } | 2501 } |
2487 | 2502 |
2488 | 2503 |
2504 void HGraph::ZapEnvironmentSlot(int index, HSimulate* simulate) { | |
2505 int operand_index = simulate->ToOperandIndex(index); | |
2506 if (operand_index == -1) { | |
2507 simulate->AddAssignedValue(index, GetConstantUndefined()); | |
2508 } else { | |
2509 simulate->SetOperandAt(operand_index, GetConstantUndefined()); | |
2510 } | |
2511 } | |
2512 | |
2513 | |
2514 void HGraph::EnvironmentLivenessAnalysis() { | |
2515 HPhase phase("H_EnvironmentLivenessAnalysis", this); | |
2516 if (biggest_environment_ever_ == 0) return; | |
2517 int block_count = blocks()->length(); | |
2518 ZoneList<BitVector*> live_at_block_start(block_count, zone()); | |
2519 ZoneList<HSimulate*> first_simulate(block_count, zone()); | |
2520 BitVector* worklist = new(zone()) BitVector(block_count, zone()); | |
2521 for (int i = 0; i < block_count; ++i) { | |
2522 live_at_block_start.Add( | |
2523 new(zone()) BitVector(biggest_environment_ever_, zone()), | |
2524 zone()); | |
2525 first_simulate.Add(NULL, zone()); | |
2526 worklist->Add(i); | |
2527 } | |
2528 | |
2529 // Liveness analysis of environment slots: visit blocks in reverse order, | |
2530 // walk backwards through each block. We need several passes to propagate | |
2531 // liveness through nested loops correctly. | |
2532 // During the main iteration, compute liveness of environment slots, and | |
2533 // store it for each block until it doesn't change any more. | |
2534 // Then, in a last pass, zap dead environment slots, and remove the | |
2535 // HEnvironment{Bind,Lookup} markers. | |
2536 enum Pass { kIterateUntilFixedPoint, kLastPass, kDone }; | |
2537 Pass pass = kIterateUntilFixedPoint; | |
2538 BitVector live(biggest_environment_ever_, zone()); | |
2539 while (pass != kDone) { | |
titzer
2013/05/23 12:34:55
I realize there are some tricky cases inside this
| |
2540 for (int block_id = block_count - 1; block_id >= 0; --block_id) { | |
2541 if (pass == kIterateUntilFixedPoint && !worklist->Contains(block_id)) { | |
titzer
2013/05/23 12:34:55
Your loop goes through the block order backwards.
Jakob Kummerow
2013/05/24 09:49:35
I'm explicitly going backwards in order to reduce
| |
2542 continue; | |
2543 } | |
2544 worklist->Remove(block_id); | |
2545 | |
2546 // Liveness at the end of each block: union of liveness in successors. | |
2547 live.Clear(); | |
2548 HBasicBlock* block = blocks()->at(block_id); | |
2549 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | |
2550 live.Union(*live_at_block_start[it.Current()->block_id()]); | |
2551 } | |
2552 | |
2553 if (pass == kLastPass) { | |
2554 // When a value is live in successor A but dead in B, we must | |
2555 // explicitly zap it in B. | |
2556 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | |
2557 HBasicBlock* successor = it.Current(); | |
2558 int successor_id = successor->block_id(); | |
2559 BitVector* live_in_successor = live_at_block_start[successor_id]; | |
2560 if (live_in_successor->Equals(live)) continue; | |
2561 // Find the first simulate in the successor block. | |
2562 HSimulate* simulate = NULL; | |
2563 HInstruction* current = successor->first(); | |
2564 while (current != NULL && simulate == NULL) { | |
2565 if (current->IsSimulate()) simulate = HSimulate::cast(current); | |
2566 if (current->IsLeaveInlined()) break; | |
2567 // No need to check for EnterInlined, because there's always | |
2568 // a simulate before an EnterInlined. | |
titzer
2013/05/23 12:34:55
Scary and brittle, and no ASSERT.
Jakob Kummerow
2013/05/24 09:49:35
ASSERT added.
| |
2569 current = current->next(); | |
2570 } | |
2571 if (simulate == NULL) continue; | |
2572 for (int i = 0; i < live.length(); ++i) { | |
2573 if (!live.Contains(i)) continue; | |
2574 if (live_in_successor->Contains(i)) continue; | |
2575 ZapEnvironmentSlot(i, simulate); | |
2576 } | |
2577 } | |
2578 } | |
2579 | |
2580 // Walk the block. | |
2581 HInstruction* instr = block->last(); | |
2582 HInstruction* next = instr->previous(); | |
2583 HSimulate* last_simulate = NULL; | |
2584 while (instr != NULL) { | |
2585 if (instr->IsEnvironmentLookup()) { | |
2586 // Begins an environment slot's live range. | |
2587 HEnvironmentLookup* lookup = HEnvironmentLookup::cast(instr); | |
2588 int index = lookup->index(); | |
2589 if (pass == kLastPass && | |
2590 !live.Contains(index) && last_simulate != NULL) { | |
2591 // The Simulate following the point where the environment value | |
2592 // dies is extended or modified to zap that value's slot. | |
2593 ZapEnvironmentSlot(index, last_simulate); | |
2594 } | |
2595 live.Add(index); | |
2596 if (pass == kLastPass) lookup->DeleteAndReplaceWith(NULL); | |
2597 } else if (instr->IsEnvironmentBind()) { | |
2598 // Ends an environment slot's live range. | |
2599 HEnvironmentBind* bind = HEnvironmentBind::cast(instr); | |
2600 int index = bind->index(); | |
2601 if (pass == 2 && !live.Contains(index) && last_simulate != NULL) { | |
2602 // Don't bother binding this value if it's never looked up. | |
2603 ZapEnvironmentSlot(index, last_simulate); | |
2604 } | |
2605 live.Remove(index); | |
2606 if (pass == kLastPass) bind->DeleteAndReplaceWith(NULL); | |
2607 } else if (instr->IsLeaveInlined()) { | |
2608 // No environment values are live at the end of an inlined section. | |
2609 live.Clear(); | |
2610 // Simulates are tied to environments, so last_simulate cannot be | |
2611 // used for what comes next. | |
2612 last_simulate = NULL; | |
2613 } else if (instr->IsEnterInlined()) { | |
titzer
2013/05/23 12:34:55
There is considerably more going on here than meet
| |
2614 HEnterInlined* enter = HEnterInlined::cast(instr); | |
2615 // Those environment values are live that are live at any return | |
2616 // target block. Here we make use of the fact that the end of an | |
2617 // inline sequence always looks like this: HLeaveInlined, HSimulate, | |
2618 // HGoto (to return_target block), with no environment lookups in | |
2619 // between. | |
2620 live.Clear(); | |
2621 for (int j = 0; j < enter->return_targets()->length(); ++j) { | |
2622 int return_id = enter->return_targets()->at(j)->block_id(); | |
2623 // When an AbnormalExit is involved, it can happen that the return | |
2624 // target block doesn't actually exist. | |
2625 if (return_id < block_count) { | |
2626 live.Union(*live_at_block_start[return_id]); | |
2627 } | |
2628 } | |
2629 if (pass == kLastPass && | |
2630 enter->return_targets()->length() == 1 && | |
2631 enter->return_targets()->at(0)->block_id() < block_count) { | |
2632 last_simulate = | |
2633 first_simulate.at(enter->return_targets()->at(0)->block_id()); | |
2634 } else { | |
2635 // Out of luck. We're inlining at a control flow split; | |
2636 // if we wanted to retrieve the correct last_simulate we'd have to | |
2637 // compute the corresponding join block, which is non-trivial. | |
2638 last_simulate = NULL; | |
2639 } | |
2640 } else if (instr->IsDeoptimize()) { | |
2641 // Keep all environment slots alive. | |
2642 HDeoptimize* deopt = HDeoptimize::cast(instr); | |
2643 for (int j = deopt->first_local_index(); | |
2644 j < deopt->first_expression_index(); ++j) { | |
2645 live.Add(j); | |
2646 } | |
2647 } else if (instr->IsSimulate()) { | |
2648 last_simulate = HSimulate::cast(instr); | |
2649 } | |
2650 instr = next; | |
2651 next = (instr != NULL) ? instr->previous() : NULL; | |
2652 } | |
2653 | |
2654 // Reached the start of the block, do necessary bookkeeping. | |
2655 if (pass == kIterateUntilFixedPoint && | |
2656 live_at_block_start[block_id]->UnionIsChanged(live)) { | |
2657 for (int j = 0; j < block->predecessors()->length(); ++j) { | |
2658 worklist->Add(block->predecessors()->at(j)->block_id()); | |
2659 } | |
2660 if (block->IsInlineReturnTarget()) { | |
2661 worklist->Add(block->enter_inlined_block()->block_id()); | |
2662 } | |
2663 } | |
2664 first_simulate.Set(block_id, last_simulate); | |
2665 } | |
2666 if (pass == kIterateUntilFixedPoint && worklist->IsEmpty()) { | |
2667 pass = kLastPass; | |
2668 } else if (pass == kLastPass) { | |
2669 pass = kDone; | |
2670 } | |
2671 } | |
2672 } | |
2673 | |
2674 | |
2489 // Mark all blocks that are dominated by an unconditional soft deoptimize to | 2675 // Mark all blocks that are dominated by an unconditional soft deoptimize to |
2490 // prevent code motion across those blocks. | 2676 // prevent code motion across those blocks. |
2491 void HGraph::PropagateDeoptimizingMark() { | 2677 void HGraph::PropagateDeoptimizingMark() { |
2492 HPhase phase("H_Propagate deoptimizing mark", this); | 2678 HPhase phase("H_Propagate deoptimizing mark", this); |
2493 // Skip this phase if there is nothing to be done anyway. | 2679 // Skip this phase if there is nothing to be done anyway. |
2494 if (!has_soft_deoptimize()) return; | 2680 if (!has_soft_deoptimize()) return; |
2495 MarkAsDeoptimizingRecursively(entry_block()); | 2681 MarkAsDeoptimizingRecursively(entry_block()); |
2496 NullifyUnreachableInstructions(); | 2682 NullifyUnreachableInstructions(); |
2497 } | 2683 } |
2498 | 2684 |
(...skipping 1925 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4424 function_return_(NULL), | 4610 function_return_(NULL), |
4425 test_context_(NULL), | 4611 test_context_(NULL), |
4426 entry_(NULL), | 4612 entry_(NULL), |
4427 arguments_elements_(NULL), | 4613 arguments_elements_(NULL), |
4428 outer_(owner->function_state()) { | 4614 outer_(owner->function_state()) { |
4429 if (outer_ != NULL) { | 4615 if (outer_ != NULL) { |
4430 // State for an inline function. | 4616 // State for an inline function. |
4431 if (owner->ast_context()->IsTest()) { | 4617 if (owner->ast_context()->IsTest()) { |
4432 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 4618 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
4433 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 4619 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
4434 if_true->MarkAsInlineReturnTarget(); | 4620 if_true->MarkAsInlineReturnTarget(owner->current_block()); |
4435 if_false->MarkAsInlineReturnTarget(); | 4621 if_false->MarkAsInlineReturnTarget(owner->current_block()); |
4436 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); | 4622 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); |
4437 Expression* cond = outer_test_context->condition(); | 4623 Expression* cond = outer_test_context->condition(); |
4438 TypeFeedbackOracle* outer_oracle = outer_test_context->oracle(); | 4624 TypeFeedbackOracle* outer_oracle = outer_test_context->oracle(); |
4439 // The AstContext constructor pushed on the context stack. This newed | 4625 // The AstContext constructor pushed on the context stack. This newed |
4440 // instance is the reason that AstContext can't be BASE_EMBEDDED. | 4626 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
4441 test_context_ = | 4627 test_context_ = |
4442 new TestContext(owner, cond, outer_oracle, if_true, if_false); | 4628 new TestContext(owner, cond, outer_oracle, if_true, if_false); |
4443 } else { | 4629 } else { |
4444 function_return_ = owner->graph()->CreateBasicBlock(); | 4630 function_return_ = owner->graph()->CreateBasicBlock(); |
4445 function_return()->MarkAsInlineReturnTarget(); | 4631 function_return()->MarkAsInlineReturnTarget(owner->current_block()); |
4446 } | 4632 } |
4447 // Set this after possibly allocating a new TestContext above. | 4633 // Set this after possibly allocating a new TestContext above. |
4448 call_context_ = owner->ast_context(); | 4634 call_context_ = owner->ast_context(); |
4449 } | 4635 } |
4450 | 4636 |
4451 // Push on the state stack. | 4637 // Push on the state stack. |
4452 owner->set_function_state(this); | 4638 owner->set_function_state(this); |
4453 } | 4639 } |
4454 | 4640 |
4455 | 4641 |
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4855 // zero-valued constant in the graph together. | 5041 // zero-valued constant in the graph together. |
4856 // The constant is needed to make idef-based bounds check work: the pass | 5042 // The constant is needed to make idef-based bounds check work: the pass |
4857 // evaluates relations with "zero" and that zero cannot be created after GVN. | 5043 // evaluates relations with "zero" and that zero cannot be created after GVN. |
4858 GetConstant0(); | 5044 GetConstant0(); |
4859 | 5045 |
4860 #ifdef DEBUG | 5046 #ifdef DEBUG |
4861 // Do a full verify after building the graph and computing dominators. | 5047 // Do a full verify after building the graph and computing dominators. |
4862 Verify(true); | 5048 Verify(true); |
4863 #endif | 5049 #endif |
4864 | 5050 |
5051 EnvironmentLivenessAnalysis(); | |
titzer
2013/05/23 12:34:55
This phase should be guarded by a flag, and should
Jakob Kummerow
2013/05/24 09:49:35
Done.
Side note: "DeadCodeElimination" isn't a ver
| |
5052 | |
4865 PropagateDeoptimizingMark(); | 5053 PropagateDeoptimizingMark(); |
4866 if (!CheckConstPhiUses()) { | 5054 if (!CheckConstPhiUses()) { |
4867 *bailout_reason = SmartArrayPointer<char>(StrDup( | 5055 *bailout_reason = SmartArrayPointer<char>(StrDup( |
4868 "Unsupported phi use of const variable")); | 5056 "Unsupported phi use of const variable")); |
4869 return false; | 5057 return false; |
4870 } | 5058 } |
4871 EliminateRedundantPhis(); | 5059 EliminateRedundantPhis(); |
4872 if (!CheckArgumentsPhiUses()) { | 5060 if (!CheckArgumentsPhiUses()) { |
4873 *bailout_reason = SmartArrayPointer<char>(StrDup( | 5061 *bailout_reason = SmartArrayPointer<char>(StrDup( |
4874 "Unsupported phi use of arguments")); | 5062 "Unsupported phi use of arguments")); |
(...skipping 1671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6546 global_object, | 6734 global_object, |
6547 variable->name(), | 6735 variable->name(), |
6548 ast_context()->is_for_typeof()); | 6736 ast_context()->is_for_typeof()); |
6549 instr->set_position(expr->position()); | 6737 instr->set_position(expr->position()); |
6550 return ast_context()->ReturnInstruction(instr, expr->id()); | 6738 return ast_context()->ReturnInstruction(instr, expr->id()); |
6551 } | 6739 } |
6552 } | 6740 } |
6553 | 6741 |
6554 case Variable::PARAMETER: | 6742 case Variable::PARAMETER: |
6555 case Variable::LOCAL: { | 6743 case Variable::LOCAL: { |
6556 HValue* value = environment()->Lookup(variable); | 6744 HValue* value = LookupAndMakeLive(variable); |
6557 if (value == graph()->GetConstantHole()) { | 6745 if (value == graph()->GetConstantHole()) { |
6558 ASSERT(IsDeclaredVariableMode(variable->mode()) && | 6746 ASSERT(IsDeclaredVariableMode(variable->mode()) && |
6559 variable->mode() != VAR); | 6747 variable->mode() != VAR); |
6560 return Bailout("reference to uninitialized variable"); | 6748 return Bailout("reference to uninitialized variable"); |
6561 } | 6749 } |
6562 return ast_context()->ReturnValue(value); | 6750 return ast_context()->ReturnValue(value); |
6563 } | 6751 } |
6564 | 6752 |
6565 case Variable::CONTEXT: { | 6753 case Variable::CONTEXT: { |
6566 HValue* context = BuildContextChainWalk(variable); | 6754 HValue* context = BuildContextChainWalk(variable); |
(...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7546 Top(), | 7734 Top(), |
7547 expr->position(), | 7735 expr->position(), |
7548 expr->AssignmentId()); | 7736 expr->AssignmentId()); |
7549 break; | 7737 break; |
7550 | 7738 |
7551 case Variable::PARAMETER: | 7739 case Variable::PARAMETER: |
7552 case Variable::LOCAL: | 7740 case Variable::LOCAL: |
7553 if (var->mode() == CONST) { | 7741 if (var->mode() == CONST) { |
7554 return Bailout("unsupported const compound assignment"); | 7742 return Bailout("unsupported const compound assignment"); |
7555 } | 7743 } |
7556 Bind(var, Top()); | 7744 BindIfLive(var, Top()); |
7557 break; | 7745 break; |
7558 | 7746 |
7559 case Variable::CONTEXT: { | 7747 case Variable::CONTEXT: { |
7560 // Bail out if we try to mutate a parameter value in a function | 7748 // Bail out if we try to mutate a parameter value in a function |
7561 // using the arguments object. We do not (yet) correctly handle the | 7749 // using the arguments object. We do not (yet) correctly handle the |
7562 // arguments property of the function. | 7750 // arguments property of the function. |
7563 if (info()->scope()->arguments() != NULL) { | 7751 if (info()->scope()->arguments() != NULL) { |
7564 // Parameters will be allocated to context slots. We have no | 7752 // Parameters will be allocated to context slots. We have no |
7565 // direct way to detect that the variable is a parameter so we do | 7753 // direct way to detect that the variable is a parameter so we do |
7566 // a linear search of the parameter variables. | 7754 // a linear search of the parameter variables. |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7775 HValue* env_value = environment()->Lookup(var); | 7963 HValue* env_value = environment()->Lookup(var); |
7776 if (env_value == graph()->GetConstantHole()) { | 7964 if (env_value == graph()->GetConstantHole()) { |
7777 return Bailout("assignment to let variable before initialization"); | 7965 return Bailout("assignment to let variable before initialization"); |
7778 } | 7966 } |
7779 } | 7967 } |
7780 // We do not allow the arguments object to occur in a context where it | 7968 // We do not allow the arguments object to occur in a context where it |
7781 // may escape, but assignments to stack-allocated locals are | 7969 // may escape, but assignments to stack-allocated locals are |
7782 // permitted. | 7970 // permitted. |
7783 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); | 7971 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); |
7784 HValue* value = Pop(); | 7972 HValue* value = Pop(); |
7785 Bind(var, value); | 7973 BindIfLive(var, value); |
7786 return ast_context()->ReturnValue(value); | 7974 return ast_context()->ReturnValue(value); |
7787 } | 7975 } |
7788 | 7976 |
7789 case Variable::CONTEXT: { | 7977 case Variable::CONTEXT: { |
7790 // Bail out if we try to mutate a parameter value in a function using | 7978 // Bail out if we try to mutate a parameter value in a function using |
7791 // the arguments object. We do not (yet) correctly handle the | 7979 // the arguments object. We do not (yet) correctly handle the |
7792 // arguments property of the function. | 7980 // arguments property of the function. |
7793 if (info()->scope()->arguments() != NULL) { | 7981 if (info()->scope()->arguments() != NULL) { |
7794 // Parameters will rewrite to context slots. We have no direct way | 7982 // Parameters will rewrite to context slots. We have no direct way |
7795 // to detect that the variable is a parameter. | 7983 // to detect that the variable is a parameter. |
(...skipping 1199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8995 } | 9183 } |
8996 } | 9184 } |
8997 | 9185 |
8998 HEnterInlined* enter_inlined = | 9186 HEnterInlined* enter_inlined = |
8999 new(zone()) HEnterInlined(target, | 9187 new(zone()) HEnterInlined(target, |
9000 arguments_count, | 9188 arguments_count, |
9001 function, | 9189 function, |
9002 function_state()->inlining_kind(), | 9190 function_state()->inlining_kind(), |
9003 function->scope()->arguments(), | 9191 function->scope()->arguments(), |
9004 arguments_values, | 9192 arguments_values, |
9005 undefined_receiver); | 9193 undefined_receiver, |
9194 zone()); | |
9006 function_state()->set_entry(enter_inlined); | 9195 function_state()->set_entry(enter_inlined); |
9007 AddInstruction(enter_inlined); | 9196 AddInstruction(enter_inlined); |
9008 | 9197 |
9009 // If the function uses arguments object create and bind one. | 9198 // If the function uses arguments object create and bind one. |
9010 if (function->scope()->arguments() != NULL) { | 9199 if (function->scope()->arguments() != NULL) { |
9011 ASSERT(function->scope()->arguments()->IsStackAllocated()); | 9200 ASSERT(function->scope()->arguments()->IsStackAllocated()); |
9012 inner_env->Bind(function->scope()->arguments(), | 9201 inner_env->Bind(function->scope()->arguments(), |
9013 graph()->GetArgumentsObject()); | 9202 graph()->GetArgumentsObject()); |
9014 } | 9203 } |
9015 | 9204 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9074 current_block()->AddLeaveInlined(undefined, state); | 9263 current_block()->AddLeaveInlined(undefined, state); |
9075 } | 9264 } |
9076 } | 9265 } |
9077 } | 9266 } |
9078 | 9267 |
9079 // Fix up the function exits. | 9268 // Fix up the function exits. |
9080 if (inlined_test_context() != NULL) { | 9269 if (inlined_test_context() != NULL) { |
9081 HBasicBlock* if_true = inlined_test_context()->if_true(); | 9270 HBasicBlock* if_true = inlined_test_context()->if_true(); |
9082 HBasicBlock* if_false = inlined_test_context()->if_false(); | 9271 HBasicBlock* if_false = inlined_test_context()->if_false(); |
9083 | 9272 |
9273 HEnterInlined* entry = function_state()->entry(); | |
9274 | |
9084 // Pop the return test context from the expression context stack. | 9275 // Pop the return test context from the expression context stack. |
9085 ASSERT(ast_context() == inlined_test_context()); | 9276 ASSERT(ast_context() == inlined_test_context()); |
9086 ClearInlinedTestContext(); | 9277 ClearInlinedTestContext(); |
9087 delete target_state; | 9278 delete target_state; |
9088 | 9279 |
9089 // Forward to the real test context. | 9280 // Forward to the real test context. |
9090 if (if_true->HasPredecessor()) { | 9281 if (if_true->HasPredecessor()) { |
9282 entry->RegisterReturnTarget(if_true, zone()); | |
9091 if_true->SetJoinId(ast_id); | 9283 if_true->SetJoinId(ast_id); |
9092 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 9284 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
9093 if_true->Goto(true_target, function_state()); | 9285 if_true->Goto(true_target, function_state()); |
9094 } | 9286 } |
9095 if (if_false->HasPredecessor()) { | 9287 if (if_false->HasPredecessor()) { |
9288 entry->RegisterReturnTarget(if_false, zone()); | |
9096 if_false->SetJoinId(ast_id); | 9289 if_false->SetJoinId(ast_id); |
9097 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 9290 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
9098 if_false->Goto(false_target, function_state()); | 9291 if_false->Goto(false_target, function_state()); |
9099 } | 9292 } |
9100 set_current_block(NULL); | 9293 set_current_block(NULL); |
9101 return true; | 9294 return true; |
9102 | 9295 |
9103 } else if (function_return()->HasPredecessor()) { | 9296 } else if (function_return()->HasPredecessor()) { |
9297 function_state()->entry()->RegisterReturnTarget(function_return(), zone()); | |
9104 function_return()->SetJoinId(ast_id); | 9298 function_return()->SetJoinId(ast_id); |
9105 set_current_block(function_return()); | 9299 set_current_block(function_return()); |
9106 } else { | 9300 } else { |
9107 set_current_block(NULL); | 9301 set_current_block(NULL); |
9108 } | 9302 } |
9109 delete target_state; | 9303 delete target_state; |
9110 return true; | 9304 return true; |
9111 } | 9305 } |
9112 | 9306 |
9113 | 9307 |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9400 return false; | 9594 return false; |
9401 } | 9595 } |
9402 | 9596 |
9403 if (info()->scope()->arguments() == NULL) return false; | 9597 if (info()->scope()->arguments() == NULL) return false; |
9404 | 9598 |
9405 ZoneList<Expression*>* args = expr->arguments(); | 9599 ZoneList<Expression*>* args = expr->arguments(); |
9406 if (args->length() != 2) return false; | 9600 if (args->length() != 2) return false; |
9407 | 9601 |
9408 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 9602 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
9409 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 9603 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
9410 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 9604 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
9411 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 9605 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
9412 | 9606 |
9413 // Found pattern f.apply(receiver, arguments). | 9607 // Found pattern f.apply(receiver, arguments). |
9414 VisitForValue(prop->obj()); | 9608 VisitForValue(prop->obj()); |
9415 if (HasStackOverflow() || current_block() == NULL) return true; | 9609 if (HasStackOverflow() || current_block() == NULL) return true; |
9416 HValue* function = Top(); | 9610 HValue* function = Top(); |
9417 AddCheckConstantFunction(expr->holder(), function, function_map); | 9611 AddCheckConstantFunction(expr->holder(), function, function_map); |
9418 Drop(1); | 9612 Drop(1); |
9419 | 9613 |
9420 VisitForValue(args->at(0)); | 9614 VisitForValue(args->at(0)); |
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10111 switch (var->location()) { | 10305 switch (var->location()) { |
10112 case Variable::UNALLOCATED: | 10306 case Variable::UNALLOCATED: |
10113 HandleGlobalVariableAssignment(var, | 10307 HandleGlobalVariableAssignment(var, |
10114 after, | 10308 after, |
10115 expr->position(), | 10309 expr->position(), |
10116 expr->AssignmentId()); | 10310 expr->AssignmentId()); |
10117 break; | 10311 break; |
10118 | 10312 |
10119 case Variable::PARAMETER: | 10313 case Variable::PARAMETER: |
10120 case Variable::LOCAL: | 10314 case Variable::LOCAL: |
10121 Bind(var, after); | 10315 BindIfLive(var, after); |
10122 break; | 10316 break; |
10123 | 10317 |
10124 case Variable::CONTEXT: { | 10318 case Variable::CONTEXT: { |
10125 // Bail out if we try to mutate a parameter value in a function | 10319 // Bail out if we try to mutate a parameter value in a function |
10126 // using the arguments object. We do not (yet) correctly handle the | 10320 // using the arguments object. We do not (yet) correctly handle the |
10127 // arguments property of the function. | 10321 // arguments property of the function. |
10128 if (info()->scope()->arguments() != NULL) { | 10322 if (info()->scope()->arguments() != NULL) { |
10129 // Parameters will rewrite to context slots. We have no direct | 10323 // Parameters will rewrite to context slots. We have no direct |
10130 // way to detect that the variable is a parameter so we use a | 10324 // way to detect that the variable is a parameter so we use a |
10131 // linear search of the parameter list. | 10325 // linear search of the parameter list. |
(...skipping 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11194 Compiler::BuildFunctionInfo(declaration->fun(), info()->script()); | 11388 Compiler::BuildFunctionInfo(declaration->fun(), info()->script()); |
11195 // Check for stack-overflow exception. | 11389 // Check for stack-overflow exception. |
11196 if (function.is_null()) return SetStackOverflow(); | 11390 if (function.is_null()) return SetStackOverflow(); |
11197 globals_.Add(function, zone()); | 11391 globals_.Add(function, zone()); |
11198 return; | 11392 return; |
11199 } | 11393 } |
11200 case Variable::PARAMETER: | 11394 case Variable::PARAMETER: |
11201 case Variable::LOCAL: { | 11395 case Variable::LOCAL: { |
11202 CHECK_ALIVE(VisitForValue(declaration->fun())); | 11396 CHECK_ALIVE(VisitForValue(declaration->fun())); |
11203 HValue* value = Pop(); | 11397 HValue* value = Pop(); |
11204 environment()->Bind(variable, value); | 11398 BindIfLive(variable, value); |
11205 break; | 11399 break; |
11206 } | 11400 } |
11207 case Variable::CONTEXT: { | 11401 case Variable::CONTEXT: { |
11208 CHECK_ALIVE(VisitForValue(declaration->fun())); | 11402 CHECK_ALIVE(VisitForValue(declaration->fun())); |
11209 HValue* value = Pop(); | 11403 HValue* value = Pop(); |
11210 HValue* context = environment()->LookupContext(); | 11404 HValue* context = environment()->LookupContext(); |
11211 HStoreContextSlot* store = new(zone()) HStoreContextSlot( | 11405 HStoreContextSlot* store = new(zone()) HStoreContextSlot( |
11212 context, variable->index(), HStoreContextSlot::kNoCheck, value); | 11406 context, variable->index(), HStoreContextSlot::kNoCheck, value); |
11213 AddInstruction(store); | 11407 AddInstruction(store); |
11214 if (store->HasObservableSideEffects()) { | 11408 if (store->HasObservableSideEffects()) { |
(...skipping 1256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12471 } | 12665 } |
12472 } | 12666 } |
12473 | 12667 |
12474 #ifdef DEBUG | 12668 #ifdef DEBUG |
12475 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 12669 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
12476 if (allocator_ != NULL) allocator_->Verify(); | 12670 if (allocator_ != NULL) allocator_->Verify(); |
12477 #endif | 12671 #endif |
12478 } | 12672 } |
12479 | 12673 |
12480 } } // namespace v8::internal | 12674 } } // namespace v8::internal |
OLD | NEW |