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 
     32 MaybeHandle<Context> JSContextSpecialization::GetSpecializationContext(
     33     Node* node) {
     34   DCHECK(node->opcode() == IrOpcode::kJSLoadContext ||
     35          node->opcode() == IrOpcode::kJSStoreContext);
     36   Node* const object = NodeProperties::GetValueInput(node, 0);
     37   return NodeProperties::GetSpecializationContext(object, context());
     38 }
     39 
     40 
     41 Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
     42   DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
     43 
     44   // Get the specialization context from the node.
     45   Handle<Context> context;
     46   if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
     47 
     48   // Find the right parent context.
     49   const ContextAccess& access = ContextAccessOf(node->op());
     50   for (size_t i = access.depth(); i > 0; --i) {
     51     context = handle(context->previous(), isolate());
     52   }
     53 
     54   // If the access itself is mutable, only fold-in the parent.
     55   if (!access.immutable()) {
     56     // The access does not have to look up a parent, nothing to fold.
     57     if (access.depth() == 0) {
     58       return NoChange();
     59     }
     60     const Operator* op = jsgraph_->javascript()->LoadContext(
     61         0, access.index(), access.immutable());
     62     node->ReplaceInput(0, jsgraph_->Constant(context));
     63     NodeProperties::ChangeOp(node, op);
     64     return Changed(node);
     65   }
     66   Handle<Object> value =
     67       handle(context->get(static_cast<int>(access.index())), isolate());
     68 
     69   // Even though the context slot is immutable, the context might have escaped
     70   // before the function to which it belongs has initialized the slot.
     71   // We must be conservative and check if the value in the slot is currently the
     72   // hole or undefined. If it is neither of these, then it must be initialized.
     73   if (value->IsUndefined() || value->IsTheHole()) {
     74     return NoChange();
     75   }
     76 
     77   // Success. The context load can be replaced with the constant.
     78   // TODO(titzer): record the specialization for sharing code across multiple
     79   // contexts that have the same value in the corresponding context slot.
     80   Node* constant = jsgraph_->Constant(value);
     81   ReplaceWithValue(node, constant);
     82   return Replace(constant);
     83 }
     84 
     85 
     86 Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
     87   DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
     88 
     89   // Get the specialization context from the node.
     90   Handle<Context> context;
     91   if (!GetSpecializationContext(node).ToHandle(&context)) return NoChange();
     92 
     93   // The access does not have to look up a parent, nothing to fold.
     94   const ContextAccess& access = ContextAccessOf(node->op());
     95   if (access.depth() == 0) {
     96     return NoChange();
     97   }
     98 
     99   // Find the right parent context.
    100   for (size_t i = access.depth(); i > 0; --i) {
    101     context = handle(context->previous(), isolate());
    102   }
    103 
    104   node->ReplaceInput(0, jsgraph_->Constant(context));
    105   NodeProperties::ChangeOp(node, javascript()->StoreContext(0, access.index()));
    106   return Changed(node);
    107 }
    108 
    109 
    110 Isolate* JSContextSpecialization::isolate() const {
    111   return jsgraph()->isolate();
    112 }
    113 
    114 
    115 JSOperatorBuilder* JSContextSpecialization::javascript() const {
    116   return jsgraph()->javascript();
    117 }
    118 
    119 }  // namespace compiler
    120 }  // namespace internal
    121 }  // namespace v8
    122