Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 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/code-factory.h"
      6 #include "src/code-stubs.h"
      7 #include "src/compiler/common-operator.h"
      8 #include "src/compiler/js-generic-lowering.h"
      9 #include "src/compiler/js-graph.h"
     10 #include "src/compiler/machine-operator.h"
     11 #include "src/compiler/node-matchers.h"
     12 #include "src/compiler/node-properties.h"
     13 #include "src/compiler/operator-properties.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 static CallDescriptor::Flags AdjustFrameStatesForCall(Node* node) {
     20   int count = OperatorProperties::GetFrameStateInputCount(node->op());
     21   if (count > 1) {
     22     int index = NodeProperties::FirstFrameStateIndex(node) + 1;
     23     do {
     24       node->RemoveInput(index);
     25     } while (--count > 1);
     26   }
     27   return count > 0 ? CallDescriptor::kNeedsFrameState
     28                    : CallDescriptor::kNoFlags;
     29 }
     30 
     31 
     32 JSGenericLowering::JSGenericLowering(bool is_typing_enabled, JSGraph* jsgraph)
     33     : is_typing_enabled_(is_typing_enabled), jsgraph_(jsgraph) {}
     34 
     35 
     36 JSGenericLowering::~JSGenericLowering() {}
     37 
     38 
     39 Reduction JSGenericLowering::Reduce(Node* node) {
     40   switch (node->opcode()) {
     41 #define DECLARE_CASE(x)  \
     42     case IrOpcode::k##x: \
     43       Lower##x(node);    \
     44       break;
     45     JS_OP_LIST(DECLARE_CASE)
     46 #undef DECLARE_CASE
     47     case IrOpcode::kBranch:
     48       // TODO(mstarzinger): If typing is enabled then simplified lowering will
     49       // have inserted the correct ChangeBoolToBit, otherwise we need to perform
     50       // poor-man's representation inference here and insert manual change.
     51       if (!is_typing_enabled_) {
     52         Node* condition = node->InputAt(0);
     53         Node* test = graph()->NewNode(machine()->WordEqual(), condition,
     54                                       jsgraph()->TrueConstant());
     55         node->ReplaceInput(0, test);
     56       }
     57       // Fall-through.
     58     default:
     59       // Nothing to see.
     60       return NoChange();
     61   }
     62   return Changed(node);
     63 }
     64 
     65 
     66 #define REPLACE_BINARY_OP_IC_CALL(Op, token)                                  \
     67   void JSGenericLowering::Lower##Op(Node* node) {                             \
     68     BinaryOperationParameters const& p =                                      \
     69         BinaryOperationParametersOf(node->op());                              \
     70     CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);             \
     71     ReplaceWithStubCall(node,                                                 \
     72                         CodeFactory::BinaryOpIC(isolate(), token,             \
     73                                                 strength(p.language_mode())), \
     74                         CallDescriptor::kPatchableCallSiteWithNop | flags);   \
     75   }
     76 REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
     77 REPLACE_BINARY_OP_IC_CALL(JSBitwiseXor, Token::BIT_XOR)
     78 REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
     79 REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
     80 REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
     81 REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
     82 REPLACE_BINARY_OP_IC_CALL(JSAdd, Token::ADD)
     83 REPLACE_BINARY_OP_IC_CALL(JSSubtract, Token::SUB)
     84 REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
     85 REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
     86 REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
     87 #undef REPLACE_BINARY_OP_IC_CALL
     88 
     89 
     90 // These ops are not language mode dependent; we arbitrarily pass Strength::WEAK
     91 // here.
     92 #define REPLACE_COMPARE_IC_CALL(op, token)             \
     93   void JSGenericLowering::Lower##op(Node* node) {      \
     94     ReplaceWithCompareIC(node, token, Strength::WEAK); \
     95   }
     96 REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ)
     97 REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE)
     98 REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT)
     99 REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT)
    100 #undef REPLACE_COMPARE_IC_CALL
    101 
    102 
    103 #define REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(op, token)        \
    104   void JSGenericLowering::Lower##op(Node* node) {                    \
    105     ReplaceWithCompareIC(node, token,                                \
    106                          strength(OpParameter<LanguageMode>(node))); \
    107   }
    108 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThan, Token::LT)
    109 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThan, Token::GT)
    110 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThanOrEqual, Token::LTE)
    111 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThanOrEqual, Token::GTE)
    112 #undef REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE
    113 
    114 
    115 #define REPLACE_RUNTIME_CALL(op, fun)             \
    116   void JSGenericLowering::Lower##op(Node* node) { \
    117     ReplaceWithRuntimeCall(node, fun);            \
    118   }
    119 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
    120 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
    121 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
    122 REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
    123 #undef REPLACE_RUNTIME
    124 
    125 
    126 static CallDescriptor::Flags FlagsForNode(Node* node) {
    127   CallDescriptor::Flags result = CallDescriptor::kNoFlags;
    128   if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
    129     result |= CallDescriptor::kNeedsFrameState;
    130   }
    131   return result;
    132 }
    133 
    134 
    135 void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
    136                                              Strength str) {
    137   Callable callable = CodeFactory::CompareIC(isolate(), token, str);
    138 
    139   // Create a new call node asking a CompareIC for help.
    140   NodeVector inputs(zone());
    141   inputs.reserve(node->InputCount() + 1);
    142   inputs.push_back(jsgraph()->HeapConstant(callable.code()));
    143   inputs.push_back(NodeProperties::GetValueInput(node, 0));
    144   inputs.push_back(NodeProperties::GetValueInput(node, 1));
    145   inputs.push_back(NodeProperties::GetContextInput(node));
    146   // Some comparisons (StrictEqual) don't have an effect, control or frame
    147   // state inputs, so handle those cases here.
    148   if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
    149     inputs.push_back(NodeProperties::GetFrameStateInput(node, 0));
    150   }
    151   Node* effect = (node->op()->EffectInputCount() > 0)
    152                      ? NodeProperties::GetEffectInput(node)
    153                      : graph()->start();
    154   inputs.push_back(effect);
    155   Node* control = (node->op()->ControlInputCount() > 0)
    156                       ? NodeProperties::GetControlInput(node)
    157                       : graph()->start();
    158   inputs.push_back(control);
    159   CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
    160       isolate(), zone(), callable.descriptor(), 0,
    161       CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
    162       Operator::kNoProperties, MachineType::IntPtr());
    163   Node* compare =
    164       graph()->NewNode(common()->Call(desc_compare),
    165                        static_cast<int>(inputs.size()), &inputs.front());
    166 
    167   // Decide how the return value from the above CompareIC can be converted into
    168   // a JavaScript boolean oddball depending on the given token.
    169   Node* false_value = jsgraph()->FalseConstant();
    170   Node* true_value = jsgraph()->TrueConstant();
    171   const Operator* op = nullptr;
    172   switch (token) {
    173     case Token::EQ:  // a == 0
    174     case Token::EQ_STRICT:
    175       op = machine()->WordEqual();
    176       break;
    177     case Token::NE:  // a != 0 becomes !(a == 0)
    178     case Token::NE_STRICT:
    179       op = machine()->WordEqual();
    180       std::swap(true_value, false_value);
    181       break;
    182     case Token::LT:  // a < 0
    183       op = machine()->IntLessThan();
    184       break;
    185     case Token::GT:  // a > 0 becomes !(a <= 0)
    186       op = machine()->IntLessThanOrEqual();
    187       std::swap(true_value, false_value);
    188       break;
    189     case Token::LTE:  // a <= 0
    190       op = machine()->IntLessThanOrEqual();
    191       break;
    192     case Token::GTE:  // a >= 0 becomes !(a < 0)
    193       op = machine()->IntLessThan();
    194       std::swap(true_value, false_value);
    195       break;
    196     default:
    197       UNREACHABLE();
    198   }
    199   Node* booleanize = graph()->NewNode(op, compare, jsgraph()->ZeroConstant());
    200 
    201   // Finally patch the original node to select a boolean.
    202   NodeProperties::ReplaceUses(node, node, compare, compare, compare);
    203   node->TrimInputCount(3);
    204   node->ReplaceInput(0, booleanize);
    205   node->ReplaceInput(1, true_value);
    206   node->ReplaceInput(2, false_value);
    207   NodeProperties::ChangeOp(node,
    208                            common()->Select(MachineRepresentation::kTagged));
    209 }
    210 
    211 
    212 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
    213                                             CallDescriptor::Flags flags) {
    214   Operator::Properties properties = node->op()->properties();
    215   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
    216       isolate(), zone(), callable.descriptor(), 0, flags, properties);
    217   Node* stub_code = jsgraph()->HeapConstant(callable.code());
    218   node->InsertInput(zone(), 0, stub_code);
    219   NodeProperties::ChangeOp(node, common()->Call(desc));
    220 }
    221 
    222 
    223 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
    224                                                Runtime::FunctionId f,
    225                                                int nargs_override) {
    226   Operator::Properties properties = node->op()->properties();
    227   const Runtime::Function* fun = Runtime::FunctionForId(f);
    228   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
    229   CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
    230       zone(), f, nargs, properties, CallDescriptor::kNeedsFrameState);
    231   Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
    232   Node* arity = jsgraph()->Int32Constant(nargs);
    233   node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
    234   node->InsertInput(zone(), nargs + 1, ref);
    235   node->InsertInput(zone(), nargs + 2, arity);
    236   NodeProperties::ChangeOp(node, common()->Call(desc));
    237 }
    238 
    239 
    240 void JSGenericLowering::LowerJSTypeOf(Node* node) {
    241   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    242   Callable callable = CodeFactory::Typeof(isolate());
    243   ReplaceWithStubCall(node, callable, flags);
    244 }
    245 
    246 
    247 void JSGenericLowering::LowerJSToBoolean(Node* node) {
    248   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    249   Callable callable = CodeFactory::ToBoolean(isolate());
    250   ReplaceWithStubCall(node, callable,
    251                       CallDescriptor::kPatchableCallSite | flags);
    252 }
    253 
    254 
    255 void JSGenericLowering::LowerJSToNumber(Node* node) {
    256   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    257   Callable callable = CodeFactory::ToNumber(isolate());
    258   ReplaceWithStubCall(node, callable, flags);
    259 }
    260 
    261 
    262 void JSGenericLowering::LowerJSToString(Node* node) {
    263   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    264   Callable callable = CodeFactory::ToString(isolate());
    265   ReplaceWithStubCall(node, callable, flags);
    266 }
    267 
    268 
    269 void JSGenericLowering::LowerJSToName(Node* node) {
    270   ReplaceWithRuntimeCall(node, Runtime::kToName);
    271 }
    272 
    273 
    274 void JSGenericLowering::LowerJSToObject(Node* node) {
    275   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    276   Callable callable = CodeFactory::ToObject(isolate());
    277   ReplaceWithStubCall(node, callable, flags);
    278 }
    279 
    280 
    281 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
    282   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    283   const PropertyAccess& p = PropertyAccessOf(node->op());
    284   Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(
    285       isolate(), p.language_mode(), UNINITIALIZED);
    286   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
    287   ReplaceWithStubCall(node, callable, flags);
    288 }
    289 
    290 
    291 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
    292   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    293   NamedAccess const& p = NamedAccessOf(node->op());
    294   Callable callable = CodeFactory::LoadICInOptimizedCode(
    295       isolate(), NOT_INSIDE_TYPEOF, p.language_mode(), UNINITIALIZED);
    296   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    297   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
    298   ReplaceWithStubCall(node, callable, flags);
    299 }
    300 
    301 
    302 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
    303   Node* context = NodeProperties::GetContextInput(node);
    304   Node* effect = NodeProperties::GetEffectInput(node);
    305   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    306   const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
    307   Callable callable = CodeFactory::LoadICInOptimizedCode(
    308       isolate(), p.typeof_mode(), SLOPPY, UNINITIALIZED);
    309   // Load global object from the context.
    310   Node* native_context =
    311       graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
    312                        jsgraph()->IntPtrConstant(
    313                            Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
    314                        effect, graph()->start());
    315   Node* global = graph()->NewNode(
    316       machine()->Load(MachineType::AnyTagged()), native_context,
    317       jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
    318       effect, graph()->start());
    319   node->InsertInput(zone(), 0, global);
    320   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    321   node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
    322   ReplaceWithStubCall(node, callable, flags);
    323 }
    324 
    325 
    326 void JSGenericLowering::LowerJSStoreProperty(Node* node) {
    327   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    328   PropertyAccess const& p = PropertyAccessOf(node->op());
    329   LanguageMode language_mode = p.language_mode();
    330   Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
    331       isolate(), language_mode, UNINITIALIZED);
    332   DCHECK(p.feedback().index() != -1);
    333   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
    334   ReplaceWithStubCall(node, callable,
    335                       CallDescriptor::kPatchableCallSite | flags);
    336 }
    337 
    338 
    339 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
    340   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    341   NamedAccess const& p = NamedAccessOf(node->op());
    342   Callable callable = CodeFactory::StoreICInOptimizedCode(
    343       isolate(), p.language_mode(), UNINITIALIZED);
    344   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    345   DCHECK(p.feedback().index() != -1);
    346   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
    347   ReplaceWithStubCall(node, callable,
    348                       CallDescriptor::kPatchableCallSite | flags);
    349 }
    350 
    351 
    352 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
    353   Node* context = NodeProperties::GetContextInput(node);
    354   Node* effect = NodeProperties::GetEffectInput(node);
    355   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    356   const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
    357   Callable callable = CodeFactory::StoreICInOptimizedCode(
    358       isolate(), p.language_mode(), UNINITIALIZED);
    359   // Load global object from the context.
    360   Node* native_context =
    361       graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
    362                        jsgraph()->IntPtrConstant(
    363                            Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
    364                        effect, graph()->start());
    365   Node* global = graph()->NewNode(
    366       machine()->Load(MachineType::AnyTagged()), native_context,
    367       jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
    368       effect, graph()->start());
    369   node->InsertInput(zone(), 0, global);
    370   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
    371   DCHECK(p.feedback().index() != -1);
    372   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
    373   ReplaceWithStubCall(node, callable,
    374                       CallDescriptor::kPatchableCallSite | flags);
    375 }
    376 
    377 
    378 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
    379   LanguageMode language_mode = OpParameter<LanguageMode>(node);
    380   ReplaceWithRuntimeCall(node, is_strict(language_mode)
    381                                    ? Runtime::kDeleteProperty_Strict
    382                                    : Runtime::kDeleteProperty_Sloppy);
    383 }
    384 
    385 
    386 void JSGenericLowering::LowerJSHasProperty(Node* node) {
    387   ReplaceWithRuntimeCall(node, Runtime::kHasProperty);
    388 }
    389 
    390 
    391 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
    392   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    393   Callable callable = CodeFactory::InstanceOf(isolate());
    394   ReplaceWithStubCall(node, callable, flags);
    395 }
    396 
    397 
    398 void JSGenericLowering::LowerJSLoadContext(Node* node) {
    399   const ContextAccess& access = ContextAccessOf(node->op());
    400   for (size_t i = 0; i < access.depth(); ++i) {
    401     node->ReplaceInput(
    402         0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
    403                             NodeProperties::GetValueInput(node, 0),
    404                             jsgraph()->Int32Constant(
    405                                 Context::SlotOffset(Context::PREVIOUS_INDEX)),
    406                             NodeProperties::GetEffectInput(node),
    407                             graph()->start()));
    408   }
    409   node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
    410                             static_cast<int>(access.index()))));
    411   node->AppendInput(zone(), graph()->start());
    412   NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
    413 }
    414 
    415 
    416 void JSGenericLowering::LowerJSStoreContext(Node* node) {
    417   const ContextAccess& access = ContextAccessOf(node->op());
    418   for (size_t i = 0; i < access.depth(); ++i) {
    419     node->ReplaceInput(
    420         0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
    421                             NodeProperties::GetValueInput(node, 0),
    422                             jsgraph()->Int32Constant(
    423                                 Context::SlotOffset(Context::PREVIOUS_INDEX)),
    424                             NodeProperties::GetEffectInput(node),
    425                             graph()->start()));
    426   }
    427   node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
    428   node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
    429                             static_cast<int>(access.index()))));
    430   NodeProperties::ChangeOp(
    431       node, machine()->Store(StoreRepresentation(MachineRepresentation::kTagged,
    432                                                  kFullWriteBarrier)));
    433 }
    434 
    435 
    436 void JSGenericLowering::LowerJSLoadDynamic(Node* node) {
    437   const DynamicAccess& access = DynamicAccessOf(node->op());
    438   Runtime::FunctionId function_id =
    439       (access.typeof_mode() == NOT_INSIDE_TYPEOF)
    440           ? Runtime::kLoadLookupSlot
    441           : Runtime::kLoadLookupSlotNoReferenceError;
    442   Node* projection = graph()->NewNode(common()->Projection(0), node);
    443   NodeProperties::ReplaceUses(node, projection, node, node, node);
    444   node->RemoveInput(NodeProperties::FirstValueIndex(node));
    445   node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
    446   ReplaceWithRuntimeCall(node, function_id);
    447   projection->ReplaceInput(0, node);
    448 }
    449 
    450 
    451 void JSGenericLowering::LowerJSCreate(Node* node) {
    452   ReplaceWithRuntimeCall(node, Runtime::kNewObject);
    453 }
    454 
    455 
    456 void JSGenericLowering::LowerJSCreateArguments(Node* node) {
    457   const CreateArgumentsParameters& p = CreateArgumentsParametersOf(node->op());
    458   switch (p.type()) {
    459     case CreateArgumentsParameters::kMappedArguments:
    460       ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
    461       break;
    462     case CreateArgumentsParameters::kUnmappedArguments:
    463       ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments_Generic);
    464       break;
    465     case CreateArgumentsParameters::kRestArray:
    466       node->InsertInput(zone(), 1, jsgraph()->Constant(p.start_index()));
    467       ReplaceWithRuntimeCall(node, Runtime::kNewRestArguments_Generic);
    468       break;
    469   }
    470 }
    471 
    472 
    473 void JSGenericLowering::LowerJSCreateArray(Node* node) {
    474   CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
    475   int const arity = static_cast<int>(p.arity());
    476   Node* new_target = node->InputAt(1);
    477   // TODO(turbofan): We embed the AllocationSite from the Operator at this
    478   // point, which we should not do once we want to both consume the feedback
    479   // but at the same time shared the optimized code across native contexts,
    480   // as the AllocationSite is associated with a single native context (it's
    481   // stored in the type feedback vector after all). Once we go for cross
    482   // context code generation, we should somehow find a way to get to the
    483   // allocation site for the actual native context at runtime.
    484   Node* type_info = p.site().is_null() ? jsgraph()->UndefinedConstant()
    485                                        : jsgraph()->HeapConstant(p.site());
    486   node->RemoveInput(1);
    487   node->InsertInput(zone(), 1 + arity, new_target);
    488   node->InsertInput(zone(), 2 + arity, type_info);
    489   ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3);
    490 }
    491 
    492 
    493 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
    494   CreateClosureParameters p = CreateClosureParametersOf(node->op());
    495   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.shared_info()));
    496   ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED)
    497                                    ? Runtime::kNewClosure_Tenured
    498                                    : Runtime::kNewClosure);
    499 }
    500 
    501 
    502 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
    503   ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject);
    504 }
    505 
    506 
    507 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
    508   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
    509   node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
    510   node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
    511   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
    512   ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
    513 }
    514 
    515 
    516 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
    517   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
    518   node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
    519   node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
    520   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
    521   ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
    522 }
    523 
    524 
    525 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
    526   CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
    527   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    528   Callable callable = CodeFactory::FastCloneRegExp(isolate());
    529   Node* literal_index = jsgraph()->SmiConstant(p.index());
    530   Node* literal_flags = jsgraph()->SmiConstant(p.flags());
    531   Node* pattern = jsgraph()->HeapConstant(p.constant());
    532   node->InsertInput(graph()->zone(), 1, literal_index);
    533   node->InsertInput(graph()->zone(), 2, pattern);
    534   node->InsertInput(graph()->zone(), 3, literal_flags);
    535   ReplaceWithStubCall(node, callable, flags);
    536 }
    537 
    538 
    539 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
    540   Handle<String> name = OpParameter<Handle<String>>(node);
    541   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name));
    542   ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
    543 }
    544 
    545 
    546 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
    547   Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
    548   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
    549   ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
    550 }
    551 
    552 
    553 void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
    554   Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
    555   node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
    556   ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
    557 }
    558 
    559 
    560 void JSGenericLowering::LowerJSCallConstruct(Node* node) {
    561   CallConstructParameters const& p = CallConstructParametersOf(node->op());
    562   int const arg_count = static_cast<int>(p.arity() - 2);
    563   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    564   Callable callable = CodeFactory::Construct(isolate());
    565   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
    566       isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
    567   Node* stub_code = jsgraph()->HeapConstant(callable.code());
    568   Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    569   Node* new_target = node->InputAt(arg_count + 1);
    570   Node* receiver = jsgraph()->UndefinedConstant();
    571   node->RemoveInput(arg_count + 1);  // Drop new target.
    572   node->InsertInput(zone(), 0, stub_code);
    573   node->InsertInput(zone(), 2, new_target);
    574   node->InsertInput(zone(), 3, stub_arity);
    575   node->InsertInput(zone(), 4, receiver);
    576   NodeProperties::ChangeOp(node, common()->Call(desc));
    577 }
    578 
    579 
    580 void JSGenericLowering::LowerJSCallFunction(Node* node) {
    581   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
    582   int const arg_count = static_cast<int>(p.arity() - 2);
    583   ConvertReceiverMode const mode = p.convert_mode();
    584   Callable callable = CodeFactory::Call(isolate(), mode);
    585   CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
    586   if (p.tail_call_mode() == TailCallMode::kAllow) {
    587     flags |= CallDescriptor::kSupportsTailCalls;
    588   }
    589   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
    590       isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
    591   Node* stub_code = jsgraph()->HeapConstant(callable.code());
    592   Node* stub_arity = jsgraph()->Int32Constant(arg_count);
    593   node->InsertInput(zone(), 0, stub_code);
    594   node->InsertInput(zone(), 2, stub_arity);
    595   NodeProperties::ChangeOp(node, common()->Call(desc));
    596 }
    597 
    598 
    599 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
    600   const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
    601   AdjustFrameStatesForCall(node);
    602   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
    603 }
    604 
    605 
    606 void JSGenericLowering::LowerJSForInDone(Node* node) {
    607   ReplaceWithRuntimeCall(node, Runtime::kForInDone);
    608 }
    609 
    610 
    611 void JSGenericLowering::LowerJSForInNext(Node* node) {
    612   ReplaceWithRuntimeCall(node, Runtime::kForInNext);
    613 }
    614 
    615 
    616 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
    617   Node* object = NodeProperties::GetValueInput(node, 0);
    618   Node* context = NodeProperties::GetContextInput(node);
    619   Node* effect = NodeProperties::GetEffectInput(node);
    620   Node* control = NodeProperties::GetControlInput(node);
    621   Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
    622 
    623   // Get the set of properties to enumerate.
    624   Runtime::Function const* function =
    625       Runtime::FunctionForId(Runtime::kGetPropertyNamesFast);
    626   CallDescriptor const* descriptor = Linkage::GetRuntimeCallDescriptor(
    627       zone(), function->function_id, 1, Operator::kNoProperties,
    628       CallDescriptor::kNeedsFrameState);
    629   Node* cache_type = effect = graph()->NewNode(
    630       common()->Call(descriptor),
    631       jsgraph()->CEntryStubConstant(function->result_size), object,
    632       jsgraph()->ExternalConstant(function->function_id),
    633       jsgraph()->Int32Constant(1), context, frame_state, effect, control);
    634   control = graph()->NewNode(common()->IfSuccess(), cache_type);
    635 
    636   Node* object_map = effect = graph()->NewNode(
    637       machine()->Load(MachineType::AnyTagged()), object,
    638       jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
    639       effect, control);
    640   Node* cache_type_map = effect = graph()->NewNode(
    641       machine()->Load(MachineType::AnyTagged()), cache_type,
    642       jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag),
    643       effect, control);
    644   Node* meta_map = jsgraph()->HeapConstant(isolate()->factory()->meta_map());
    645 
    646   // If we got a map from the GetPropertyNamesFast runtime call, we can do a
    647   // fast modification check. Otherwise, we got a fixed array, and we have to
    648   // perform a slow check on every iteration.
    649   Node* check0 =
    650       graph()->NewNode(machine()->WordEqual(), cache_type_map, meta_map);
    651   Node* branch0 =
    652       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
    653 
    654   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
    655   Node* cache_array_true0;
    656   Node* cache_length_true0;
    657   Node* cache_type_true0;
    658   Node* etrue0;
    659   {
    660     // Enum cache case.
    661     Node* cache_type_enum_length = etrue0 = graph()->NewNode(
    662         machine()->Load(MachineType::Uint32()), cache_type,
    663         jsgraph()->IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag),
    664         effect, if_true0);
    665     cache_type_enum_length =
    666         graph()->NewNode(machine()->Word32And(), cache_type_enum_length,
    667                          jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask));
    668 
    669     Node* check1 =
    670         graph()->NewNode(machine()->Word32Equal(), cache_type_enum_length,
    671                          jsgraph()->Int32Constant(0));
    672     Node* branch1 =
    673         graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0);
    674 
    675     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    676     Node* cache_array_true1;
    677     Node* etrue1;
    678     {
    679       // No properties to enumerate.
    680       cache_array_true1 =
    681           jsgraph()->HeapConstant(isolate()->factory()->empty_fixed_array());
    682       etrue1 = etrue0;
    683     }
    684 
    685     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    686     Node* cache_array_false1;
    687     Node* efalse1;
    688     {
    689       // Load the enumeration cache from the instance descriptors of {object}.
    690       Node* object_map_descriptors = efalse1 = graph()->NewNode(
    691           machine()->Load(MachineType::AnyTagged()), object_map,
    692           jsgraph()->IntPtrConstant(Map::kDescriptorsOffset - kHeapObjectTag),
    693           etrue0, if_false1);
    694       Node* object_map_enum_cache = efalse1 = graph()->NewNode(
    695           machine()->Load(MachineType::AnyTagged()), object_map_descriptors,
    696           jsgraph()->IntPtrConstant(DescriptorArray::kEnumCacheOffset -
    697                                     kHeapObjectTag),
    698           efalse1, if_false1);
    699       cache_array_false1 = efalse1 = graph()->NewNode(
    700           machine()->Load(MachineType::AnyTagged()), object_map_enum_cache,
    701           jsgraph()->IntPtrConstant(
    702               DescriptorArray::kEnumCacheBridgeCacheOffset - kHeapObjectTag),
    703           efalse1, if_false1);
    704     }
    705 
    706     if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    707     etrue0 =
    708         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
    709     cache_array_true0 =
    710         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    711                          cache_array_true1, cache_array_false1, if_true0);
    712 
    713     cache_length_true0 = graph()->NewNode(
    714         machine()->WordShl(),
    715         machine()->Is64()
    716             ? graph()->NewNode(machine()->ChangeUint32ToUint64(),
    717                                cache_type_enum_length)
    718             : cache_type_enum_length,
    719         jsgraph()->Int32Constant(kSmiShiftSize + kSmiTagSize));
    720     cache_type_true0 = cache_type;
    721   }
    722 
    723   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
    724   Node* cache_array_false0;
    725   Node* cache_length_false0;
    726   Node* cache_type_false0;
    727   Node* efalse0;
    728   {
    729     // FixedArray case.
    730     cache_type_false0 = jsgraph()->OneConstant();  // Smi means slow check
    731     cache_array_false0 = cache_type;
    732     cache_length_false0 = efalse0 = graph()->NewNode(
    733         machine()->Load(MachineType::AnyTagged()), cache_array_false0,
    734         jsgraph()->IntPtrConstant(FixedArray::kLengthOffset - kHeapObjectTag),
    735         effect, if_false0);
    736   }
    737 
    738   control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
    739   effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
    740   Node* cache_array =
    741       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    742                        cache_array_true0, cache_array_false0, control);
    743   Node* cache_length =
    744       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    745                        cache_length_true0, cache_length_false0, control);
    746   cache_type =
    747       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    748                        cache_type_true0, cache_type_false0, control);
    749 
    750   for (auto edge : node->use_edges()) {
    751     if (NodeProperties::IsEffectEdge(edge)) {
    752       edge.UpdateTo(effect);
    753     } else if (NodeProperties::IsControlEdge(edge)) {
    754       Node* const use = edge.from();
    755       if (use->opcode() == IrOpcode::kIfSuccess) {
    756         use->ReplaceUses(control);
    757         use->Kill();
    758       } else if (use->opcode() == IrOpcode::kIfException) {
    759         edge.UpdateTo(cache_type_true0);
    760       } else {
    761         UNREACHABLE();
    762       }
    763     } else {
    764       Node* const use = edge.from();
    765       DCHECK(NodeProperties::IsValueEdge(edge));
    766       DCHECK_EQ(IrOpcode::kProjection, use->opcode());
    767       switch (ProjectionIndexOf(use->op())) {
    768         case 0:
    769           use->ReplaceUses(cache_type);
    770           break;
    771         case 1:
    772           use->ReplaceUses(cache_array);
    773           break;
    774         case 2:
    775           use->ReplaceUses(cache_length);
    776           break;
    777         default:
    778           UNREACHABLE();
    779           break;
    780       }
    781       use->Kill();
    782     }
    783   }
    784 }
    785 
    786 
    787 void JSGenericLowering::LowerJSForInStep(Node* node) {
    788   ReplaceWithRuntimeCall(node, Runtime::kForInStep);
    789 }
    790 
    791 
    792 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
    793   ExternalReference message_address =
    794       ExternalReference::address_of_pending_message_obj(isolate());
    795   node->RemoveInput(NodeProperties::FirstContextIndex(node));
    796   node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
    797   node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
    798   NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
    799 }
    800 
    801 
    802 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
    803   ExternalReference message_address =
    804       ExternalReference::address_of_pending_message_obj(isolate());
    805   node->RemoveInput(NodeProperties::FirstContextIndex(node));
    806   node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
    807   node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
    808   StoreRepresentation representation(MachineRepresentation::kTagged,
    809                                      kNoWriteBarrier);
    810   NodeProperties::ChangeOp(node, machine()->Store(representation));
    811 }
    812 
    813 
    814 void JSGenericLowering::LowerJSYield(Node* node) { UNIMPLEMENTED(); }
    815 
    816 
    817 void JSGenericLowering::LowerJSStackCheck(Node* node) {
    818   Node* effect = NodeProperties::GetEffectInput(node);
    819   Node* control = NodeProperties::GetControlInput(node);
    820 
    821   Node* limit = graph()->NewNode(
    822       machine()->Load(MachineType::Pointer()),
    823       jsgraph()->ExternalConstant(
    824           ExternalReference::address_of_stack_limit(isolate())),
    825       jsgraph()->IntPtrConstant(0), effect, control);
    826   Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
    827 
    828   Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
    829   Node* branch =
    830       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
    831 
    832   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    833   Node* etrue = effect;
    834 
    835   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    836   NodeProperties::ReplaceControlInput(node, if_false);
    837   Node* efalse = node;
    838 
    839   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    840   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
    841 
    842   // Wire the new diamond into the graph, {node} can still throw.
    843   NodeProperties::ReplaceUses(node, node, ephi, node, node);
    844   NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
    845 
    846   // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
    847   // the node and places it inside the diamond. Come up with a helper method!
    848   for (Node* use : node->uses()) {
    849     if (use->opcode() == IrOpcode::kIfSuccess) {
    850       use->ReplaceUses(merge);
    851       merge->ReplaceInput(1, use);
    852     }
    853   }
    854 
    855   // Turn the stack check into a runtime call.
    856   ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
    857 }
    858 
    859 
    860 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
    861 
    862 
    863 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
    864 
    865 
    866 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
    867 
    868 
    869 CommonOperatorBuilder* JSGenericLowering::common() const {
    870   return jsgraph()->common();
    871 }
    872 
    873 
    874 MachineOperatorBuilder* JSGenericLowering::machine() const {
    875   return jsgraph()->machine();
    876 }
    877 
    878 }  // namespace compiler
    879 }  // namespace internal
    880 }  // namespace v8
    881