| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 | |
| 6 #include "src/hydrogen-environment-liveness.h" | |
| 7 | |
| 8 | |
| 9 namespace v8 { | |
| 10 namespace internal { | |
| 11 | |
| 12 | |
| 13 HEnvironmentLivenessAnalysisPhase::HEnvironmentLivenessAnalysisPhase( | |
| 14 HGraph* graph) | |
| 15 : HPhase("H_Environment liveness analysis", graph), | |
| 16 block_count_(graph->blocks()->length()), | |
| 17 maximum_environment_size_(graph->maximum_environment_size()), | |
| 18 live_at_block_start_(block_count_, zone()), | |
| 19 first_simulate_(block_count_, zone()), | |
| 20 first_simulate_invalid_for_index_(block_count_, zone()), | |
| 21 markers_(maximum_environment_size_, zone()), | |
| 22 collect_markers_(true), | |
| 23 last_simulate_(NULL), | |
| 24 went_live_since_last_simulate_(maximum_environment_size_, zone()) { | |
| 25 DCHECK(maximum_environment_size_ > 0); | |
| 26 for (int i = 0; i < block_count_; ++i) { | |
| 27 live_at_block_start_.Add( | |
| 28 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); | |
| 29 first_simulate_.Add(NULL, zone()); | |
| 30 first_simulate_invalid_for_index_.Add( | |
| 31 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 | |
| 36 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlot( | |
| 37 int index, HSimulate* simulate) { | |
| 38 int operand_index = simulate->ToOperandIndex(index); | |
| 39 if (operand_index == -1) { | |
| 40 simulate->AddAssignedValue(index, graph()->GetConstantUndefined()); | |
| 41 } else { | |
| 42 simulate->SetOperandAt(operand_index, graph()->GetConstantUndefined()); | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 | |
| 47 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlotsInSuccessors( | |
| 48 HBasicBlock* block, BitVector* live) { | |
| 49 // When a value is live in successor A but dead in B, we must | |
| 50 // explicitly zap it in B. | |
| 51 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | |
| 52 HBasicBlock* successor = it.Current(); | |
| 53 int successor_id = successor->block_id(); | |
| 54 BitVector* live_in_successor = live_at_block_start_[successor_id]; | |
| 55 if (live_in_successor->Equals(*live)) continue; | |
| 56 for (int i = 0; i < live->length(); ++i) { | |
| 57 if (!live->Contains(i)) continue; | |
| 58 if (live_in_successor->Contains(i)) continue; | |
| 59 if (first_simulate_invalid_for_index_.at(successor_id)->Contains(i)) { | |
| 60 continue; | |
| 61 } | |
| 62 HSimulate* simulate = first_simulate_.at(successor_id); | |
| 63 if (simulate == NULL) continue; | |
| 64 DCHECK(VerifyClosures(simulate->closure(), | |
| 65 block->last_environment()->closure())); | |
| 66 ZapEnvironmentSlot(i, simulate); | |
| 67 } | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 | |
| 72 void HEnvironmentLivenessAnalysisPhase::ZapEnvironmentSlotsForInstruction( | |
| 73 HEnvironmentMarker* marker) { | |
| 74 if (!marker->CheckFlag(HValue::kEndsLiveRange)) return; | |
| 75 HSimulate* simulate = marker->next_simulate(); | |
| 76 if (simulate != NULL) { | |
| 77 DCHECK(VerifyClosures(simulate->closure(), marker->closure())); | |
| 78 ZapEnvironmentSlot(marker->index(), simulate); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 | |
| 83 void HEnvironmentLivenessAnalysisPhase::UpdateLivenessAtBlockEnd( | |
| 84 HBasicBlock* block, | |
| 85 BitVector* live) { | |
| 86 // Liveness at the end of each block: union of liveness in successors. | |
| 87 live->Clear(); | |
| 88 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { | |
| 89 live->Union(*live_at_block_start_[it.Current()->block_id()]); | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 | |
| 94 void HEnvironmentLivenessAnalysisPhase::UpdateLivenessAtInstruction( | |
| 95 HInstruction* instr, | |
| 96 BitVector* live) { | |
| 97 switch (instr->opcode()) { | |
| 98 case HValue::kEnvironmentMarker: { | |
| 99 HEnvironmentMarker* marker = HEnvironmentMarker::cast(instr); | |
| 100 int index = marker->index(); | |
| 101 if (!live->Contains(index)) { | |
| 102 marker->SetFlag(HValue::kEndsLiveRange); | |
| 103 } else { | |
| 104 marker->ClearFlag(HValue::kEndsLiveRange); | |
| 105 } | |
| 106 if (!went_live_since_last_simulate_.Contains(index)) { | |
| 107 marker->set_next_simulate(last_simulate_); | |
| 108 } | |
| 109 if (marker->kind() == HEnvironmentMarker::LOOKUP) { | |
| 110 live->Add(index); | |
| 111 } else { | |
| 112 DCHECK(marker->kind() == HEnvironmentMarker::BIND); | |
| 113 live->Remove(index); | |
| 114 went_live_since_last_simulate_.Add(index); | |
| 115 } | |
| 116 if (collect_markers_) { | |
| 117 // Populate |markers_| list during the first pass. | |
| 118 markers_.Add(marker, zone()); | |
| 119 } | |
| 120 break; | |
| 121 } | |
| 122 case HValue::kLeaveInlined: | |
| 123 // No environment values are live at the end of an inlined section. | |
| 124 live->Clear(); | |
| 125 last_simulate_ = NULL; | |
| 126 | |
| 127 // The following DCHECKs guard the assumption used in case | |
| 128 // kEnterInlined below: | |
| 129 DCHECK(instr->next()->IsSimulate()); | |
| 130 DCHECK(instr->next()->next()->IsGoto()); | |
| 131 | |
| 132 break; | |
| 133 case HValue::kEnterInlined: { | |
| 134 // Those environment values are live that are live at any return | |
| 135 // target block. Here we make use of the fact that the end of an | |
| 136 // inline sequence always looks like this: HLeaveInlined, HSimulate, | |
| 137 // HGoto (to return_target block), with no environment lookups in | |
| 138 // between (see DCHECKs above). | |
| 139 HEnterInlined* enter = HEnterInlined::cast(instr); | |
| 140 live->Clear(); | |
| 141 for (int i = 0; i < enter->return_targets()->length(); ++i) { | |
| 142 int return_id = enter->return_targets()->at(i)->block_id(); | |
| 143 live->Union(*live_at_block_start_[return_id]); | |
| 144 } | |
| 145 last_simulate_ = NULL; | |
| 146 break; | |
| 147 } | |
| 148 case HValue::kSimulate: | |
| 149 last_simulate_ = HSimulate::cast(instr); | |
| 150 went_live_since_last_simulate_.Clear(); | |
| 151 break; | |
| 152 default: | |
| 153 break; | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 | |
| 158 void HEnvironmentLivenessAnalysisPhase::Run() { | |
| 159 DCHECK(maximum_environment_size_ > 0); | |
| 160 | |
| 161 // Main iteration. Compute liveness of environment slots, and store it | |
| 162 // for each block until it doesn't change any more. For efficiency, visit | |
| 163 // blocks in reverse order and walk backwards through each block. We | |
| 164 // need several iterations to propagate liveness through nested loops. | |
| 165 BitVector live(maximum_environment_size_, zone()); | |
| 166 BitVector worklist(block_count_, zone()); | |
| 167 for (int i = 0; i < block_count_; ++i) { | |
| 168 worklist.Add(i); | |
| 169 } | |
| 170 while (!worklist.IsEmpty()) { | |
| 171 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { | |
| 172 if (!worklist.Contains(block_id)) { | |
| 173 continue; | |
| 174 } | |
| 175 worklist.Remove(block_id); | |
| 176 last_simulate_ = NULL; | |
| 177 | |
| 178 HBasicBlock* block = graph()->blocks()->at(block_id); | |
| 179 UpdateLivenessAtBlockEnd(block, &live); | |
| 180 | |
| 181 for (HInstruction* instr = block->end(); instr != NULL; | |
| 182 instr = instr->previous()) { | |
| 183 UpdateLivenessAtInstruction(instr, &live); | |
| 184 } | |
| 185 | |
| 186 // Reached the start of the block, do necessary bookkeeping: | |
| 187 // store computed information for this block and add predecessors | |
| 188 // to the work list as necessary. | |
| 189 first_simulate_.Set(block_id, last_simulate_); | |
| 190 first_simulate_invalid_for_index_[block_id]->CopyFrom( | |
| 191 went_live_since_last_simulate_); | |
| 192 if (live_at_block_start_[block_id]->UnionIsChanged(live)) { | |
| 193 for (int i = 0; i < block->predecessors()->length(); ++i) { | |
| 194 worklist.Add(block->predecessors()->at(i)->block_id()); | |
| 195 } | |
| 196 if (block->IsInlineReturnTarget()) { | |
| 197 worklist.Add(block->inlined_entry_block()->block_id()); | |
| 198 } | |
| 199 } | |
| 200 } | |
| 201 // Only collect bind/lookup instructions during the first pass. | |
| 202 collect_markers_ = false; | |
| 203 } | |
| 204 | |
| 205 // Analysis finished. Zap dead environment slots. | |
| 206 for (int i = 0; i < markers_.length(); ++i) { | |
| 207 ZapEnvironmentSlotsForInstruction(markers_[i]); | |
| 208 } | |
| 209 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { | |
| 210 HBasicBlock* block = graph()->blocks()->at(block_id); | |
| 211 UpdateLivenessAtBlockEnd(block, &live); | |
| 212 ZapEnvironmentSlotsInSuccessors(block, &live); | |
| 213 } | |
| 214 | |
| 215 // Finally, remove the HEnvironment{Bind,Lookup} markers. | |
| 216 for (int i = 0; i < markers_.length(); ++i) { | |
| 217 markers_[i]->DeleteAndReplaceWith(NULL); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 | |
| 222 #ifdef DEBUG | |
| 223 bool HEnvironmentLivenessAnalysisPhase::VerifyClosures( | |
| 224 Handle<JSFunction> a, Handle<JSFunction> b) { | |
| 225 Heap::RelocationLock for_heap_access(isolate()->heap()); | |
| 226 AllowHandleDereference for_verification; | |
| 227 return a.is_identical_to(b); | |
| 228 } | |
| 229 #endif | |
| 230 | |
| 231 } // namespace internal | |
| 232 } // namespace v8 | |
| OLD | NEW |