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 // TODO(sigurds): Change this to GetFrameStateInputCount once |
| 41 // it is working. For now we use EffectInputCount > 0 to determine |
| 42 // whether a node might have a frame state input. |
| 43 if (node->op()->EffectInputCount() > 0) { |
| 44 return ReduceFrameStateUses(node); |
| 45 } |
43 break; | 46 break; |
44 } | 47 } |
45 return NoChange(); | 48 return NoChange(); |
46 } | 49 } |
47 | 50 |
48 | 51 |
49 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { | 52 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { |
50 DCHECK(node->opcode() == IrOpcode::kLoadField || | 53 DCHECK(node->opcode() == IrOpcode::kLoadField || |
51 node->opcode() == IrOpcode::kLoadElement); | 54 node->opcode() == IrOpcode::kLoadElement); |
52 if (Node* rep = escape_analysis()->GetReplacement(node)) { | 55 if (Node* rep = escape_analysis()->GetReplacement(node)) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 } | 113 } |
111 return NoChange(); | 114 return NoChange(); |
112 } | 115 } |
113 | 116 |
114 | 117 |
115 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { | 118 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { |
116 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); | 119 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); |
117 Node* left = NodeProperties::GetValueInput(node, 0); | 120 Node* left = NodeProperties::GetValueInput(node, 0); |
118 Node* right = NodeProperties::GetValueInput(node, 1); | 121 Node* right = NodeProperties::GetValueInput(node, 1); |
119 if (escape_analysis()->IsVirtual(left)) { | 122 if (escape_analysis()->IsVirtual(left)) { |
120 if (escape_analysis()->IsVirtual(right)) { | 123 if (escape_analysis()->IsVirtual(right) && |
121 if (Node* rep = escape_analysis()->GetReplacement(left)) { | 124 escape_analysis()->CompareVirtualObjects(left, right)) { |
122 left = rep; | 125 ReplaceWithValue(node, jsgraph()->TrueConstant()); |
123 } | 126 if (FLAG_trace_turbo_escape) { |
124 if (Node* rep = escape_analysis()->GetReplacement(right)) { | 127 PrintF("Replaced ref eq #%d with true\n", node->id()); |
125 right = rep; | |
126 } | |
127 // TODO(sigurds): What to do if either is a PHI? | |
128 if (left == right) { | |
129 ReplaceWithValue(node, jsgraph()->TrueConstant()); | |
130 if (FLAG_trace_turbo_escape) { | |
131 PrintF("Replaced ref eq #%d with true\n", node->id()); | |
132 } | |
133 return Replace(node); | |
134 } | 128 } |
135 } | 129 } |
136 // Right-hand side is either not virtual, or a different node. | 130 // Right-hand side is not a virtual object, or a different one. |
137 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 131 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
138 if (FLAG_trace_turbo_escape) { | 132 if (FLAG_trace_turbo_escape) { |
139 PrintF("Replaced ref eq #%d with false\n", node->id()); | 133 PrintF("Replaced ref eq #%d with false\n", node->id()); |
140 } | 134 } |
141 return Replace(node); | 135 return Replace(node); |
142 } else if (escape_analysis()->IsVirtual(right)) { | 136 } else if (escape_analysis()->IsVirtual(right)) { |
143 // Left-hand side is not a virtual object. | 137 // Left-hand side is not a virtual object. |
144 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 138 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
145 if (FLAG_trace_turbo_escape) { | 139 if (FLAG_trace_turbo_escape) { |
146 PrintF("Replaced ref eq #%d with false\n", node->id()); | 140 PrintF("Replaced ref eq #%d with false\n", node->id()); |
(...skipping 10 matching lines...) Expand all Loading... |
157 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 151 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
158 if (FLAG_trace_turbo_escape) { | 152 if (FLAG_trace_turbo_escape) { |
159 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); | 153 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); |
160 } | 154 } |
161 return Replace(node); | 155 return Replace(node); |
162 } | 156 } |
163 return NoChange(); | 157 return NoChange(); |
164 } | 158 } |
165 | 159 |
166 | 160 |
167 // TODO(sigurds): This is a temporary solution until escape analysis | 161 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { |
168 // supports deoptimization. | 162 DCHECK_GE(node->op()->EffectInputCount(), 1); |
169 Reduction EscapeAnalysisReducer::ReplaceWithDeoptDummy(Node* node) { | 163 bool changed = false; |
170 DCHECK(node->opcode() == IrOpcode::kStateValues || | 164 for (int i = 0; i < node->InputCount(); ++i) { |
171 node->opcode() == IrOpcode::kFrameState); | 165 Node* input = node->InputAt(i); |
172 Reduction r = NoChange(); | 166 if (input->opcode() == IrOpcode::kFrameState) { |
173 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 167 if (Node* ret = ReduceFrameState(input, node, false)) { |
174 Node* input = NodeProperties::GetValueInput(node, i); | 168 node->ReplaceInput(i, ret); |
175 if (input->opcode() == IrOpcode::kFinishRegion || | 169 changed = true; |
176 input->opcode() == IrOpcode::kAllocate || | |
177 input->opcode() == IrOpcode::kPhi) { | |
178 if (escape_analysis()->IsVirtual(input)) { | |
179 NodeProperties::ReplaceValueInput(node, jsgraph()->UndefinedConstant(), | |
180 i); | |
181 if (FLAG_trace_turbo_escape) { | |
182 PrintF("Replaced state value (#%d) input with dummy\n", node->id()); | |
183 } | |
184 r = Changed(node); | |
185 } | 170 } |
186 } | 171 } |
187 } | 172 } |
188 return r; | 173 if (changed) { |
| 174 return Changed(node); |
| 175 } |
| 176 return NoChange(); |
189 } | 177 } |
190 | 178 |
191 | 179 |
| 180 // Returns the clone if it duplicated the node, and null otherwise. |
| 181 Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect, |
| 182 bool multiple_users) { |
| 183 DCHECK(node->opcode() == IrOpcode::kFrameState); |
| 184 if (FLAG_trace_turbo_escape) { |
| 185 PrintF("Reducing FrameState %d\n", node->id()); |
| 186 } |
| 187 Node* clone = nullptr; |
| 188 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
| 189 Node* input = NodeProperties::GetValueInput(node, i); |
| 190 Node* ret = |
| 191 input->opcode() == IrOpcode::kStateValues |
| 192 ? ReduceStateValueInputs(input, effect, node->UseCount() > 1) |
| 193 : ReduceStateValueInput(node, i, effect, node->UseCount() > 1); |
| 194 if (ret) { |
| 195 if (node->UseCount() > 1 || multiple_users) { |
| 196 if (FLAG_trace_turbo_escape) { |
| 197 PrintF(" Cloning #%d", node->id()); |
| 198 } |
| 199 node = clone = jsgraph()->graph()->CloneNode(node); |
| 200 if (FLAG_trace_turbo_escape) { |
| 201 PrintF(" to #%d\n", node->id()); |
| 202 } |
| 203 multiple_users = false; // Don't clone anymore. |
| 204 } |
| 205 NodeProperties::ReplaceValueInput(node, ret, i); |
| 206 } |
| 207 } |
| 208 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 209 if (outer_frame_state->opcode() == IrOpcode::kFrameState) { |
| 210 if (Node* ret = |
| 211 ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) { |
| 212 if (node->UseCount() > 1 || multiple_users) { |
| 213 if (FLAG_trace_turbo_escape) { |
| 214 PrintF(" Cloning #%d", node->id()); |
| 215 } |
| 216 node = clone = jsgraph()->graph()->CloneNode(node); |
| 217 if (FLAG_trace_turbo_escape) { |
| 218 PrintF(" to #%d\n", node->id()); |
| 219 } |
| 220 multiple_users = false; |
| 221 } |
| 222 NodeProperties::ReplaceFrameStateInput(node, 0, ret); |
| 223 } |
| 224 } |
| 225 return clone; |
| 226 } |
| 227 |
| 228 |
| 229 // Returns the clone if it duplicated the node, and null otherwise. |
| 230 Node* EscapeAnalysisReducer::ReduceStateValueInputs(Node* node, Node* effect, |
| 231 bool multiple_users) { |
| 232 if (FLAG_trace_turbo_escape) { |
| 233 PrintF("Reducing StateValue #%d\n", node->id()); |
| 234 } |
| 235 DCHECK(node->opcode() == IrOpcode::kStateValues); |
| 236 DCHECK_NOT_NULL(effect); |
| 237 Node* clone = nullptr; |
| 238 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
| 239 if (Node* ret = ReduceStateValueInput(node, i, effect, multiple_users)) { |
| 240 node = ret; |
| 241 DCHECK_NULL(clone); |
| 242 clone = ret; |
| 243 multiple_users = false; |
| 244 } |
| 245 } |
| 246 return clone; |
| 247 } |
| 248 |
| 249 |
| 250 // Returns the clone if it duplicated the node, and null otherwise. |
| 251 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, |
| 252 Node* effect, |
| 253 bool multiple_users) { |
| 254 Node* input = NodeProperties::GetValueInput(node, node_index); |
| 255 if (FLAG_trace_turbo_escape) { |
| 256 PrintF("Reducing State Input #%d (%s)\n", input->id(), |
| 257 input->op()->mnemonic()); |
| 258 } |
| 259 Node* clone = nullptr; |
| 260 if (input->opcode() == IrOpcode::kFinishRegion || |
| 261 input->opcode() == IrOpcode::kAllocate) { |
| 262 if (escape_analysis()->IsVirtual(input)) { |
| 263 if (Node* object_state = |
| 264 escape_analysis()->GetOrCreateObjectState(effect, input)) { |
| 265 if (node->UseCount() > 1 || multiple_users) { |
| 266 if (FLAG_trace_turbo_escape) { |
| 267 PrintF("Cloning #%d", node->id()); |
| 268 } |
| 269 node = clone = jsgraph()->graph()->CloneNode(node); |
| 270 if (FLAG_trace_turbo_escape) { |
| 271 PrintF(" to #%d\n", node->id()); |
| 272 } |
| 273 } |
| 274 NodeProperties::ReplaceValueInput(node, object_state, node_index); |
| 275 if (FLAG_trace_turbo_escape) { |
| 276 PrintF("Replaced state #%d input #%d with object state #%d\n", |
| 277 node->id(), input->id(), object_state->id()); |
| 278 } |
| 279 } else { |
| 280 if (FLAG_trace_turbo_escape) { |
| 281 PrintF("No object state replacement available.\n"); |
| 282 } |
| 283 } |
| 284 } |
| 285 } |
| 286 return clone; |
| 287 } |
| 288 |
| 289 |
192 Counters* EscapeAnalysisReducer::counters() const { | 290 Counters* EscapeAnalysisReducer::counters() const { |
193 return jsgraph_->isolate()->counters(); | 291 return jsgraph_->isolate()->counters(); |
194 } | 292 } |
195 | 293 |
196 } // namespace compiler | 294 } // namespace compiler |
197 } // namespace internal | 295 } // namespace internal |
198 } // namespace v8 | 296 } // namespace v8 |
OLD | NEW |