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