Move back primary header includes next to config.h
[WebKit-https.git] / Source / JavaScriptCore / 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_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                 ValueSource source = ValueSource::forFlushFormat(
201                     data.calleeVariable->machineLocal(),
202                     data.calleeVariable->flushFormat());
203                 inlineCallFrame->calleeRecovery = source.valueRecovery();
204             } else
205                 RELEASE_ASSERT(inlineCallFrame->calleeRecovery.isConstant());
206         }
207         
208         if (symbolTable) {
209             if (symbolTable->captureCount()) {
210                 unsigned captureStartLocal = allocation[
211                     VirtualRegister(codeBlock()->symbolTable()->captureStart()).toLocal()];
212                 ASSERT(captureStartLocal != UINT_MAX);
213                 m_graph.m_machineCaptureStart = virtualRegisterForLocal(captureStartLocal).offset();
214             } else
215                 m_graph.m_machineCaptureStart = virtualRegisterForLocal(0).offset();
216         
217             // This is an abomination. If we had captured an argument then the argument ends
218             // up being "slow", meaning that loads of the argument go through an extra lookup
219             // table.
220             if (const SlowArgument* slowArguments = symbolTable->slowArguments()) {
221                 auto newSlowArguments = std::make_unique<SlowArgument[]>(
222                     symbolTable->parameterCount());
223                 for (size_t i = symbolTable->parameterCount(); i--;) {
224                     newSlowArguments[i] = slowArguments[i];
225                     VirtualRegister reg = VirtualRegister(slowArguments[i].index);
226                     if (reg.isLocal())
227                         newSlowArguments[i].index = virtualRegisterForLocal(allocation[reg.toLocal()]).offset();
228                 }
229             
230                 m_graph.m_slowArguments = std::move(newSlowArguments);
231             }
232         }
233         
234         // Fix GetLocalUnlinked's variable references.
235         if (hasGetLocalUnlinked) {
236             for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
237                 BasicBlock* block = m_graph.block(blockIndex);
238                 if (!block)
239                     continue;
240                 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
241                     Node* node = block->at(nodeIndex);
242                     switch (node->op()) {
243                     case GetLocalUnlinked: {
244                         VirtualRegister operand = node->unlinkedLocal();
245                         if (operand.isLocal())
246                             operand = virtualRegisterForLocal(allocation[operand.toLocal()]);
247                         node->setUnlinkedMachineLocal(operand);
248                         break;
249                     }
250                         
251                     default:
252                         break;
253                     }
254                 }
255             }
256         }
257         
258         return true;
259     }
260 };
261
262 bool performStackLayout(Graph& graph)
263 {
264     SamplingRegion samplingRegion("DFG Stack Layout Phase");
265     return runPhase<StackLayoutPhase>(graph);
266 }
267
268 } } // namespace JSC::DFG
269
270 #endif // ENABLE(DFG_JIT)
271