LCOV - code coverage report
Current view: top level - src/compiler - js-type-hint-lowering.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 97 101 96.0 %
Date: 2017-04-26 Functions: 17 17 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/js-graph.h"
       8             : #include "src/compiler/operator-properties.h"
       9             : #include "src/compiler/simplified-operator.h"
      10             : #include "src/feedback-vector.h"
      11             : #include "src/type-hints.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : namespace compiler {
      16             : 
      17             : namespace {
      18             : 
      19             : bool BinaryOperationHintToNumberOperationHint(
      20             :     BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
      21      490418 :   switch (binop_hint) {
      22             :     case BinaryOperationHint::kSignedSmall:
      23      157528 :       *number_hint = NumberOperationHint::kSignedSmall;
      24             :       return true;
      25             :     case BinaryOperationHint::kSigned32:
      26           0 :       *number_hint = NumberOperationHint::kSigned32;
      27             :       return true;
      28             :     case BinaryOperationHint::kNumberOrOddball:
      29       98802 :       *number_hint = NumberOperationHint::kNumberOrOddball;
      30             :       return true;
      31             :     case BinaryOperationHint::kAny:
      32             :     case BinaryOperationHint::kNone:
      33             :     case BinaryOperationHint::kString:
      34             :       break;
      35             :   }
      36             :   return false;
      37             : }
      38             : 
      39             : }  // namespace
      40             : 
      41             : class JSSpeculativeBinopBuilder final {
      42             :  public:
      43             :   JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
      44             :                             const Operator* op, Node* left, Node* right,
      45             :                             Node* effect, Node* control, FeedbackSlot slot)
      46             :       : lowering_(lowering),
      47             :         op_(op),
      48             :         left_(left),
      49             :         right_(right),
      50             :         effect_(effect),
      51             :         control_(control),
      52      586189 :         slot_(slot) {}
      53             : 
      54      485425 :   BinaryOperationHint GetBinaryOperationHint() {
      55             :     DCHECK_EQ(FeedbackSlotKind::kBinaryOp, feedback_vector()->GetKind(slot_));
      56             :     BinaryOpICNexus nexus(feedback_vector(), slot_);
      57      485425 :     return nexus.GetBinaryOperationFeedback();
      58             :   }
      59             : 
      60      100764 :   CompareOperationHint GetCompareOperationHint() {
      61             :     DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot_));
      62             :     CompareICNexus nexus(feedback_vector(), slot_);
      63      100764 :     return nexus.GetCompareOperationFeedback();
      64             :   }
      65             : 
      66      485425 :   bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
      67             :     return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
      68      970850 :                                                     hint);
      69             :   }
      70             : 
      71      100764 :   bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
      72      100764 :     switch (GetCompareOperationHint()) {
      73             :       case CompareOperationHint::kSignedSmall:
      74       52937 :         *hint = NumberOperationHint::kSignedSmall;
      75       52937 :         return true;
      76             :       case CompareOperationHint::kNumber:
      77        1686 :         *hint = NumberOperationHint::kNumber;
      78        1686 :         return true;
      79             :       case CompareOperationHint::kNumberOrOddball:
      80          61 :         *hint = NumberOperationHint::kNumberOrOddball;
      81          61 :         return true;
      82             :       case CompareOperationHint::kAny:
      83             :       case CompareOperationHint::kNone:
      84             :       case CompareOperationHint::kString:
      85             :       case CompareOperationHint::kReceiver:
      86             :       case CompareOperationHint::kInternalizedString:
      87             :         break;
      88             :     }
      89             :     return false;
      90             :   }
      91             : 
      92      256330 :   const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
      93      256330 :     switch (op_->opcode()) {
      94             :       case IrOpcode::kJSAdd:
      95      150566 :         return simplified()->SpeculativeNumberAdd(hint);
      96             :       case IrOpcode::kJSSubtract:
      97       25027 :         return simplified()->SpeculativeNumberSubtract(hint);
      98             :       case IrOpcode::kJSMultiply:
      99       27320 :         return simplified()->SpeculativeNumberMultiply(hint);
     100             :       case IrOpcode::kJSDivide:
     101       16757 :         return simplified()->SpeculativeNumberDivide(hint);
     102             :       case IrOpcode::kJSModulus:
     103        3812 :         return simplified()->SpeculativeNumberModulus(hint);
     104             :       case IrOpcode::kJSBitwiseAnd:
     105        5038 :         return simplified()->SpeculativeNumberBitwiseAnd(hint);
     106             :       case IrOpcode::kJSBitwiseOr:
     107       17150 :         return simplified()->SpeculativeNumberBitwiseOr(hint);
     108             :       case IrOpcode::kJSBitwiseXor:
     109        1435 :         return simplified()->SpeculativeNumberBitwiseXor(hint);
     110             :       case IrOpcode::kJSShiftLeft:
     111        2296 :         return simplified()->SpeculativeNumberShiftLeft(hint);
     112             :       case IrOpcode::kJSShiftRight:
     113        5022 :         return simplified()->SpeculativeNumberShiftRight(hint);
     114             :       case IrOpcode::kJSShiftRightLogical:
     115        1907 :         return simplified()->SpeculativeNumberShiftRightLogical(hint);
     116             :       default:
     117             :         break;
     118             :     }
     119           0 :     UNREACHABLE();
     120             :     return nullptr;
     121             :   }
     122             : 
     123       54684 :   const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
     124       54684 :     switch (op_->opcode()) {
     125             :       case IrOpcode::kJSEqual:
     126        6543 :         return simplified()->SpeculativeNumberEqual(hint);
     127             :       case IrOpcode::kJSLessThan:
     128       14604 :         return simplified()->SpeculativeNumberLessThan(hint);
     129             :       case IrOpcode::kJSGreaterThan:
     130             :         std::swap(left_, right_);  // a > b => b < a
     131       31975 :         return simplified()->SpeculativeNumberLessThan(hint);
     132             :       case IrOpcode::kJSLessThanOrEqual:
     133         709 :         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
     134             :       case IrOpcode::kJSGreaterThanOrEqual:
     135             :         std::swap(left_, right_);  // a >= b => b <= a
     136         853 :         return simplified()->SpeculativeNumberLessThanOrEqual(hint);
     137             :       default:
     138             :         break;
     139             :     }
     140           0 :     UNREACHABLE();
     141             :     return nullptr;
     142             :   }
     143             : 
     144      311014 :   Node* BuildSpeculativeOperation(const Operator* op) {
     145             :     DCHECK_EQ(2, op->ValueInputCount());
     146             :     DCHECK_EQ(1, op->EffectInputCount());
     147             :     DCHECK_EQ(1, op->ControlInputCount());
     148             :     DCHECK_EQ(false, OperatorProperties::HasFrameStateInput(op));
     149             :     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
     150             :     DCHECK_EQ(1, op->EffectOutputCount());
     151             :     DCHECK_EQ(0, op->ControlOutputCount());
     152      622028 :     return graph()->NewNode(op, left_, right_, effect_, control_);
     153             :   }
     154             : 
     155      485425 :   Node* TryBuildNumberBinop() {
     156             :     NumberOperationHint hint;
     157      485425 :     if (GetBinaryNumberOperationHint(&hint)) {
     158      256330 :       const Operator* op = SpeculativeNumberOp(hint);
     159      256330 :       Node* node = BuildSpeculativeOperation(op);
     160      256330 :       return node;
     161             :     }
     162             :     return nullptr;
     163             :   }
     164             : 
     165      100764 :   Node* TryBuildNumberCompare() {
     166             :     NumberOperationHint hint;
     167      100764 :     if (GetCompareNumberOperationHint(&hint)) {
     168       54684 :       const Operator* op = SpeculativeCompareOp(hint);
     169       54684 :       Node* node = BuildSpeculativeOperation(op);
     170       54684 :       return node;
     171             :     }
     172             :     return nullptr;
     173             :   }
     174             : 
     175      622028 :   JSGraph* jsgraph() const { return lowering_->jsgraph(); }
     176      622028 :   Graph* graph() const { return jsgraph()->graph(); }
     177             :   JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
     178      622028 :   SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
     179             :   CommonOperatorBuilder* common() { return jsgraph()->common(); }
     180             :   const Handle<FeedbackVector>& feedback_vector() const {
     181             :     return lowering_->feedback_vector();
     182             :   }
     183             : 
     184             :  private:
     185             :   const JSTypeHintLowering* lowering_;
     186             :   const Operator* op_;
     187             :   Node* left_;
     188             :   Node* right_;
     189             :   Node* effect_;
     190             :   Node* control_;
     191             :   FeedbackSlot slot_;
     192             : };
     193             : 
     194      430866 : JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
     195             :                                        Handle<FeedbackVector> feedback_vector,
     196             :                                        Flags flags)
     197      430866 :     : jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
     198             : 
     199      840415 : Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
     200             :                                                     Node* left, Node* right,
     201             :                                                     Node* effect, Node* control,
     202             :                                                     FeedbackSlot slot) const {
     203             :   switch (op->opcode()) {
     204             :     case IrOpcode::kJSStrictEqual:
     205             :       break;
     206             :     case IrOpcode::kJSEqual:
     207             :     case IrOpcode::kJSLessThan:
     208             :     case IrOpcode::kJSGreaterThan:
     209             :     case IrOpcode::kJSLessThanOrEqual:
     210             :     case IrOpcode::kJSGreaterThanOrEqual: {
     211             :       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
     212      100764 :       if (Node* node = b.TryBuildNumberCompare()) {
     213       54684 :         return Reduction(node);
     214             :       }
     215       46080 :       break;
     216             :     }
     217             :     case IrOpcode::kJSBitwiseOr:
     218             :     case IrOpcode::kJSBitwiseXor:
     219             :     case IrOpcode::kJSBitwiseAnd:
     220             :     case IrOpcode::kJSShiftLeft:
     221             :     case IrOpcode::kJSShiftRight:
     222             :     case IrOpcode::kJSShiftRightLogical:
     223             :     case IrOpcode::kJSAdd:
     224             :     case IrOpcode::kJSSubtract:
     225             :     case IrOpcode::kJSMultiply:
     226             :     case IrOpcode::kJSDivide:
     227             :     case IrOpcode::kJSModulus: {
     228             :       JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
     229      485425 :       if (Node* node = b.TryBuildNumberBinop()) {
     230      256330 :         return Reduction(node);
     231             :       }
     232      229095 :       break;
     233             :     }
     234             :     default:
     235           0 :       UNREACHABLE();
     236             :       break;
     237             :   }
     238      529401 :   return Reduction();
     239             : }
     240             : 
     241        4993 : Reduction JSTypeHintLowering::ReduceToNumberOperation(Node* input, Node* effect,
     242             :                                                       Node* control,
     243        4438 :                                                       FeedbackSlot slot) const {
     244             :   DCHECK(!slot.IsInvalid());
     245             :   BinaryOpICNexus nexus(feedback_vector(), slot);
     246             :   NumberOperationHint hint;
     247        4993 :   if (BinaryOperationHintToNumberOperationHint(
     248        4993 :           nexus.GetBinaryOperationFeedback(), &hint)) {
     249             :     Node* node = jsgraph()->graph()->NewNode(
     250             :         jsgraph()->simplified()->SpeculativeToNumber(hint), input, effect,
     251        4438 :         control);
     252        2219 :     return Reduction(node);
     253             :   }
     254        2774 :   return Reduction();
     255             : }
     256             : 
     257      455619 : Reduction JSTypeHintLowering::ReduceLoadNamedOperation(
     258             :     const Operator* op, Node* obj, Node* effect, Node* control,
     259             :     FeedbackSlot slot) const {
     260             :   DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
     261             :   DCHECK(!slot.IsInvalid());
     262             :   LoadICNexus nexus(feedback_vector(), slot);
     263      455619 :   if (Node* node = TryBuildSoftDeopt(
     264             :           nexus, effect, control,
     265      455619 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
     266       22623 :     return Reduction(node);
     267             :   }
     268      432996 :   return Reduction();
     269             : }
     270             : 
     271       67876 : Reduction JSTypeHintLowering::ReduceLoadKeyedOperation(
     272             :     const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
     273             :     FeedbackSlot slot) const {
     274             :   DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
     275             :   DCHECK(!slot.IsInvalid());
     276             :   KeyedLoadICNexus nexus(feedback_vector(), slot);
     277       67876 :   if (Node* node = TryBuildSoftDeopt(
     278             :           nexus, effect, control,
     279       67876 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
     280         348 :     return Reduction(node);
     281             :   }
     282       67528 :   return Reduction();
     283             : }
     284             : 
     285       98217 : Reduction JSTypeHintLowering::ReduceStoreNamedOperation(
     286             :     const Operator* op, Node* obj, Node* val, Node* effect, Node* control,
     287             :     FeedbackSlot slot) const {
     288             :   DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
     289             :          op->opcode() == IrOpcode::kJSStoreNamedOwn);
     290             :   DCHECK(!slot.IsInvalid());
     291             :   StoreICNexus nexus(feedback_vector(), slot);
     292       98217 :   if (Node* node = TryBuildSoftDeopt(
     293             :           nexus, effect, control,
     294       98217 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
     295         375 :     return Reduction(node);
     296             :   }
     297       97842 :   return Reduction();
     298             : }
     299             : 
     300       39360 : Reduction JSTypeHintLowering::ReduceStoreKeyedOperation(
     301             :     const Operator* op, Node* obj, Node* key, Node* val, Node* effect,
     302             :     Node* control, FeedbackSlot slot) const {
     303             :   DCHECK_EQ(IrOpcode::kJSStoreProperty, op->opcode());
     304             :   DCHECK(!slot.IsInvalid());
     305             :   KeyedStoreICNexus nexus(feedback_vector(), slot);
     306       39360 :   if (Node* node = TryBuildSoftDeopt(
     307             :           nexus, effect, control,
     308       39360 :           DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
     309          69 :     return Reduction(node);
     310             :   }
     311       39291 :   return Reduction();
     312             : }
     313             : 
     314      661072 : Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
     315             :                                             Node* control,
     316       70245 :                                             DeoptimizeReason reason) const {
     317      789090 :   if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
     318             :     Node* deoptimize = jsgraph()->graph()->NewNode(
     319             :         jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason),
     320       70245 :         jsgraph()->Dead(), effect, control);
     321       23415 :     Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
     322       23415 :     deoptimize->ReplaceInput(0, frame_state);
     323       23415 :     return deoptimize;
     324             :   }
     325             :   return nullptr;
     326             : }
     327             : 
     328             : }  // namespace compiler
     329             : }  // namespace internal
     330             : }  // namespace v8

Generated by: LCOV version 1.10