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      394751 : 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      394751 :       true_type_(Type::HeapConstant(factory()->true_value(), graph()->zone())),
      26             :       false_type_(
      27      394751 :           Type::HeapConstant(factory()->false_value(), graph()->zone())),
      28     1184253 :       type_cache_(TypeCache::Get()) {}
      29             : 
      30      789502 : TypedOptimization::~TypedOptimization() {}
      31             : 
      32    63430671 : 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    77440369 :   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    14269111 :     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    14078182 :     if (upper->IsInhabited()) {
      47    14078022 :       if (upper->IsHeapConstant()) {
      48             :         Node* replacement =
      49       49540 :             jsgraph()->Constant(upper->AsHeapConstant()->Value());
      50      143775 :         ReplaceWithValue(node, replacement);
      51             :         return Changed(replacement);
      52    14028470 :       } 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    14028413 :       } else if (upper->Is(Type::NaN())) {
      57         703 :         Node* replacement = jsgraph()->NaNConstant();
      58             :         ReplaceWithValue(node, replacement);
      59             :         return Changed(replacement);
      60    14027713 :       } else if (upper->Is(Type::Null())) {
      61           1 :         Node* replacement = jsgraph()->NullConstant();
      62             :         ReplaceWithValue(node, replacement);
      63             :         return Changed(replacement);
      64    14568223 :       } else if (upper->Is(Type::PlainNumber()) &&
      65      540516 :                  upper->Min() == upper->Max()) {
      66      187008 :         Node* replacement = jsgraph()->Constant(upper->Min());
      67             :         ReplaceWithValue(node, replacement);
      68             :         return Changed(replacement);
      69    13934190 :       } else if (upper->Is(Type::Undefined())) {
      70           1 :         Node* replacement = jsgraph()->UndefinedConstant();
      71             :         ReplaceWithValue(node, replacement);
      72             :         return Changed(replacement);
      73             :       }
      74             :     }
      75             :   }
      76    31476080 :   switch (node->opcode()) {
      77             :     case IrOpcode::kCheckHeapObject:
      78       39877 :       return ReduceCheckHeapObject(node);
      79             :     case IrOpcode::kCheckMaps:
      80       69011 :       return ReduceCheckMaps(node);
      81             :     case IrOpcode::kCheckNumber:
      82        3876 :       return ReduceCheckNumber(node);
      83             :     case IrOpcode::kCheckString:
      84        2866 :       return ReduceCheckString(node);
      85             :     case IrOpcode::kLoadField:
      86     1077968 :       return ReduceLoadField(node);
      87             :     case IrOpcode::kNumberCeil:
      88             :     case IrOpcode::kNumberRound:
      89             :     case IrOpcode::kNumberTrunc:
      90        7175 :       return ReduceNumberRoundop(node);
      91             :     case IrOpcode::kNumberFloor:
      92        9287 :       return ReduceNumberFloor(node);
      93             :     case IrOpcode::kNumberToUint8Clamped:
      94         432 :       return ReduceNumberToUint8Clamped(node);
      95             :     case IrOpcode::kPhi:
      96      502529 :       return ReducePhi(node);
      97             :     case IrOpcode::kReferenceEqual:
      98      234099 :       return ReduceReferenceEqual(node);
      99             :     case IrOpcode::kSelect:
     100       16045 :       return ReduceSelect(node);
     101             :     case IrOpcode::kSpeculativeToNumber:
     102        2304 :       return ReduceSpeculativeToNumber(node);
     103             :     default:
     104             :       break;
     105             :   }
     106             :   return NoChange();
     107             : }
     108             : 
     109             : namespace {
     110             : 
     111       78879 : MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
     112       78879 :   if (object_type->IsHeapConstant()) {
     113             :     Handle<Map> object_map(object_type->AsHeapConstant()->Value()->map());
     114        4418 :     if (object_map->is_stable()) return object_map;
     115             :   }
     116             :   return MaybeHandle<Map>();
     117             : }
     118             : 
     119             : }  // namespace
     120             : 
     121       39877 : Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
     122       39877 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     123             :   Type* const input_type = NodeProperties::GetType(input);
     124       39877 :   if (!input_type->Maybe(Type::SignedSmall())) {
     125       10473 :     ReplaceWithValue(node, input);
     126             :     return Replace(input);
     127             :   }
     128             :   return NoChange();
     129             : }
     130             : 
     131       69404 : 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       69011 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     138             :   Type* const object_type = NodeProperties::GetType(object);
     139       69011 :   Node* const effect = NodeProperties::GetEffectInput(node);
     140             :   Handle<Map> object_map;
     141      138022 :   if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
     142         786 :     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        3876 : Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
     158        3876 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     159             :   Type* const input_type = NodeProperties::GetType(input);
     160        3876 :   if (input_type->Is(Type::Number())) {
     161        3379 :     ReplaceWithValue(node, input);
     162             :     return Replace(input);
     163             :   }
     164             :   return NoChange();
     165             : }
     166             : 
     167        2866 : Reduction TypedOptimization::ReduceCheckString(Node* node) {
     168        2866 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     169             :   Type* const input_type = NodeProperties::GetType(input);
     170        2866 :   if (input_type->Is(Type::String())) {
     171         991 :     ReplaceWithValue(node, input);
     172             :     return Replace(input);
     173             :   }
     174             :   return NoChange();
     175             : }
     176             : 
     177     2156050 : Reduction TypedOptimization::ReduceLoadField(Node* node) {
     178     1077968 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     179             :   Type* const object_type = NodeProperties::GetType(object);
     180     1077968 :   FieldAccess const& access = FieldAccessOf(node->op());
     181     1077968 :   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       19736 :     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        9287 : Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
     206        9649 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     207             :   Type* const input_type = NodeProperties::GetType(input);
     208       18574 :   if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
     209             :     return Replace(input);
     210             :   }
     211       18904 :   if (input_type->Is(Type::PlainNumber()) &&
     212          48 :       (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        7175 : Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
     241        7175 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     242             :   Type* const input_type = NodeProperties::GetType(input);
     243       14350 :   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      502529 : 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      502529 :   int arity = node->op()->ValueInputCount();
     264             :   Type* type = NodeProperties::GetType(node->InputAt(0));
     265     1482625 :   for (int i = 1; i < arity; ++i) {
     266             :     type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
     267     1960192 :                        graph()->zone());
     268             :   }
     269             :   Type* const node_type = NodeProperties::GetType(node);
     270      502529 :   if (!node_type->Is(type)) {
     271       36452 :     type = Type::Intersect(node_type, type, graph()->zone());
     272             :     NodeProperties::SetType(node, type);
     273             :     return Changed(node);
     274             :   }
     275             :   return NoChange();
     276             : }
     277             : 
     278      248253 : Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
     279             :   DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
     280      234099 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     281      234099 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     282             :   Type* const lhs_type = NodeProperties::GetType(lhs);
     283             :   Type* const rhs_type = NodeProperties::GetType(rhs);
     284      234099 :   if (!lhs_type->Maybe(rhs_type)) {
     285       14154 :     return Replace(jsgraph()->FalseConstant());
     286             :   }
     287             :   return NoChange();
     288             : }
     289             : 
     290       16045 : Reduction TypedOptimization::ReduceSelect(Node* node) {
     291             :   DCHECK_EQ(IrOpcode::kSelect, node->opcode());
     292       16045 :   Node* const condition = NodeProperties::GetValueInput(node, 0);
     293             :   Type* const condition_type = NodeProperties::GetType(condition);
     294       16045 :   Node* const vtrue = NodeProperties::GetValueInput(node, 1);
     295             :   Type* const vtrue_type = NodeProperties::GetType(vtrue);
     296       16045 :   Node* const vfalse = NodeProperties::GetValueInput(node, 2);
     297             :   Type* const vfalse_type = NodeProperties::GetType(vfalse);
     298       32090 :   if (condition_type->Is(true_type_)) {
     299             :     // Select(condition:true, vtrue, vfalse) => vtrue
     300             :     return Replace(vtrue);
     301             :   }
     302       31876 :   if (condition_type->Is(false_type_)) {
     303             :     // Select(condition:false, vtrue, vfalse) => vfalse
     304             :     return Replace(vfalse);
     305             :   }
     306       28965 :   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       22053 :   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       10031 :   Type* type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
     319             :   Type* const node_type = NodeProperties::GetType(node);
     320       10031 :   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        2304 : Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
     329             :   DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
     330        2304 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     331             :   Type* const input_type = NodeProperties::GetType(input);
     332        2304 :   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     1816081 : Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
     343             : 
     344      789528 : 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