| 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 #include "src/hydrogen-flow-engine.h" | |
| 6 #include "src/hydrogen-instructions.h" | |
| 7 #include "src/hydrogen-removable-simulates.h" | |
| 8 | |
| 9 namespace v8 { | |
| 10 namespace internal { | |
| 11 | |
| 12 class State : public ZoneObject { | |
| 13 public: | |
| 14 explicit State(Zone* zone) | |
| 15 : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { } | |
| 16 | |
| 17 State* Process(HInstruction* instr, Zone* zone) { | |
| 18 if (FLAG_trace_removable_simulates) { | |
| 19 PrintF("[%s with state %p in B%d: #%d %s]\n", | |
| 20 mode_ == NORMAL ? "processing" : "collecting", | |
| 21 reinterpret_cast<void*>(this), instr->block()->block_id(), | |
| 22 instr->id(), instr->Mnemonic()); | |
| 23 } | |
| 24 // Forward-merge "trains" of simulates after an instruction with observable | |
| 25 // side effects to keep live ranges short. | |
| 26 if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) { | |
| 27 if (instr->IsSimulate()) { | |
| 28 HSimulate* current_simulate = HSimulate::cast(instr); | |
| 29 if (current_simulate->is_candidate_for_removal() && | |
| 30 !current_simulate->ast_id().IsNone()) { | |
| 31 Remember(current_simulate); | |
| 32 return this; | |
| 33 } | |
| 34 } | |
| 35 FlushSimulates(); | |
| 36 mode_ = NORMAL; | |
| 37 } | |
| 38 // Ensure there's a non-foldable HSimulate before an HEnterInlined to avoid | |
| 39 // folding across HEnterInlined. | |
| 40 DCHECK(!(instr->IsEnterInlined() && | |
| 41 HSimulate::cast(instr->previous())->is_candidate_for_removal())); | |
| 42 if (instr->IsLeaveInlined() || instr->IsReturn()) { | |
| 43 // Never fold simulates from inlined environments into simulates in the | |
| 44 // outer environment. Simply remove all accumulated simulates without | |
| 45 // merging. This is safe because simulates after instructions with side | |
| 46 // effects are never added to the merge list. The same reasoning holds for | |
| 47 // return instructions. | |
| 48 RemoveSimulates(); | |
| 49 return this; | |
| 50 } | |
| 51 if (instr->IsControlInstruction()) { | |
| 52 // Merge the accumulated simulates at the end of the block. | |
| 53 FlushSimulates(); | |
| 54 return this; | |
| 55 } | |
| 56 if (instr->IsCapturedObject()) { | |
| 57 // Do not merge simulates across captured objects - captured objects | |
| 58 // change environments during environment replay, and such changes | |
| 59 // would not be reflected in the simulate. | |
| 60 FlushSimulates(); | |
| 61 return this; | |
| 62 } | |
| 63 // Skip the non-simulates and the first simulate. | |
| 64 if (!instr->IsSimulate()) return this; | |
| 65 if (first_) { | |
| 66 first_ = false; | |
| 67 return this; | |
| 68 } | |
| 69 HSimulate* current_simulate = HSimulate::cast(instr); | |
| 70 if (!current_simulate->is_candidate_for_removal()) { | |
| 71 Remember(current_simulate); | |
| 72 FlushSimulates(); | |
| 73 } else if (current_simulate->ast_id().IsNone()) { | |
| 74 DCHECK(current_simulate->next()->IsEnterInlined()); | |
| 75 FlushSimulates(); | |
| 76 } else if (current_simulate->previous()->HasObservableSideEffects()) { | |
| 77 Remember(current_simulate); | |
| 78 mode_ = COLLECT_CONSECUTIVE_SIMULATES; | |
| 79 } else { | |
| 80 Remember(current_simulate); | |
| 81 } | |
| 82 | |
| 83 return this; | |
| 84 } | |
| 85 | |
| 86 static State* Merge(State* succ_state, | |
| 87 HBasicBlock* succ_block, | |
| 88 State* pred_state, | |
| 89 HBasicBlock* pred_block, | |
| 90 Zone* zone) { | |
| 91 return (succ_state == NULL) | |
| 92 ? pred_state->Copy(succ_block, pred_block, zone) | |
| 93 : succ_state->Merge(succ_block, pred_state, pred_block, zone); | |
| 94 } | |
| 95 | |
| 96 static State* Finish(State* state, HBasicBlock* block, Zone* zone) { | |
| 97 if (FLAG_trace_removable_simulates) { | |
| 98 PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state), | |
| 99 block->block_id()); | |
| 100 } | |
| 101 // For our current local analysis, we should not remember simulates across | |
| 102 // block boundaries. | |
| 103 DCHECK(!state->HasRememberedSimulates()); | |
| 104 // Nasty heuristic: Never remove the first simulate in a block. This | |
| 105 // just so happens to have a beneficial effect on register allocation. | |
| 106 state->first_ = true; | |
| 107 return state; | |
| 108 } | |
| 109 | |
| 110 private: | |
| 111 explicit State(const State& other) | |
| 112 : zone_(other.zone_), | |
| 113 mergelist_(other.mergelist_, other.zone_), | |
| 114 first_(other.first_), | |
| 115 mode_(other.mode_) { } | |
| 116 | |
| 117 enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES }; | |
| 118 | |
| 119 bool HasRememberedSimulates() const { return !mergelist_.is_empty(); } | |
| 120 | |
| 121 void Remember(HSimulate* sim) { | |
| 122 mergelist_.Add(sim, zone_); | |
| 123 } | |
| 124 | |
| 125 void FlushSimulates() { | |
| 126 if (HasRememberedSimulates()) { | |
| 127 mergelist_.RemoveLast()->MergeWith(&mergelist_); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 void RemoveSimulates() { | |
| 132 while (HasRememberedSimulates()) { | |
| 133 mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) { | |
| 138 State* copy = new(zone) State(*this); | |
| 139 if (FLAG_trace_removable_simulates) { | |
| 140 PrintF("[copy state %p from B%d to new state %p for B%d]\n", | |
| 141 reinterpret_cast<void*>(this), pred_block->block_id(), | |
| 142 reinterpret_cast<void*>(copy), succ_block->block_id()); | |
| 143 } | |
| 144 return copy; | |
| 145 } | |
| 146 | |
| 147 State* Merge(HBasicBlock* succ_block, | |
| 148 State* pred_state, | |
| 149 HBasicBlock* pred_block, | |
| 150 Zone* zone) { | |
| 151 // For our current local analysis, we should not remember simulates across | |
| 152 // block boundaries. | |
| 153 DCHECK(!pred_state->HasRememberedSimulates()); | |
| 154 DCHECK(!HasRememberedSimulates()); | |
| 155 if (FLAG_trace_removable_simulates) { | |
| 156 PrintF("[merge state %p from B%d into %p for B%d]\n", | |
| 157 reinterpret_cast<void*>(pred_state), pred_block->block_id(), | |
| 158 reinterpret_cast<void*>(this), succ_block->block_id()); | |
| 159 } | |
| 160 return this; | |
| 161 } | |
| 162 | |
| 163 Zone* zone_; | |
| 164 ZoneList<HSimulate*> mergelist_; | |
| 165 bool first_; | |
| 166 Mode mode_; | |
| 167 }; | |
| 168 | |
| 169 | |
| 170 // We don't use effects here. | |
| 171 class Effects : public ZoneObject { | |
| 172 public: | |
| 173 explicit Effects(Zone* zone) { } | |
| 174 bool Disabled() { return true; } | |
| 175 void Process(HInstruction* instr, Zone* zone) { } | |
| 176 void Apply(State* state) { } | |
| 177 void Union(Effects* that, Zone* zone) { } | |
| 178 }; | |
| 179 | |
| 180 | |
| 181 void HMergeRemovableSimulatesPhase::Run() { | |
| 182 HFlowEngine<State, Effects> engine(graph(), zone()); | |
| 183 State* state = new(zone()) State(zone()); | |
| 184 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state); | |
| 185 } | |
| 186 | |
| 187 } // namespace internal | |
| 188 } // namespace v8 | |
| OLD | NEW |