LCOV - code coverage report
Current view: top level - src/compiler - typed-optimization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 112 118 94.9 %
Date: 2017-04-26 Functions: 16 21 76.2 %

          Line data    Source code
       1             : // Copyright 2016 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/typed-optimization.h"
       6             : 
       7             : #include "src/compilation-dependencies.h"
       8             : #include "src/compiler/js-graph.h"
       9             : #include "src/compiler/node-properties.h"
      10             : #include "src/compiler/simplified-operator.h"
      11             : #include "src/compiler/type-cache.h"
      12             : #include "src/isolate-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace compiler {
      17             : 
      18      395470 : TypedOptimization::TypedOptimization(Editor* editor,
      19             :                                      CompilationDependencies* dependencies,
      20             :                                      Flags flags, JSGraph* jsgraph)
      21             :     : AdvancedReducer(editor),
      22             :       dependencies_(dependencies),
      23             :       flags_(flags),
      24             :       jsgraph_(jsgraph),
      25      395470 :       true_type_(Type::HeapConstant(factory()->true_value(), graph()->zone())),
      26             :       false_type_(
      27      395470 :           Type::HeapConstant(factory()->false_value(), graph()->zone())),
      28     1186410 :       type_cache_(TypeCache::Get()) {}
      29             : 
      30      790940 : TypedOptimization::~TypedOptimization() {}
      31             : 
      32    63414014 : Reduction TypedOptimization::Reduce(Node* node) {
      33             :   // Check if the output type is a singleton.  In that case we already know the
      34             :   // result value and can simply replace the node if it's eliminable.
      35    77419951 :   if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
      36             :       node->op()->HasProperty(Operator::kEliminatable)) {
      37             :     // TODO(v8:5303): We must not eliminate FinishRegion here. This special
      38             :     // case can be removed once we have separate operators for value and
      39             :     // effect regions.
      40    14265994 :     if (node->opcode() == IrOpcode::kFinishRegion) return NoChange();
      41             :     // We can only constant-fold nodes here, that are known to not cause any
      42             :     // side-effect, may it be a JavaScript observable side-effect or a possible
      43             :     // eager deoptimization exit (i.e. {node} has an operator that doesn't have
      44             :     // the Operator::kNoDeopt property).
      45             :     Type* upper = NodeProperties::GetType(node);
      46    14075808 :     if (upper->IsInhabited()) {
      47    14075624 :       if (upper->IsHeapConstant()) {
      48             :         Node* replacement =
      49       49228 :             jsgraph()->Constant(upper->AsHeapConstant()->Value());
      50      143269 :         ReplaceWithValue(node, replacement);
      51             :         return Changed(replacement);
      52    14026391 :       } else if (upper->Is(Type::MinusZero())) {
      53          26 :         Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
      54             :         ReplaceWithValue(node, replacement);
      55             :         return Changed(replacement);
      56    14026355 :       } else if (upper->Is(Type::NaN())) {
      57         702 :         Node* replacement = jsgraph()->NaNConstant();
      58             :         ReplaceWithValue(node, replacement);
      59             :         return Changed(replacement);
      60    14025654 :       } else if (upper->Is(Type::Null())) {
      61           1 :         Node* replacement = jsgraph()->NullConstant();
      62             :         ReplaceWithValue(node, replacement);
      63             :         return Changed(replacement);
      64    14561942 :       } else if (upper->Is(Type::PlainNumber()) &&
      65      536298 :                  upper->Min() == upper->Max()) {
      66      186622 :         Node* replacement = jsgraph()->Constant(upper->Min());
      67             :         ReplaceWithValue(node, replacement);
      68             :         return Changed(replacement);
      69    13932324 :       } else if (upper->Is(Type::Undefined())) {
      70           1 :         Node* replacement = jsgraph()->UndefinedConstant();
      71             :         ReplaceWithValue(node, replacement);
      72             :         return Changed(replacement);
      73             :       }
      74             :     }
      75             :   }
      76    31468642 :   switch (node->opcode()) {
      77             :     case IrOpcode::kCheckHeapObject:
      78       40041 :       return ReduceCheckHeapObject(node);
      79             :     case IrOpcode::kCheckMaps:
      80       68915 :       return ReduceCheckMaps(node);
      81             :     case IrOpcode::kCheckNumber:
      82        3873 :       return ReduceCheckNumber(node);
      83             :     case IrOpcode::kCheckString:
      84        2870 :       return ReduceCheckString(node);
      85             :     case IrOpcode::kLoadField:
      86     1074467 :       return ReduceLoadField(node);
      87             :     case IrOpcode::kNumberCeil:
      88             :     case IrOpcode::kNumberRound:
      89             :     case IrOpcode::kNumberTrunc:
      90        7176 :       return ReduceNumberRoundop(node);
      91             :     case IrOpcode::kNumberFloor:
      92        9315 :       return ReduceNumberFloor(node);
      93             :     case IrOpcode::kNumberToUint8Clamped:
      94         432 :       return ReduceNumberToUint8Clamped(node);
      95             :     case IrOpcode::kPhi:
      96      501078 :       return ReducePhi(node);
      97             :     case IrOpcode::kReferenceEqual:
      98      234331 :       return ReduceReferenceEqual(node);
      99             :     case IrOpcode::kSelect:
     100       16010 :       return ReduceSelect(node);
     101             :     case IrOpcode::kSpeculativeToNumber:
     102        2289 :       return ReduceSpeculativeToNumber(node);
     103             :     default:
     104             :       break;
     105             :   }
     106             :   return NoChange();
     107             : }
     108             : 
     109             : namespace {
     110             : 
     111       78850 : MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
     112       78850 :   if (object_type->IsHeapConstant()) {
     113             :     Handle<Map> object_map(object_type->AsHeapConstant()->Value()->map());
     114        4367 :     if (object_map->is_stable()) return object_map;
     115             :   }
     116             :   return MaybeHandle<Map>();
     117             : }
     118             : 
     119             : }  // namespace
     120             : 
     121       40041 : Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
     122       40041 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     123             :   Type* const input_type = NodeProperties::GetType(input);
     124       40041 :   if (!input_type->Maybe(Type::SignedSmall())) {
     125       10471 :     ReplaceWithValue(node, input);
     126             :     return Replace(input);
     127             :   }
     128             :   return NoChange();
     129             : }
     130             : 
     131       69306 : Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
     132             :   // The CheckMaps(o, ...map...) can be eliminated if map is stable,
     133             :   // o has type Constant(object) and map == object->map, and either
     134             :   //  (1) map cannot transition further, or
     135             :   //  (2) we can add a code dependency on the stability of map
     136             :   //      (to guard the Constant type information).
     137       68915 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     138             :   Type* const object_type = NodeProperties::GetType(object);
     139       68915 :   Node* const effect = NodeProperties::GetEffectInput(node);
     140             :   Handle<Map> object_map;
     141      137830 :   if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
     142         782 :     for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
     143           0 :       Node* const map = NodeProperties::GetValueInput(node, i);
     144             :       Type* const map_type = NodeProperties::GetType(map);
     145           0 :       if (map_type->IsHeapConstant() &&
     146             :           map_type->AsHeapConstant()->Value().is_identical_to(object_map)) {
     147           0 :         if (object_map->CanTransition()) {
     148           0 :           dependencies()->AssumeMapStable(object_map);
     149             :         }
     150             :         return Replace(effect);
     151             :       }
     152             :     }
     153             :   }
     154             :   return NoChange();
     155             : }
     156             : 
     157        3873 : Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
     158        3873 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     159             :   Type* const input_type = NodeProperties::GetType(input);
     160        3873 :   if (input_type->Is(Type::Number())) {
     161        3378 :     ReplaceWithValue(node, input);
     162             :     return Replace(input);
     163             :   }
     164             :   return NoChange();
     165             : }
     166             : 
     167        2870 : Reduction TypedOptimization::ReduceCheckString(Node* node) {
     168        2870 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     169             :   Type* const input_type = NodeProperties::GetType(input);
     170        2870 :   if (input_type->Is(Type::String())) {
     171         989 :     ReplaceWithValue(node, input);
     172             :     return Replace(input);
     173             :   }
     174             :   return NoChange();
     175             : }
     176             : 
     177     2149048 : Reduction TypedOptimization::ReduceLoadField(Node* node) {
     178     1074467 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     179             :   Type* const object_type = NodeProperties::GetType(object);
     180     1074467 :   FieldAccess const& access = FieldAccessOf(node->op());
     181     1074467 :   if (access.base_is_tagged == kTaggedBase &&
     182             :       access.offset == HeapObject::kMapOffset) {
     183             :     // We can replace LoadField[Map](o) with map if is stable, and
     184             :     // o has type Constant(object) and map == object->map, and either
     185             :     //  (1) map cannot transition further, or
     186             :     //  (2) deoptimization is enabled and we can add a code dependency on the
     187             :     //      stability of map (to guard the Constant type information).
     188             :     Handle<Map> object_map;
     189       19870 :     if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
     190          57 :       if (object_map->CanTransition()) {
     191          57 :         if (flags() & kDeoptimizationEnabled) {
     192          57 :           dependencies()->AssumeMapStable(object_map);
     193             :         } else {
     194             :           return NoChange();
     195             :         }
     196             :       }
     197          57 :       Node* const value = jsgraph()->HeapConstant(object_map);
     198          57 :       ReplaceWithValue(node, value);
     199             :       return Replace(value);
     200             :     }
     201             :   }
     202             :   return NoChange();
     203             : }
     204             : 
     205        9315 : Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
     206        9675 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     207             :   Type* const input_type = NodeProperties::GetType(input);
     208       18630 :   if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
     209             :     return Replace(input);
     210             :   }
     211       18958 :   if (input_type->Is(Type::PlainNumber()) &&
     212          46 :       (input->opcode() == IrOpcode::kNumberDivide ||
     213             :        input->opcode() == IrOpcode::kSpeculativeNumberDivide)) {
     214         321 :     Node* const lhs = NodeProperties::GetValueInput(input, 0);
     215             :     Type* const lhs_type = NodeProperties::GetType(lhs);
     216         321 :     Node* const rhs = NodeProperties::GetValueInput(input, 1);
     217             :     Type* const rhs_type = NodeProperties::GetType(rhs);
     218         337 :     if (lhs_type->Is(Type::Unsigned32()) && rhs_type->Is(Type::Unsigned32())) {
     219             :       // We can replace
     220             :       //
     221             :       //   NumberFloor(NumberDivide(lhs: unsigned32,
     222             :       //                            rhs: unsigned32)): plain-number
     223             :       //
     224             :       // with
     225             :       //
     226             :       //   NumberToUint32(NumberDivide(lhs, rhs))
     227             :       //
     228             :       // and just smash the type of the {lhs} on the {node},
     229             :       // as the truncated result must be in the same range as
     230             :       // {lhs} since {rhs} cannot be less than 1 (due to the
     231             :       // plain-number type constraint on the {node}).
     232          16 :       NodeProperties::ChangeOp(node, simplified()->NumberToUint32());
     233             :       NodeProperties::SetType(node, lhs_type);
     234             :       return Changed(node);
     235             :     }
     236             :   }
     237             :   return NoChange();
     238             : }
     239             : 
     240        7176 : Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
     241        7176 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     242             :   Type* const input_type = NodeProperties::GetType(input);
     243       14352 :   if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
     244             :     return Replace(input);
     245             :   }
     246             :   return NoChange();
     247             : }
     248             : 
     249         432 : Reduction TypedOptimization::ReduceNumberToUint8Clamped(Node* node) {
     250         432 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     251             :   Type* const input_type = NodeProperties::GetType(input);
     252         864 :   if (input_type->Is(type_cache_.kUint8)) {
     253             :     return Replace(input);
     254             :   }
     255             :   return NoChange();
     256             : }
     257             : 
     258      501078 : Reduction TypedOptimization::ReducePhi(Node* node) {
     259             :   // Try to narrow the type of the Phi {node}, which might be more precise now
     260             :   // after lowering based on types, i.e. a SpeculativeNumberAdd has a more
     261             :   // precise type than the JSAdd that was in the graph when the Typer was run.
     262             :   DCHECK_EQ(IrOpcode::kPhi, node->opcode());
     263      501078 :   int arity = node->op()->ValueInputCount();
     264             :   Type* type = NodeProperties::GetType(node->InputAt(0));
     265     1478634 :   for (int i = 1; i < arity; ++i) {
     266             :     type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
     267     1955112 :                        graph()->zone());
     268             :   }
     269             :   Type* const node_type = NodeProperties::GetType(node);
     270      501078 :   if (!node_type->Is(type)) {
     271       35529 :     type = Type::Intersect(node_type, type, graph()->zone());
     272             :     NodeProperties::SetType(node, type);
     273             :     return Changed(node);
     274             :   }
     275             :   return NoChange();
     276             : }
     277             : 
     278      248442 : Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
     279             :   DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
     280      234331 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     281      234331 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     282             :   Type* const lhs_type = NodeProperties::GetType(lhs);
     283             :   Type* const rhs_type = NodeProperties::GetType(rhs);
     284      234331 :   if (!lhs_type->Maybe(rhs_type)) {
     285       14111 :     return Replace(jsgraph()->FalseConstant());
     286             :   }
     287             :   return NoChange();
     288             : }
     289             : 
     290       16010 : Reduction TypedOptimization::ReduceSelect(Node* node) {
     291             :   DCHECK_EQ(IrOpcode::kSelect, node->opcode());
     292       16010 :   Node* const condition = NodeProperties::GetValueInput(node, 0);
     293             :   Type* const condition_type = NodeProperties::GetType(condition);
     294       16010 :   Node* const vtrue = NodeProperties::GetValueInput(node, 1);
     295             :   Type* const vtrue_type = NodeProperties::GetType(vtrue);
     296       16010 :   Node* const vfalse = NodeProperties::GetValueInput(node, 2);
     297             :   Type* const vfalse_type = NodeProperties::GetType(vfalse);
     298       32020 :   if (condition_type->Is(true_type_)) {
     299             :     // Select(condition:true, vtrue, vfalse) => vtrue
     300             :     return Replace(vtrue);
     301             :   }
     302       31806 :   if (condition_type->Is(false_type_)) {
     303             :     // Select(condition:false, vtrue, vfalse) => vfalse
     304             :     return Replace(vfalse);
     305             :   }
     306       29009 :   if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) {
     307             :     // Select(condition, vtrue:true, vfalse:false) => condition
     308             :     return Replace(condition);
     309             :   }
     310       22085 :   if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) {
     311             :     // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
     312         182 :     node->TrimInputCount(1);
     313         182 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     314             :     return Changed(node);
     315             :   }
     316             :   // Try to narrow the type of the Select {node}, which might be more precise
     317             :   // now after lowering based on types.
     318       10049 :   Type* type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
     319             :   Type* const node_type = NodeProperties::GetType(node);
     320       10049 :   if (!node_type->Is(type)) {
     321           0 :     type = Type::Intersect(node_type, type, graph()->zone());
     322             :     NodeProperties::SetType(node, type);
     323             :     return Changed(node);
     324             :   }
     325             :   return NoChange();
     326             : }
     327             : 
     328        2289 : Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
     329             :   DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
     330        2289 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     331             :   Type* const input_type = NodeProperties::GetType(input);
     332        2289 :   if (input_type->Is(Type::Number())) {
     333             :     // SpeculativeToNumber(x:number) => x
     334        1184 :     ReplaceWithValue(node, input);
     335             :     return Replace(input);
     336             :   }
     337             :   return NoChange();
     338             : }
     339             : 
     340           0 : Factory* TypedOptimization::factory() const { return isolate()->factory(); }
     341             : 
     342     1814074 : Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
     343             : 
     344      790966 : Isolate* TypedOptimization::isolate() const { return jsgraph()->isolate(); }
     345             : 
     346         198 : SimplifiedOperatorBuilder* TypedOptimization::simplified() const {
     347         198 :   return jsgraph()->simplified();
     348             : }
     349             : 
     350             : }  // namespace compiler
     351             : }  // namespace internal
     352             : }  // namespace v8

Generated by: LCOV version 1.10