| 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 { | 
| 11 namespace internal { | 11 namespace internal { | 
| 12 namespace compiler { | 12 namespace compiler { | 
| 13 | 13 | 
| 14 EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph, | 14 EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph, | 
| 15                                              EscapeAnalysis* escape_analysis, | 15                                              EscapeAnalysis* escape_analysis, | 
| 16                                              Zone* zone) | 16                                              Zone* zone) | 
| 17     : AdvancedReducer(editor), | 17     : AdvancedReducer(editor), | 
| 18       jsgraph_(jsgraph), | 18       jsgraph_(jsgraph), | 
| 19       escape_analysis_(escape_analysis), | 19       escape_analysis_(escape_analysis), | 
| 20       zone_(zone), | 20       zone_(zone), | 
| 21       visited_(static_cast<int>(jsgraph->graph()->NodeCount()), zone) {} | 21       visited_(static_cast<int>(jsgraph->graph()->NodeCount() * 2), zone), | 
|  | 22       exists_virtual_allocate_(true) {} | 
| 22 | 23 | 
| 23 | 24 | 
| 24 Reduction EscapeAnalysisReducer::Reduce(Node* node) { | 25 Reduction EscapeAnalysisReducer::Reduce(Node* node) { | 
| 25   switch (node->opcode()) { | 26   switch (node->opcode()) { | 
| 26     case IrOpcode::kLoadField: | 27     case IrOpcode::kLoadField: | 
| 27     case IrOpcode::kLoadElement: | 28     case IrOpcode::kLoadElement: | 
| 28       return ReduceLoad(node); | 29       return ReduceLoad(node); | 
| 29     case IrOpcode::kStoreField: | 30     case IrOpcode::kStoreField: | 
| 30     case IrOpcode::kStoreElement: | 31     case IrOpcode::kStoreElement: | 
| 31       return ReduceStore(node); | 32       return ReduceStore(node); | 
| 32     case IrOpcode::kAllocate: | 33     case IrOpcode::kAllocate: | 
| 33       return ReduceAllocate(node); | 34       return ReduceAllocate(node); | 
| 34     case IrOpcode::kFinishRegion: | 35     case IrOpcode::kFinishRegion: | 
| 35       return ReduceFinishRegion(node); | 36       return ReduceFinishRegion(node); | 
| 36     case IrOpcode::kReferenceEqual: | 37     case IrOpcode::kReferenceEqual: | 
| 37       return ReduceReferenceEqual(node); | 38       return ReduceReferenceEqual(node); | 
| 38     case IrOpcode::kObjectIsSmi: | 39     case IrOpcode::kObjectIsSmi: | 
| 39       return ReduceObjectIsSmi(node); | 40       return ReduceObjectIsSmi(node); | 
|  | 41     case IrOpcode::kFrameState: | 
|  | 42     case IrOpcode::kStateValues: { | 
|  | 43       if (node->id() >= static_cast<NodeId>(visited_.length()) || | 
|  | 44           visited_.Contains(node->id())) { | 
|  | 45         break; | 
|  | 46       } | 
|  | 47       bool needs_visit = false; | 
|  | 48       for (int i = 0; i < node->InputCount(); i++) { | 
|  | 49         Node* input = node->InputAt(i); | 
|  | 50         switch (input->opcode()) { | 
|  | 51           case IrOpcode::kAllocate: | 
|  | 52           case IrOpcode::kFinishRegion: | 
|  | 53             needs_visit = needs_visit || escape_analysis()->IsVirtual(input); | 
|  | 54             break; | 
|  | 55           case IrOpcode::kFrameState: | 
|  | 56           case IrOpcode::kStateValues: | 
|  | 57             needs_visit = | 
|  | 58                 needs_visit || | 
|  | 59                 input->id() >= static_cast<NodeId>(visited_.length()) || | 
|  | 60                 !visited_.Contains(input->id()); | 
|  | 61             break; | 
|  | 62           default: | 
|  | 63             break; | 
|  | 64         } | 
|  | 65       } | 
|  | 66       if (!needs_visit) { | 
|  | 67         visited_.Add(node->id()); | 
|  | 68       } | 
|  | 69       break; | 
|  | 70     } | 
| 40     default: | 71     default: | 
| 41       // TODO(sigurds): Change this to GetFrameStateInputCount once | 72       // TODO(sigurds): Change this to GetFrameStateInputCount once | 
| 42       // it is working. For now we use EffectInputCount > 0 to determine | 73       // it is working. For now we use EffectInputCount > 0 to determine | 
| 43       // whether a node might have a frame state input. | 74       // whether a node might have a frame state input. | 
| 44       if (node->op()->EffectInputCount() > 0) { | 75       if (exists_virtual_allocate_ && node->op()->EffectInputCount() > 0) { | 
| 45         return ReduceFrameStateUses(node); | 76         return ReduceFrameStateUses(node); | 
| 46       } | 77       } | 
| 47       break; | 78       break; | 
| 48   } | 79   } | 
| 49   return NoChange(); | 80   return NoChange(); | 
| 50 } | 81 } | 
| 51 | 82 | 
| 52 | 83 | 
| 53 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { | 84 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { | 
| 54   DCHECK(node->opcode() == IrOpcode::kLoadField || | 85   DCHECK(node->opcode() == IrOpcode::kLoadField || | 
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 167 | 198 | 
| 168 | 199 | 
| 169 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { | 200 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { | 
| 170   if (visited_.Contains(node->id())) return NoChange(); | 201   if (visited_.Contains(node->id())) return NoChange(); | 
| 171   visited_.Add(node->id()); | 202   visited_.Add(node->id()); | 
| 172   DCHECK_GE(node->op()->EffectInputCount(), 1); | 203   DCHECK_GE(node->op()->EffectInputCount(), 1); | 
| 173   bool changed = false; | 204   bool changed = false; | 
| 174   for (int i = 0; i < node->InputCount(); ++i) { | 205   for (int i = 0; i < node->InputCount(); ++i) { | 
| 175     Node* input = node->InputAt(i); | 206     Node* input = node->InputAt(i); | 
| 176     if (input->opcode() == IrOpcode::kFrameState) { | 207     if (input->opcode() == IrOpcode::kFrameState) { | 
| 177       if (Node* ret = ReduceFrameState(input, node, false)) { | 208       if (Node* ret = ReduceDeoptState(input, node, false)) { | 
| 178         node->ReplaceInput(i, ret); | 209         node->ReplaceInput(i, ret); | 
| 179         changed = true; | 210         changed = true; | 
| 180       } | 211       } | 
| 181     } | 212     } | 
| 182   } | 213   } | 
| 183   if (changed) { | 214   if (changed) { | 
| 184     return Changed(node); | 215     return Changed(node); | 
| 185   } | 216   } | 
| 186   return NoChange(); | 217   return NoChange(); | 
| 187 } | 218 } | 
| 188 | 219 | 
| 189 | 220 | 
| 190 // Returns the clone if it duplicated the node, and null otherwise. | 221 // Returns the clone if it duplicated the node, and null otherwise. | 
| 191 Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect, | 222 Node* EscapeAnalysisReducer::ReduceDeoptState(Node* node, Node* effect, | 
| 192                                               bool multiple_users) { | 223                                               bool multiple_users) { | 
| 193   DCHECK(node->opcode() == IrOpcode::kFrameState); | 224   DCHECK(node->opcode() == IrOpcode::kFrameState || | 
|  | 225          node->opcode() == IrOpcode::kStateValues); | 
|  | 226   if (node->id() < static_cast<NodeId>(visited_.length()) && | 
|  | 227       visited_.Contains(node->id())) { | 
|  | 228     return nullptr; | 
|  | 229   } | 
| 194   if (FLAG_trace_turbo_escape) { | 230   if (FLAG_trace_turbo_escape) { | 
| 195     PrintF("Reducing FrameState %d\n", node->id()); | 231     PrintF("Reducing %s %d\n", node->op()->mnemonic(), node->id()); | 
| 196   } | 232   } | 
| 197   Node* clone = nullptr; | 233   Node* clone = nullptr; | 
|  | 234   bool node_multiused = node->UseCount() > 1; | 
|  | 235   bool multiple_users_rec = multiple_users || node_multiused; | 
| 198   for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 236   for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 
| 199     Node* input = NodeProperties::GetValueInput(node, i); | 237     Node* input = NodeProperties::GetValueInput(node, i); | 
| 200     Node* ret = | 238     if (input->opcode() == IrOpcode::kStateValues) { | 
| 201         input->opcode() == IrOpcode::kStateValues | 239       if (Node* ret = ReduceDeoptState(input, effect, multiple_users_rec)) { | 
| 202             ? ReduceStateValueInputs(input, effect, node->UseCount() > 1) | 240         if (node_multiused || (multiple_users && !clone)) { | 
| 203             : ReduceStateValueInput(node, i, effect, node->UseCount() > 1); | 241           if (FLAG_trace_turbo_escape) { | 
| 204     if (ret) { | 242             PrintF("  Cloning #%d", node->id()); | 
| 205       if (node->UseCount() > 1 || multiple_users) { | 243           } | 
| 206         if (FLAG_trace_turbo_escape) { | 244           node = clone = jsgraph()->graph()->CloneNode(node); | 
| 207           PrintF("  Cloning #%d", node->id()); | 245           if (FLAG_trace_turbo_escape) { | 
|  | 246             PrintF(" to #%d\n", node->id()); | 
|  | 247           } | 
|  | 248           node_multiused = false; | 
| 208         } | 249         } | 
| 209         node = clone = jsgraph()->graph()->CloneNode(node); | 250         NodeProperties::ReplaceValueInput(node, ret, i); | 
| 210         if (FLAG_trace_turbo_escape) { |  | 
| 211           PrintF(" to #%d\n", node->id()); |  | 
| 212         } |  | 
| 213         multiple_users = false;  // Don't clone anymore. |  | 
| 214       } | 251       } | 
| 215       NodeProperties::ReplaceValueInput(node, ret, i); | 252     } else { | 
|  | 253       if (Node* ret = ReduceStateValueInput(node, i, effect, node_multiused, | 
|  | 254                                             clone, multiple_users)) { | 
|  | 255         DCHECK_NULL(clone); | 
|  | 256         node_multiused = false;  // Don't clone anymore. | 
|  | 257         node = clone = ret; | 
|  | 258       } | 
| 216     } | 259     } | 
| 217   } | 260   } | 
| 218   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); | 261   if (node->opcode() == IrOpcode::kFrameState) { | 
| 219   if (outer_frame_state->opcode() == IrOpcode::kFrameState) { | 262     Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); | 
| 220     if (Node* ret = | 263     if (outer_frame_state->opcode() == IrOpcode::kFrameState) { | 
| 221             ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) { | 264       if (Node* ret = | 
| 222       if (node->UseCount() > 1 || multiple_users) { | 265               ReduceDeoptState(outer_frame_state, effect, multiple_users_rec)) { | 
| 223         if (FLAG_trace_turbo_escape) { | 266         if (node_multiused || (multiple_users && !clone)) { | 
| 224           PrintF("  Cloning #%d", node->id()); | 267           if (FLAG_trace_turbo_escape) { | 
|  | 268             PrintF("    Cloning #%d", node->id()); | 
|  | 269           } | 
|  | 270           node = clone = jsgraph()->graph()->CloneNode(node); | 
|  | 271           if (FLAG_trace_turbo_escape) { | 
|  | 272             PrintF(" to #%d\n", node->id()); | 
|  | 273           } | 
| 225         } | 274         } | 
| 226         node = clone = jsgraph()->graph()->CloneNode(node); | 275         NodeProperties::ReplaceFrameStateInput(node, 0, ret); | 
| 227         if (FLAG_trace_turbo_escape) { |  | 
| 228           PrintF(" to #%d\n", node->id()); |  | 
| 229         } |  | 
| 230         multiple_users = false; |  | 
| 231       } | 276       } | 
| 232       NodeProperties::ReplaceFrameStateInput(node, 0, ret); |  | 
| 233     } | 277     } | 
| 234   } | 278   } | 
| 235   return clone; | 279   return clone; | 
| 236 } |  | 
| 237 |  | 
| 238 |  | 
| 239 // Returns the clone if it duplicated the node, and null otherwise. |  | 
| 240 Node* EscapeAnalysisReducer::ReduceStateValueInputs(Node* node, Node* effect, |  | 
| 241                                                     bool multiple_users) { |  | 
| 242   if (FLAG_trace_turbo_escape) { |  | 
| 243     PrintF("Reducing StateValue #%d\n", node->id()); |  | 
| 244   } |  | 
| 245   DCHECK(node->opcode() == IrOpcode::kStateValues); |  | 
| 246   DCHECK_NOT_NULL(effect); |  | 
| 247   Node* clone = nullptr; |  | 
| 248   for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |  | 
| 249     Node* input = NodeProperties::GetValueInput(node, i); |  | 
| 250     Node* ret = nullptr; |  | 
| 251     if (input->opcode() == IrOpcode::kStateValues) { |  | 
| 252       ret = ReduceStateValueInputs(input, effect, multiple_users); |  | 
| 253     } else { |  | 
| 254       ret = ReduceStateValueInput(node, i, effect, multiple_users); |  | 
| 255     } |  | 
| 256     if (ret) { |  | 
| 257       node = ret; |  | 
| 258       DCHECK_NULL(clone); |  | 
| 259       clone = ret; |  | 
| 260       multiple_users = false; |  | 
| 261     } |  | 
| 262   } |  | 
| 263   return clone; |  | 
| 264 } | 280 } | 
| 265 | 281 | 
| 266 | 282 | 
| 267 // Returns the clone if it duplicated the node, and null otherwise. | 283 // Returns the clone if it duplicated the node, and null otherwise. | 
| 268 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, | 284 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, | 
| 269                                                    Node* effect, | 285                                                    Node* effect, | 
|  | 286                                                    bool node_multiused, | 
|  | 287                                                    bool already_cloned, | 
| 270                                                    bool multiple_users) { | 288                                                    bool multiple_users) { | 
| 271   Node* input = NodeProperties::GetValueInput(node, node_index); | 289   Node* input = NodeProperties::GetValueInput(node, node_index); | 
| 272   if (FLAG_trace_turbo_escape) { | 290   if (FLAG_trace_turbo_escape) { | 
| 273     PrintF("Reducing State Input #%d (%s)\n", input->id(), | 291     PrintF("Reducing State Input #%d (%s)\n", input->id(), | 
| 274            input->op()->mnemonic()); | 292            input->op()->mnemonic()); | 
| 275   } | 293   } | 
| 276   Node* clone = nullptr; | 294   Node* clone = nullptr; | 
| 277   if (input->opcode() == IrOpcode::kFinishRegion || | 295   if (input->opcode() == IrOpcode::kFinishRegion || | 
| 278       input->opcode() == IrOpcode::kAllocate) { | 296       input->opcode() == IrOpcode::kAllocate) { | 
| 279     if (escape_analysis()->IsVirtual(input)) { | 297     if (escape_analysis()->IsVirtual(input)) { | 
| 280       if (Node* object_state = | 298       if (Node* object_state = | 
| 281               escape_analysis()->GetOrCreateObjectState(effect, input)) { | 299               escape_analysis()->GetOrCreateObjectState(effect, input)) { | 
| 282         if (node->UseCount() > 1 || multiple_users) { | 300         if (node_multiused || (multiple_users && !already_cloned)) { | 
| 283           if (FLAG_trace_turbo_escape) { | 301           if (FLAG_trace_turbo_escape) { | 
| 284             PrintF("Cloning #%d", node->id()); | 302             PrintF("Cloning #%d", node->id()); | 
| 285           } | 303           } | 
| 286           node = clone = jsgraph()->graph()->CloneNode(node); | 304           node = clone = jsgraph()->graph()->CloneNode(node); | 
| 287           if (FLAG_trace_turbo_escape) { | 305           if (FLAG_trace_turbo_escape) { | 
| 288             PrintF(" to #%d\n", node->id()); | 306             PrintF(" to #%d\n", node->id()); | 
| 289           } | 307           } | 
|  | 308           node_multiused = false; | 
|  | 309           already_cloned = true; | 
| 290         } | 310         } | 
| 291         NodeProperties::ReplaceValueInput(node, object_state, node_index); | 311         NodeProperties::ReplaceValueInput(node, object_state, node_index); | 
| 292         if (FLAG_trace_turbo_escape) { | 312         if (FLAG_trace_turbo_escape) { | 
| 293           PrintF("Replaced state #%d input #%d with object state #%d\n", | 313           PrintF("Replaced state #%d input #%d with object state #%d\n", | 
| 294                  node->id(), input->id(), object_state->id()); | 314                  node->id(), input->id(), object_state->id()); | 
| 295         } | 315         } | 
| 296       } else { | 316       } else { | 
| 297         if (FLAG_trace_turbo_escape) { | 317         if (FLAG_trace_turbo_escape) { | 
| 298           PrintF("No object state replacement available.\n"); | 318           PrintF("No object state replacement available.\n"); | 
| 299         } | 319         } | 
| 300       } | 320       } | 
| 301     } | 321     } | 
| 302   } | 322   } | 
| 303   return clone; | 323   return clone; | 
| 304 } | 324 } | 
| 305 | 325 | 
| 306 | 326 | 
| 307 Counters* EscapeAnalysisReducer::counters() const { | 327 Counters* EscapeAnalysisReducer::counters() const { | 
| 308   return jsgraph_->isolate()->counters(); | 328   return jsgraph_->isolate()->counters(); | 
| 309 } | 329 } | 
| 310 | 330 | 
| 311 }  // namespace compiler | 331 }  // namespace compiler | 
| 312 }  // namespace internal | 332 }  // namespace internal | 
| 313 }  // namespace v8 | 333 }  // namespace v8 | 
| OLD | NEW | 
|---|