LCOV - code coverage report
Current view: top level - src/compiler - js-type-hint-lowering.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 109 113 96.5 %
Date: 2017-10-20 Functions: 21 21 100.0 %

          Line data    Source code
       1             : // Copyright 2017 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-type-hint-lowering.h"
       6             : 
       7             : #include "src/compiler/access-builder.h"
       8             : #include "src/compiler/js-graph.h"
       9             : #include "src/compiler/operator-properties.h"
      10             : #include "src/compiler/simplified-operator.h"
      11             : #include "src/feedback-vector.h"
      12             : #include "src/type-hints.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace compiler {
      17             : 
      18             : namespace {
      19             : 
      20             : bool BinaryOperationHintToNumberOperationHint(
      21             :     BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
      22      469324 :   switch (binop_hint) {
      23             :     case BinaryOperationHint::kSignedSmall:
      24      172736 :       *number_hint = NumberOperationHint::kSignedSmall;
      25             :       return true;
      26             :     case BinaryOperationHint::kSignedSmallInputs:
      27       12341 :       *number_hint = NumberOperationHint::kSignedSmallInputs;
      28             :       return true;
      29             :     case BinaryOperationHint::kSigned32:
      30           0 :       *number_hint = NumberOperationHint::kSigned32;
      31             :       return true;
      32             :     case BinaryOperationHint::kNumber:
      33       78500 :       *number_hint = NumberOperationHint::kNumber;
      34             :       return true;
      35             :     case BinaryOperationHint::kNumberOrOddball:
      36        3235 :       *number_hint = NumberOperationHint::kNumberOrOddball;
      37             :       return true;
      38             :     case BinaryOperationHint::kAny:
      39             :     case BinaryOperationHint::kNone:
      40             :     case BinaryOperationHint::kString:
      41             :       break;
      42             :   }
      43             :   return false;
      44             : }
      45             : 
      46             : }  // namespace
      47             : 
      48             : class JSSpeculativeBinopBuilder final {
      49             :  public:
      50             :   JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
      51             :                             const Operator* op, Node* left, Node* right,
      52             :                             Node* effect, Node* control, FeedbackSlot slot)
      53             :       : lowering_(lowering),
      54             :         op_(op),
      55             :         left_(left),
      56             :         right_(right),
      57             :         effect_(effect),
      58             :         control_(control),
      59      549615 :         slot_(slot) {}
      60             : 
      61      437936 :   BinaryOperationHint GetBinaryOperationHint() {
      62             :     DCHECK_EQ(FeedbackSlotKind::kBinaryOp, feedback_vector()->GetKind(slot_));
      63             :     BinaryOpICNexus nexus(feedback_vector(), slot_);
      64      437936 :     return nexus.GetBinaryOperationFeedback();
      65             :   }
      66             : 
      67      111679 :   CompareOperationHint GetCompareOperationHint() {
      68             :     DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot_));
      69             :     CompareICNexus nexus(feedback_vector(), slot_);
      70      111679 :     return nexus.GetCompareOperationFeedback();
      71             :   }
      72             : 
      73      437936 :   bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
      74             :     return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
      75      875872 :                                                     hint);
      76             :   }
      77             : 
      78      111679 :   bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
      79      111679 :     switch (GetCompareOperationHint()) {
      80             :       case CompareOperationHint::kSignedSmall:
      81       63045 :         *hint = NumberOperationHint::kSignedSmall;
      82       63045 :         return true;
      83             :       case CompareOperationHint::kNumber:
      84        1727 :         *hint = NumberOperationHint::kNumber;
      85        1727 :         return true;
      86             :       case CompareOperationHint::kNumberOrOddball:
      87           8 :         *hint = NumberOperationHint::kNumberOrOddball;
      88           8 :         return true;
      89             :       case CompareOperationHint::kAny:
      90             :       case CompareOperationHint::kNone:
      91             :       case CompareOperationHint::kString:
      92             :       case CompareOperationHint::kSymbol:
      93             :       case CompareOperationHint::kReceiver:
      94             :       case CompareOperationHint::kInternalizedString:
      95             :         break;
      96             :     }
      97             :     return false;
      98             :   }
      99             : 
     100      266812 :   const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
     101      266812 :     switch (op_->opcode()) {
     102             :       case IrOpcode::kJSAdd:
     103      301288 :         if (hint == NumberOperationHint::kSignedSmall ||
     104      150644 :             hint == NumberOperationHint::kSigned32) {
     105       98090 :           return simplified()->SpeculativeSafeIntegerAdd(hint);
     106             :         } else {
     107       52554 :           return simplified()->SpeculativeNumberAdd(hint);
     108             :         }
     109             :       case IrOpcode::kJSSubtract:
     110       89494 :         if (hint == NumberOperationHint::kSignedSmall ||
     111       44747 :             hint == NumberOperationHint::kSigned32) {
     112       43315 :           return simplified()->SpeculativeSafeIntegerSubtract(hint);
     113             :         } else {
     114        1432 :           return simplified()->SpeculativeNumberSubtract(hint);
     115             :         }
     116             :       case IrOpcode::kJSMultiply:
     117       18720 :         return simplified()->SpeculativeNumberMultiply(hint);
     118             :       case IrOpcode::kJSDivide:
     119       18624 :         return simplified()->SpeculativeNumberDivide(hint);
     120             :       case IrOpcode::kJSModulus:
     121        3586 :         return simplified()->SpeculativeNumberModulus(hint);
     122             :       case IrOpcode::kJSBitwiseAnd:
     123        4906 :         return simplified()->SpeculativeNumberBitwiseAnd(hint);
     124             :       case IrOpcode::kJSBitwiseOr:
     125       15798 :         return simplified()->SpeculativeNumberBitwiseOr(hint);
     126             :       case IrOpcode::kJSBitwiseXor:
     127         974 :         return simplified()->SpeculativeNumberBitwiseXor(hint);
     128             :       case IrOpcode::kJSShiftLeft:
     129        2074 :         return simplified()->SpeculativeNumberShiftLeft(hint);
     130             :       case IrOpcode::kJSShiftRight:
     131        4866 :         return simplified()->SpeculativeNumberShiftRight(hint);
     132             :       case IrOpcode::kJSShiftRightLogical:
     133        1873 :         return simplified()->SpeculativeNumberShiftRightLogical(hint);
     134             :       default:
     135             :         break;
     136             :     }
     137           0 :     UNREACHABLE();
     138             :   }
     139             : 
     140       64780 :   const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
     141       64780 :     switch (op_->opcode()) {
     142             :       case IrOpcode::kJSEqual:
     143       16449 :         return simplified()->SpeculativeNumberEqual(hint);
     144             :       case IrOpcode::kJSLessThan:
     145       14590 :         return simplified()->SpeculativeNumberLessThan(hint);
     146             :       case IrOpcode::kJSGreaterThan:
     147             :         std::swap(left_, right_);  // a > b => b < a
     148       32103 :         return simplified()->SpeculativeNumberLessThan(hint);
     149             :       case IrOpcode::kJSLessThanOrEqual:
     150         744 :         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
     151             :       case IrOpcode::kJSGreaterThanOrEqual:
     152             :         std::swap(left_, right_);  // a >= b => b <= a
     153         894 :         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
     154             :       default:
     155             :         break;
     156             :     }
     157           0 :     UNREACHABLE();
     158             :   }
     159             : 
     160      331592 :   Node* BuildSpeculativeOperation(const Operator* op) {
     161             :     DCHECK_EQ(2, op->ValueInputCount());
     162             :     DCHECK_EQ(1, op->EffectInputCount());
     163             :     DCHECK_EQ(1, op->ControlInputCount());
     164             :     DCHECK_EQ(false, OperatorProperties::HasFrameStateInput(op));
     165             :     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
     166             :     DCHECK_EQ(1, op->EffectOutputCount());
     167             :     DCHECK_EQ(0, op->ControlOutputCount());
     168      663184 :     return graph()->NewNode(op, left_, right_, effect_, control_);
     169             :   }
     170             : 
     171      437936 :   Node* TryBuildNumberBinop() {
     172             :     NumberOperationHint hint;
     173      437936 :     if (GetBinaryNumberOperationHint(&hint)) {
     174      266812 :       const Operator* op = SpeculativeNumberOp(hint);
     175      266812 :       Node* node = BuildSpeculativeOperation(op);
     176      266812 :       return node;
     177             :     }
     178             :     return nullptr;
     179             :   }
     180             : 
     181      111679 :   Node* TryBuildNumberCompare() {
     182             :     NumberOperationHint hint;
     183      111679 :     if (GetCompareNumberOperationHint(&hint)) {
     184       64780 :       const Operator* op = SpeculativeCompareOp(hint);
     185       64780 :       Node* node = BuildSpeculativeOperation(op);
     186       64780 :       return node;
     187             :     }
     188             :     return nullptr;
     189             :   }
     190             : 
     191      663184 :   JSGraph* jsgraph() const { return lowering_->jsgraph(); }
     192      663184 :   Graph* graph() const { return jsgraph()->graph(); }
     193             :   JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
     194      663184 :   SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
     195             :   CommonOperatorBuilder* common() { return jsgraph()->common(); }
     196             :   const Handle<FeedbackVector>& feedback_vector() const {
     197             :     return lowering_->feedback_vector();
     198             :   }
     199             : 
     200             :  private:
     201             :   const JSTypeHintLowering* lowering_;
     202             :   const Operator* op_;
     203             :   Node* left_;
     204             :   Node* right_;
     205             :   Node* effect_;
     206             :   Node* control_;
     207             :   FeedbackSlot slot_;
     208             : };
     209             : 
     210      504909 : JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
     211             :                                        Handle<FeedbackVector> feedback_vector,
     212             :                                        Flags flags)
     213      504909 :     : jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
     214             : 
     215      737452 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
     216      737452 :     const Operator* op, Node* left, Node* right, Node* effect, Node* control,
     217             :     FeedbackSlot slot) const {
     218             :   switch (op->opcode()) {
     219             :     case IrOpcode::kJSStrictEqual: {
     220             :       DCHECK(!slot.IsInvalid());
     221             :       CompareICNexus nexus(feedback_vector(), slot);
     222      173243 :       if (Node* node = TryBuildSoftDeopt(
     223             :               nexus, effect, control,
     224      173243 :               DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
     225             :         return LoweringResult::Exit(node);
     226             :       }
     227             :       // TODO(turbofan): Should we generally support early lowering of
     228             :       // JSStrictEqual operators here?
     229             :       break;
     230             :     }
     231             :     case IrOpcode::kJSEqual:
     232             :     case IrOpcode::kJSLessThan:
     233             :     case IrOpcode::kJSGreaterThan:
     234             :     case IrOpcode::kJSLessThanOrEqual:
     235             :     case IrOpcode::kJSGreaterThanOrEqual: {
     236             :       DCHECK(!slot.IsInvalid());
     237             :       CompareICNexus nexus(feedback_vector(), slot);
     238      112322 :       if (Node* node = TryBuildSoftDeopt(
     239             :               nexus, effect, control,
     240      112322 :               DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
     241             :         return LoweringResult::Exit(node);
     242             :       }
     243             :       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
     244      111679 :       if (Node* node = b.TryBuildNumberCompare()) {
     245             :         return LoweringResult::SideEffectFree(node, node, control);
     246             :       }
     247             :       break;
     248             :     }
     249             :     case IrOpcode::kJSBitwiseOr:
     250             :     case IrOpcode::kJSBitwiseXor:
     251             :     case IrOpcode::kJSBitwiseAnd:
     252             :     case IrOpcode::kJSShiftLeft:
     253             :     case IrOpcode::kJSShiftRight:
     254             :     case IrOpcode::kJSShiftRightLogical:
     255             :     case IrOpcode::kJSAdd:
     256             :     case IrOpcode::kJSSubtract:
     257             :     case IrOpcode::kJSMultiply:
     258             :     case IrOpcode::kJSDivide:
     259             :     case IrOpcode::kJSModulus: {
     260             :       DCHECK(!slot.IsInvalid());
     261             :       BinaryOpICNexus nexus(feedback_vector(), slot);
     262      451887 :       if (Node* node = TryBuildSoftDeopt(
     263             :               nexus, effect, control,
     264      451887 :               DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
     265             :         return LoweringResult::Exit(node);
     266             :       }
     267             :       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
     268      437936 :       if (Node* node = b.TryBuildNumberBinop()) {
     269             :         return LoweringResult::SideEffectFree(node, node, control);
     270             :       }
     271             :       break;
     272             :     }
     273             :     default:
     274           0 :       UNREACHABLE();
     275             :       break;
     276             :   }
     277             :   return LoweringResult::NoChange();
     278             : }
     279             : 
     280        1710 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
     281             :     Node* receiver, Node* cache_array, Node* cache_type, Node* index,
     282             :     Node* effect, Node* control, FeedbackSlot slot) const {
     283             :   DCHECK(!slot.IsInvalid());
     284             :   ForInICNexus nexus(feedback_vector(), slot);
     285        1710 :   if (Node* node = TryBuildSoftDeopt(
     286             :           nexus, effect, control,
     287        1710 :           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
     288             :     return LoweringResult::Exit(node);
     289             :   }
     290             :   return LoweringResult::NoChange();
     291             : }
     292             : 
     293             : JSTypeHintLowering::LoweringResult
     294        1548 : JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
     295             :                                                 Node* control,
     296             :                                                 FeedbackSlot slot) const {
     297             :   DCHECK(!slot.IsInvalid());
     298             :   ForInICNexus nexus(feedback_vector(), slot);
     299        1548 :   if (Node* node = TryBuildSoftDeopt(
     300             :           nexus, effect, control,
     301        1548 :           DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
     302             :     return LoweringResult::Exit(node);
     303             :   }
     304             :   return LoweringResult::NoChange();
     305             : }
     306             : 
     307       31388 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
     308       39852 :     Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
     309             :   DCHECK(!slot.IsInvalid());
     310             :   BinaryOpICNexus nexus(feedback_vector(), slot);
     311             :   NumberOperationHint hint;
     312       31388 :   if (BinaryOperationHintToNumberOperationHint(
     313       31388 :           nexus.GetBinaryOperationFeedback(), &hint)) {
     314             :     Node* node = jsgraph()->graph()->NewNode(
     315             :         jsgraph()->simplified()->SpeculativeToNumber(hint), input, effect,
     316       39852 :         control);
     317             :     return LoweringResult::SideEffectFree(node, node, control);
     318             :   }
     319             :   return LoweringResult::NoChange();
     320             : }
     321             : 
     322      581777 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
     323             :     const Operator* op, Node* const* args, int arg_count, Node* effect,
     324             :     Node* control, FeedbackSlot slot) const {
     325             :   DCHECK(op->opcode() == IrOpcode::kJSCall ||
     326             :          op->opcode() == IrOpcode::kJSCallWithSpread);
     327             :   DCHECK(!slot.IsInvalid());
     328             :   CallICNexus nexus(feedback_vector(), slot);
     329      581777 :   if (Node* node = TryBuildSoftDeopt(
     330             :           nexus, effect, control,
     331      581777 :           DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
     332             :     return LoweringResult::Exit(node);
     333             :   }
     334             :   return LoweringResult::NoChange();
     335             : }
     336             : 
     337       38495 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
     338             :     const Operator* op, Node* const* args, int arg_count, Node* effect,
     339             :     Node* control, FeedbackSlot slot) const {
     340             :   DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
     341             :          op->opcode() == IrOpcode::kJSConstructWithSpread);
     342             :   DCHECK(!slot.IsInvalid());
     343             :   CallICNexus nexus(feedback_vector(), slot);
     344       38495 :   if (Node* node = TryBuildSoftDeopt(
     345             :           nexus, effect, control,
     346       38495 :           DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
     347             :     return LoweringResult::Exit(node);
     348             :   }
     349             :   return LoweringResult::NoChange();
     350             : }
     351             : 
     352      598905 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
     353             :     const Operator* op, Node* receiver, Node* effect, Node* control,
     354             :     FeedbackSlot slot) const {
     355             :   DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
     356             :   DCHECK(!slot.IsInvalid());
     357             :   LoadICNexus nexus(feedback_vector(), slot);
     358      598905 :   if (Node* node = TryBuildSoftDeopt(
     359             :           nexus, effect, control,
     360      598905 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
     361             :     return LoweringResult::Exit(node);
     362             :   }
     363             :   return LoweringResult::NoChange();
     364             : }
     365             : 
     366       55016 : JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
     367             :     const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
     368             :     FeedbackSlot slot) const {
     369             :   DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
     370             :   DCHECK(!slot.IsInvalid());
     371             :   KeyedLoadICNexus nexus(feedback_vector(), slot);
     372       55016 :   if (Node* node = TryBuildSoftDeopt(
     373             :           nexus, effect, control,
     374       55016 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
     375             :     return LoweringResult::Exit(node);
     376             :   }
     377             :   return LoweringResult::NoChange();
     378             : }
     379             : 
     380             : JSTypeHintLowering::LoweringResult
     381      310724 : JSTypeHintLowering::ReduceStoreNamedOperation(const Operator* op, Node* obj,
     382             :                                               Node* val, Node* effect,
     383             :                                               Node* control,
     384             :                                               FeedbackSlot slot) const {
     385             :   DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
     386             :          op->opcode() == IrOpcode::kJSStoreNamedOwn);
     387             :   DCHECK(!slot.IsInvalid());
     388             :   StoreICNexus nexus(feedback_vector(), slot);
     389      310724 :   if (Node* node = TryBuildSoftDeopt(
     390             :           nexus, effect, control,
     391      310724 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
     392             :     return LoweringResult::Exit(node);
     393             :   }
     394             :   return LoweringResult::NoChange();
     395             : }
     396             : 
     397             : JSTypeHintLowering::LoweringResult
     398       63175 : JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
     399             :                                               Node* key, Node* val,
     400             :                                               Node* effect, Node* control,
     401             :                                               FeedbackSlot slot) const {
     402             :   DCHECK_EQ(IrOpcode::kJSStoreProperty, op->opcode());
     403             :   DCHECK(!slot.IsInvalid());
     404             :   KeyedStoreICNexus nexus(feedback_vector(), slot);
     405       63175 :   if (Node* node = TryBuildSoftDeopt(
     406             :           nexus, effect, control,
     407       63175 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
     408             :     return LoweringResult::Exit(node);
     409             :   }
     410             :   return LoweringResult::NoChange();
     411             : }
     412             : 
     413     2388797 : Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
     414             :                                             Node* control,
     415      187374 :                                             DeoptimizeReason reason) const {
     416     3146678 :   if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
     417             :     Node* deoptimize = jsgraph()->graph()->NewNode(
     418             :         jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason),
     419      187374 :         jsgraph()->Dead(), effect, control);
     420       62458 :     Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
     421       62458 :     deoptimize->ReplaceInput(0, frame_state);
     422       62458 :     return deoptimize;
     423             :   }
     424             :   return nullptr;
     425             : }
     426             : 
     427             : }  // namespace compiler
     428             : }  // namespace internal
     429             : }  // namespace v8

Generated by: LCOV version 1.10