OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/escape-analysis-reducer.h" | 5 #include "src/compiler/escape-analysis-reducer.h" |
6 | 6 |
7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
8 #include "src/counters.h" | 8 #include "src/counters.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 18 matching lines...) Expand all Loading... | |
29 case IrOpcode::kStoreElement: | 29 case IrOpcode::kStoreElement: |
30 return ReduceStore(node); | 30 return ReduceStore(node); |
31 case IrOpcode::kAllocate: | 31 case IrOpcode::kAllocate: |
32 return ReduceAllocate(node); | 32 return ReduceAllocate(node); |
33 case IrOpcode::kFinishRegion: | 33 case IrOpcode::kFinishRegion: |
34 return ReduceFinishRegion(node); | 34 return ReduceFinishRegion(node); |
35 case IrOpcode::kReferenceEqual: | 35 case IrOpcode::kReferenceEqual: |
36 return ReduceReferenceEqual(node); | 36 return ReduceReferenceEqual(node); |
37 case IrOpcode::kObjectIsSmi: | 37 case IrOpcode::kObjectIsSmi: |
38 return ReduceObjectIsSmi(node); | 38 return ReduceObjectIsSmi(node); |
39 case IrOpcode::kStateValues: | |
40 case IrOpcode::kFrameState: | |
41 return ReplaceWithDeoptDummy(node); | |
42 default: | 39 default: |
40 if (node->op()->EffectInputCount() > 0) { | |
Jarin
2016/01/05 12:51:19
As discussed offline, this serves as an over-appro
sigurds
2016/01/05 13:08:57
Done.
| |
41 return ReduceFrameStateUses(node); | |
42 } | |
43 break; | 43 break; |
44 } | 44 } |
45 return NoChange(); | 45 return NoChange(); |
46 } | 46 } |
47 | 47 |
48 | 48 |
49 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { | 49 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { |
50 DCHECK(node->opcode() == IrOpcode::kLoadField || | 50 DCHECK(node->opcode() == IrOpcode::kLoadField || |
51 node->opcode() == IrOpcode::kLoadElement); | 51 node->opcode() == IrOpcode::kLoadElement); |
52 if (Node* rep = escape_analysis()->GetReplacement(node)) { | 52 if (Node* rep = escape_analysis()->GetReplacement(node)) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 } | 118 } |
119 return NoChange(); | 119 return NoChange(); |
120 } | 120 } |
121 | 121 |
122 | 122 |
123 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { | 123 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { |
124 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); | 124 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); |
125 Node* left = NodeProperties::GetValueInput(node, 0); | 125 Node* left = NodeProperties::GetValueInput(node, 0); |
126 Node* right = NodeProperties::GetValueInput(node, 1); | 126 Node* right = NodeProperties::GetValueInput(node, 1); |
127 if (escape_analysis()->IsVirtual(left)) { | 127 if (escape_analysis()->IsVirtual(left)) { |
128 if (escape_analysis()->IsVirtual(right)) { | 128 if (escape_analysis()->IsVirtual(right) && |
129 if (Node* rep = escape_analysis()->GetReplacement(left)) { | 129 escape_analysis()->CompareVirtualObjects(left, right)) { |
130 left = rep; | 130 ReplaceWithValue(node, jsgraph()->TrueConstant()); |
131 } | 131 if (FLAG_trace_turbo_escape) { |
132 if (Node* rep = escape_analysis()->GetReplacement(right)) { | 132 PrintF("Replaced ref eq #%d with true\n", node->id()); |
133 right = rep; | |
134 } | |
135 // TODO(sigurds): What to do if either is a PHI? | |
136 if (left == right) { | |
137 ReplaceWithValue(node, jsgraph()->TrueConstant()); | |
138 if (FLAG_trace_turbo_escape) { | |
139 PrintF("Replaced ref eq #%d with true\n", node->id()); | |
140 } | |
141 return Replace(node); | |
142 } | 133 } |
143 } | 134 } |
144 // Right-hand side is either not virtual, or a different node. | 135 // Right-hand side is not a virtual object, or a different one. |
145 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 136 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
146 if (FLAG_trace_turbo_escape) { | 137 if (FLAG_trace_turbo_escape) { |
147 PrintF("Replaced ref eq #%d with false\n", node->id()); | 138 PrintF("Replaced ref eq #%d with false\n", node->id()); |
148 } | 139 } |
149 return Replace(node); | 140 return Replace(node); |
150 } else if (escape_analysis()->IsVirtual(right)) { | 141 } else if (escape_analysis()->IsVirtual(right)) { |
151 // Left-hand side is not a virtual object. | 142 // Left-hand side is not a virtual object. |
152 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 143 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
153 if (FLAG_trace_turbo_escape) { | 144 if (FLAG_trace_turbo_escape) { |
154 PrintF("Replaced ref eq #%d with false\n", node->id()); | 145 PrintF("Replaced ref eq #%d with false\n", node->id()); |
(...skipping 10 matching lines...) Expand all Loading... | |
165 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 156 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
166 if (FLAG_trace_turbo_escape) { | 157 if (FLAG_trace_turbo_escape) { |
167 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); | 158 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); |
168 } | 159 } |
169 return Replace(node); | 160 return Replace(node); |
170 } | 161 } |
171 return NoChange(); | 162 return NoChange(); |
172 } | 163 } |
173 | 164 |
174 | 165 |
175 // TODO(sigurds): This is a temporary solution until escape analysis | 166 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { |
176 // supports deoptimization. | 167 DCHECK_GE(node->op()->EffectInputCount(), 1); |
177 Reduction EscapeAnalysisReducer::ReplaceWithDeoptDummy(Node* node) { | 168 bool changed = false; |
178 DCHECK(node->opcode() == IrOpcode::kStateValues || | 169 for (int i = 0; i < node->InputCount(); ++i) { |
179 node->opcode() == IrOpcode::kFrameState); | 170 Node* input = node->InputAt(i); |
180 Reduction r = NoChange(); | 171 if (input->opcode() == IrOpcode::kFrameState) { |
181 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 172 if (Node* ret = ReduceFrameState(input, node, false)) { |
182 Node* input = NodeProperties::GetValueInput(node, i); | 173 node->ReplaceInput(i, ret); |
183 if (input->opcode() == IrOpcode::kFinishRegion || | 174 changed = true; |
184 input->opcode() == IrOpcode::kAllocate || | |
185 input->opcode() == IrOpcode::kPhi) { | |
186 if (escape_analysis()->IsVirtual(input)) { | |
187 NodeProperties::ReplaceValueInput(node, jsgraph()->UndefinedConstant(), | |
188 i); | |
189 if (FLAG_trace_turbo_escape) { | |
190 PrintF("Replaced state value (#%d) input with dummy\n", node->id()); | |
191 } | |
192 r = Changed(node); | |
193 } | 175 } |
194 } | 176 } |
195 } | 177 } |
196 return r; | 178 if (changed) { |
179 return Changed(node); | |
180 } | |
181 return NoChange(); | |
197 } | 182 } |
198 | 183 |
199 | 184 |
185 Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect, | |
186 bool multiple_users) { | |
187 DCHECK(node->opcode() == IrOpcode::kFrameState); | |
188 if (FLAG_trace_turbo_escape) { | |
189 PrintF("Reducing FrameState %d\n", node->id()); | |
190 } | |
191 Node* clone = nullptr; | |
192 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | |
193 Node* input = NodeProperties::GetValueInput(node, i); | |
194 Node* ret = | |
195 input->opcode() == IrOpcode::kStateValues | |
196 ? ReduceStateValueInputs(input, effect, node->UseCount() > 1) | |
197 : ReduceStateValueInput(node, i, effect, node->UseCount() > 1); | |
198 if (ret) { | |
199 if (node->UseCount() > 1 || multiple_users) { | |
200 if (FLAG_trace_turbo_escape) { | |
201 PrintF(" Cloning #%d", node->id()); | |
202 } | |
203 node = clone = jsgraph()->graph()->CloneNode(node); | |
204 if (FLAG_trace_turbo_escape) { | |
205 PrintF(" to #%d\n", node->id()); | |
206 } | |
207 multiple_users = false; // Don't clone anymore. | |
208 } | |
209 NodeProperties::ReplaceValueInput(node, ret, i); | |
210 } | |
211 } | |
212 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); | |
213 if (outer_frame_state->opcode() == IrOpcode::kFrameState) { | |
214 if (Node* ret = | |
215 ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) { | |
216 if (node->UseCount() > 1 || multiple_users) { | |
217 if (FLAG_trace_turbo_escape) { | |
218 PrintF(" Cloning #%d", node->id()); | |
219 } | |
220 node = clone = jsgraph()->graph()->CloneNode(node); | |
221 if (FLAG_trace_turbo_escape) { | |
222 PrintF(" to #%d\n", node->id()); | |
223 } | |
224 multiple_users = false; | |
225 } | |
226 NodeProperties::ReplaceFrameStateInput(node, 0, ret); | |
227 } | |
228 } | |
229 return clone; | |
230 } | |
231 | |
232 | |
233 Node* EscapeAnalysisReducer::ReduceStateValueInputs(Node* node, Node* effect, | |
234 bool multiple_users) { | |
235 if (FLAG_trace_turbo_escape) { | |
236 PrintF("Reducing StateValue #%d\n", node->id()); | |
237 } | |
238 DCHECK(node->opcode() == IrOpcode::kStateValues); | |
239 DCHECK_NOT_NULL(effect); | |
240 Node* clone = nullptr; | |
241 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | |
242 if (Node* ret = ReduceStateValueInput(node, i, effect, multiple_users)) { | |
243 node = ret; | |
244 DCHECK_NULL(clone); | |
245 clone = ret; | |
246 multiple_users = false; | |
247 } | |
248 } | |
249 return clone; | |
250 } | |
251 | |
252 | |
253 // Return the clone if it duplicated the node, and null otherwise. | |
Jarin
2016/01/05 12:51:19
Maybe you want to add the same comment to the meth
sigurds
2016/01/05 13:08:57
Done.
| |
254 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, | |
255 Node* effect, | |
256 bool multiple_users) { | |
257 Node* input = NodeProperties::GetValueInput(node, node_index); | |
258 if (FLAG_trace_turbo_escape) { | |
259 PrintF("Reducing State Input #%d (%s)\n", input->id(), | |
260 input->op()->mnemonic()); | |
261 } | |
262 Node* clone = nullptr; | |
263 if (input->opcode() == IrOpcode::kFinishRegion || | |
264 input->opcode() == IrOpcode::kAllocate) { | |
265 if (escape_analysis()->IsVirtual(input)) { | |
266 if (Node* object_state = | |
267 escape_analysis()->GetOrCreateObjectState(effect, input)) { | |
268 if (node->UseCount() > 1 || multiple_users) { | |
269 if (FLAG_trace_turbo_escape) { | |
270 PrintF("Cloning #%d", node->id()); | |
271 } | |
272 node = clone = jsgraph()->graph()->CloneNode(node); | |
273 if (FLAG_trace_turbo_escape) { | |
274 PrintF(" to #%d\n", node->id()); | |
275 } | |
276 } | |
277 NodeProperties::ReplaceValueInput(node, object_state, node_index); | |
278 if (FLAG_trace_turbo_escape) { | |
279 PrintF("Replaced state #%d input #%d with object state #%d\n", | |
280 node->id(), input->id(), object_state->id()); | |
281 } | |
282 } else { | |
283 if (FLAG_trace_turbo_escape) { | |
284 PrintF("No object state replacement available.\n"); | |
285 } | |
286 } | |
287 } | |
288 } | |
289 return clone; | |
290 } | |
291 | |
200 } // namespace compiler | 292 } // namespace compiler |
201 } // namespace internal | 293 } // namespace internal |
202 } // namespace v8 | 294 } // namespace v8 |
OLD | NEW |