Home | History | Annotate | Download | only in compiler
      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/node-matchers.h"
     11 #include "src/compiler/node-properties.h"
     12 #include "src/contexts.h"
     13 #include "src/objects-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 Reduction JSContextSpecialization::Reduce(Node* node) {
     20   switch (node->opcode()) {
     21     case IrOpcode::kJSLoadContext:
     22       return ReduceJSLoadContext(node);
     23     case IrOpcode::kJSStoreContext:
     24       return ReduceJSStoreContext(node);
     25     default:
     26       break;
     27   }
     28   return NoChange();
     29 }
     30 
     31 Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
     32                                                          Node* new_context,
     33                                                          size_t new_depth) {
     34   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     35   const ContextAccess& access = ContextAccessOf(node->op());
     36   DCHECK_LE(new_depth, access.depth());
     37 
     38   if (new_depth == access.depth() &&
     39       new_context == NodeProperties::GetContextInput(node)) {
     40     return NoChange();
     41   }
     42 
     43   const Operator* op = jsgraph_->javascript()->LoadContext(
     44       new_depth, access.index(), access.immutable());
     45   NodeProperties::ReplaceContextInput(node, new_context);
     46   NodeProperties::ChangeOp(node, op);
     47   return Changed(node);
     48 }
     49 
     50 Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
     51                                                           Node* new_context,
     52                                                           size_t new_depth) {
     53   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
     54   const ContextAccess& access = ContextAccessOf(node->op());
     55   DCHECK_LE(new_depth, access.depth());
     56 
     57   if (new_depth == access.depth() &&
     58       new_context == NodeProperties::GetContextInput(node)) {
     59     return NoChange();
     60   }
     61 
     62   const Operator* op =
     63       jsgraph_->javascript()->StoreContext(new_depth, access.index());
     64   NodeProperties::ReplaceContextInput(node, new_context);
     65   NodeProperties::ChangeOp(node, op);
     66   return Changed(node);
     67 }
     68 
     69 Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
     70   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     71 
     72   const ContextAccess& access = ContextAccessOf(node->op());
     73   size_t depth = access.depth();
     74 
     75   // First walk up the context chain in the graph as far as possible.
     76   Node* outer = NodeProperties::GetOuterContext(node, &depth);
     77 
     78   Handle<Context> concrete;
     79   if (!NodeProperties::GetSpecializationContext(outer, context())
     80            .ToHandle(&concrete)) {
     81     // We do not have a concrete context object, so we can only partially reduce
     82     // the load by folding-in the outer context node.
     83     return SimplifyJSLoadContext(node, outer, depth);
     84   }
     85 
     86   // Now walk up the concrete context chain for the remaining depth.
     87   for (; depth > 0; --depth) {
     88     concrete = handle(concrete->previous(), isolate());
     89   }
     90 
     91   if (!access.immutable()) {
     92     // We found the requested context object but since the context slot is
     93     // mutable we can only partially reduce the load.
     94     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
     95   }
     96 
     97   // Even though the context slot is immutable, the context might have escaped
     98   // before the function to which it belongs has initialized the slot.
     99   // We must be conservative and check if the value in the slot is currently
    100   // the hole or undefined. Only if it is neither of these, can we be sure that
    101   // it won't change anymore.
    102   Handle<Object> value(concrete->get(static_cast<int>(access.index())),
    103                        isolate());
    104   if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
    105     return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
    106   }
    107 
    108   // Success. The context load can be replaced with the constant.
    109   // TODO(titzer): record the specialization for sharing code across multiple
    110   // contexts that have the same value in the corresponding context slot.
    111   Node* constant = jsgraph_->Constant(value);
    112   ReplaceWithValue(node, constant);
    113   return Replace(constant);
    114 }
    115 
    116 
    117 Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
    118   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
    119 
    120   const ContextAccess& access = ContextAccessOf(node->op());
    121   size_t depth = access.depth();
    122 
    123   // First walk up the context chain in the graph until we reduce the depth to 0
    124   // or hit a node that does not have a CreateXYZContext operator.
    125   Node* outer = NodeProperties::GetOuterContext(node, &depth);
    126 
    127   Handle<Context> concrete;
    128   if (!NodeProperties::GetSpecializationContext(outer, context())
    129            .ToHandle(&concrete)) {
    130     // We do not have a concrete context object, so we can only partially reduce
    131     // the load by folding-in the outer context node.
    132     return SimplifyJSStoreContext(node, outer, depth);
    133   }
    134 
    135   // Now walk up the concrete context chain for the remaining depth.
    136   for (; depth > 0; --depth) {
    137     concrete = handle(concrete->previous(), isolate());
    138   }
    139 
    140   return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
    141 }
    142 
    143 
    144 Isolate* JSContextSpecialization::isolate() const {
    145   return jsgraph()->isolate();
    146 }
    147 
    148 
    149 JSOperatorBuilder* JSContextSpecialization::javascript() const {
    150   return jsgraph()->javascript();
    151 }
    152 
    153 }  // namespace compiler
    154 }  // namespace internal
    155 }  // namespace v8
    156