2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGStackLayoutPhase.h"
33 #include "DFGValueSource.h"
34 #include "JSCInlines.h"
36 namespace JSC
{ namespace DFG
{
38 class StackLayoutPhase
: public Phase
{
39 static const bool verbose
= false;
42 StackLayoutPhase(Graph
& graph
)
43 : Phase(graph
, "stack layout")
49 SymbolTable
* symbolTable
= codeBlock()->symbolTable();
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).
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
);
64 for (unsigned nodeIndex
= block
->size(); nodeIndex
--;) {
65 Node
* node
= block
->at(nodeIndex
);
71 VariableAccessData
* variable
= node
->variableAccessData();
72 if (variable
->local().isArgument())
74 usedLocals
.set(variable
->local().toLocal());
78 case GetLocalUnlinked
: {
79 VirtualRegister operand
= node
->unlinkedLocal();
80 if (operand
.isArgument())
82 usedLocals
.set(operand
.toLocal());
83 hasGetLocalUnlinked
= true;
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
97 for (int i
= symbolTable
->captureStart(); i
> symbolTable
->captureEnd(); i
--)
98 usedLocals
.set(VirtualRegister(i
).toLocal());
100 if (codeBlock()->usesArguments()) {
101 usedLocals
.set(codeBlock()->argumentsRegister().toLocal());
102 usedLocals
.set(unmodifiedArgumentsRegister(codeBlock()->argumentsRegister()).toLocal());
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())
111 VirtualRegister argumentsRegister
= m_graph
.argumentsRegisterFor(inlineCallFrame
);
112 usedLocals
.set(argumentsRegister
.toLocal());
113 usedLocals
.set(unmodifiedArgumentsRegister(argumentsRegister
).toLocal());
115 for (unsigned argument
= inlineCallFrame
->arguments
.size(); argument
-- > 1;) {
116 usedLocals
.set(VirtualRegister(
117 virtualRegisterForArgument(argument
).offset() +
118 inlineCallFrame
->stackOffset
).toLocal());
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
;
130 allocation
[i
] = m_graph
.m_nextMachineLocal
++;
133 for (unsigned i
= m_graph
.m_variableAccessData
.size(); i
--;) {
134 VariableAccessData
* variable
= &m_graph
.m_variableAccessData
[i
];
135 if (!variable
->isRoot())
138 if (variable
->local().isArgument()) {
139 variable
->machineLocal() = variable
->local();
143 size_t local
= variable
->local().toLocal();
144 if (local
>= allocation
.size())
147 if (allocation
[local
] == UINT_MAX
)
150 variable
->machineLocal() = virtualRegisterForLocal(
151 allocation
[variable
->local().toLocal()]);
154 if (codeBlock()->usesArguments()) {
155 VirtualRegister argumentsRegister
= virtualRegisterForLocal(
156 allocation
[codeBlock()->argumentsRegister().toLocal()]);
158 virtualRegisterForLocal(allocation
[
159 unmodifiedArgumentsRegister(
160 codeBlock()->argumentsRegister()).toLocal()])
161 == unmodifiedArgumentsRegister(argumentsRegister
));
162 codeBlock()->setArgumentsRegister(argumentsRegister
);
165 if (codeBlock()->uncheckedActivationRegister().isValid()) {
166 codeBlock()->setActivationRegister(
167 virtualRegisterForLocal(allocation
[codeBlock()->activationRegister().toLocal()]));
170 for (unsigned i
= m_graph
.m_inlineVariableData
.size(); i
--;) {
171 InlineVariableData data
= m_graph
.m_inlineVariableData
[i
];
172 InlineCallFrame
* inlineCallFrame
= data
.inlineCallFrame
;
174 if (inlineCallFrame
->executable
->usesArguments()) {
175 inlineCallFrame
->argumentsRegister
= virtualRegisterForLocal(
176 allocation
[m_graph
.argumentsRegisterFor(inlineCallFrame
).toLocal()]);
179 virtualRegisterForLocal(allocation
[unmodifiedArgumentsRegister(
180 m_graph
.argumentsRegisterFor(inlineCallFrame
)).toLocal()])
181 == unmodifiedArgumentsRegister(inlineCallFrame
->argumentsRegister
));
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();
190 source
= ValueSource(SourceIsDead
);
192 source
= ValueSource::forFlushFormat(
193 variable
->machineLocal(), variable
->flushFormat());
195 inlineCallFrame
->arguments
[argument
] = source
.valueRecovery();
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();
206 RELEASE_ASSERT(inlineCallFrame
->calleeRecovery
.isConstant());
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();
216 m_graph
.m_machineCaptureStart
= virtualRegisterForLocal(0).offset();
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
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
);
228 newSlowArguments
[i
].index
= virtualRegisterForLocal(allocation
[reg
.toLocal()]).offset();
231 m_graph
.m_slowArguments
= WTF::move(newSlowArguments
);
235 // Fix GetLocalUnlinked's variable references.
236 if (hasGetLocalUnlinked
) {
237 for (BlockIndex blockIndex
= m_graph
.numBlocks(); blockIndex
--;) {
238 BasicBlock
* block
= m_graph
.block(blockIndex
);
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
);
263 bool performStackLayout(Graph
& graph
)
265 SamplingRegion
samplingRegion("DFG Stack Layout Phase");
266 return runPhase
<StackLayoutPhase
>(graph
);
269 } } // namespace JSC::DFG
271 #endif // ENABLE(DFG_JIT)