Home | History | Annotate | Download | only in compiler
      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
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/escape-analysis-reducer.h"
      6 
      7 #include "src/compiler/js-graph.h"
      8 #include "src/counters.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 namespace compiler {
     13 
     14 EscapeAnalysisReducer::EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph,
     15                                              EscapeAnalysis* escape_analysis,
     16                                              Zone* zone)
     17     : AdvancedReducer(editor),
     18       jsgraph_(jsgraph),
     19       escape_analysis_(escape_analysis),
     20       zone_(zone),
     21       visited_(static_cast<int>(jsgraph->graph()->NodeCount()), zone) {}
     22 
     23 
     24 Reduction EscapeAnalysisReducer::Reduce(Node* node) {
     25   switch (node->opcode()) {
     26     case IrOpcode::kLoadField:
     27     case IrOpcode::kLoadElement:
     28       return ReduceLoad(node);
     29     case IrOpcode::kStoreField:
     30     case IrOpcode::kStoreElement:
     31       return ReduceStore(node);
     32     case IrOpcode::kAllocate:
     33       return ReduceAllocate(node);
     34     case IrOpcode::kFinishRegion:
     35       return ReduceFinishRegion(node);
     36     case IrOpcode::kReferenceEqual:
     37       return ReduceReferenceEqual(node);
     38     case IrOpcode::kObjectIsSmi:
     39       return ReduceObjectIsSmi(node);
     40     default:
     41       // TODO(sigurds): Change this to GetFrameStateInputCount once
     42       // it is working. For now we use EffectInputCount > 0 to determine
     43       // whether a node might have a frame state input.
     44       if (node->op()->EffectInputCount() > 0) {
     45         return ReduceFrameStateUses(node);
     46       }
     47       break;
     48   }
     49   return NoChange();
     50 }
     51 
     52 
     53 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) {
     54   DCHECK(node->opcode() == IrOpcode::kLoadField ||
     55          node->opcode() == IrOpcode::kLoadElement);
     56   if (visited_.Contains(node->id())) return NoChange();
     57   visited_.Add(node->id());
     58   if (Node* rep = escape_analysis()->GetReplacement(node)) {
     59     visited_.Add(node->id());
     60     counters()->turbo_escape_loads_replaced()->Increment();
     61     if (FLAG_trace_turbo_escape) {
     62       PrintF("Replaced #%d (%s) with #%d (%s)\n", node->id(),
     63              node->op()->mnemonic(), rep->id(), rep->op()->mnemonic());
     64     }
     65     ReplaceWithValue(node, rep);
     66     return Changed(rep);
     67   }
     68   return NoChange();
     69 }
     70 
     71 
     72 Reduction EscapeAnalysisReducer::ReduceStore(Node* node) {
     73   DCHECK(node->opcode() == IrOpcode::kStoreField ||
     74          node->opcode() == IrOpcode::kStoreElement);
     75   if (visited_.Contains(node->id())) return NoChange();
     76   visited_.Add(node->id());
     77   if (escape_analysis()->IsVirtual(NodeProperties::GetValueInput(node, 0))) {
     78     if (FLAG_trace_turbo_escape) {
     79       PrintF("Removed #%d (%s) from effect chain\n", node->id(),
     80              node->op()->mnemonic());
     81     }
     82     RelaxEffectsAndControls(node);
     83     return Changed(node);
     84   }
     85   return NoChange();
     86 }
     87 
     88 
     89 Reduction EscapeAnalysisReducer::ReduceAllocate(Node* node) {
     90   DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
     91   if (visited_.Contains(node->id())) return NoChange();
     92   visited_.Add(node->id());
     93   if (escape_analysis()->IsVirtual(node)) {
     94     RelaxEffectsAndControls(node);
     95     counters()->turbo_escape_allocs_replaced()->Increment();
     96     if (FLAG_trace_turbo_escape) {
     97       PrintF("Removed allocate #%d from effect chain\n", node->id());
     98     }
     99     return Changed(node);
    100   }
    101   return NoChange();
    102 }
    103 
    104 
    105 Reduction EscapeAnalysisReducer::ReduceFinishRegion(Node* node) {
    106   DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
    107   Node* effect = NodeProperties::GetEffectInput(node, 0);
    108   if (effect->opcode() == IrOpcode::kBeginRegion) {
    109     RelaxEffectsAndControls(effect);
    110     RelaxEffectsAndControls(node);
    111     if (FLAG_trace_turbo_escape) {
    112       PrintF("Removed region #%d / #%d from effect chain,", effect->id(),
    113              node->id());
    114       PrintF(" %d user(s) of #%d remain(s):", node->UseCount(), node->id());
    115       for (Edge edge : node->use_edges()) {
    116         PrintF(" #%d", edge.from()->id());
    117       }
    118       PrintF("\n");
    119     }
    120     return Changed(node);
    121   }
    122   return NoChange();
    123 }
    124 
    125 
    126 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) {
    127   DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual);
    128   Node* left = NodeProperties::GetValueInput(node, 0);
    129   Node* right = NodeProperties::GetValueInput(node, 1);
    130   if (escape_analysis()->IsVirtual(left)) {
    131     if (escape_analysis()->IsVirtual(right) &&
    132         escape_analysis()->CompareVirtualObjects(left, right)) {
    133       ReplaceWithValue(node, jsgraph()->TrueConstant());
    134       if (FLAG_trace_turbo_escape) {
    135         PrintF("Replaced ref eq #%d with true\n", node->id());
    136       }
    137     }
    138     // Right-hand side is not a virtual object, or a different one.
    139     ReplaceWithValue(node, jsgraph()->FalseConstant());
    140     if (FLAG_trace_turbo_escape) {
    141       PrintF("Replaced ref eq #%d with false\n", node->id());
    142     }
    143     return Replace(node);
    144   } else if (escape_analysis()->IsVirtual(right)) {
    145     // Left-hand side is not a virtual object.
    146     ReplaceWithValue(node, jsgraph()->FalseConstant());
    147     if (FLAG_trace_turbo_escape) {
    148       PrintF("Replaced ref eq #%d with false\n", node->id());
    149     }
    150   }
    151   return NoChange();
    152 }
    153 
    154 
    155 Reduction EscapeAnalysisReducer::ReduceObjectIsSmi(Node* node) {
    156   DCHECK_EQ(node->opcode(), IrOpcode::kObjectIsSmi);
    157   Node* input = NodeProperties::GetValueInput(node, 0);
    158   if (escape_analysis()->IsVirtual(input)) {
    159     ReplaceWithValue(node, jsgraph()->FalseConstant());
    160     if (FLAG_trace_turbo_escape) {
    161       PrintF("Replaced ObjectIsSmi #%d with false\n", node->id());
    162     }
    163     return Replace(node);
    164   }
    165   return NoChange();
    166 }
    167 
    168 
    169 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) {
    170   if (visited_.Contains(node->id())) return NoChange();
    171   visited_.Add(node->id());
    172   DCHECK_GE(node->op()->EffectInputCount(), 1);
    173   bool changed = false;
    174   for (int i = 0; i < node->InputCount(); ++i) {
    175     Node* input = node->InputAt(i);
    176     if (input->opcode() == IrOpcode::kFrameState) {
    177       if (Node* ret = ReduceFrameState(input, node, false)) {
    178         node->ReplaceInput(i, ret);
    179         changed = true;
    180       }
    181     }
    182   }
    183   if (changed) {
    184     return Changed(node);
    185   }
    186   return NoChange();
    187 }
    188 
    189 
    190 // Returns the clone if it duplicated the node, and null otherwise.
    191 Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect,
    192                                               bool multiple_users) {
    193   DCHECK(node->opcode() == IrOpcode::kFrameState);
    194   if (FLAG_trace_turbo_escape) {
    195     PrintF("Reducing FrameState %d\n", node->id());
    196   }
    197   Node* clone = nullptr;
    198   for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
    199     Node* input = NodeProperties::GetValueInput(node, i);
    200     Node* ret =
    201         input->opcode() == IrOpcode::kStateValues
    202             ? ReduceStateValueInputs(input, effect, node->UseCount() > 1)
    203             : ReduceStateValueInput(node, i, effect, node->UseCount() > 1);
    204     if (ret) {
    205       if (node->UseCount() > 1 || multiple_users) {
    206         if (FLAG_trace_turbo_escape) {
    207           PrintF("  Cloning #%d", node->id());
    208         }
    209         node = clone = jsgraph()->graph()->CloneNode(node);
    210         if (FLAG_trace_turbo_escape) {
    211           PrintF(" to #%d\n", node->id());
    212         }
    213         multiple_users = false;  // Don't clone anymore.
    214       }
    215       NodeProperties::ReplaceValueInput(node, ret, i);
    216     }
    217   }
    218   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0);
    219   if (outer_frame_state->opcode() == IrOpcode::kFrameState) {
    220     if (Node* ret =
    221             ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) {
    222       if (node->UseCount() > 1 || multiple_users) {
    223         if (FLAG_trace_turbo_escape) {
    224           PrintF("  Cloning #%d", node->id());
    225         }
    226         node = clone = jsgraph()->graph()->CloneNode(node);
    227         if (FLAG_trace_turbo_escape) {
    228           PrintF(" to #%d\n", node->id());
    229         }
    230         multiple_users = false;
    231       }
    232       NodeProperties::ReplaceFrameStateInput(node, 0, ret);
    233     }
    234   }
    235   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 }
    265 
    266 
    267 // Returns the clone if it duplicated the node, and null otherwise.
    268 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index,
    269                                                    Node* effect,
    270                                                    bool multiple_users) {
    271   Node* input = NodeProperties::GetValueInput(node, node_index);
    272   if (FLAG_trace_turbo_escape) {
    273     PrintF("Reducing State Input #%d (%s)\n", input->id(),
    274            input->op()->mnemonic());
    275   }
    276   Node* clone = nullptr;
    277   if (input->opcode() == IrOpcode::kFinishRegion ||
    278       input->opcode() == IrOpcode::kAllocate) {
    279     if (escape_analysis()->IsVirtual(input)) {
    280       if (Node* object_state =
    281               escape_analysis()->GetOrCreateObjectState(effect, input)) {
    282         if (node->UseCount() > 1 || multiple_users) {
    283           if (FLAG_trace_turbo_escape) {
    284             PrintF("Cloning #%d", node->id());
    285           }
    286           node = clone = jsgraph()->graph()->CloneNode(node);
    287           if (FLAG_trace_turbo_escape) {
    288             PrintF(" to #%d\n", node->id());
    289           }
    290         }
    291         NodeProperties::ReplaceValueInput(node, object_state, node_index);
    292         if (FLAG_trace_turbo_escape) {
    293           PrintF("Replaced state #%d input #%d with object state #%d\n",
    294                  node->id(), input->id(), object_state->id());
    295         }
    296       } else {
    297         if (FLAG_trace_turbo_escape) {
    298           PrintF("No object state replacement available.\n");
    299         }
    300       }
    301     }
    302   }
    303   return clone;
    304 }
    305 
    306 
    307 Counters* EscapeAnalysisReducer::counters() const {
    308   return jsgraph_->isolate()->counters();
    309 }
    310 
    311 }  // namespace compiler
    312 }  // namespace internal
    313 }  // namespace v8
    314