LCOV - code coverage report
Current view: top level - src/compiler - typed-optimization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 349 372 93.8 %
Date: 2019-02-19 Functions: 38 41 92.7 %

          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/base/optional.h"
       8             : #include "src/compiler/compilation-dependencies.h"
       9             : #include "src/compiler/js-graph.h"
      10             : #include "src/compiler/js-heap-broker.h"
      11             : #include "src/compiler/node-matchers.h"
      12             : #include "src/compiler/node-properties.h"
      13             : #include "src/compiler/simplified-operator.h"
      14             : #include "src/compiler/type-cache.h"
      15             : #include "src/isolate-inl.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : namespace compiler {
      20             : 
      21      913383 : TypedOptimization::TypedOptimization(Editor* editor,
      22             :                                      CompilationDependencies* dependencies,
      23             :                                      JSGraph* jsgraph, JSHeapBroker* broker)
      24             :     : AdvancedReducer(editor),
      25             :       dependencies_(dependencies),
      26             :       jsgraph_(jsgraph),
      27             :       broker_(broker),
      28             :       true_type_(
      29     1826773 :           Type::HeapConstant(broker, factory()->true_value(), graph()->zone())),
      30             :       false_type_(Type::HeapConstant(broker, factory()->false_value(),
      31     1826780 :                                      graph()->zone())),
      32     4566936 :       type_cache_(TypeCache::Get()) {}
      33             : 
      34             : TypedOptimization::~TypedOptimization() = default;
      35             : 
      36    70846743 : Reduction TypedOptimization::Reduce(Node* node) {
      37             :   DisallowHeapAccess no_heap_access;
      38    70846743 :   switch (node->opcode()) {
      39             :     case IrOpcode::kConvertReceiver:
      40       73039 :       return ReduceConvertReceiver(node);
      41             :     case IrOpcode::kCheckHeapObject:
      42       97543 :       return ReduceCheckHeapObject(node);
      43             :     case IrOpcode::kCheckNotTaggedHole:
      44         747 :       return ReduceCheckNotTaggedHole(node);
      45             :     case IrOpcode::kCheckMaps:
      46      235872 :       return ReduceCheckMaps(node);
      47             :     case IrOpcode::kCheckNumber:
      48        3574 :       return ReduceCheckNumber(node);
      49             :     case IrOpcode::kCheckString:
      50       33046 :       return ReduceCheckString(node);
      51             :     case IrOpcode::kCheckEqualsInternalizedString:
      52         201 :       return ReduceCheckEqualsInternalizedString(node);
      53             :     case IrOpcode::kCheckEqualsSymbol:
      54          78 :       return ReduceCheckEqualsSymbol(node);
      55             :     case IrOpcode::kLoadField:
      56     2802884 :       return ReduceLoadField(node);
      57             :     case IrOpcode::kNumberCeil:
      58             :     case IrOpcode::kNumberRound:
      59             :     case IrOpcode::kNumberTrunc:
      60       31761 :       return ReduceNumberRoundop(node);
      61             :     case IrOpcode::kNumberFloor:
      62       55088 :       return ReduceNumberFloor(node);
      63             :     case IrOpcode::kNumberSilenceNaN:
      64        1745 :       return ReduceNumberSilenceNaN(node);
      65             :     case IrOpcode::kNumberToUint8Clamped:
      66         950 :       return ReduceNumberToUint8Clamped(node);
      67             :     case IrOpcode::kPhi:
      68      896380 :       return ReducePhi(node);
      69             :     case IrOpcode::kReferenceEqual:
      70      501297 :       return ReduceReferenceEqual(node);
      71             :     case IrOpcode::kStringEqual:
      72             :     case IrOpcode::kStringLessThan:
      73             :     case IrOpcode::kStringLessThanOrEqual:
      74       31148 :       return ReduceStringComparison(node);
      75             :     case IrOpcode::kStringLength:
      76       86798 :       return ReduceStringLength(node);
      77             :     case IrOpcode::kSameValue:
      78         216 :       return ReduceSameValue(node);
      79             :     case IrOpcode::kSelect:
      80       29815 :       return ReduceSelect(node);
      81             :     case IrOpcode::kTypeOf:
      82       75013 :       return ReduceTypeOf(node);
      83             :     case IrOpcode::kToBoolean:
      84      141257 :       return ReduceToBoolean(node);
      85             :     case IrOpcode::kSpeculativeToNumber:
      86      114542 :       return ReduceSpeculativeToNumber(node);
      87             :     case IrOpcode::kSpeculativeNumberAdd:
      88       52787 :       return ReduceSpeculativeNumberAdd(node);
      89             :     case IrOpcode::kSpeculativeNumberSubtract:
      90             :     case IrOpcode::kSpeculativeNumberMultiply:
      91             :     case IrOpcode::kSpeculativeNumberDivide:
      92             :     case IrOpcode::kSpeculativeNumberModulus:
      93       91783 :       return ReduceSpeculativeNumberBinop(node);
      94             :     case IrOpcode::kSpeculativeNumberEqual:
      95             :     case IrOpcode::kSpeculativeNumberLessThan:
      96             :     case IrOpcode::kSpeculativeNumberLessThanOrEqual:
      97      248457 :       return ReduceSpeculativeNumberComparison(node);
      98             :     default:
      99             :       break;
     100             :   }
     101             :   return NoChange();
     102             : }
     103             : 
     104             : namespace {
     105             : 
     106      245170 : base::Optional<MapRef> GetStableMapFromObjectType(JSHeapBroker* broker,
     107             :                                                   Type object_type) {
     108      245170 :   if (object_type.IsHeapConstant()) {
     109       13418 :     HeapObjectRef object = object_type.AsHeapConstant()->Ref();
     110       13418 :     MapRef object_map = object.map();
     111       14388 :     if (object_map.is_stable()) return object_map;
     112             :   }
     113      244200 :   return {};
     114             : }
     115             : 
     116             : }  // namespace
     117             : 
     118       73039 : Reduction TypedOptimization::ReduceConvertReceiver(Node* node) {
     119       73039 :   Node* const value = NodeProperties::GetValueInput(node, 0);
     120       73039 :   Type const value_type = NodeProperties::GetType(value);
     121       73039 :   Node* const global_proxy = NodeProperties::GetValueInput(node, 1);
     122       73039 :   if (value_type.Is(Type::Receiver())) {
     123       70745 :     ReplaceWithValue(node, value);
     124             :     return Replace(value);
     125       73032 :   } else if (value_type.Is(Type::NullOrUndefined())) {
     126             :     ReplaceWithValue(node, global_proxy);
     127             :     return Replace(global_proxy);
     128             :   }
     129             :   return NoChange();
     130             : }
     131             : 
     132       97543 : Reduction TypedOptimization::ReduceCheckHeapObject(Node* node) {
     133       97543 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     134       97543 :   Type const input_type = NodeProperties::GetType(input);
     135       97543 :   if (!input_type.Maybe(Type::SignedSmall())) {
     136        5518 :     ReplaceWithValue(node, input);
     137             :     return Replace(input);
     138             :   }
     139             :   return NoChange();
     140             : }
     141             : 
     142         747 : Reduction TypedOptimization::ReduceCheckNotTaggedHole(Node* node) {
     143         747 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     144         747 :   Type const input_type = NodeProperties::GetType(input);
     145         747 :   if (!input_type.Maybe(Type::Hole())) {
     146           0 :     ReplaceWithValue(node, input);
     147             :     return Replace(input);
     148             :   }
     149             :   return NoChange();
     150             : }
     151             : 
     152      236821 : Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
     153             :   // The CheckMaps(o, ...map...) can be eliminated if map is stable,
     154             :   // o has type Constant(object) and map == object->map, and either
     155             :   //  (1) map cannot transition further, or
     156             :   //  (2) we can add a code dependency on the stability of map
     157             :   //      (to guard the Constant type information).
     158      235872 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     159      235872 :   Type const object_type = NodeProperties::GetType(object);
     160      235872 :   Node* const effect = NodeProperties::GetEffectInput(node);
     161             :   base::Optional<MapRef> object_map =
     162      235872 :       GetStableMapFromObjectType(broker(), object_type);
     163      235872 :   if (object_map.has_value()) {
     164        1898 :     for (int i = 1; i < node->op()->ValueInputCount(); ++i) {
     165           0 :       Node* const map = NodeProperties::GetValueInput(node, i);
     166           0 :       Type const map_type = NodeProperties::GetType(map);
     167           0 :       if (map_type.IsHeapConstant() &&
     168           0 :           map_type.AsHeapConstant()->Ref().equals(*object_map)) {
     169           0 :         if (object_map->CanTransition()) {
     170           0 :           dependencies()->DependOnStableMap(*object_map);
     171             :         }
     172           0 :         return Replace(effect);
     173             :       }
     174             :     }
     175             :   }
     176             :   return NoChange();
     177             : }
     178             : 
     179        3574 : Reduction TypedOptimization::ReduceCheckNumber(Node* node) {
     180        3574 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     181        3574 :   Type const input_type = NodeProperties::GetType(input);
     182        3574 :   if (input_type.Is(Type::Number())) {
     183        1482 :     ReplaceWithValue(node, input);
     184             :     return Replace(input);
     185             :   }
     186             :   return NoChange();
     187             : }
     188             : 
     189       33046 : Reduction TypedOptimization::ReduceCheckString(Node* node) {
     190       33046 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     191       33046 :   Type const input_type = NodeProperties::GetType(input);
     192       33046 :   if (input_type.Is(Type::String())) {
     193        4967 :     ReplaceWithValue(node, input);
     194             :     return Replace(input);
     195             :   }
     196             :   return NoChange();
     197             : }
     198             : 
     199         201 : Reduction TypedOptimization::ReduceCheckEqualsInternalizedString(Node* node) {
     200         201 :   Node* const exp = NodeProperties::GetValueInput(node, 0);
     201             :   Type const exp_type = NodeProperties::GetType(exp);
     202         201 :   Node* const val = NodeProperties::GetValueInput(node, 1);
     203         201 :   Type const val_type = NodeProperties::GetType(val);
     204         201 :   Node* const effect = NodeProperties::GetEffectInput(node);
     205         201 :   if (val_type.Is(exp_type)) return Replace(effect);
     206             :   // TODO(turbofan): Should we also try to optimize the
     207             :   // non-internalized String case for {val} here?
     208             :   return NoChange();
     209             : }
     210             : 
     211          78 : Reduction TypedOptimization::ReduceCheckEqualsSymbol(Node* node) {
     212          78 :   Node* const exp = NodeProperties::GetValueInput(node, 0);
     213             :   Type const exp_type = NodeProperties::GetType(exp);
     214          78 :   Node* const val = NodeProperties::GetValueInput(node, 1);
     215          78 :   Type const val_type = NodeProperties::GetType(val);
     216          78 :   Node* const effect = NodeProperties::GetEffectInput(node);
     217          78 :   if (val_type.Is(exp_type)) return Replace(effect);
     218             :   return NoChange();
     219             : }
     220             : 
     221     5605810 : Reduction TypedOptimization::ReduceLoadField(Node* node) {
     222     2802884 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     223     2802884 :   Type const object_type = NodeProperties::GetType(object);
     224     2802884 :   FieldAccess const& access = FieldAccessOf(node->op());
     225     2802884 :   if (access.base_is_tagged == kTaggedBase &&
     226             :       access.offset == HeapObject::kMapOffset) {
     227             :     // We can replace LoadField[Map](o) with map if is stable, and
     228             :     // o has type Constant(object) and map == object->map, and either
     229             :     //  (1) map cannot transition further, or
     230             :     //  (2) deoptimization is enabled and we can add a code dependency on the
     231             :     //      stability of map (to guard the Constant type information).
     232             :     base::Optional<MapRef> object_map =
     233        9298 :         GetStableMapFromObjectType(broker(), object_type);
     234        9298 :     if (object_map.has_value()) {
     235          21 :       dependencies()->DependOnStableMap(*object_map);
     236          21 :       Node* const value = jsgraph()->Constant(*object_map);
     237          21 :       ReplaceWithValue(node, value);
     238          21 :       return Replace(value);
     239             :     }
     240             :   }
     241             :   return NoChange();
     242             : }
     243             : 
     244       55088 : Reduction TypedOptimization::ReduceNumberFloor(Node* node) {
     245       56536 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     246       55088 :   Type const input_type = NodeProperties::GetType(input);
     247      110176 :   if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
     248             :     return Replace(input);
     249             :   }
     250      111582 :   if (input_type.Is(Type::PlainNumber()) &&
     251        1441 :       (input->opcode() == IrOpcode::kNumberDivide ||
     252             :        input->opcode() == IrOpcode::kSpeculativeNumberDivide)) {
     253        1366 :     Node* const lhs = NodeProperties::GetValueInput(input, 0);
     254        1366 :     Type const lhs_type = NodeProperties::GetType(lhs);
     255        1366 :     Node* const rhs = NodeProperties::GetValueInput(input, 1);
     256        1366 :     Type const rhs_type = NodeProperties::GetType(rhs);
     257        1542 :     if (lhs_type.Is(Type::Unsigned32()) && rhs_type.Is(Type::Unsigned32())) {
     258             :       // We can replace
     259             :       //
     260             :       //   NumberFloor(NumberDivide(lhs: unsigned32,
     261             :       //                            rhs: unsigned32)): plain-number
     262             :       //
     263             :       // with
     264             :       //
     265             :       //   NumberToUint32(NumberDivide(lhs, rhs))
     266             :       //
     267             :       // and just smash the type [0...lhs.Max] on the {node},
     268             :       // as the truncated result must be loewr than {lhs}'s maximum
     269             :       // value (note that {rhs} cannot be less than 1 due to the
     270             :       // plain-number type constraint on the {node}).
     271         176 :       NodeProperties::ChangeOp(node, simplified()->NumberToUint32());
     272             :       NodeProperties::SetType(node,
     273         176 :                               Type::Range(0, lhs_type.Max(), graph()->zone()));
     274         176 :       return Changed(node);
     275             :     }
     276             :   }
     277             :   return NoChange();
     278             : }
     279             : 
     280       31761 : Reduction TypedOptimization::ReduceNumberRoundop(Node* node) {
     281       31761 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     282       31761 :   Type const input_type = NodeProperties::GetType(input);
     283       63522 :   if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
     284             :     return Replace(input);
     285             :   }
     286             :   return NoChange();
     287             : }
     288             : 
     289        1745 : Reduction TypedOptimization::ReduceNumberSilenceNaN(Node* node) {
     290        1745 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     291        1745 :   Type const input_type = NodeProperties::GetType(input);
     292        1745 :   if (input_type.Is(Type::OrderedNumber())) {
     293             :     return Replace(input);
     294             :   }
     295             :   return NoChange();
     296             : }
     297             : 
     298         950 : Reduction TypedOptimization::ReduceNumberToUint8Clamped(Node* node) {
     299         950 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     300         950 :   Type const input_type = NodeProperties::GetType(input);
     301        1900 :   if (input_type.Is(type_cache_->kUint8)) {
     302             :     return Replace(input);
     303             :   }
     304             :   return NoChange();
     305             : }
     306             : 
     307      896400 : Reduction TypedOptimization::ReducePhi(Node* node) {
     308             :   // Try to narrow the type of the Phi {node}, which might be more precise now
     309             :   // after lowering based on types, i.e. a SpeculativeNumberAdd has a more
     310             :   // precise type than the JSAdd that was in the graph when the Typer was run.
     311             :   DCHECK_EQ(IrOpcode::kPhi, node->opcode());
     312      896400 :   int arity = node->op()->ValueInputCount();
     313             :   Type type = NodeProperties::GetType(node->InputAt(0));
     314     5025830 :   for (int i = 1; i < arity; ++i) {
     315             :     type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)),
     316     8258796 :                        graph()->zone());
     317             :   }
     318      896432 :   Type const node_type = NodeProperties::GetType(node);
     319      896429 :   if (!node_type.Is(type)) {
     320       66050 :     type = Type::Intersect(node_type, type, graph()->zone());
     321             :     NodeProperties::SetType(node, type);
     322             :     return Changed(node);
     323             :   }
     324             :   return NoChange();
     325             : }
     326             : 
     327      599197 : Reduction TypedOptimization::ReduceReferenceEqual(Node* node) {
     328             :   DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
     329      501297 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     330      501297 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     331      501297 :   Type const lhs_type = NodeProperties::GetType(lhs);
     332      501297 :   Type const rhs_type = NodeProperties::GetType(rhs);
     333      501297 :   if (!lhs_type.Maybe(rhs_type)) {
     334       48950 :     Node* replacement = jsgraph()->FalseConstant();
     335             :     // Make sure we do not widen the type.
     336       48950 :     if (NodeProperties::GetType(replacement)
     337       97900 :             .Is(NodeProperties::GetType(node))) {
     338       48950 :       return Replace(jsgraph()->FalseConstant());
     339             :     }
     340             :   }
     341             :   return NoChange();
     342             : }
     343             : 
     344         164 : const Operator* TypedOptimization::NumberComparisonFor(const Operator* op) {
     345         164 :   switch (op->opcode()) {
     346             :     case IrOpcode::kStringEqual:
     347          80 :       return simplified()->NumberEqual();
     348             :     case IrOpcode::kStringLessThan:
     349          42 :       return simplified()->NumberLessThan();
     350             :     case IrOpcode::kStringLessThanOrEqual:
     351          42 :       return simplified()->NumberLessThanOrEqual();
     352             :     default:
     353             :       break;
     354             :   }
     355           0 :   UNREACHABLE();
     356             : }
     357             : 
     358         141 : Reduction TypedOptimization::
     359             :     TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
     360         183 :         Node* comparison, const StringRef& string, bool inverted) {
     361         141 :   switch (comparison->opcode()) {
     362             :     case IrOpcode::kStringEqual:
     363          57 :       if (string.length() != 1) {
     364             :         // String.fromCharCode(x) always has length 1.
     365          14 :         return Replace(jsgraph()->BooleanConstant(false));
     366             :       }
     367             :       break;
     368             :     case IrOpcode::kStringLessThan:
     369             :       V8_FALLTHROUGH;
     370             :     case IrOpcode::kStringLessThanOrEqual:
     371          84 :       if (string.length() == 0) {
     372             :         // String.fromCharCode(x) <= "" is always false,
     373             :         // "" < String.fromCharCode(x) is always true.
     374          56 :         return Replace(jsgraph()->BooleanConstant(inverted));
     375             :       }
     376             :       break;
     377             :     default:
     378           0 :       UNREACHABLE();
     379             :   }
     380             :   return NoChange();
     381             : }
     382             : 
     383             : // Try to reduces a string comparison of the form
     384             : // String.fromCharCode(x) {comparison} {constant} if inverted is false,
     385             : // and {constant} {comparison} String.fromCharCode(x) if inverted is true.
     386             : Reduction
     387         141 : TypedOptimization::TryReduceStringComparisonOfStringFromSingleCharCode(
     388         233 :     Node* comparison, Node* from_char_code, Type constant_type, bool inverted) {
     389             :   DCHECK_EQ(IrOpcode::kStringFromSingleCharCode, from_char_code->opcode());
     390             : 
     391         141 :   if (!constant_type.IsHeapConstant()) return NoChange();
     392         141 :   ObjectRef constant = constant_type.AsHeapConstant()->Ref();
     393             : 
     394         141 :   if (!constant.IsString()) return NoChange();
     395         141 :   StringRef string = constant.AsString();
     396             : 
     397             :   // Check if comparison can be resolved statically.
     398             :   Reduction red = TryReduceStringComparisonOfStringFromSingleCharCodeToConstant(
     399         141 :       comparison, string, inverted);
     400         141 :   if (red.Changed()) return red;
     401             : 
     402          99 :   const Operator* comparison_op = NumberComparisonFor(comparison->op());
     403          99 :   Node* from_char_code_repl = NodeProperties::GetValueInput(from_char_code, 0);
     404          99 :   Type from_char_code_repl_type = NodeProperties::GetType(from_char_code_repl);
     405         198 :   if (!from_char_code_repl_type.Is(type_cache_->kUint16)) {
     406             :     // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
     407             :     from_char_code_repl =
     408           7 :         graph()->NewNode(simplified()->NumberToInt32(), from_char_code_repl);
     409             :     from_char_code_repl = graph()->NewNode(
     410             :         simplified()->NumberBitwiseAnd(), from_char_code_repl,
     411          14 :         jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
     412             :   }
     413         198 :   Node* constant_repl = jsgraph()->Constant(string.GetFirstChar());
     414             : 
     415             :   Node* number_comparison = nullptr;
     416          99 :   if (inverted) {
     417             :     // "x..." <= String.fromCharCode(z) is true if x < z.
     418          42 :     if (string.length() > 1 &&
     419             :         comparison->opcode() == IrOpcode::kStringLessThanOrEqual) {
     420           7 :       comparison_op = simplified()->NumberLessThan();
     421             :     }
     422             :     number_comparison =
     423             :         graph()->NewNode(comparison_op, constant_repl, from_char_code_repl);
     424             :   } else {
     425             :     // String.fromCharCode(z) < "x..." is true if z <= x.
     426          85 :     if (string.length() > 1 &&
     427             :         comparison->opcode() == IrOpcode::kStringLessThan) {
     428           7 :       comparison_op = simplified()->NumberLessThanOrEqual();
     429             :     }
     430             :     number_comparison =
     431             :         graph()->NewNode(comparison_op, from_char_code_repl, constant_repl);
     432             :   }
     433          99 :   ReplaceWithValue(comparison, number_comparison);
     434             :   return Replace(number_comparison);
     435             : }
     436             : 
     437       31220 : Reduction TypedOptimization::ReduceStringComparison(Node* node) {
     438             :   DCHECK(IrOpcode::kStringEqual == node->opcode() ||
     439             :          IrOpcode::kStringLessThan == node->opcode() ||
     440             :          IrOpcode::kStringLessThanOrEqual == node->opcode());
     441       62296 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     442       62296 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     443       31148 :   Type lhs_type = NodeProperties::GetType(lhs);
     444       31148 :   Type rhs_type = NodeProperties::GetType(rhs);
     445       31148 :   if (lhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
     446         164 :     if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
     447          65 :       Node* left = NodeProperties::GetValueInput(lhs, 0);
     448          65 :       Node* right = NodeProperties::GetValueInput(rhs, 0);
     449          65 :       Type left_type = NodeProperties::GetType(left);
     450          65 :       Type right_type = NodeProperties::GetType(right);
     451         130 :       if (!left_type.Is(type_cache_->kUint16)) {
     452             :         // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
     453           7 :         left = graph()->NewNode(simplified()->NumberToInt32(), left);
     454             :         left = graph()->NewNode(
     455             :             simplified()->NumberBitwiseAnd(), left,
     456          14 :             jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
     457             :       }
     458         130 :       if (!right_type.Is(type_cache_->kUint16)) {
     459             :         // Convert to signed int32 to satisfy type of {NumberBitwiseAnd}.
     460           0 :         right = graph()->NewNode(simplified()->NumberToInt32(), right);
     461             :         right = graph()->NewNode(
     462             :             simplified()->NumberBitwiseAnd(), right,
     463           0 :             jsgraph()->Constant(std::numeric_limits<uint16_t>::max()));
     464             :       }
     465             :       Node* equal =
     466          65 :           graph()->NewNode(NumberComparisonFor(node->op()), left, right);
     467          65 :       ReplaceWithValue(node, equal);
     468             :       return Replace(equal);
     469             :     } else {
     470             :       return TryReduceStringComparisonOfStringFromSingleCharCode(
     471          99 :           node, lhs, rhs_type, false);
     472             :     }
     473       30984 :   } else if (rhs->opcode() == IrOpcode::kStringFromSingleCharCode) {
     474             :     return TryReduceStringComparisonOfStringFromSingleCharCode(node, rhs,
     475          42 :                                                                lhs_type, true);
     476             :   }
     477             :   return NoChange();
     478             : }
     479             : 
     480      145316 : Reduction TypedOptimization::ReduceStringLength(Node* node) {
     481             :   DCHECK_EQ(IrOpcode::kStringLength, node->opcode());
     482       86798 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     483       86798 :   switch (input->opcode()) {
     484             :     case IrOpcode::kHeapConstant: {
     485             :       // Constant-fold the String::length of the {input}.
     486             :       HeapObjectMatcher m(input);
     487       19506 :       if (m.Ref(broker()).IsString()) {
     488       19506 :         uint32_t const length = m.Ref(broker()).AsString().length();
     489       39012 :         Node* value = jsgraph()->Constant(length);
     490             :         return Replace(value);
     491             :       }
     492             :       break;
     493             :     }
     494             :     case IrOpcode::kStringConcat: {
     495             :       // The first value input to the {input} is the resulting length.
     496             :       return Replace(input->InputAt(0));
     497             :     }
     498             :     default:
     499             :       break;
     500             :   }
     501             :   return NoChange();
     502             : }
     503             : 
     504         223 : Reduction TypedOptimization::ReduceSameValue(Node* node) {
     505             :   DCHECK_EQ(IrOpcode::kSameValue, node->opcode());
     506         216 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     507         216 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     508         216 :   Type const lhs_type = NodeProperties::GetType(lhs);
     509         216 :   Type const rhs_type = NodeProperties::GetType(rhs);
     510         216 :   if (lhs == rhs) {
     511             :     // SameValue(x,x) => #true
     512           7 :     return Replace(jsgraph()->TrueConstant());
     513         216 :   } else if (lhs_type.Is(Type::Unique()) && rhs_type.Is(Type::Unique())) {
     514             :     // SameValue(x:unique,y:unique) => ReferenceEqual(x,y)
     515           7 :     NodeProperties::ChangeOp(node, simplified()->ReferenceEqual());
     516             :     return Changed(node);
     517         216 :   } else if (lhs_type.Is(Type::String()) && rhs_type.Is(Type::String())) {
     518             :     // SameValue(x:string,y:string) => StringEqual(x,y)
     519          14 :     NodeProperties::ChangeOp(node, simplified()->StringEqual());
     520             :     return Changed(node);
     521         188 :   } else if (lhs_type.Is(Type::MinusZero())) {
     522             :     // SameValue(x:minus-zero,y) => ObjectIsMinusZero(y)
     523          70 :     node->RemoveInput(0);
     524          70 :     NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
     525             :     return Changed(node);
     526         118 :   } else if (rhs_type.Is(Type::MinusZero())) {
     527             :     // SameValue(x,y:minus-zero) => ObjectIsMinusZero(x)
     528          42 :     node->RemoveInput(1);
     529          42 :     NodeProperties::ChangeOp(node, simplified()->ObjectIsMinusZero());
     530             :     return Changed(node);
     531          76 :   } else if (lhs_type.Is(Type::NaN())) {
     532             :     // SameValue(x:nan,y) => ObjectIsNaN(y)
     533          35 :     node->RemoveInput(0);
     534          35 :     NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
     535             :     return Changed(node);
     536          41 :   } else if (rhs_type.Is(Type::NaN())) {
     537             :     // SameValue(x,y:nan) => ObjectIsNaN(x)
     538          14 :     node->RemoveInput(1);
     539          14 :     NodeProperties::ChangeOp(node, simplified()->ObjectIsNaN());
     540             :     return Changed(node);
     541          48 :   } else if (lhs_type.Is(Type::PlainNumber()) &&
     542             :              rhs_type.Is(Type::PlainNumber())) {
     543             :     // SameValue(x:plain-number,y:plain-number) => NumberEqual(x,y)
     544           7 :     NodeProperties::ChangeOp(node, simplified()->NumberEqual());
     545             :     return Changed(node);
     546             :   }
     547             :   return NoChange();
     548             : }
     549             : 
     550       29815 : Reduction TypedOptimization::ReduceSelect(Node* node) {
     551             :   DCHECK_EQ(IrOpcode::kSelect, node->opcode());
     552       29815 :   Node* const condition = NodeProperties::GetValueInput(node, 0);
     553       29815 :   Type const condition_type = NodeProperties::GetType(condition);
     554       29815 :   Node* const vtrue = NodeProperties::GetValueInput(node, 1);
     555       29815 :   Type const vtrue_type = NodeProperties::GetType(vtrue);
     556       29815 :   Node* const vfalse = NodeProperties::GetValueInput(node, 2);
     557       29815 :   Type const vfalse_type = NodeProperties::GetType(vfalse);
     558       29815 :   if (condition_type.Is(true_type_)) {
     559             :     // Select(condition:true, vtrue, vfalse) => vtrue
     560             :     return Replace(vtrue);
     561             :   }
     562       29214 :   if (condition_type.Is(false_type_)) {
     563             :     // Select(condition:false, vtrue, vfalse) => vfalse
     564             :     return Replace(vfalse);
     565             :   }
     566       36921 :   if (vtrue_type.Is(true_type_) && vfalse_type.Is(false_type_)) {
     567             :     // Select(condition, vtrue:true, vfalse:false) => condition
     568             :     return Replace(condition);
     569             :   }
     570       26353 :   if (vtrue_type.Is(false_type_) && vfalse_type.Is(true_type_)) {
     571             :     // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition)
     572           0 :     node->TrimInputCount(1);
     573           0 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     574             :     return Changed(node);
     575             :   }
     576             :   // Try to narrow the type of the Select {node}, which might be more precise
     577             :   // now after lowering based on types.
     578       24468 :   Type type = Type::Union(vtrue_type, vfalse_type, graph()->zone());
     579       24468 :   Type const node_type = NodeProperties::GetType(node);
     580       24468 :   if (!node_type.Is(type)) {
     581        1029 :     type = Type::Intersect(node_type, type, graph()->zone());
     582             :     NodeProperties::SetType(node, type);
     583             :     return Changed(node);
     584             :   }
     585             :   return NoChange();
     586             : }
     587             : 
     588      114542 : Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
     589             :   DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
     590      114542 :   Node* const input = NodeProperties::GetValueInput(node, 0);
     591      114542 :   Type const input_type = NodeProperties::GetType(input);
     592      114542 :   if (input_type.Is(Type::Number())) {
     593             :     // SpeculativeToNumber(x:number) => x
     594       33201 :     ReplaceWithValue(node, input);
     595             :     return Replace(input);
     596             :   }
     597             :   return NoChange();
     598             : }
     599             : 
     600      113383 : Reduction TypedOptimization::ReduceTypeOf(Node* node) {
     601             :   Node* const input = node->InputAt(0);
     602       75013 :   Type const type = NodeProperties::GetType(input);
     603             :   Factory* const f = factory();
     604       75013 :   if (type.Is(Type::Boolean())) {
     605             :     return Replace(
     606        8332 :         jsgraph()->Constant(ObjectRef(broker(), f->boolean_string())));
     607       70847 :   } else if (type.Is(Type::Number())) {
     608             :     return Replace(
     609       22542 :         jsgraph()->Constant(ObjectRef(broker(), f->number_string())));
     610       59576 :   } else if (type.Is(Type::String())) {
     611             :     return Replace(
     612        2842 :         jsgraph()->Constant(ObjectRef(broker(), f->string_string())));
     613       58155 :   } else if (type.Is(Type::BigInt())) {
     614             :     return Replace(
     615          24 :         jsgraph()->Constant(ObjectRef(broker(), f->bigint_string())));
     616       58143 :   } else if (type.Is(Type::Symbol())) {
     617             :     return Replace(
     618           0 :         jsgraph()->Constant(ObjectRef(broker(), f->symbol_string())));
     619       58143 :   } else if (type.Is(Type::OtherUndetectableOrUndefined())) {
     620             :     return Replace(
     621         478 :         jsgraph()->Constant(ObjectRef(broker(), f->undefined_string())));
     622       57904 :   } else if (type.Is(Type::NonCallableOrNull())) {
     623             :     return Replace(
     624        3846 :         jsgraph()->Constant(ObjectRef(broker(), f->object_string())));
     625       55981 :   } else if (type.Is(Type::Function())) {
     626             :     return Replace(
     627         306 :         jsgraph()->Constant(ObjectRef(broker(), f->function_string())));
     628             :   }
     629             :   return NoChange();
     630             : }
     631             : 
     632      143728 : Reduction TypedOptimization::ReduceToBoolean(Node* node) {
     633             :   Node* const input = node->InputAt(0);
     634      141257 :   Type const input_type = NodeProperties::GetType(input);
     635      141257 :   if (input_type.Is(Type::Boolean())) {
     636             :     // ToBoolean(x:boolean) => x
     637             :     return Replace(input);
     638      121373 :   } else if (input_type.Is(Type::OrderedNumber())) {
     639             :     // SToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
     640             :     node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
     641        7287 :                                            jsgraph()->ZeroConstant()));
     642        2429 :     node->TrimInputCount(1);
     643        2429 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     644             :     return Changed(node);
     645      118944 :   } else if (input_type.Is(Type::Number())) {
     646             :     // ToBoolean(x:number) => NumberToBoolean(x)
     647         110 :     node->TrimInputCount(1);
     648         110 :     NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
     649             :     return Changed(node);
     650      118834 :   } else if (input_type.Is(Type::DetectableReceiverOrNull())) {
     651             :     // ToBoolean(x:detectable receiver \/ null)
     652             :     //   => BooleanNot(ReferenceEqual(x,#null))
     653             :     node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
     654          60 :                                            input, jsgraph()->NullConstant()));
     655          20 :     node->TrimInputCount(1);
     656          20 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     657             :     return Changed(node);
     658      118814 :   } else if (input_type.Is(Type::ReceiverOrNullOrUndefined())) {
     659             :     // ToBoolean(x:receiver \/ null \/ undefined)
     660             :     //   => BooleanNot(ObjectIsUndetectable(x))
     661             :     node->ReplaceInput(
     662         132 :         0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
     663          66 :     node->TrimInputCount(1);
     664          66 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     665             :     return Changed(node);
     666      118748 :   } else if (input_type.Is(Type::String())) {
     667             :     // ToBoolean(x:string) => BooleanNot(ReferenceEqual(x,""))
     668             :     node->ReplaceInput(0,
     669             :                        graph()->NewNode(simplified()->ReferenceEqual(), input,
     670          66 :                                         jsgraph()->EmptyStringConstant()));
     671          22 :     node->TrimInputCount(1);
     672          22 :     NodeProperties::ChangeOp(node, simplified()->BooleanNot());
     673             :     return Changed(node);
     674             :   }
     675             :   return NoChange();
     676             : }
     677             : 
     678             : namespace {
     679     1519639 : bool BothAre(Type t1, Type t2, Type t3) { return t1.Is(t3) && t2.Is(t3); }
     680             : 
     681       50411 : bool NeitherCanBe(Type t1, Type t2, Type t3) {
     682       50411 :   return !t1.Maybe(t3) && !t2.Maybe(t3);
     683             : }
     684             : 
     685       29761 : const Operator* NumberOpFromSpeculativeNumberOp(
     686       29761 :     SimplifiedOperatorBuilder* simplified, const Operator* op) {
     687       29761 :   switch (op->opcode()) {
     688             :     case IrOpcode::kSpeculativeNumberEqual:
     689        6279 :       return simplified->NumberEqual();
     690             :     case IrOpcode::kSpeculativeNumberLessThan:
     691       10525 :       return simplified->NumberLessThan();
     692             :     case IrOpcode::kSpeculativeNumberLessThanOrEqual:
     693         347 :       return simplified->NumberLessThanOrEqual();
     694             :     case IrOpcode::kSpeculativeNumberAdd:
     695             :       // Handled by ReduceSpeculativeNumberAdd.
     696           0 :       UNREACHABLE();
     697             :     case IrOpcode::kSpeculativeNumberSubtract:
     698         760 :       return simplified->NumberSubtract();
     699             :     case IrOpcode::kSpeculativeNumberMultiply:
     700        8277 :       return simplified->NumberMultiply();
     701             :     case IrOpcode::kSpeculativeNumberDivide:
     702        3184 :       return simplified->NumberDivide();
     703             :     case IrOpcode::kSpeculativeNumberModulus:
     704         389 :       return simplified->NumberModulus();
     705             :     default:
     706             :       break;
     707             :   }
     708           0 :   UNREACHABLE();
     709             : }
     710             : 
     711             : }  // namespace
     712             : 
     713      105575 : Reduction TypedOptimization::ReduceSpeculativeNumberAdd(Node* node) {
     714       52787 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     715       52787 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     716       52788 :   Type const lhs_type = NodeProperties::GetType(lhs);
     717       52788 :   Type const rhs_type = NodeProperties::GetType(rhs);
     718       52788 :   NumberOperationHint hint = NumberOperationHintOf(node->op());
     719      105577 :   if ((hint == NumberOperationHint::kNumber ||
     720       52789 :        hint == NumberOperationHint::kNumberOrOddball) &&
     721      103201 :       BothAre(lhs_type, rhs_type, Type::PlainPrimitive()) &&
     722       50413 :       NeitherCanBe(lhs_type, rhs_type, Type::StringOrReceiver())) {
     723             :     // SpeculativeNumberAdd(x:-string, y:-string) =>
     724             :     //     NumberAdd(ToNumber(x), ToNumber(y))
     725       50343 :     Node* const toNum_lhs = ConvertPlainPrimitiveToNumber(lhs);
     726       50342 :     Node* const toNum_rhs = ConvertPlainPrimitiveToNumber(rhs);
     727             :     Node* const value =
     728       50343 :         graph()->NewNode(simplified()->NumberAdd(), toNum_lhs, toNum_rhs);
     729       50343 :     ReplaceWithValue(node, value);
     730             :     return Replace(node);
     731             :   }
     732             :   return NoChange();
     733             : }
     734             : 
     735      126150 : Reduction TypedOptimization::ReduceJSToNumberInput(Node* input) {
     736             :   // Try constant-folding of JSToNumber with constant inputs.
     737      125904 :   Type input_type = NodeProperties::GetType(input);
     738             : 
     739      125904 :   if (input_type.Is(Type::String())) {
     740             :     HeapObjectMatcher m(input);
     741           0 :     if (m.HasValue() && m.Ref(broker()).IsString()) {
     742           0 :       StringRef input_value = m.Ref(broker()).AsString();
     743             :       double number;
     744           0 :       ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(number, input_value.ToNumber());
     745           0 :       return Replace(jsgraph()->Constant(number));
     746             :     }
     747             :   }
     748      125904 :   if (input_type.IsHeapConstant()) {
     749         246 :     HeapObjectRef input_value = input_type.AsHeapConstant()->Ref();
     750             :     double value;
     751         492 :     if (input_value.OddballToNumber().To(&value)) {
     752         246 :       return Replace(jsgraph()->Constant(value));
     753             :     }
     754             :   }
     755      125659 :   if (input_type.Is(Type::Number())) {
     756             :     // JSToNumber(x:number) => x
     757             :     return Changed(input);
     758             :   }
     759         343 :   if (input_type.Is(Type::Undefined())) {
     760             :     // JSToNumber(undefined) => #NaN
     761           0 :     return Replace(jsgraph()->NaNConstant());
     762             :   }
     763         343 :   if (input_type.Is(Type::Null())) {
     764             :     // JSToNumber(null) => #0
     765           0 :     return Replace(jsgraph()->ZeroConstant());
     766             :   }
     767             :   return NoChange();
     768             : }
     769             : 
     770      125904 : Node* TypedOptimization::ConvertPlainPrimitiveToNumber(Node* node) {
     771             :   DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
     772             :   // Avoid inserting too many eager ToNumber() operations.
     773      125904 :   Reduction const reduction = ReduceJSToNumberInput(node);
     774      125905 :   if (reduction.Changed()) return reduction.replacement();
     775         686 :   if (NodeProperties::GetType(node).Is(Type::Number())) {
     776             :     return node;
     777             :   }
     778         686 :   return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
     779             : }
     780             : 
     781      196176 : Reduction TypedOptimization::ReduceSpeculativeNumberBinop(Node* node) {
     782       91783 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     783       91783 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     784       91783 :   Type const lhs_type = NodeProperties::GetType(lhs);
     785       91783 :   Type const rhs_type = NodeProperties::GetType(rhs);
     786       91783 :   NumberOperationHint hint = NumberOperationHintOf(node->op());
     787      183566 :   if ((hint == NumberOperationHint::kNumber ||
     788      122873 :        hint == NumberOperationHint::kNumberOrOddball) &&
     789       31090 :       BothAre(lhs_type, rhs_type, Type::NumberOrUndefinedOrNullOrBoolean())) {
     790             :     // We intentionally do this only in the Number and NumberOrOddball hint case
     791             :     // because simplified lowering of these speculative ops may do some clever
     792             :     // reductions in the other cases.
     793       12610 :     Node* const toNum_lhs = ConvertPlainPrimitiveToNumber(lhs);
     794       12610 :     Node* const toNum_rhs = ConvertPlainPrimitiveToNumber(rhs);
     795             :     Node* const value = graph()->NewNode(
     796             :         NumberOpFromSpeculativeNumberOp(simplified(), node->op()), toNum_lhs,
     797       12610 :         toNum_rhs);
     798       12610 :     ReplaceWithValue(node, value);
     799             :     return Replace(node);
     800             :   }
     801             :   return NoChange();
     802             : }
     803             : 
     804      265608 : Reduction TypedOptimization::ReduceSpeculativeNumberComparison(Node* node) {
     805      248457 :   Node* const lhs = NodeProperties::GetValueInput(node, 0);
     806      248458 :   Node* const rhs = NodeProperties::GetValueInput(node, 1);
     807      248455 :   Type const lhs_type = NodeProperties::GetType(lhs);
     808      248455 :   Type const rhs_type = NodeProperties::GetType(rhs);
     809      479989 :   if (BothAre(lhs_type, rhs_type, Type::Signed32()) ||
     810      231536 :       BothAre(lhs_type, rhs_type, Type::Unsigned32())) {
     811             :     Node* const value = graph()->NewNode(
     812       17151 :         NumberOpFromSpeculativeNumberOp(simplified(), node->op()), lhs, rhs);
     813       17151 :     ReplaceWithValue(node, value);
     814             :     return Replace(node);
     815             :   }
     816             :   return NoChange();
     817             : }
     818             : 
     819       75013 : Factory* TypedOptimization::factory() const {
     820     1901786 :   return jsgraph()->isolate()->factory();
     821             : }
     822             : 
     823     6131069 : Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
     824             : 
     825       86202 : SimplifiedOperatorBuilder* TypedOptimization::simplified() const {
     826       86202 :   return jsgraph()->simplified();
     827             : }
     828             : 
     829             : }  // namespace compiler
     830             : }  // namespace internal
     831      178779 : }  // namespace v8

Generated by: LCOV version 1.10