OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 |
| 29 #include "hydrogen-environment-liveness.h" |
| 30 |
| 31 |
| 32 namespace v8 { |
| 33 namespace internal { |
| 34 |
| 35 |
| 36 EnvironmentSlotLivenessAnalyzer::EnvironmentSlotLivenessAnalyzer( |
| 37 HGraph* graph) |
| 38 : graph_(graph), |
| 39 zone_(graph->isolate()), |
| 40 zone_scope_(&zone_, DELETE_ON_EXIT), |
| 41 block_count_(graph->blocks()->length()), |
| 42 maximum_environment_size_(graph->maximum_environment_size()), |
| 43 collect_markers_(true), |
| 44 last_simulate_(NULL) { |
| 45 if (maximum_environment_size_ == 0) return; |
| 46 |
| 47 live_at_block_start_ = |
| 48 new(zone()) ZoneList<BitVector*>(block_count_, zone()); |
| 49 first_simulate_ = new(zone()) ZoneList<HSimulate*>(block_count_, zone()); |
| 50 first_simulate_invalid_for_index_ = |
| 51 new(zone()) ZoneList<BitVector*>(block_count_, zone()); |
| 52 markers_ = new(zone()) |
| 53 ZoneList<HEnvironmentMarker*>(maximum_environment_size_, zone()); |
| 54 went_live_since_last_simulate_ = |
| 55 new(zone()) BitVector(maximum_environment_size_, zone()); |
| 56 |
| 57 for (int i = 0; i < block_count_; ++i) { |
| 58 live_at_block_start_->Add( |
| 59 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); |
| 60 first_simulate_->Add(NULL, zone()); |
| 61 first_simulate_invalid_for_index_->Add( |
| 62 new(zone()) BitVector(maximum_environment_size_, zone()), zone()); |
| 63 } |
| 64 } |
| 65 |
| 66 |
| 67 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlot(int index, |
| 68 HSimulate* simulate) { |
| 69 int operand_index = simulate->ToOperandIndex(index); |
| 70 if (operand_index == -1) { |
| 71 simulate->AddAssignedValue(index, graph_->GetConstantUndefined()); |
| 72 } else { |
| 73 simulate->SetOperandAt(operand_index, graph_->GetConstantUndefined()); |
| 74 } |
| 75 } |
| 76 |
| 77 |
| 78 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlotsInSuccessors( |
| 79 HBasicBlock* block, |
| 80 BitVector* live) { |
| 81 // When a value is live in successor A but dead in B, we must |
| 82 // explicitly zap it in B. |
| 83 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 84 HBasicBlock* successor = it.Current(); |
| 85 int successor_id = successor->block_id(); |
| 86 BitVector* live_in_successor = live_at_block_start_->at(successor_id); |
| 87 if (live_in_successor->Equals(*live)) continue; |
| 88 for (int i = 0; i < live->length(); ++i) { |
| 89 if (!live->Contains(i)) continue; |
| 90 if (live_in_successor->Contains(i)) continue; |
| 91 if (first_simulate_invalid_for_index_->at(successor_id)->Contains(i)) { |
| 92 continue; |
| 93 } |
| 94 HSimulate* simulate = first_simulate_->at(successor_id); |
| 95 if (simulate == NULL) continue; |
| 96 ASSERT(simulate->closure().is_identical_to( |
| 97 block->last_environment()->closure())); |
| 98 ZapEnvironmentSlot(i, simulate); |
| 99 } |
| 100 } |
| 101 } |
| 102 |
| 103 |
| 104 void EnvironmentSlotLivenessAnalyzer::ZapEnvironmentSlotsForInstruction( |
| 105 HEnvironmentMarker* marker) { |
| 106 if (!marker->CheckFlag(HValue::kEndsLiveRange)) return; |
| 107 HSimulate* simulate = marker->next_simulate(); |
| 108 if (simulate != NULL) { |
| 109 ASSERT(simulate->closure().is_identical_to(marker->closure())); |
| 110 ZapEnvironmentSlot(marker->index(), simulate); |
| 111 } |
| 112 } |
| 113 |
| 114 |
| 115 void EnvironmentSlotLivenessAnalyzer::UpdateLivenessAtBlockEnd( |
| 116 HBasicBlock* block, |
| 117 BitVector* live) { |
| 118 // Liveness at the end of each block: union of liveness in successors. |
| 119 live->Clear(); |
| 120 for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) { |
| 121 live->Union(*live_at_block_start_->at(it.Current()->block_id())); |
| 122 } |
| 123 } |
| 124 |
| 125 |
| 126 void EnvironmentSlotLivenessAnalyzer::UpdateLivenessAtInstruction( |
| 127 HInstruction* instr, |
| 128 BitVector* live) { |
| 129 switch (instr->opcode()) { |
| 130 case HValue::kEnvironmentMarker: { |
| 131 HEnvironmentMarker* marker = HEnvironmentMarker::cast(instr); |
| 132 int index = marker->index(); |
| 133 if (!live->Contains(index)) { |
| 134 marker->SetFlag(HValue::kEndsLiveRange); |
| 135 } else { |
| 136 marker->ClearFlag(HValue::kEndsLiveRange); |
| 137 } |
| 138 if (!went_live_since_last_simulate_->Contains(index)) { |
| 139 marker->set_next_simulate(last_simulate_); |
| 140 } |
| 141 if (marker->kind() == HEnvironmentMarker::LOOKUP) { |
| 142 live->Add(index); |
| 143 } else { |
| 144 ASSERT(marker->kind() == HEnvironmentMarker::BIND); |
| 145 live->Remove(index); |
| 146 went_live_since_last_simulate_->Add(index); |
| 147 } |
| 148 if (collect_markers_) { |
| 149 // Populate |markers_| list during the first pass. |
| 150 markers_->Add(marker, &zone_); |
| 151 } |
| 152 break; |
| 153 } |
| 154 case HValue::kLeaveInlined: |
| 155 // No environment values are live at the end of an inlined section. |
| 156 live->Clear(); |
| 157 last_simulate_ = NULL; |
| 158 |
| 159 // The following ASSERTs guard the assumption used in case |
| 160 // kEnterInlined below: |
| 161 ASSERT(instr->next()->IsSimulate()); |
| 162 ASSERT(instr->next()->next()->IsGoto()); |
| 163 |
| 164 break; |
| 165 case HValue::kEnterInlined: { |
| 166 // Those environment values are live that are live at any return |
| 167 // target block. Here we make use of the fact that the end of an |
| 168 // inline sequence always looks like this: HLeaveInlined, HSimulate, |
| 169 // HGoto (to return_target block), with no environment lookups in |
| 170 // between (see ASSERTs above). |
| 171 HEnterInlined* enter = HEnterInlined::cast(instr); |
| 172 live->Clear(); |
| 173 for (int i = 0; i < enter->return_targets()->length(); ++i) { |
| 174 int return_id = enter->return_targets()->at(i)->block_id(); |
| 175 // When an AbnormalExit is involved, it can happen that the return |
| 176 // target block doesn't actually exist. |
| 177 if (return_id < live_at_block_start_->length()) { |
| 178 live->Union(*live_at_block_start_->at(return_id)); |
| 179 } |
| 180 } |
| 181 last_simulate_ = NULL; |
| 182 break; |
| 183 } |
| 184 case HValue::kDeoptimize: { |
| 185 // Keep all environment slots alive. |
| 186 HDeoptimize* deopt = HDeoptimize::cast(instr); |
| 187 for (int i = deopt->first_local_index(); |
| 188 i < deopt->first_expression_index(); ++i) { |
| 189 live->Add(i); |
| 190 } |
| 191 break; |
| 192 } |
| 193 case HValue::kSimulate: |
| 194 last_simulate_ = HSimulate::cast(instr); |
| 195 went_live_since_last_simulate_->Clear(); |
| 196 break; |
| 197 default: |
| 198 break; |
| 199 } |
| 200 } |
| 201 |
| 202 |
| 203 void EnvironmentSlotLivenessAnalyzer::AnalyzeAndTrim() { |
| 204 HPhase phase("H_EnvironmentLivenessAnalysis", graph_); |
| 205 if (maximum_environment_size_ == 0) return; |
| 206 |
| 207 // Main iteration. Compute liveness of environment slots, and store it |
| 208 // for each block until it doesn't change any more. For efficiency, visit |
| 209 // blocks in reverse order and walk backwards through each block. We |
| 210 // need several iterations to propagate liveness through nested loops. |
| 211 BitVector* live = new(zone()) BitVector(maximum_environment_size_, zone()); |
| 212 BitVector* worklist = new(zone()) BitVector(block_count_, zone()); |
| 213 for (int i = 0; i < block_count_; ++i) { |
| 214 worklist->Add(i); |
| 215 } |
| 216 while (!worklist->IsEmpty()) { |
| 217 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { |
| 218 if (!worklist->Contains(block_id)) { |
| 219 continue; |
| 220 } |
| 221 worklist->Remove(block_id); |
| 222 last_simulate_ = NULL; |
| 223 |
| 224 HBasicBlock* block = graph_->blocks()->at(block_id); |
| 225 UpdateLivenessAtBlockEnd(block, live); |
| 226 |
| 227 for (HInstruction* instr = block->last(); instr != NULL; |
| 228 instr = instr->previous()) { |
| 229 UpdateLivenessAtInstruction(instr, live); |
| 230 } |
| 231 |
| 232 // Reached the start of the block, do necessary bookkeeping: |
| 233 // store computed information for this block and add predecessors |
| 234 // to the work list as necessary. |
| 235 first_simulate_->Set(block_id, last_simulate_); |
| 236 first_simulate_invalid_for_index_->at(block_id)->CopyFrom( |
| 237 *went_live_since_last_simulate_); |
| 238 if (live_at_block_start_->at(block_id)->UnionIsChanged(*live)) { |
| 239 for (int i = 0; i < block->predecessors()->length(); ++i) { |
| 240 worklist->Add(block->predecessors()->at(i)->block_id()); |
| 241 } |
| 242 if (block->IsInlineReturnTarget()) { |
| 243 worklist->Add(block->inlined_entry_block()->block_id()); |
| 244 } |
| 245 } |
| 246 } |
| 247 // Only collect bind/lookup instructions during the first pass. |
| 248 collect_markers_ = false; |
| 249 } |
| 250 |
| 251 // Analysis finished. Zap dead environment slots. |
| 252 for (int i = 0; i < markers_->length(); ++i) { |
| 253 ZapEnvironmentSlotsForInstruction(markers_->at(i)); |
| 254 } |
| 255 for (int block_id = block_count_ - 1; block_id >= 0; --block_id) { |
| 256 HBasicBlock* block = graph_->blocks()->at(block_id); |
| 257 UpdateLivenessAtBlockEnd(block, live); |
| 258 ZapEnvironmentSlotsInSuccessors(block, live); |
| 259 } |
| 260 |
| 261 // Finally, remove the HEnvironment{Bind,Lookup} markers. |
| 262 for (int i = 0; i < markers_->length(); ++i) { |
| 263 markers_->at(i)->DeleteAndReplaceWith(NULL); |
| 264 } |
| 265 } |
| 266 |
| 267 } } // namespace v8::internal |
OLD | NEW |