| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 15 matching lines...) Expand all Loading... |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 | 28 |
| 29 #include "hydrogen-environment-liveness.h" | 29 #include "hydrogen-environment-liveness.h" |
| 30 | 30 |
| 31 | 31 |
| 32 namespace v8 { | 32 namespace v8 { |
| 33 namespace internal { | 33 namespace internal { |
| 34 | 34 |
| 35 | 35 |
| 36 EnvironmentSlotLivenessAnalyzer::EnvironmentSlotLivenessAnalyzer( | 36 HEnvironmentLivenessAnalysisPhase::HEnvironmentLivenessAnalysisPhase( |
| 37 HGraph* graph) | 37 HGraph* graph) |
| 38 : graph_(graph), | 38 : HPhase("H_Environment liveness analysis", graph), |
| 39 zone_(graph->isolate()), | |
| 40 block_count_(graph->blocks()->length()), | 39 block_count_(graph->blocks()->length()), |
| 41 maximum_environment_size_(graph->maximum_environment_size()), | 40 maximum_environment_size_(graph->maximum_environment_size()), |
| 41 live_at_block_start_(block_count_, zone()), |
| 42 first_simulate_(block_count_, zone()), |
| 43 first_simulate_invalid_for_index_(block_count_, zone()), |
| 44 markers_(maximum_environment_size_, zone()), |
| 42 collect_markers_(true), | 45 collect_markers_(true), |
| 43 last_simulate_(NULL) { | 46 last_simulate_(NULL), |
| 44 if (maximum_environment_size_ == 0) return; | 47 went_live_since_last_simulate_(maximum_environment_size_, zone()) { |
| 45 | 48 ASSERT(maximum_environment_size_ > 0); |
| 46 live_at_block_start_ = | |
| 47 new(zone()) ZoneList<BitVector*>(block_count_, zone()); | |
| 48 first_simulate_ = new(zone()) ZoneList<HSimulate*>(block_count_, zone()); | |
| 49 first_simulate_invalid_for_index_ = | |
| 50 new(zone()) ZoneList<BitVector*>(block_count_, zone()); | |
| 51 markers_ = new(zone()) | |
| 52 ZoneList<HEnvironmentMarker*>(maximum_environment_size_, zone()); | |
| 53 went_live_since_last_simulate_ = | |
| 54 new(zone()) BitVector(maximum_environment_size_, zone()); | |
| 55 | |
| 56 for (int i = 0; i < block_count_; ++i) { | 49 for (int i = 0; i < block_count_; ++i) { |
| 57 live_at_block_start_->Add( | 50 live_at_block_start_.Add( |
| 58 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); | 51 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); |
| 59 first_simulate_->Add(NULL, zone()); | 52 first_simulate_.Add(NULL, zone()); |
| 60 first_simulate_invalid_for_index_->Add( | 53 first_simulate_invalid_for_index_.Add( |
| 61 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); | 54 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); |
| 62 } | 55 } |
| 63 } | 56 } |
| 64 | 57 |
| 65 | 58 |
| 66 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlot(int index, | 59 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlot( |
| 67 HSimulate* simulate) { | 60 int index, HSimulate* simulate) { |
| 68 int operand_index = simulate->ToOperandIndex(index); | 61 int operand_index = simulate->ToOperandIndex(index); |
| 69 if (operand_index == -1) { | 62 if (operand_index == -1) { |
| 70 simulate->AddAssignedValue(index, graph_->GetConstantUndefined()); | 63 simulate->AddAssignedValue(index, graph()->GetConstantUndefined()); |
| 71 } else { | 64 } else { |
| 72 simulate->SetOperandAt(operand_index, graph_->GetConstantUndefined()); | 65 simulate->SetOperandAt(operand_index, graph()->GetConstantUndefined()); |
| 73 } | 66 } |
| 74 } | 67 } |
| 75 | 68 |
| 76 | 69 |
| 77 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlotsInSuccessors( | 70 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlotsInSuccessors( |
| 78 HBasicBlock* block, | 71 HBasicBlock* block, BitVector* live) { |
| 79 BitVector* live) { | |
| 80 // When a value is live in successor A but dead in B, we must | 72 // When a value is live in successor A but dead in B, we must |
| 81 // explicitly zap it in B. | 73 // explicitly zap it in B. |
| 82 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | 74 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 83 HBasicBlock* successor = it.Current(); | 75 HBasicBlock* successor = it.Current(); |
| 84 int successor_id = successor->block_id(); | 76 int successor_id = successor->block_id(); |
| 85 BitVector* live_in_successor = live_at_block_start_->at(successor_id); | 77 BitVector* live_in_successor = live_at_block_start_[successor_id]; |
| 86 if (live_in_successor->Equals(*live)) continue; | 78 if (live_in_successor->Equals(*live)) continue; |
| 87 for (int i = 0; i < live->length(); ++i) { | 79 for (int i = 0; i < live->length(); ++i) { |
| 88 if (!live->Contains(i)) continue; | 80 if (!live->Contains(i)) continue; |
| 89 if (live_in_successor->Contains(i)) continue; | 81 if (live_in_successor->Contains(i)) continue; |
| 90 if (first_simulate_invalid_for_index_->at(successor_id)->Contains(i)) { | 82 if (first_simulate_invalid_for_index_.at(successor_id)->Contains(i)) { |
| 91 continue; | 83 continue; |
| 92 } | 84 } |
| 93 HSimulate* simulate = first_simulate_->at(successor_id); | 85 HSimulate* simulate = first_simulate_.at(successor_id); |
| 94 if (simulate == NULL) continue; | 86 if (simulate == NULL) continue; |
| 95 ASSERT(simulate->closure().is_identical_to( | 87 ASSERT(simulate->closure().is_identical_to( |
| 96 block->last_environment()->closure())); | 88 block->last_environment()->closure())); |
| 97 ZapEnvironmentSlot(i, simulate); | 89 ZapEnvironmentSlot(i, simulate); |
| 98 } | 90 } |
| 99 } | 91 } |
| 100 } | 92 } |
| 101 | 93 |
| 102 | 94 |
| 103 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlotsForInstruction( | 95 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlotsForInstruction( |
| 104 HEnvironmentMarker* marker) { | 96 HEnvironmentMarker* marker) { |
| 105 if (!marker->CheckFlag(HValue::kEndsLiveRange)) return; | 97 if (!marker->CheckFlag(HValue::kEndsLiveRange)) return; |
| 106 HSimulate* simulate = marker->next_simulate(); | 98 HSimulate* simulate = marker->next_simulate(); |
| 107 if (simulate != NULL) { | 99 if (simulate != NULL) { |
| 108 ASSERT(simulate->closure().is_identical_to(marker->closure())); | 100 ASSERT(simulate->closure().is_identical_to(marker->closure())); |
| 109 ZapEnvironmentSlot(marker->index(), simulate); | 101 ZapEnvironmentSlot(marker->index(), simulate); |
| 110 } | 102 } |
| 111 } | 103 } |
| 112 | 104 |
| 113 | 105 |
| 114 void EnvironmentSlotLivenessAnalyzer::UpdateLivenessAtBlockEnd( | 106 void HEnvironmentLivenessAnalysisPhase::UpdateLivenessAtBlockEnd( |
| 115 HBasicBlock* block, | 107 HBasicBlock* block, |
| 116 BitVector* live) { | 108 BitVector* live) { |
| 117 // Liveness at the end of each block: union of liveness in successors. | 109 // Liveness at the end of each block: union of liveness in successors. |
| 118 live->Clear(); | 110 live->Clear(); |
| 119 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | 111 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 120 live->Union(*live_at_block_start_->at(it.Current()->block_id())); | 112 live->Union(*live_at_block_start_[it.Current()->block_id()]); |
| 121 } | 113 } |
| 122 } | 114 } |
| 123 | 115 |
| 124 | 116 |
| 125 void EnvironmentSlotLivenessAnalyzer::UpdateLivenessAtInstruction( | 117 void HEnvironmentLivenessAnalysisPhase::UpdateLivenessAtInstruction( |
| 126 HInstruction* instr, | 118 HInstruction* instr, |
| 127 BitVector* live) { | 119 BitVector* live) { |
| 128 switch (instr->opcode()) { | 120 switch (instr->opcode()) { |
| 129 case HValue::kEnvironmentMarker: { | 121 case HValue::kEnvironmentMarker: { |
| 130 HEnvironmentMarker* marker = HEnvironmentMarker::cast(instr); | 122 HEnvironmentMarker* marker = HEnvironmentMarker::cast(instr); |
| 131 int index = marker->index(); | 123 int index = marker->index(); |
| 132 if (!live->Contains(index)) { | 124 if (!live->Contains(index)) { |
| 133 marker->SetFlag(HValue::kEndsLiveRange); | 125 marker->SetFlag(HValue::kEndsLiveRange); |
| 134 } else { | 126 } else { |
| 135 marker->ClearFlag(HValue::kEndsLiveRange); | 127 marker->ClearFlag(HValue::kEndsLiveRange); |
| 136 } | 128 } |
| 137 if (!went_live_since_last_simulate_->Contains(index)) { | 129 if (!went_live_since_last_simulate_.Contains(index)) { |
| 138 marker->set_next_simulate(last_simulate_); | 130 marker->set_next_simulate(last_simulate_); |
| 139 } | 131 } |
| 140 if (marker->kind() == HEnvironmentMarker::LOOKUP) { | 132 if (marker->kind() == HEnvironmentMarker::LOOKUP) { |
| 141 live->Add(index); | 133 live->Add(index); |
| 142 } else { | 134 } else { |
| 143 ASSERT(marker->kind() == HEnvironmentMarker::BIND); | 135 ASSERT(marker->kind() == HEnvironmentMarker::BIND); |
| 144 live->Remove(index); | 136 live->Remove(index); |
| 145 went_live_since_last_simulate_->Add(index); | 137 went_live_since_last_simulate_.Add(index); |
| 146 } | 138 } |
| 147 if (collect_markers_) { | 139 if (collect_markers_) { |
| 148 // Populate |markers_| list during the first pass. | 140 // Populate |markers_| list during the first pass. |
| 149 markers_->Add(marker, zone()); | 141 markers_.Add(marker, zone()); |
| 150 } | 142 } |
| 151 break; | 143 break; |
| 152 } | 144 } |
| 153 case HValue::kLeaveInlined: | 145 case HValue::kLeaveInlined: |
| 154 // No environment values are live at the end of an inlined section. | 146 // No environment values are live at the end of an inlined section. |
| 155 live->Clear(); | 147 live->Clear(); |
| 156 last_simulate_ = NULL; | 148 last_simulate_ = NULL; |
| 157 | 149 |
| 158 // The following ASSERTs guard the assumption used in case | 150 // The following ASSERTs guard the assumption used in case |
| 159 // kEnterInlined below: | 151 // kEnterInlined below: |
| 160 ASSERT(instr->next()->IsSimulate()); | 152 ASSERT(instr->next()->IsSimulate()); |
| 161 ASSERT(instr->next()->next()->IsGoto()); | 153 ASSERT(instr->next()->next()->IsGoto()); |
| 162 | 154 |
| 163 break; | 155 break; |
| 164 case HValue::kEnterInlined: { | 156 case HValue::kEnterInlined: { |
| 165 // Those environment values are live that are live at any return | 157 // Those environment values are live that are live at any return |
| 166 // target block. Here we make use of the fact that the end of an | 158 // target block. Here we make use of the fact that the end of an |
| 167 // inline sequence always looks like this: HLeaveInlined, HSimulate, | 159 // inline sequence always looks like this: HLeaveInlined, HSimulate, |
| 168 // HGoto (to return_target block), with no environment lookups in | 160 // HGoto (to return_target block), with no environment lookups in |
| 169 // between (see ASSERTs above). | 161 // between (see ASSERTs above). |
| 170 HEnterInlined* enter = HEnterInlined::cast(instr); | 162 HEnterInlined* enter = HEnterInlined::cast(instr); |
| 171 live->Clear(); | 163 live->Clear(); |
| 172 for (int i = 0; i < enter->return_targets()->length(); ++i) { | 164 for (int i = 0; i < enter->return_targets()->length(); ++i) { |
| 173 int return_id = enter->return_targets()->at(i)->block_id(); | 165 int return_id = enter->return_targets()->at(i)->block_id(); |
| 174 // When an AbnormalExit is involved, it can happen that the return | 166 // When an AbnormalExit is involved, it can happen that the return |
| 175 // target block doesn't actually exist. | 167 // target block doesn't actually exist. |
| 176 if (return_id < live_at_block_start_->length()) { | 168 if (return_id < live_at_block_start_.length()) { |
| 177 live->Union(*live_at_block_start_->at(return_id)); | 169 live->Union(*live_at_block_start_[return_id]); |
| 178 } | 170 } |
| 179 } | 171 } |
| 180 last_simulate_ = NULL; | 172 last_simulate_ = NULL; |
| 181 break; | 173 break; |
| 182 } | 174 } |
| 183 case HValue::kDeoptimize: { | 175 case HValue::kDeoptimize: { |
| 184 // Keep all environment slots alive. | 176 // Keep all environment slots alive. |
| 185 HDeoptimize* deopt = HDeoptimize::cast(instr); | 177 HDeoptimize* deopt = HDeoptimize::cast(instr); |
| 186 for (int i = deopt->first_local_index(); | 178 for (int i = deopt->first_local_index(); |
| 187 i < deopt->first_expression_index(); ++i) { | 179 i < deopt->first_expression_index(); ++i) { |
| 188 live->Add(i); | 180 live->Add(i); |
| 189 } | 181 } |
| 190 break; | 182 break; |
| 191 } | 183 } |
| 192 case HValue::kSimulate: | 184 case HValue::kSimulate: |
| 193 last_simulate_ = HSimulate::cast(instr); | 185 last_simulate_ = HSimulate::cast(instr); |
| 194 went_live_since_last_simulate_->Clear(); | 186 went_live_since_last_simulate_.Clear(); |
| 195 break; | 187 break; |
| 196 default: | 188 default: |
| 197 break; | 189 break; |
| 198 } | 190 } |
| 199 } | 191 } |
| 200 | 192 |
| 201 | 193 |
| 202 void EnvironmentSlotLivenessAnalyzer::AnalyzeAndTrim() { | 194 void HEnvironmentLivenessAnalysisPhase::Run() { |
| 203 HPhase phase("H_EnvironmentLivenessAnalysis", graph_); | 195 ASSERT(maximum_environment_size_ > 0); |
| 204 if (maximum_environment_size_ == 0) return; | |
| 205 | 196 |
| 206 // Main iteration. Compute liveness of environment slots, and store it | 197 // Main iteration. Compute liveness of environment slots, and store it |
| 207 // for each block until it doesn't change any more. For efficiency, visit | 198 // for each block until it doesn't change any more. For efficiency, visit |
| 208 // blocks in reverse order and walk backwards through each block. We | 199 // blocks in reverse order and walk backwards through each block. We |
| 209 // need several iterations to propagate liveness through nested loops. | 200 // need several iterations to propagate liveness through nested loops. |
| 210 BitVector* live = new(zone()) BitVector(maximum_environment_size_, zone()); | 201 BitVector live(maximum_environment_size_, zone()); |
| 211 BitVector* worklist = new(zone()) BitVector(block_count_, zone()); | 202 BitVector worklist(block_count_, zone()); |
| 212 for (int i = 0; i < block_count_; ++i) { | 203 for (int i = 0; i < block_count_; ++i) { |
| 213 worklist->Add(i); | 204 worklist.Add(i); |
| 214 } | 205 } |
| 215 while (!worklist->IsEmpty()) { | 206 while (!worklist.IsEmpty()) { |
| 216 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { | 207 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { |
| 217 if (!worklist->Contains(block_id)) { | 208 if (!worklist.Contains(block_id)) { |
| 218 continue; | 209 continue; |
| 219 } | 210 } |
| 220 worklist->Remove(block_id); | 211 worklist.Remove(block_id); |
| 221 last_simulate_ = NULL; | 212 last_simulate_ = NULL; |
| 222 | 213 |
| 223 HBasicBlock* block = graph_->blocks()->at(block_id); | 214 HBasicBlock* block = graph()->blocks()->at(block_id); |
| 224 UpdateLivenessAtBlockEnd(block, live); | 215 UpdateLivenessAtBlockEnd(block, &live); |
| 225 | 216 |
| 226 for (HInstruction* instr = block->last(); instr != NULL; | 217 for (HInstruction* instr = block->last(); instr != NULL; |
| 227 instr = instr->previous()) { | 218 instr = instr->previous()) { |
| 228 UpdateLivenessAtInstruction(instr, live); | 219 UpdateLivenessAtInstruction(instr, &live); |
| 229 } | 220 } |
| 230 | 221 |
| 231 // Reached the start of the block, do necessary bookkeeping: | 222 // Reached the start of the block, do necessary bookkeeping: |
| 232 // store computed information for this block and add predecessors | 223 // store computed information for this block and add predecessors |
| 233 // to the work list as necessary. | 224 // to the work list as necessary. |
| 234 first_simulate_->Set(block_id, last_simulate_); | 225 first_simulate_.Set(block_id, last_simulate_); |
| 235 first_simulate_invalid_for_index_->at(block_id)->CopyFrom( | 226 first_simulate_invalid_for_index_[block_id]->CopyFrom( |
| 236 *went_live_since_last_simulate_); | 227 went_live_since_last_simulate_); |
| 237 if (live_at_block_start_->at(block_id)->UnionIsChanged(*live)) { | 228 if (live_at_block_start_[block_id]->UnionIsChanged(live)) { |
| 238 for (int i = 0; i < block->predecessors()->length(); ++i) { | 229 for (int i = 0; i < block->predecessors()->length(); ++i) { |
| 239 worklist->Add(block->predecessors()->at(i)->block_id()); | 230 worklist.Add(block->predecessors()->at(i)->block_id()); |
| 240 } | 231 } |
| 241 if (block->IsInlineReturnTarget()) { | 232 if (block->IsInlineReturnTarget()) { |
| 242 worklist->Add(block->inlined_entry_block()->block_id()); | 233 worklist.Add(block->inlined_entry_block()->block_id()); |
| 243 } | 234 } |
| 244 } | 235 } |
| 245 } | 236 } |
| 246 // Only collect bind/lookup instructions during the first pass. | 237 // Only collect bind/lookup instructions during the first pass. |
| 247 collect_markers_ = false; | 238 collect_markers_ = false; |
| 248 } | 239 } |
| 249 | 240 |
| 250 // Analysis finished. Zap dead environment slots. | 241 // Analysis finished. Zap dead environment slots. |
| 251 for (int i = 0; i < markers_->length(); ++i) { | 242 for (int i = 0; i < markers_.length(); ++i) { |
| 252 ZapEnvironmentSlotsForInstruction(markers_->at(i)); | 243 ZapEnvironmentSlotsForInstruction(markers_[i]); |
| 253 } | 244 } |
| 254 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { | 245 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { |
| 255 HBasicBlock* block = graph_->blocks()->at(block_id); | 246 HBasicBlock* block = graph()->blocks()->at(block_id); |
| 256 UpdateLivenessAtBlockEnd(block, live); | 247 UpdateLivenessAtBlockEnd(block, &live); |
| 257 ZapEnvironmentSlotsInSuccessors(block, live); | 248 ZapEnvironmentSlotsInSuccessors(block, &live); |
| 258 } | 249 } |
| 259 | 250 |
| 260 // Finally, remove the HEnvironment{Bind,Lookup} markers. | 251 // Finally, remove the HEnvironment{Bind,Lookup} markers. |
| 261 for (int i = 0; i < markers_->length(); ++i) { | 252 for (int i = 0; i < markers_.length(); ++i) { |
| 262 markers_->at(i)->DeleteAndReplaceWith(NULL); | 253 markers_[i]->DeleteAndReplaceWith(NULL); |
| 263 } | 254 } |
| 264 } | 255 } |
| 265 | 256 |
| 266 } } // namespace v8::internal | 257 } } // namespace v8::internal |
| OLD | NEW |