LCOV - code coverage report
Current view: top level - src/compiler - js-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 74 77 96.1 %
Date: 2019-04-17 Functions: 9 10 90.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/js-context-specialization.h"
       6             : 
       7             : #include "src/compiler/common-operator.h"
       8             : #include "src/compiler/js-graph.h"
       9             : #include "src/compiler/js-operator.h"
      10             : #include "src/compiler/linkage.h"
      11             : #include "src/compiler/node-matchers.h"
      12             : #include "src/compiler/node-properties.h"
      13             : #include "src/contexts-inl.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace compiler {
      18             : 
      19    34339829 : Reduction JSContextSpecialization::Reduce(Node* node) {
      20    34339829 :   switch (node->opcode()) {
      21             :     case IrOpcode::kParameter:
      22     2437888 :       return ReduceParameter(node);
      23             :     case IrOpcode::kJSLoadContext:
      24      427181 :       return ReduceJSLoadContext(node);
      25             :     case IrOpcode::kJSStoreContext:
      26      451907 :       return ReduceJSStoreContext(node);
      27             :     default:
      28             :       break;
      29             :   }
      30             :   return NoChange();
      31             : }
      32             : 
      33     2437887 : Reduction JSContextSpecialization::ReduceParameter(Node* node) {
      34             :   DCHECK_EQ(IrOpcode::kParameter, node->opcode());
      35     2437887 :   int const index = ParameterIndexOf(node->op());
      36     2437889 :   if (index == Linkage::kJSCallClosureParamIndex) {
      37             :     // Constant-fold the function parameter {node}.
      38             :     Handle<JSFunction> function;
      39      464204 :     if (closure().ToHandle(&function)) {
      40      437653 :       Node* value = jsgraph()->HeapConstant(function);
      41             :       return Replace(value);
      42             :     }
      43             :   }
      44             :   return NoChange();
      45             : }
      46             : 
      47      400003 : Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
      48             :                                                          Node* new_context,
      49             :                                                          size_t new_depth) {
      50             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
      51      400003 :   const ContextAccess& access = ContextAccessOf(node->op());
      52             :   DCHECK_LE(new_depth, access.depth());
      53             : 
      54      776965 :   if (new_depth == access.depth() &&
      55      376962 :       new_context == NodeProperties::GetContextInput(node)) {
      56             :     return NoChange();
      57             :   }
      58             : 
      59      247522 :   const Operator* op = jsgraph_->javascript()->LoadContext(
      60      123761 :       new_depth, access.index(), access.immutable());
      61      123761 :   NodeProperties::ReplaceContextInput(node, new_context);
      62      123761 :   NodeProperties::ChangeOp(node, op);
      63             :   return Changed(node);
      64             : }
      65             : 
      66      451907 : Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
      67             :                                                           Node* new_context,
      68             :                                                           size_t new_depth) {
      69             :   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
      70      451907 :   const ContextAccess& access = ContextAccessOf(node->op());
      71             :   DCHECK_LE(new_depth, access.depth());
      72             : 
      73      903183 :   if (new_depth == access.depth() &&
      74      451276 :       new_context == NodeProperties::GetContextInput(node)) {
      75             :     return NoChange();
      76             :   }
      77             : 
      78             :   const Operator* op =
      79        2993 :       jsgraph_->javascript()->StoreContext(new_depth, access.index());
      80        2993 :   NodeProperties::ReplaceContextInput(node, new_context);
      81        2993 :   NodeProperties::ChangeOp(node, op);
      82             :   return Changed(node);
      83             : }
      84             : 
      85             : namespace {
      86             : 
      87      149355 : bool IsContextParameter(Node* node) {
      88             :   DCHECK_EQ(IrOpcode::kParameter, node->opcode());
      89      149355 :   Node* const start = NodeProperties::GetValueInput(node, 0);
      90             :   DCHECK_EQ(IrOpcode::kStart, start->opcode());
      91      149355 :   int const index = ParameterIndexOf(node->op());
      92             :   // The context is always the last parameter to a JavaScript function, and
      93             :   // {Parameter} indices start at -1, so value outputs of {Start} look like
      94             :   // this: closure, receiver, param0, ..., paramN, context.
      95      149355 :   return index == start->op()->ValueOutputCount() - 2;
      96             : }
      97             : 
      98             : // Given a context {node} and the {distance} from that context to the target
      99             : // context (which we want to read from or store to), try to return a
     100             : // specialization context.  If successful, update {distance} to whatever
     101             : // distance remains from the specialization context.
     102      879088 : base::Optional<ContextRef> GetSpecializationContext(
     103             :     JSHeapBroker* broker, Node* node, size_t* distance,
     104             :     Maybe<OuterContext> maybe_outer) {
     105      879088 :   switch (node->opcode()) {
     106             :     case IrOpcode::kHeapConstant: {
     107      124566 :       HeapObjectRef object(broker, HeapConstantOf(node->op()));
     108      249132 :       if (object.IsContext()) return object.AsContext();
     109           0 :       break;
     110             :     }
     111             :     case IrOpcode::kParameter: {
     112             :       OuterContext outer;
     113      314859 :       if (maybe_outer.To(&outer) && IsContextParameter(node) &&
     114      149355 :           *distance >= outer.distance) {
     115      149355 :         *distance -= outer.distance;
     116      149355 :         return ContextRef(broker, outer.context);
     117             :       }
     118             :       break;
     119             :     }
     120             :     default:
     121             :       break;
     122             :   }
     123      605167 :   return base::Optional<ContextRef>();
     124             : }
     125             : 
     126             : }  // anonymous namespace
     127             : 
     128      427181 : Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
     129             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     130             : 
     131      427181 :   const ContextAccess& access = ContextAccessOf(node->op());
     132      427181 :   size_t depth = access.depth();
     133             : 
     134             :   // First walk up the context chain in the graph as far as possible.
     135      427181 :   Node* context = NodeProperties::GetOuterContext(node, &depth);
     136             : 
     137             :   base::Optional<ContextRef> maybe_concrete =
     138      427181 :       GetSpecializationContext(broker(), context, &depth, outer());
     139      427181 :   if (!maybe_concrete.has_value()) {
     140             :     // We do not have a concrete context object, so we can only partially reduce
     141             :     // the load by folding-in the outer context node.
     142      157097 :     return SimplifyJSLoadContext(node, context, depth);
     143             :   }
     144             : 
     145             :   // Now walk up the concrete context chain for the remaining depth.
     146      270084 :   ContextRef concrete = maybe_concrete.value();
     147      270084 :   concrete.SerializeContextChain();  // TODO(neis): Remove later.
     148      316474 :   for (; depth > 0; --depth) {
     149       23195 :     concrete = concrete.previous();
     150             :   }
     151             : 
     152      270084 :   if (!access.immutable()) {
     153             :     // We found the requested context object but since the context slot is
     154             :     // mutable we can only partially reduce the load.
     155      242359 :     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
     156             :   }
     157             : 
     158             :   // This will hold the final value, if we can figure it out.
     159       27725 :   base::Optional<ObjectRef> maybe_value;
     160             : 
     161       27725 :   concrete.SerializeSlot(static_cast<int>(access.index()));
     162       55450 :   maybe_value = concrete.get(static_cast<int>(access.index()));
     163       27725 :   if (maybe_value.has_value() && !maybe_value->IsSmi()) {
     164             :     // Even though the context slot is immutable, the context might have escaped
     165             :     // before the function to which it belongs has initialized the slot.
     166             :     // We must be conservative and check if the value in the slot is currently
     167             :     // the hole or undefined. Only if it is neither of these, can we be sure
     168             :     // that it won't change anymore.
     169       25018 :     OddballType oddball_type = maybe_value->AsHeapObject().map().oddball_type();
     170       50036 :     if (oddball_type == OddballType::kUndefined ||
     171       25018 :         oddball_type == OddballType::kHole) {
     172             :       maybe_value.reset();
     173             :     }
     174             :   }
     175             : 
     176       27725 :   if (!maybe_value.has_value()) {
     177         547 :     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
     178             :   }
     179             : 
     180             :   // Success. The context load can be replaced with the constant.
     181             :   // TODO(titzer): record the specialization for sharing code across
     182             :   // multiple contexts that have the same value in the corresponding context
     183             :   // slot.
     184       27178 :   Node* constant = jsgraph_->Constant(*maybe_value);
     185             :   ReplaceWithValue(node, constant);
     186             :   return Replace(constant);
     187             : }
     188             : 
     189             : 
     190      451907 : Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
     191             :   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
     192             : 
     193      451907 :   const ContextAccess& access = ContextAccessOf(node->op());
     194      451907 :   size_t depth = access.depth();
     195             : 
     196             :   // First walk up the context chain in the graph until we reduce the depth to 0
     197             :   // or hit a node that does not have a CreateXYZContext operator.
     198      451907 :   Node* context = NodeProperties::GetOuterContext(node, &depth);
     199             : 
     200             :   base::Optional<ContextRef> maybe_concrete =
     201      451907 :       GetSpecializationContext(broker(), context, &depth, outer());
     202      451907 :   if (!maybe_concrete.has_value()) {
     203             :     // We do not have a concrete context object, so we can only partially reduce
     204             :     // the load by folding-in the outer context node.
     205      448070 :     return SimplifyJSStoreContext(node, context, depth);
     206             :   }
     207             : 
     208             :   // Now walk up the concrete context chain for the remaining depth.
     209        3837 :   ContextRef concrete = maybe_concrete.value();
     210        3837 :   concrete.SerializeContextChain();  // TODO(neis): Remove later.
     211        4763 :   for (; depth > 0; --depth) {
     212         463 :     concrete = concrete.previous();
     213             :   }
     214             : 
     215        3837 :   return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
     216             : }
     217             : 
     218             : 
     219           0 : Isolate* JSContextSpecialization::isolate() const {
     220           0 :   return jsgraph()->isolate();
     221             : }
     222             : 
     223             : }  // namespace compiler
     224             : }  // namespace internal
     225      122004 : }  // namespace v8

Generated by: LCOV version 1.10