• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Reduce(Node * node)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 
SimplifyJSLoadContext(Node * node,Node * new_context,size_t new_depth)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 
SimplifyJSStoreContext(Node * node,Node * new_context,size_t new_depth)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 
ReduceJSLoadContext(Node * node)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 
ReduceJSStoreContext(Node * node)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 
isolate() const144 Isolate* JSContextSpecialization::isolate() const {
145   return jsgraph()->isolate();
146 }
147 
148 
javascript() const149 JSOperatorBuilder* JSContextSpecialization::javascript() const {
150   return jsgraph()->javascript();
151 }
152 
153 }  // namespace compiler
154 }  // namespace internal
155 }  // namespace v8
156