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/common-operator.h"
      6 #include "src/compiler/graph.h"
      7 #include "src/compiler/linkage.h"
      8 #include "src/compiler/node-properties.h"
      9 #include "src/compiler/operator-properties.h"
     10 #include "src/compiler/verifier.h"
     11 #include "src/types-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 namespace compiler {
     16 
     17 // static
     18 int NodeProperties::PastValueIndex(Node* node) {
     19   return FirstValueIndex(node) + node->op()->ValueInputCount();
     20 }
     21 
     22 
     23 // static
     24 int NodeProperties::PastContextIndex(Node* node) {
     25   return FirstContextIndex(node) +
     26          OperatorProperties::GetContextInputCount(node->op());
     27 }
     28 
     29 
     30 // static
     31 int NodeProperties::PastFrameStateIndex(Node* node) {
     32   return FirstFrameStateIndex(node) +
     33          OperatorProperties::GetFrameStateInputCount(node->op());
     34 }
     35 
     36 
     37 // static
     38 int NodeProperties::PastEffectIndex(Node* node) {
     39   return FirstEffectIndex(node) + node->op()->EffectInputCount();
     40 }
     41 
     42 
     43 // static
     44 int NodeProperties::PastControlIndex(Node* node) {
     45   return FirstControlIndex(node) + node->op()->ControlInputCount();
     46 }
     47 
     48 
     49 // static
     50 Node* NodeProperties::GetValueInput(Node* node, int index) {
     51   DCHECK(0 <= index && index < node->op()->ValueInputCount());
     52   return node->InputAt(FirstValueIndex(node) + index);
     53 }
     54 
     55 
     56 // static
     57 Node* NodeProperties::GetContextInput(Node* node) {
     58   DCHECK(OperatorProperties::HasContextInput(node->op()));
     59   return node->InputAt(FirstContextIndex(node));
     60 }
     61 
     62 
     63 // static
     64 Node* NodeProperties::GetFrameStateInput(Node* node, int index) {
     65   DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
     66   return node->InputAt(FirstFrameStateIndex(node) + index);
     67 }
     68 
     69 
     70 // static
     71 Node* NodeProperties::GetEffectInput(Node* node, int index) {
     72   DCHECK(0 <= index && index < node->op()->EffectInputCount());
     73   return node->InputAt(FirstEffectIndex(node) + index);
     74 }
     75 
     76 
     77 // static
     78 Node* NodeProperties::GetControlInput(Node* node, int index) {
     79   DCHECK(0 <= index && index < node->op()->ControlInputCount());
     80   return node->InputAt(FirstControlIndex(node) + index);
     81 }
     82 
     83 
     84 // static
     85 bool NodeProperties::IsValueEdge(Edge edge) {
     86   Node* const node = edge.from();
     87   return IsInputRange(edge, FirstValueIndex(node),
     88                       node->op()->ValueInputCount());
     89 }
     90 
     91 
     92 // static
     93 bool NodeProperties::IsContextEdge(Edge edge) {
     94   Node* const node = edge.from();
     95   return IsInputRange(edge, FirstContextIndex(node),
     96                       OperatorProperties::GetContextInputCount(node->op()));
     97 }
     98 
     99 
    100 // static
    101 bool NodeProperties::IsFrameStateEdge(Edge edge) {
    102   Node* const node = edge.from();
    103   return IsInputRange(edge, FirstFrameStateIndex(node),
    104                       OperatorProperties::GetFrameStateInputCount(node->op()));
    105 }
    106 
    107 
    108 // static
    109 bool NodeProperties::IsEffectEdge(Edge edge) {
    110   Node* const node = edge.from();
    111   return IsInputRange(edge, FirstEffectIndex(node),
    112                       node->op()->EffectInputCount());
    113 }
    114 
    115 
    116 // static
    117 bool NodeProperties::IsControlEdge(Edge edge) {
    118   Node* const node = edge.from();
    119   return IsInputRange(edge, FirstControlIndex(node),
    120                       node->op()->ControlInputCount());
    121 }
    122 
    123 
    124 // static
    125 bool NodeProperties::IsExceptionalCall(Node* node) {
    126   for (Edge const edge : node->use_edges()) {
    127     if (!NodeProperties::IsControlEdge(edge)) continue;
    128     if (edge.from()->opcode() == IrOpcode::kIfException) return true;
    129   }
    130   return false;
    131 }
    132 
    133 
    134 // static
    135 void NodeProperties::ReplaceValueInput(Node* node, Node* value, int index) {
    136   DCHECK(index < node->op()->ValueInputCount());
    137   node->ReplaceInput(FirstValueIndex(node) + index, value);
    138 }
    139 
    140 
    141 // static
    142 void NodeProperties::ReplaceValueInputs(Node* node, Node* value) {
    143   int value_input_count = node->op()->ValueInputCount();
    144   DCHECK_LE(1, value_input_count);
    145   node->ReplaceInput(0, value);
    146   while (--value_input_count > 0) {
    147     node->RemoveInput(value_input_count);
    148   }
    149 }
    150 
    151 
    152 // static
    153 void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
    154   node->ReplaceInput(FirstContextIndex(node), context);
    155 }
    156 
    157 
    158 // static
    159 void NodeProperties::ReplaceControlInput(Node* node, Node* control) {
    160   node->ReplaceInput(FirstControlIndex(node), control);
    161 }
    162 
    163 
    164 // static
    165 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
    166   DCHECK(index < node->op()->EffectInputCount());
    167   return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
    168 }
    169 
    170 
    171 // static
    172 void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
    173                                             Node* frame_state) {
    174   DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
    175   node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state);
    176 }
    177 
    178 
    179 // static
    180 void NodeProperties::RemoveFrameStateInput(Node* node, int index) {
    181   DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
    182   node->RemoveInput(FirstFrameStateIndex(node) + index);
    183 }
    184 
    185 
    186 // static
    187 void NodeProperties::RemoveNonValueInputs(Node* node) {
    188   node->TrimInputCount(node->op()->ValueInputCount());
    189 }
    190 
    191 
    192 // static
    193 void NodeProperties::RemoveValueInputs(Node* node) {
    194   int value_input_count = node->op()->ValueInputCount();
    195   while (--value_input_count >= 0) {
    196     node->RemoveInput(value_input_count);
    197   }
    198 }
    199 
    200 
    201 void NodeProperties::MergeControlToEnd(Graph* graph,
    202                                        CommonOperatorBuilder* common,
    203                                        Node* node) {
    204   graph->end()->AppendInput(graph->zone(), node);
    205   graph->end()->set_op(common->End(graph->end()->InputCount()));
    206 }
    207 
    208 
    209 // static
    210 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
    211                                  Node* success, Node* exception) {
    212   // Requires distinguishing between value, effect and control edges.
    213   for (Edge edge : node->use_edges()) {
    214     if (IsControlEdge(edge)) {
    215       if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
    216         DCHECK_NOT_NULL(success);
    217         edge.UpdateTo(success);
    218       } else if (edge.from()->opcode() == IrOpcode::kIfException) {
    219         DCHECK_NOT_NULL(exception);
    220         edge.UpdateTo(exception);
    221       } else {
    222         UNREACHABLE();
    223       }
    224     } else if (IsEffectEdge(edge)) {
    225       DCHECK_NOT_NULL(effect);
    226       edge.UpdateTo(effect);
    227     } else {
    228       DCHECK_NOT_NULL(value);
    229       edge.UpdateTo(value);
    230     }
    231   }
    232 }
    233 
    234 
    235 // static
    236 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
    237   node->set_op(new_op);
    238   Verifier::VerifyNode(node);
    239 }
    240 
    241 
    242 // static
    243 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
    244   for (auto use : node->uses()) {
    245     if (use->opcode() == IrOpcode::kProjection &&
    246         ProjectionIndexOf(use->op()) == projection_index) {
    247       return use;
    248     }
    249   }
    250   return nullptr;
    251 }
    252 
    253 
    254 // static
    255 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
    256                                                size_t projection_count) {
    257 #ifdef DEBUG
    258   DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
    259   std::memset(projections, 0, sizeof(*projections) * projection_count);
    260 #endif
    261   size_t if_value_index = 0;
    262   for (Edge const edge : node->use_edges()) {
    263     if (!IsControlEdge(edge)) continue;
    264     Node* use = edge.from();
    265     size_t index;
    266     switch (use->opcode()) {
    267       case IrOpcode::kIfTrue:
    268         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
    269         index = 0;
    270         break;
    271       case IrOpcode::kIfFalse:
    272         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
    273         index = 1;
    274         break;
    275       case IrOpcode::kIfSuccess:
    276         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
    277         index = 0;
    278         break;
    279       case IrOpcode::kIfException:
    280         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
    281         index = 1;
    282         break;
    283       case IrOpcode::kIfValue:
    284         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
    285         index = if_value_index++;
    286         break;
    287       case IrOpcode::kIfDefault:
    288         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
    289         index = projection_count - 1;
    290         break;
    291       default:
    292         continue;
    293     }
    294     DCHECK_LT(if_value_index, projection_count);
    295     DCHECK_LT(index, projection_count);
    296     DCHECK_NULL(projections[index]);
    297     projections[index] = use;
    298   }
    299 #ifdef DEBUG
    300   for (size_t index = 0; index < projection_count; ++index) {
    301     DCHECK_NOT_NULL(projections[index]);
    302   }
    303 #endif
    304 }
    305 
    306 
    307 // static
    308 MaybeHandle<Context> NodeProperties::GetSpecializationContext(
    309     Node* node, MaybeHandle<Context> context) {
    310   switch (node->opcode()) {
    311     case IrOpcode::kHeapConstant:
    312       return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
    313     case IrOpcode::kParameter: {
    314       Node* const start = NodeProperties::GetValueInput(node, 0);
    315       DCHECK_EQ(IrOpcode::kStart, start->opcode());
    316       int const index = ParameterIndexOf(node->op());
    317       // The context is always the last parameter to a JavaScript function, and
    318       // {Parameter} indices start at -1, so value outputs of {Start} look like
    319       // this: closure, receiver, param0, ..., paramN, context.
    320       if (index == start->op()->ValueOutputCount() - 2) {
    321         return context;
    322       }
    323       break;
    324     }
    325     default:
    326       break;
    327   }
    328   return MaybeHandle<Context>();
    329 }
    330 
    331 
    332 // static
    333 MaybeHandle<Context> NodeProperties::GetSpecializationNativeContext(
    334     Node* node, MaybeHandle<Context> native_context) {
    335   while (true) {
    336     switch (node->opcode()) {
    337       case IrOpcode::kJSCreateBlockContext:
    338       case IrOpcode::kJSCreateCatchContext:
    339       case IrOpcode::kJSCreateFunctionContext:
    340       case IrOpcode::kJSCreateModuleContext:
    341       case IrOpcode::kJSCreateScriptContext:
    342       case IrOpcode::kJSCreateWithContext: {
    343         // Skip over the intermediate contexts, we're only interested in the
    344         // very last context in the context chain anyway.
    345         node = NodeProperties::GetContextInput(node);
    346         break;
    347       }
    348       case IrOpcode::kHeapConstant: {
    349         // Extract the native context from the actual {context}.
    350         Handle<Context> context =
    351             Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
    352         return handle(context->native_context());
    353       }
    354       case IrOpcode::kOsrValue: {
    355         int const index = OpParameter<int>(node);
    356         if (index == Linkage::kOsrContextSpillSlotIndex) {
    357           return native_context;
    358         }
    359         return MaybeHandle<Context>();
    360       }
    361       case IrOpcode::kParameter: {
    362         Node* const start = NodeProperties::GetValueInput(node, 0);
    363         DCHECK_EQ(IrOpcode::kStart, start->opcode());
    364         int const index = ParameterIndexOf(node->op());
    365         // The context is always the last parameter to a JavaScript function,
    366         // and {Parameter} indices start at -1, so value outputs of {Start}
    367         // look like this: closure, receiver, param0, ..., paramN, context.
    368         if (index == start->op()->ValueOutputCount() - 2) {
    369           return native_context;
    370         }
    371         return MaybeHandle<Context>();
    372       }
    373       default:
    374         return MaybeHandle<Context>();
    375     }
    376   }
    377 }
    378 
    379 
    380 // static
    381 MaybeHandle<JSGlobalObject> NodeProperties::GetSpecializationGlobalObject(
    382     Node* node, MaybeHandle<Context> native_context) {
    383   Handle<Context> context;
    384   if (GetSpecializationNativeContext(node, native_context).ToHandle(&context)) {
    385     return handle(context->global_object());
    386   }
    387   return MaybeHandle<JSGlobalObject>();
    388 }
    389 
    390 
    391 // static
    392 Type* NodeProperties::GetTypeOrAny(Node* node) {
    393   return IsTyped(node) ? node->type() : Type::Any();
    394 }
    395 
    396 
    397 // static
    398 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
    399   int input_count = node->op()->ValueInputCount();
    400   for (int index = 0; index < input_count; ++index) {
    401     if (!IsTyped(GetValueInput(node, index))) return false;
    402   }
    403   return true;
    404 }
    405 
    406 
    407 // static
    408 bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
    409   if (num == 0) return false;
    410   int const index = edge.index();
    411   return first <= index && index < first + num;
    412 }
    413 
    414 }  // namespace compiler
    415 }  // namespace internal
    416 }  // namespace v8
    417