]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGStackLayoutPhase.cpp
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / dfg / DFGStackLayoutPhase.cpp
1 /*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "DFGStackLayoutPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "DFGPhase.h"
33 #include "DFGValueSource.h"
34 #include "JSCInlines.h"
35
36 namespace JSC { namespace DFG {
37
38 class StackLayoutPhase : public Phase {
39 static const bool verbose = false;
40
41 public:
42 StackLayoutPhase(Graph& graph)
43 : Phase(graph, "stack layout")
44 {
45 }
46
47 bool run()
48 {
49 SymbolTable* symbolTable = codeBlock()->symbolTable();
50
51 // This enumerates the locals that we actually care about and packs them. So for example
52 // if we use local 1, 3, 4, 5, 7, then we remap them: 1->0, 3->1, 4->2, 5->3, 7->4. We
53 // treat a variable as being "used" if there exists an access to it (SetLocal, GetLocal,
54 // Flush, PhantomLocal).
55
56 BitVector usedLocals;
57
58 // Collect those variables that are used from IR.
59 bool hasGetLocalUnlinked = false;
60 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
61 BasicBlock* block = m_graph.block(blockIndex);
62 if (!block)
63 continue;
64 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
65 Node* node = block->at(nodeIndex);
66 switch (node->op()) {
67 case GetLocal:
68 case SetLocal:
69 case Flush:
70 case PhantomLocal: {
71 VariableAccessData* variable = node->variableAccessData();
72 if (variable->local().isArgument())
73 break;
74 usedLocals.set(variable->local().toLocal());
75 break;
76 }
77
78 case GetLocalUnlinked: {
79 VirtualRegister operand = node->unlinkedLocal();
80 if (operand.isArgument())
81 break;
82 usedLocals.set(operand.toLocal());
83 hasGetLocalUnlinked = true;
84 break;
85 }
86
87 default:
88 break;
89 }
90 }
91 }
92
93 // Ensure that captured variables and captured inline arguments are pinned down.
94 // They should have been because of flushes, except that the flushes can be optimized
95 // away.
96 if (symbolTable) {
97 for (int i = symbolTable->captureStart(); i > symbolTable->captureEnd(); i--)
98 usedLocals.set(VirtualRegister(i).toLocal());
99 }
100 if (codeBlock()->usesArguments()) {
101 usedLocals.set(codeBlock()->argumentsRegister().toLocal());
102 usedLocals.set(unmodifiedArgumentsRegister(codeBlock()->argumentsRegister()).toLocal());
103 }
104 if (codeBlock()->uncheckedActivationRegister().isValid())
105 usedLocals.set(codeBlock()->activationRegister().toLocal());
106 for (InlineCallFrameSet::iterator iter = m_graph.m_plan.inlineCallFrames->begin(); !!iter; ++iter) {
107 InlineCallFrame* inlineCallFrame = *iter;
108 if (!inlineCallFrame->executable->usesArguments())
109 continue;
110
111 VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(inlineCallFrame);
112 usedLocals.set(argumentsRegister.toLocal());
113 usedLocals.set(unmodifiedArgumentsRegister(argumentsRegister).toLocal());
114
115 for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) {
116 usedLocals.set(VirtualRegister(
117 virtualRegisterForArgument(argument).offset() +
118 inlineCallFrame->stackOffset).toLocal());
119 }
120 }
121
122 Vector<unsigned> allocation(usedLocals.size());
123 m_graph.m_nextMachineLocal = 0;
124 for (unsigned i = 0; i < usedLocals.size(); ++i) {
125 if (!usedLocals.get(i)) {
126 allocation[i] = UINT_MAX;
127 continue;
128 }
129
130 allocation[i] = m_graph.m_nextMachineLocal++;
131 }
132
133 for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
134 VariableAccessData* variable = &m_graph.m_variableAccessData[i];
135 if (!variable->isRoot())
136 continue;
137
138 if (variable->local().isArgument()) {
139 variable->machineLocal() = variable->local();
140 continue;
141 }
142
143 size_t local = variable->local().toLocal();
144 if (local >= allocation.size())
145 continue;
146
147 if (allocation[local] == UINT_MAX)
148 continue;
149
150 variable->machineLocal() = virtualRegisterForLocal(
151 allocation[variable->local().toLocal()]);
152 }
153
154 if (codeBlock()->usesArguments()) {
155 VirtualRegister argumentsRegister = virtualRegisterForLocal(
156 allocation[codeBlock()->argumentsRegister().toLocal()]);
157 RELEASE_ASSERT(
158 virtualRegisterForLocal(allocation[
159 unmodifiedArgumentsRegister(
160 codeBlock()->argumentsRegister()).toLocal()])
161 == unmodifiedArgumentsRegister(argumentsRegister));
162 codeBlock()->setArgumentsRegister(argumentsRegister);
163 }
164
165 if (codeBlock()->uncheckedActivationRegister().isValid()) {
166 codeBlock()->setActivationRegister(
167 virtualRegisterForLocal(allocation[codeBlock()->activationRegister().toLocal()]));
168 }
169
170 for (unsigned i = m_graph.m_inlineVariableData.size(); i--;) {
171 InlineVariableData data = m_graph.m_inlineVariableData[i];
172 InlineCallFrame* inlineCallFrame = data.inlineCallFrame;
173
174 if (inlineCallFrame->executable->usesArguments()) {
175 inlineCallFrame->argumentsRegister = virtualRegisterForLocal(
176 allocation[m_graph.argumentsRegisterFor(inlineCallFrame).toLocal()]);
177
178 RELEASE_ASSERT(
179 virtualRegisterForLocal(allocation[unmodifiedArgumentsRegister(
180 m_graph.argumentsRegisterFor(inlineCallFrame)).toLocal()])
181 == unmodifiedArgumentsRegister(inlineCallFrame->argumentsRegister));
182 }
183
184 for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) {
185 ArgumentPosition& position = m_graph.m_argumentPositions[
186 data.argumentPositionStart + argument];
187 VariableAccessData* variable = position.someVariable();
188 ValueSource source;
189 if (!variable)
190 source = ValueSource(SourceIsDead);
191 else {
192 source = ValueSource::forFlushFormat(
193 variable->machineLocal(), variable->flushFormat());
194 }
195 inlineCallFrame->arguments[argument] = source.valueRecovery();
196 }
197
198 RELEASE_ASSERT(inlineCallFrame->isClosureCall == !!data.calleeVariable);
199 if (inlineCallFrame->isClosureCall) {
200 VariableAccessData* variable = data.calleeVariable->find();
201 ValueSource source = ValueSource::forFlushFormat(
202 variable->machineLocal(),
203 variable->flushFormat());
204 inlineCallFrame->calleeRecovery = source.valueRecovery();
205 } else
206 RELEASE_ASSERT(inlineCallFrame->calleeRecovery.isConstant());
207 }
208
209 if (symbolTable) {
210 if (symbolTable->captureCount()) {
211 unsigned captureStartLocal = allocation[
212 VirtualRegister(codeBlock()->symbolTable()->captureStart()).toLocal()];
213 ASSERT(captureStartLocal != UINT_MAX);
214 m_graph.m_machineCaptureStart = virtualRegisterForLocal(captureStartLocal).offset();
215 } else
216 m_graph.m_machineCaptureStart = virtualRegisterForLocal(0).offset();
217
218 // This is an abomination. If we had captured an argument then the argument ends
219 // up being "slow", meaning that loads of the argument go through an extra lookup
220 // table.
221 if (const SlowArgument* slowArguments = symbolTable->slowArguments()) {
222 auto newSlowArguments = std::make_unique<SlowArgument[]>(
223 symbolTable->parameterCount());
224 for (size_t i = symbolTable->parameterCount(); i--;) {
225 newSlowArguments[i] = slowArguments[i];
226 VirtualRegister reg = VirtualRegister(slowArguments[i].index);
227 if (reg.isLocal())
228 newSlowArguments[i].index = virtualRegisterForLocal(allocation[reg.toLocal()]).offset();
229 }
230
231 m_graph.m_slowArguments = WTF::move(newSlowArguments);
232 }
233 }
234
235 // Fix GetLocalUnlinked's variable references.
236 if (hasGetLocalUnlinked) {
237 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
238 BasicBlock* block = m_graph.block(blockIndex);
239 if (!block)
240 continue;
241 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
242 Node* node = block->at(nodeIndex);
243 switch (node->op()) {
244 case GetLocalUnlinked: {
245 VirtualRegister operand = node->unlinkedLocal();
246 if (operand.isLocal())
247 operand = virtualRegisterForLocal(allocation[operand.toLocal()]);
248 node->setUnlinkedMachineLocal(operand);
249 break;
250 }
251
252 default:
253 break;
254 }
255 }
256 }
257 }
258
259 return true;
260 }
261 };
262
263 bool performStackLayout(Graph& graph)
264 {
265 SamplingRegion samplingRegion("DFG Stack Layout Phase");
266 return runPhase<StackLayoutPhase>(graph);
267 }
268
269 } } // namespace JSC::DFG
270
271 #endif // ENABLE(DFG_JIT)
272