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