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 |