Line data Source code
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/linkage.h"
11 : #include "src/compiler/node-matchers.h"
12 : #include "src/compiler/node-properties.h"
13 : #include "src/contexts-inl.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 : namespace compiler {
18 :
19 31329978 : Reduction JSContextSpecialization::Reduce(Node* node) {
20 31329978 : switch (node->opcode()) {
21 : case IrOpcode::kParameter:
22 2460696 : return ReduceParameter(node);
23 : case IrOpcode::kJSLoadContext:
24 689379 : return ReduceJSLoadContext(node);
25 : case IrOpcode::kJSStoreContext:
26 346545 : return ReduceJSStoreContext(node);
27 : default:
28 : break;
29 : }
30 : return NoChange();
31 : }
32 :
33 2880983 : Reduction JSContextSpecialization::ReduceParameter(Node* node) {
34 : DCHECK_EQ(IrOpcode::kParameter, node->opcode());
35 2460694 : int const index = ParameterIndexOf(node->op());
36 2460693 : if (index == Linkage::kJSCallClosureParamIndex) {
37 : // Constant-fold the function parameter {node}.
38 : Handle<JSFunction> function;
39 443382 : if (closure().ToHandle(&function)) {
40 420289 : Node* value = jsgraph()->HeapConstant(function);
41 : return Replace(value);
42 : }
43 : }
44 : return NoChange();
45 : }
46 :
47 616926 : Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
48 : Node* new_context,
49 : size_t new_depth) {
50 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
51 848368 : const ContextAccess& access = ContextAccessOf(node->op());
52 : DCHECK_LE(new_depth, access.depth());
53 :
54 1223835 : if (new_depth == access.depth() &&
55 606909 : new_context == NodeProperties::GetContextInput(node)) {
56 : return NoChange();
57 : }
58 :
59 : const Operator* op = jsgraph_->javascript()->LoadContext(
60 231442 : new_depth, access.index(), access.immutable());
61 115721 : NodeProperties::ReplaceContextInput(node, new_context);
62 115721 : NodeProperties::ChangeOp(node, op);
63 : return Changed(node);
64 : }
65 :
66 346545 : Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
67 : Node* new_context,
68 : size_t new_depth) {
69 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
70 349311 : const ContextAccess& access = ContextAccessOf(node->op());
71 : DCHECK_LE(new_depth, access.depth());
72 :
73 692906 : if (new_depth == access.depth() &&
74 346361 : new_context == NodeProperties::GetContextInput(node)) {
75 : return NoChange();
76 : }
77 :
78 : const Operator* op =
79 2766 : jsgraph_->javascript()->StoreContext(new_depth, access.index());
80 2766 : NodeProperties::ReplaceContextInput(node, new_context);
81 2766 : NodeProperties::ChangeOp(node, op);
82 : return Changed(node);
83 : }
84 :
85 : namespace {
86 :
87 348120 : bool IsContextParameter(Node* node) {
88 : DCHECK_EQ(IrOpcode::kParameter, node->opcode());
89 348120 : Node* const start = NodeProperties::GetValueInput(node, 0);
90 : DCHECK_EQ(IrOpcode::kStart, start->opcode());
91 174060 : int const index = ParameterIndexOf(node->op());
92 : // The context is always the last parameter to a JavaScript function, and
93 : // {Parameter} indices start at -1, so value outputs of {Start} look like
94 : // this: closure, receiver, param0, ..., paramN, context.
95 348120 : return index == start->op()->ValueOutputCount() - 2;
96 : }
97 :
98 : // Given a context {node} and the {distance} from that context to the target
99 : // context (which we want to read from or store to), try to return a
100 : // specialization context. If successful, update {distance} to whatever
101 : // distance remains from the specialization context.
102 1035924 : MaybeHandle<Context> GetSpecializationContext(Node* node, size_t* distance,
103 : Maybe<OuterContext> maybe_outer) {
104 1035924 : switch (node->opcode()) {
105 : case IrOpcode::kHeapConstant:
106 169081 : return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
107 : case IrOpcode::kParameter: {
108 : OuterContext outer;
109 364838 : if (maybe_outer.To(&outer) && IsContextParameter(node) &&
110 174060 : *distance >= outer.distance) {
111 174060 : *distance -= outer.distance;
112 174060 : return outer.context;
113 : }
114 : break;
115 : }
116 : default:
117 : break;
118 : }
119 692783 : return MaybeHandle<Context>();
120 : }
121 :
122 : } // anonymous namespace
123 :
124 956506 : Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
125 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
126 :
127 1101913 : const ContextAccess& access = ContextAccessOf(node->op());
128 689379 : size_t depth = access.depth();
129 :
130 : // First walk up the context chain in the graph as far as possible.
131 689379 : Node* context = NodeProperties::GetOuterContext(node, &depth);
132 :
133 : Handle<Context> concrete;
134 1378758 : if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
135 : // We do not have a concrete context object, so we can only partially reduce
136 : // the load by folding-in the outer context node.
137 349799 : return SimplifyJSLoadContext(node, context, depth);
138 : }
139 :
140 : // Now walk up the concrete context chain for the remaining depth.
141 7943 : for (; depth > 0; --depth) {
142 : concrete = handle(concrete->previous(), isolate());
143 : }
144 :
145 339580 : if (!access.immutable()) {
146 : // We found the requested context object but since the context slot is
147 : // mutable we can only partially reduce the load.
148 266626 : return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
149 : }
150 :
151 : // Even though the context slot is immutable, the context might have escaped
152 : // before the function to which it belongs has initialized the slot.
153 : // We must be conservative and check if the value in the slot is currently
154 : // the hole or undefined. Only if it is neither of these, can we be sure that
155 : // it won't change anymore.
156 : Handle<Object> value(concrete->get(static_cast<int>(access.index())),
157 72954 : isolate());
158 145487 : if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
159 1002 : return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
160 : }
161 :
162 : // Success. The context load can be replaced with the constant.
163 : // TODO(titzer): record the specialization for sharing code across multiple
164 : // contexts that have the same value in the corresponding context slot.
165 72453 : Node* constant = jsgraph_->Constant(value);
166 72453 : ReplaceWithValue(node, constant);
167 : return Replace(constant);
168 : }
169 :
170 :
171 350106 : Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
172 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
173 :
174 346545 : const ContextAccess& access = ContextAccessOf(node->op());
175 346545 : size_t depth = access.depth();
176 :
177 : // First walk up the context chain in the graph until we reduce the depth to 0
178 : // or hit a node that does not have a CreateXYZContext operator.
179 346545 : Node* context = NodeProperties::GetOuterContext(node, &depth);
180 :
181 : Handle<Context> concrete;
182 693090 : if (!GetSpecializationContext(context, &depth, outer()).ToHandle(&concrete)) {
183 : // We do not have a concrete context object, so we can only partially reduce
184 : // the load by folding-in the outer context node.
185 342984 : return SimplifyJSStoreContext(node, context, depth);
186 : }
187 :
188 : // Now walk up the concrete context chain for the remaining depth.
189 77 : for (; depth > 0; --depth) {
190 : concrete = handle(concrete->previous(), isolate());
191 : }
192 :
193 3561 : return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
194 : }
195 :
196 :
197 226461 : Isolate* JSContextSpecialization::isolate() const {
198 226461 : return jsgraph()->isolate();
199 : }
200 :
201 : } // namespace compiler
202 : } // namespace internal
203 : } // namespace v8
|