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/js-intrinsic-lowering.h"
      6 
      7 #include <stack>
      8 
      9 #include "src/code-factory.h"
     10 #include "src/compiler/access-builder.h"
     11 #include "src/compiler/js-graph.h"
     12 #include "src/compiler/linkage.h"
     13 #include "src/compiler/node-matchers.h"
     14 #include "src/compiler/node-properties.h"
     15 #include "src/compiler/operator-properties.h"
     16 #include "src/counters.h"
     17 #include "src/objects-inl.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 namespace compiler {
     22 
     23 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
     24                                          DeoptimizationMode mode)
     25     : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {}
     26 
     27 Reduction JSIntrinsicLowering::Reduce(Node* node) {
     28   if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
     29   const Runtime::Function* const f =
     30       Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
     31   if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange();
     32   switch (f->function_id) {
     33     case Runtime::kInlineCreateIterResultObject:
     34       return ReduceCreateIterResultObject(node);
     35     case Runtime::kInlineDebugIsActive:
     36       return ReduceDebugIsActive(node);
     37     case Runtime::kInlineDeoptimizeNow:
     38       return ReduceDeoptimizeNow(node);
     39     case Runtime::kInlineGeneratorClose:
     40       return ReduceGeneratorClose(node);
     41     case Runtime::kInlineGeneratorGetInputOrDebugPos:
     42       return ReduceGeneratorGetInputOrDebugPos(node);
     43     case Runtime::kInlineGeneratorGetResumeMode:
     44       return ReduceGeneratorGetResumeMode(node);
     45     case Runtime::kInlineGeneratorGetContext:
     46       return ReduceGeneratorGetContext(node);
     47     case Runtime::kInlineIsArray:
     48       return ReduceIsInstanceType(node, JS_ARRAY_TYPE);
     49     case Runtime::kInlineIsTypedArray:
     50       return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
     51     case Runtime::kInlineIsJSProxy:
     52       return ReduceIsInstanceType(node, JS_PROXY_TYPE);
     53     case Runtime::kInlineIsJSReceiver:
     54       return ReduceIsJSReceiver(node);
     55     case Runtime::kInlineIsSmi:
     56       return ReduceIsSmi(node);
     57     case Runtime::kInlineFixedArrayGet:
     58       return ReduceFixedArrayGet(node);
     59     case Runtime::kInlineFixedArraySet:
     60       return ReduceFixedArraySet(node);
     61     case Runtime::kInlineSubString:
     62       return ReduceSubString(node);
     63     case Runtime::kInlineToInteger:
     64       return ReduceToInteger(node);
     65     case Runtime::kInlineToLength:
     66       return ReduceToLength(node);
     67     case Runtime::kInlineToNumber:
     68       return ReduceToNumber(node);
     69     case Runtime::kInlineToObject:
     70       return ReduceToObject(node);
     71     case Runtime::kInlineToString:
     72       return ReduceToString(node);
     73     case Runtime::kInlineCall:
     74       return ReduceCall(node);
     75     case Runtime::kInlineGetSuperConstructor:
     76       return ReduceGetSuperConstructor(node);
     77     case Runtime::kInlineArrayBufferViewGetByteLength:
     78       return ReduceArrayBufferViewField(
     79           node, AccessBuilder::ForJSArrayBufferViewByteLength());
     80     case Runtime::kInlineArrayBufferViewGetByteOffset:
     81       return ReduceArrayBufferViewField(
     82           node, AccessBuilder::ForJSArrayBufferViewByteOffset());
     83     case Runtime::kInlineMaxSmi:
     84       return ReduceMaxSmi(node);
     85     case Runtime::kInlineTypedArrayGetLength:
     86       return ReduceArrayBufferViewField(node,
     87                                         AccessBuilder::ForJSTypedArrayLength());
     88     case Runtime::kInlineTypedArrayMaxSizeInHeap:
     89       return ReduceTypedArrayMaxSizeInHeap(node);
     90     case Runtime::kInlineJSCollectionGetTable:
     91       return ReduceJSCollectionGetTable(node);
     92     case Runtime::kInlineStringGetRawHashField:
     93       return ReduceStringGetRawHashField(node);
     94     case Runtime::kInlineTheHole:
     95       return ReduceTheHole(node);
     96     case Runtime::kInlineClassOf:
     97       return ReduceClassOf(node);
     98     default:
     99       break;
    100   }
    101   return NoChange();
    102 }
    103 
    104 
    105 Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) {
    106   Node* const value = NodeProperties::GetValueInput(node, 0);
    107   Node* const done = NodeProperties::GetValueInput(node, 1);
    108   Node* const context = NodeProperties::GetContextInput(node);
    109   Node* const effect = NodeProperties::GetEffectInput(node);
    110   return Change(node, javascript()->CreateIterResultObject(), value, done,
    111                 context, effect);
    112 }
    113 
    114 Reduction JSIntrinsicLowering::ReduceDebugIsActive(Node* node) {
    115   Node* const value = jsgraph()->ExternalConstant(
    116       ExternalReference::debug_is_active_address(isolate()));
    117   Node* const effect = NodeProperties::GetEffectInput(node);
    118   Node* const control = NodeProperties::GetControlInput(node);
    119   Operator const* const op =
    120       simplified()->LoadField(AccessBuilder::ForExternalUint8Value());
    121   return Change(node, op, value, effect, control);
    122 }
    123 
    124 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
    125   if (mode() != kDeoptimizationEnabled) return NoChange();
    126   Node* const frame_state = NodeProperties::GetFrameStateInput(node);
    127   Node* const effect = NodeProperties::GetEffectInput(node);
    128   Node* const control = NodeProperties::GetControlInput(node);
    129 
    130   // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
    131   Node* deoptimize = graph()->NewNode(
    132       common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason),
    133       frame_state, effect, control);
    134   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
    135   Revisit(graph()->end());
    136 
    137   node->TrimInputCount(0);
    138   NodeProperties::ChangeOp(node, common()->Dead());
    139   return Changed(node);
    140 }
    141 
    142 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) {
    143   Node* const generator = NodeProperties::GetValueInput(node, 0);
    144   Node* const effect = NodeProperties::GetEffectInput(node);
    145   Node* const control = NodeProperties::GetControlInput(node);
    146   Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed);
    147   Node* const undefined = jsgraph()->UndefinedConstant();
    148   Operator const* const op = simplified()->StoreField(
    149       AccessBuilder::ForJSGeneratorObjectContinuation());
    150 
    151   ReplaceWithValue(node, undefined, node);
    152   NodeProperties::RemoveType(node);
    153   return Change(node, op, generator, closed, effect, control);
    154 }
    155 
    156 Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) {
    157   Node* const generator = NodeProperties::GetValueInput(node, 0);
    158   Node* const effect = NodeProperties::GetEffectInput(node);
    159   Node* const control = NodeProperties::GetControlInput(node);
    160   Operator const* const op = simplified()->LoadField(
    161       AccessBuilder::ForJSGeneratorObjectInputOrDebugPos());
    162 
    163   return Change(node, op, generator, effect, control);
    164 }
    165 
    166 Reduction JSIntrinsicLowering::ReduceGeneratorGetContext(Node* node) {
    167   Node* const generator = NodeProperties::GetValueInput(node, 0);
    168   Node* const effect = NodeProperties::GetEffectInput(node);
    169   Node* const control = NodeProperties::GetControlInput(node);
    170   Operator const* const op =
    171       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext());
    172 
    173   return Change(node, op, generator, effect, control);
    174 }
    175 
    176 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) {
    177   Node* const generator = NodeProperties::GetValueInput(node, 0);
    178   Node* const effect = NodeProperties::GetEffectInput(node);
    179   Node* const control = NodeProperties::GetControlInput(node);
    180   Operator const* const op =
    181       simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode());
    182 
    183   return Change(node, op, generator, effect, control);
    184 }
    185 
    186 Reduction JSIntrinsicLowering::ReduceIsInstanceType(
    187     Node* node, InstanceType instance_type) {
    188   // if (%_IsSmi(value)) {
    189   //   return false;
    190   // } else {
    191   //   return %_GetInstanceType(%_GetMap(value)) == instance_type;
    192   // }
    193   Node* value = NodeProperties::GetValueInput(node, 0);
    194   Node* effect = NodeProperties::GetEffectInput(node);
    195   Node* control = NodeProperties::GetControlInput(node);
    196 
    197   Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
    198   Node* branch = graph()->NewNode(common()->Branch(), check, control);
    199 
    200   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    201   Node* etrue = effect;
    202   Node* vtrue = jsgraph()->FalseConstant();
    203 
    204   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    205   Node* efalse = graph()->NewNode(
    206       simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
    207       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
    208                        effect, if_false),
    209       effect, if_false);
    210   Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse,
    211                                   jsgraph()->Constant(instance_type));
    212 
    213   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
    214 
    215   // Replace all effect uses of {node} with the {ephi}.
    216   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
    217   ReplaceWithValue(node, node, ephi);
    218 
    219   // Turn the {node} into a Phi.
    220   return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue,
    221                 vfalse, merge);
    222 }
    223 
    224 
    225 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
    226   return Change(node, simplified()->ObjectIsReceiver());
    227 }
    228 
    229 
    230 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) {
    231   return Change(node, simplified()->ObjectIsSmi());
    232 }
    233 
    234 
    235 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
    236   // Replace all effect uses of {node} with the effect dependency.
    237   RelaxEffectsAndControls(node);
    238   // Remove the inputs corresponding to context, effect and control.
    239   NodeProperties::RemoveNonValueInputs(node);
    240   // Finally update the operator to the new one.
    241   NodeProperties::ChangeOp(node, op);
    242   return Changed(node);
    243 }
    244 
    245 
    246 Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) {
    247   Node* base = node->InputAt(0);
    248   Node* index = node->InputAt(1);
    249   Node* effect = NodeProperties::GetEffectInput(node);
    250   Node* control = NodeProperties::GetControlInput(node);
    251   return Change(
    252       node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
    253       base, index, effect, control);
    254 }
    255 
    256 
    257 Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
    258   Node* base = node->InputAt(0);
    259   Node* index = node->InputAt(1);
    260   Node* value = node->InputAt(2);
    261   Node* effect = NodeProperties::GetEffectInput(node);
    262   Node* control = NodeProperties::GetControlInput(node);
    263   Node* store = (graph()->NewNode(
    264       simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
    265       index, value, effect, control));
    266   ReplaceWithValue(node, value, store);
    267   return Changed(store);
    268 }
    269 
    270 
    271 Reduction JSIntrinsicLowering::ReduceSubString(Node* node) {
    272   return Change(node, CodeFactory::SubString(isolate()), 3);
    273 }
    274 
    275 
    276 Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) {
    277   NodeProperties::ChangeOp(node, javascript()->ToInteger());
    278   return Changed(node);
    279 }
    280 
    281 
    282 Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) {
    283   NodeProperties::ChangeOp(node, javascript()->ToNumber());
    284   return Changed(node);
    285 }
    286 
    287 
    288 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) {
    289   NodeProperties::ChangeOp(node, javascript()->ToLength());
    290   return Changed(node);
    291 }
    292 
    293 
    294 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
    295   NodeProperties::ChangeOp(node, javascript()->ToObject());
    296   return Changed(node);
    297 }
    298 
    299 
    300 Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
    301   NodeProperties::ChangeOp(node, javascript()->ToString());
    302   return Changed(node);
    303 }
    304 
    305 
    306 Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
    307   size_t const arity = CallRuntimeParametersOf(node->op()).arity();
    308   NodeProperties::ChangeOp(
    309       node,
    310       javascript()->Call(arity, 0.0f, VectorSlotPair(),
    311                          ConvertReceiverMode::kAny, TailCallMode::kDisallow));
    312   return Changed(node);
    313 }
    314 
    315 Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
    316   Node* active_function = NodeProperties::GetValueInput(node, 0);
    317   Node* effect = NodeProperties::GetEffectInput(node);
    318   Node* control = NodeProperties::GetControlInput(node);
    319   Node* active_function_map = effect =
    320       graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
    321                        active_function, effect, control);
    322   return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()),
    323                 active_function_map, effect, control);
    324 }
    325 
    326 Reduction JSIntrinsicLowering::ReduceArrayBufferViewField(
    327     Node* node, FieldAccess const& access) {
    328   Node* receiver = NodeProperties::GetValueInput(node, 0);
    329   Node* effect = NodeProperties::GetEffectInput(node);
    330   Node* control = NodeProperties::GetControlInput(node);
    331 
    332   // Load the {receiver}s field.
    333   Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
    334                                           receiver, effect, control);
    335 
    336   // Check if the {receiver}s buffer was neutered.
    337   Node* receiver_buffer = effect = graph()->NewNode(
    338       simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
    339       receiver, effect, control);
    340   Node* check = effect = graph()->NewNode(
    341       simplified()->ArrayBufferWasNeutered(), receiver_buffer, effect, control);
    342 
    343   // Default to zero if the {receiver}s buffer was neutered.
    344   value = graph()->NewNode(
    345       common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
    346       check, jsgraph()->ZeroConstant(), value);
    347 
    348   ReplaceWithValue(node, value, effect, control);
    349   return Replace(value);
    350 }
    351 
    352 Reduction JSIntrinsicLowering::ReduceMaxSmi(Node* node) {
    353   Node* value = jsgraph()->Constant(Smi::kMaxValue);
    354   ReplaceWithValue(node, value);
    355   return Replace(value);
    356 }
    357 
    358 Reduction JSIntrinsicLowering::ReduceTypedArrayMaxSizeInHeap(Node* node) {
    359   Node* value = jsgraph()->Constant(FLAG_typed_array_max_size_in_heap);
    360   ReplaceWithValue(node, value);
    361   return Replace(value);
    362 }
    363 
    364 Reduction JSIntrinsicLowering::ReduceJSCollectionGetTable(Node* node) {
    365   Node* collection = NodeProperties::GetValueInput(node, 0);
    366   Node* effect = NodeProperties::GetEffectInput(node);
    367   Node* control = NodeProperties::GetControlInput(node);
    368   return Change(node,
    369                 simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
    370                 collection, effect, control);
    371 }
    372 
    373 Reduction JSIntrinsicLowering::ReduceStringGetRawHashField(Node* node) {
    374   Node* string = NodeProperties::GetValueInput(node, 0);
    375   Node* effect = NodeProperties::GetEffectInput(node);
    376   Node* control = NodeProperties::GetControlInput(node);
    377   return Change(node,
    378                 simplified()->LoadField(AccessBuilder::ForNameHashField()),
    379                 string, effect, control);
    380 }
    381 
    382 Reduction JSIntrinsicLowering::ReduceTheHole(Node* node) {
    383   Node* value = jsgraph()->TheHoleConstant();
    384   ReplaceWithValue(node, value);
    385   return Replace(value);
    386 }
    387 
    388 Reduction JSIntrinsicLowering::ReduceClassOf(Node* node) {
    389   RelaxEffectsAndControls(node);
    390   node->TrimInputCount(2);
    391   NodeProperties::ChangeOp(node, javascript()->ClassOf());
    392   return Changed(node);
    393 }
    394 
    395 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
    396                                       Node* b) {
    397   RelaxControls(node);
    398   node->ReplaceInput(0, a);
    399   node->ReplaceInput(1, b);
    400   node->TrimInputCount(2);
    401   NodeProperties::ChangeOp(node, op);
    402   return Changed(node);
    403 }
    404 
    405 
    406 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
    407                                       Node* b, Node* c) {
    408   RelaxControls(node);
    409   node->ReplaceInput(0, a);
    410   node->ReplaceInput(1, b);
    411   node->ReplaceInput(2, c);
    412   node->TrimInputCount(3);
    413   NodeProperties::ChangeOp(node, op);
    414   return Changed(node);
    415 }
    416 
    417 
    418 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
    419                                       Node* b, Node* c, Node* d) {
    420   RelaxControls(node);
    421   node->ReplaceInput(0, a);
    422   node->ReplaceInput(1, b);
    423   node->ReplaceInput(2, c);
    424   node->ReplaceInput(3, d);
    425   node->TrimInputCount(4);
    426   NodeProperties::ChangeOp(node, op);
    427   return Changed(node);
    428 }
    429 
    430 
    431 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable,
    432                                       int stack_parameter_count) {
    433   CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
    434       isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count,
    435       CallDescriptor::kNeedsFrameState, node->op()->properties());
    436   node->InsertInput(graph()->zone(), 0,
    437                     jsgraph()->HeapConstant(callable.code()));
    438   NodeProperties::ChangeOp(node, common()->Call(desc));
    439   return Changed(node);
    440 }
    441 
    442 
    443 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); }
    444 
    445 
    446 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); }
    447 
    448 
    449 CommonOperatorBuilder* JSIntrinsicLowering::common() const {
    450   return jsgraph()->common();
    451 }
    452 
    453 JSOperatorBuilder* JSIntrinsicLowering::javascript() const {
    454   return jsgraph_->javascript();
    455 }
    456 
    457 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const {
    458   return jsgraph()->simplified();
    459 }
    460 
    461 }  // namespace compiler
    462 }  // namespace internal
    463 }  // namespace v8
    464