LCOV - code coverage report
Current view: top level - src/compiler - js-context-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 60 60 100.0 %
Date: 2017-10-20 Functions: 8 9 88.9 %

          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    31329978 : Reduction JSContextSpecialization::Reduce(Node* node) {
      20    31329978 :   switch (node->opcode()) {
      21             :     case IrOpcode::kParameter:
      22     2460696 :       return ReduceParameter(node);
      23             :     case IrOpcode::kJSLoadContext:
      24      689379 :       return ReduceJSLoadContext(node);
      25             :     case IrOpcode::kJSStoreContext:
      26      346545 :       return ReduceJSStoreContext(node);
      27             :     default:
      28             :       break;
      29             :   }
      30             :   return NoChange();
      31             : }
      32             : 
      33     2880983 : Reduction JSContextSpecialization::ReduceParameter(Node* node) {
      34             :   DCHECK_EQ(IrOpcode::kParameter, node->opcode());
      35     2460694 :   int const index = ParameterIndexOf(node->op());
      36     2460693 :   if (index == Linkage::kJSCallClosureParamIndex) {
      37             :     // Constant-fold the function parameter {node}.
      38             :     Handle<JSFunction> function;
      39      443382 :     if (closure().ToHandle(&function)) {
      40      420289 :       Node* value = jsgraph()->HeapConstant(function);
      41             :       return Replace(value);
      42             :     }
      43             :   }
      44             :   return NoChange();
      45             : }
      46             : 
      47      616926 : Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
      48             :                                                          Node* new_context,
      49             :                                                          size_t new_depth) {
      50             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
      51      848368 :   const ContextAccess& access = ContextAccessOf(node->op());
      52             :   DCHECK_LE(new_depth, access.depth());
      53             : 
      54     1223835 :   if (new_depth == access.depth() &&
      55      606909 :       new_context == NodeProperties::GetContextInput(node)) {
      56             :     return NoChange();
      57             :   }
      58             : 
      59             :   const Operator* op = jsgraph_->javascript()->LoadContext(
      60      231442 :       new_depth, access.index(), access.immutable());
      61      115721 :   NodeProperties::ReplaceContextInput(node, new_context);
      62      115721 :   NodeProperties::ChangeOp(node, op);
      63             :   return Changed(node);
      64             : }
      65             : 
      66      346545 : Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
      67             :                                                           Node* new_context,
      68             :                                                           size_t new_depth) {
      69             :   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
      70      349311 :   const ContextAccess& access = ContextAccessOf(node->op());
      71             :   DCHECK_LE(new_depth, access.depth());
      72             : 
      73      692906 :   if (new_depth == access.depth() &&
      74      346361 :       new_context == NodeProperties::GetContextInput(node)) {
      75             :     return NoChange();
      76             :   }
      77             : 
      78             :   const Operator* op =
      79        2766 :       jsgraph_->javascript()->StoreContext(new_depth, access.index());
      80        2766 :   NodeProperties::ReplaceContextInput(node, new_context);
      81        2766 :   NodeProperties::ChangeOp(node, op);
      82             :   return Changed(node);
      83             : }
      84             : 
      85             : namespace {
      86             : 
      87      348120 : bool IsContextParameter(Node* node) {
      88             :   DCHECK_EQ(IrOpcode::kParameter, node->opcode());
      89      348120 :   Node* const start = NodeProperties::GetValueInput(node, 0);
      90             :   DCHECK_EQ(IrOpcode::kStart, start->opcode());
      91      174060 :   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      348120 :   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     1035924 : MaybeHandle<Context> GetSpecializationContext(Node* node, size_t* distance,
     103             :                                               Maybe<OuterContext> maybe_outer) {
     104     1035924 :   switch (node->opcode()) {
     105             :     case IrOpcode::kHeapConstant:
     106      169081 :       return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
     107             :     case IrOpcode::kParameter: {
     108             :       OuterContext outer;
     109      364838 :       if (maybe_outer.To(&outer) && IsContextParameter(node) &&
     110      174060 :           *distance >= outer.distance) {
     111      174060 :         *distance -= outer.distance;
     112      174060 :         return outer.context;
     113             :       }
     114             :       break;
     115             :     }
     116             :     default:
     117             :       break;
     118             :   }
     119      692783 :   return MaybeHandle<Context>();
     120             : }
     121             : 
     122             : }  // anonymous namespace
     123             : 
     124      956506 : Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
     125             :   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     126             : 
     127     1101913 :   const ContextAccess& access = ContextAccessOf(node->op());
     128      689379 :   size_t depth = access.depth();
     129             : 
     130             :   // First walk up the context chain in the graph as far as possible.
     131      689379 :   Node* context = NodeProperties::GetOuterContext(node, &depth);
     132             : 
     133             :   Handle<Context> concrete;
     134     1378758 :   if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
     135             :     // We do not have a concrete context object, so we can only partially reduce
     136             :     // the load by folding-in the outer context node.
     137      349799 :     return SimplifyJSLoadContext(node, context, depth);
     138             :   }
     139             : 
     140             :   // Now walk up the concrete context chain for the remaining depth.
     141        7943 :   for (; depth > 0; --depth) {
     142             :     concrete = handle(concrete->previous(), isolate());
     143             :   }
     144             : 
     145      339580 :   if (!access.immutable()) {
     146             :     // We found the requested context object but since the context slot is
     147             :     // mutable we can only partially reduce the load.
     148      266626 :     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
     149             :   }
     150             : 
     151             :   // Even though the context slot is immutable, the context might have escaped
     152             :   // before the function to which it belongs has initialized the slot.
     153             :   // We must be conservative and check if the value in the slot is currently
     154             :   // the hole or undefined. Only if it is neither of these, can we be sure that
     155             :   // it won't change anymore.
     156             :   Handle<Object> value(concrete->get(static_cast<int>(access.index())),
     157       72954 :                        isolate());
     158      145487 :   if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
     159        1002 :     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
     160             :   }
     161             : 
     162             :   // Success. The context load can be replaced with the constant.
     163             :   // TODO(titzer): record the specialization for sharing code across multiple
     164             :   // contexts that have the same value in the corresponding context slot.
     165       72453 :   Node* constant = jsgraph_->Constant(value);
     166       72453 :   ReplaceWithValue(node, constant);
     167             :   return Replace(constant);
     168             : }
     169             : 
     170             : 
     171      350106 : Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
     172             :   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
     173             : 
     174      346545 :   const ContextAccess& access = ContextAccessOf(node->op());
     175      346545 :   size_t depth = access.depth();
     176             : 
     177             :   // First walk up the context chain in the graph until we reduce the depth to 0
     178             :   // or hit a node that does not have a CreateXYZContext operator.
     179      346545 :   Node* context = NodeProperties::GetOuterContext(node, &depth);
     180             : 
     181             :   Handle<Context> concrete;
     182      693090 :   if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
     183             :     // We do not have a concrete context object, so we can only partially reduce
     184             :     // the load by folding-in the outer context node.
     185      342984 :     return SimplifyJSStoreContext(node, context, depth);
     186             :   }
     187             : 
     188             :   // Now walk up the concrete context chain for the remaining depth.
     189          77 :   for (; depth > 0; --depth) {
     190             :     concrete = handle(concrete->previous(), isolate());
     191             :   }
     192             : 
     193        3561 :   return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
     194             : }
     195             : 
     196             : 
     197      226461 : Isolate* JSContextSpecialization::isolate() const {
     198      226461 :   return jsgraph()->isolate();
     199             : }
     200             : 
     201             : }  // namespace compiler
     202             : }  // namespace internal
     203             : }  // namespace v8

Generated by: LCOV version 1.10