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 15namespace v8 { 16namespace internal { 17namespace compiler { 18 19Reduction 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 31Reduction 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 50Reduction 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 69Reduction 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 117Reduction 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 144Isolate* JSContextSpecialization::isolate() const { 145 return jsgraph()->isolate(); 146} 147 148 149JSOperatorBuilder* JSContextSpecialization::javascript() const { 150 return jsgraph()->javascript(); 151} 152 153} // namespace compiler 154} // namespace internal 155} // namespace v8 156