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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 56 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
57 HInstruction* instr = it.Current(); | 57 HInstruction* instr = it.Current(); |
58 if (instr->IsAllocate()) { | 58 if (instr->IsAllocate()) { |
59 CollectIfNoEscapingUses(instr); | 59 CollectIfNoEscapingUses(instr); |
60 } | 60 } |
61 } | 61 } |
62 } | 62 } |
63 } | 63 } |
64 | 64 |
65 | 65 |
66 HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) { | |
67 Zone* zone = graph()->zone(); | |
68 HCapturedObject* state = new(zone) HCapturedObject(number_of_values_, zone); | |
69 state->InsertAfter(previous); | |
70 return state; | |
71 } | |
72 | |
73 | |
74 // Create a new state for replacing HAllocate instructions. | |
75 HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation( | |
76 HInstruction* previous) { | |
77 HConstant* undefined = graph()->GetConstantUndefined(); | |
78 HCapturedObject* state = NewState(previous); | |
79 for (int index = 0; index < number_of_values_; index++) { | |
80 state->SetOperandAt(index, undefined); | |
81 } | |
82 return state; | |
83 } | |
84 | |
85 | |
86 // Create a new state full of phis for loop header entries. | |
87 HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader( | |
88 HInstruction* previous, HCapturedObject* old_state) { | |
89 HBasicBlock* block = previous->block(); | |
90 HCapturedObject* state = NewState(previous); | |
91 for (int index = 0; index < number_of_values_; index++) { | |
92 HValue* operand = old_state->OperandAt(index); | |
93 HPhi* phi = NewPhiAndInsert(block, operand, index); | |
94 state->SetOperandAt(index, phi); | |
95 } | |
96 return state; | |
97 } | |
98 | |
99 | |
100 // Create a new state by copying an existing one. | |
101 HCapturedObject* HEscapeAnalysisPhase::NewStateCopy( | |
102 HInstruction* previous, HCapturedObject* old_state) { | |
103 HCapturedObject* state = NewState(previous); | |
104 for (int index = 0; index < number_of_values_; index++) { | |
105 HValue* operand = old_state->OperandAt(index); | |
106 state->SetOperandAt(index, operand); | |
107 } | |
108 return state; | |
109 } | |
110 | |
111 | |
112 // Insert a newly created phi into the given block and fill all incoming | |
113 // edges with the given value. The merge index is chosen so that it is | |
114 // unique for this particular scalar replacement index. | |
115 HPhi* HEscapeAnalysisPhase::NewPhiAndInsert( | |
116 HBasicBlock* block, HValue* incoming_value, int index) { | |
117 Zone* zone = graph()->zone(); | |
118 HBasicBlock* pred = block->predecessors()->first(); | |
119 int phi_index = pred->last_environment()->length() + cumulative_values_; | |
120 HPhi* phi = new(zone) HPhi(phi_index + index, zone); | |
121 for (int i = 0; i < block->predecessors()->length(); i++) { | |
122 phi->AddInput(incoming_value); | |
123 } | |
124 block->AddPhi(phi); | |
125 return phi; | |
126 } | |
127 | |
128 | |
129 // Performs a forward data-flow analysis of all loads and stores on the | |
130 // given captured allocation. This uses a reverse post-order iteration | |
131 // over affected basic blocks. All non-escaping instructions are handled | |
132 // and replaced during the analysis. | |
133 void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) { | |
134 HBasicBlock* allocate_block = allocate->block(); | |
135 block_states_.AddBlock(NULL, graph()->blocks()->length(), zone()); | |
136 | |
137 // Iterate all blocks starting with the allocation block, since the | |
138 // allocation cannot dominate blocks that come before. | |
139 int start = allocate_block->block_id(); | |
140 for (int i = start; i < graph()->blocks()->length(); i++) { | |
141 HBasicBlock* block = graph()->blocks()->at(i); | |
142 HCapturedObject* state = StateAt(block); | |
143 | |
144 // Skip blocks that are not dominated by the captured allocation. | |
145 if (!allocate_block->Dominates(block) && allocate_block != block) continue; | |
146 if (FLAG_trace_escape_analysis) { | |
147 PrintF("Analyzing data-flow in B%d\n", block->block_id()); | |
148 } | |
149 | |
150 // Go through all instructions of the current block. | |
151 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | |
152 HInstruction* instr = it.Current(); | |
153 switch (instr->opcode()) { | |
154 case HValue::kAllocate: { | |
155 if (instr != allocate) continue; | |
156 state = NewStateForAllocation(allocate); | |
157 break; | |
158 } | |
159 case HValue::kLoadNamedField: { | |
160 HLoadNamedField* load = HLoadNamedField::cast(instr); | |
161 int index = load->access().offset() / kPointerSize; | |
162 if (load->object() != allocate) continue; | |
163 ASSERT(load->access().IsInobject()); | |
164 HValue* replacement = state->OperandAt(index); | |
165 load->DeleteAndReplaceWith(replacement); | |
166 if (FLAG_trace_escape_analysis) { | |
167 PrintF("Replacing load #%d with #%d (%s)\n", instr->id(), | |
168 replacement->id(), replacement->Mnemonic()); | |
169 } | |
170 break; | |
171 } | |
172 case HValue::kStoreNamedField: { | |
173 HStoreNamedField* store = HStoreNamedField::cast(instr); | |
174 int index = store->access().offset() / kPointerSize; | |
175 if (store->object() != allocate) continue; | |
176 ASSERT(store->access().IsInobject()); | |
177 state = NewStateCopy(store, state); | |
178 state->SetOperandAt(index, store->value()); | |
179 if (!store->transition().is_null()) { | |
180 // TODO(mstarzinger): Handle dereference is actually not allowed | |
181 // here. Fix this by allocating the HConstant at graph building. | |
182 AllowHandleDereference allow_deref; | |
183 Zone* graph_zone = graph()->zone(); | |
184 HConstant* map = new(graph_zone) HConstant(store->transition()); | |
185 map->FinalizeUniqueValueId(); | |
186 map->InsertBefore(store); | |
187 state->SetOperandAt(0, map); | |
188 } | |
189 store->DeleteAndReplaceWith(NULL); | |
190 if (FLAG_trace_escape_analysis) { | |
191 PrintF("Replacing store #%d%s\n", instr->id(), | |
192 store->transition().is_null() ? "" : " (with transition)"); | |
193 } | |
194 break; | |
195 } | |
196 case HValue::kSimulate: { | |
197 HSimulate* simulate = HSimulate::cast(instr); | |
198 // TODO(mstarzinger): This doesn't track deltas for values on the | |
199 // operand stack yet. Find a repro test case and fix this. | |
200 for (int i = 0; i < simulate->OperandCount(); i++) { | |
201 if (simulate->OperandAt(i) != allocate) continue; | |
202 simulate->SetOperandAt(i, state); | |
203 } | |
204 break; | |
205 } | |
206 case HValue::kArgumentsObject: | |
207 case HValue::kCapturedObject: { | |
208 for (int i = 0; i < instr->OperandCount(); i++) { | |
209 if (instr->OperandAt(i) != allocate) continue; | |
210 instr->SetOperandAt(i, state); | |
211 } | |
212 break; | |
213 } | |
214 case HValue::kCheckHeapObject: { | |
215 HCheckHeapObject* check = HCheckHeapObject::cast(instr); | |
216 if (check->value() != allocate) continue; | |
217 check->DeleteAndReplaceWith(NULL); | |
218 break; | |
219 } | |
220 case HValue::kCheckMaps: { | |
221 HCheckMaps* mapcheck = HCheckMaps::cast(instr); | |
222 if (mapcheck->value() != allocate) continue; | |
223 // TODO(mstarzinger): This approach breaks if the tracked map value | |
224 // is not a HConstant. Find a repro test case and fix this. | |
titzer
2013/08/06 12:15:47
Could it be the case that a later load or store st
Michael Starzinger
2013/08/07 10:51:16
Yes, this could unfortunately happen. We cannot en
| |
225 ASSERT(mapcheck->HasNoUses()); | |
226 mapcheck->DeleteAndReplaceWith(NULL); | |
227 break; | |
228 } | |
229 default: | |
230 // Nothing to see here, move along ... | |
231 break; | |
232 } | |
233 } | |
234 | |
235 // Propagate the block state forward to all successor blocks. | |
236 for (int i = 0; i < block->end()->SuccessorCount(); i++) { | |
237 HBasicBlock* succ = block->end()->SuccessorAt(i); | |
238 if (!allocate_block->Dominates(succ)) continue; | |
239 if (succ->predecessors()->length() == 1) { | |
240 // Case 1: This is the only predecessor, just reuse state. | |
241 SetStateAt(succ, state); | |
242 } else if (StateAt(succ) == NULL && succ->IsLoopHeader()) { | |
243 // Case 2: This is a state that enters a loop header, be | |
244 // pessimistic about loop headers, add phis for all values. | |
245 SetStateAt(succ, NewStateForLoopHeader(succ->first(), state)); | |
246 } else if (StateAt(succ) == NULL) { | |
247 // Case 3: This is the first state propagated forward to the | |
248 // successor, leave a copy of the current state. | |
249 SetStateAt(succ, NewStateCopy(succ->first(), state)); | |
250 } else { | |
251 // Case 4: This is a state that needs merging with previously | |
252 // propagated states, potentially introducing new phis lazily or | |
253 // adding values to existing phis. | |
254 HCapturedObject* succ_state = StateAt(succ); | |
255 for (int index = 0; index < number_of_values_; index++) { | |
256 HValue* operand = state->OperandAt(index); | |
257 HValue* succ_operand = succ_state->OperandAt(index); | |
258 if (succ_operand->IsPhi() && succ_operand->block() == succ) { | |
259 // Phi already exists, add operand. | |
260 HPhi* phi = HPhi::cast(succ_operand); | |
261 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); | |
262 } else if (succ_operand != operand) { | |
263 // Phi does not exist, introduce one. | |
264 HPhi* phi = NewPhiAndInsert(succ, succ_operand, index); | |
265 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); | |
266 succ_state->SetOperandAt(index, phi); | |
267 } | |
268 } | |
269 } | |
270 } | |
271 } | |
272 | |
273 // All uses have been handled. | |
274 ASSERT(allocate->HasNoUses()); | |
275 allocate->DeleteAndReplaceWith(NULL); | |
276 } | |
277 | |
278 | |
279 void HEscapeAnalysisPhase::PerformScalarReplacement() { | |
280 for (int i = 0; i < captured_.length(); i++) { | |
281 HAllocate* allocate = HAllocate::cast(captured_.at(i)); | |
282 | |
283 // Compute number of scalar values and start with clean slate. | |
284 if (!allocate->size()->IsInteger32Constant()) continue; | |
285 int size_in_bytes = allocate->size()->GetInteger32Constant(); | |
286 number_of_values_ = size_in_bytes / kPointerSize; | |
287 block_states_.Clear(); | |
288 | |
289 // Perform actual analysis steps. | |
290 AnalyzeDataFlow(allocate); | |
291 | |
292 cumulative_values_ += number_of_values_; | |
293 ASSERT(allocate->HasNoUses()); | |
294 ASSERT(!allocate->IsLinked()); | |
295 } | |
296 } | |
297 | |
298 | |
66 } } // namespace v8::internal | 299 } } // namespace v8::internal |
OLD | NEW |