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.h"
14 : #include "src/objects-inl.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 : namespace compiler {
19 :
20 32494705 : Reduction JSContextSpecialization::Reduce(Node* node) {
21 32494705 : switch (node->opcode()) {
22 : case IrOpcode::kParameter:
23 1389476 : return ReduceParameter(node);
24 : case IrOpcode::kJSLoadContext:
25 615201 : return ReduceJSLoadContext(node);
26 : case IrOpcode::kJSStoreContext:
27 157925 : return ReduceJSStoreContext(node);
28 : default:
29 : break;
30 : }
31 : return NoChange();
32 : }
33 :
34 1754996 : Reduction JSContextSpecialization::ReduceParameter(Node* node) {
35 : DCHECK_EQ(IrOpcode::kParameter, node->opcode());
36 1389476 : int const index = ParameterIndexOf(node->op());
37 1389476 : if (index == Linkage::kJSCallClosureParamIndex) {
38 : // Constant-fold the function parameter {node}.
39 : Handle<JSFunction> function;
40 393276 : if (closure().ToHandle(&function)) {
41 365520 : Node* value = jsgraph()->HeapConstant(function);
42 : return Replace(value);
43 : }
44 : }
45 : return NoChange();
46 : }
47 :
48 493911 : Reduction JSContextSpecialization::SimplifyJSLoadContext(Node* node,
49 : Node* new_context,
50 : size_t new_depth) {
51 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
52 745095 : const ContextAccess& access = ContextAccessOf(node->op());
53 : DCHECK_LE(new_depth, access.depth());
54 :
55 980733 : if (new_depth == access.depth() &&
56 486822 : new_context == NodeProperties::GetContextInput(node)) {
57 : return NoChange();
58 : }
59 :
60 : const Operator* op = jsgraph_->javascript()->LoadContext(
61 251184 : new_depth, access.index(), access.immutable());
62 125592 : NodeProperties::ReplaceContextInput(node, new_context);
63 125592 : NodeProperties::ChangeOp(node, op);
64 : return Changed(node);
65 : }
66 :
67 157925 : Reduction JSContextSpecialization::SimplifyJSStoreContext(Node* node,
68 : Node* new_context,
69 : size_t new_depth) {
70 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
71 163134 : const ContextAccess& access = ContextAccessOf(node->op());
72 : DCHECK_LE(new_depth, access.depth());
73 :
74 315753 : if (new_depth == access.depth() &&
75 157828 : new_context == NodeProperties::GetContextInput(node)) {
76 : return NoChange();
77 : }
78 :
79 : const Operator* op =
80 5209 : jsgraph_->javascript()->StoreContext(new_depth, access.index());
81 5209 : NodeProperties::ReplaceContextInput(node, new_context);
82 5209 : NodeProperties::ChangeOp(node, op);
83 : return Changed(node);
84 : }
85 :
86 898707 : Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
87 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
88 :
89 1141946 : const ContextAccess& access = ContextAccessOf(node->op());
90 615200 : size_t depth = access.depth();
91 :
92 : // First walk up the context chain in the graph as far as possible.
93 615200 : Node* outer = NodeProperties::GetOuterContext(node, &depth);
94 :
95 : Handle<Context> concrete;
96 615201 : if (!NodeProperties::GetSpecializationContext(outer, context())
97 1230401 : .ToHandle(&concrete)) {
98 : // We do not have a concrete context object, so we can only partially reduce
99 : // the load by folding-in the outer context node.
100 210405 : return SimplifyJSLoadContext(node, outer, depth);
101 : }
102 :
103 : // Now walk up the concrete context chain for the remaining depth.
104 7557 : for (; depth > 0; --depth) {
105 : concrete = handle(concrete->previous(), isolate());
106 : }
107 :
108 404796 : if (!access.immutable()) {
109 : // We found the requested context object but since the context slot is
110 : // mutable we can only partially reduce the load.
111 282847 : return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
112 : }
113 :
114 : // Even though the context slot is immutable, the context might have escaped
115 : // before the function to which it belongs has initialized the slot.
116 : // We must be conservative and check if the value in the slot is currently
117 : // the hole or undefined. Only if it is neither of these, can we be sure that
118 : // it won't change anymore.
119 : Handle<Object> value(concrete->get(static_cast<int>(access.index())),
120 121949 : isolate());
121 243295 : if (value->IsUndefined(isolate()) || value->IsTheHole(isolate())) {
122 1318 : return SimplifyJSLoadContext(node, jsgraph()->Constant(concrete), depth);
123 : }
124 :
125 : // Success. The context load can be replaced with the constant.
126 : // TODO(titzer): record the specialization for sharing code across multiple
127 : // contexts that have the same value in the corresponding context slot.
128 121290 : Node* constant = jsgraph_->Constant(value);
129 121290 : ReplaceWithValue(node, constant);
130 : return Replace(constant);
131 : }
132 :
133 :
134 164039 : Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
135 : DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
136 :
137 157925 : const ContextAccess& access = ContextAccessOf(node->op());
138 157925 : size_t depth = access.depth();
139 :
140 : // First walk up the context chain in the graph until we reduce the depth to 0
141 : // or hit a node that does not have a CreateXYZContext operator.
142 157925 : Node* outer = NodeProperties::GetOuterContext(node, &depth);
143 :
144 : Handle<Context> concrete;
145 157925 : if (!NodeProperties::GetSpecializationContext(outer, context())
146 315850 : .ToHandle(&concrete)) {
147 : // We do not have a concrete context object, so we can only partially reduce
148 : // the load by folding-in the outer context node.
149 151811 : return SimplifyJSStoreContext(node, outer, depth);
150 : }
151 :
152 : // Now walk up the concrete context chain for the remaining depth.
153 61 : for (; depth > 0; --depth) {
154 : concrete = handle(concrete->previous(), isolate());
155 : }
156 :
157 6114 : return SimplifyJSStoreContext(node, jsgraph()->Constant(concrete), depth);
158 : }
159 :
160 :
161 372862 : Isolate* JSContextSpecialization::isolate() const {
162 372862 : return jsgraph()->isolate();
163 : }
164 :
165 :
166 0 : JSOperatorBuilder* JSContextSpecialization::javascript() const {
167 0 : return jsgraph()->javascript();
168 : }
169 :
170 : } // namespace compiler
171 : } // namespace internal
172 : } // namespace v8
|