]>
git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGVarargsForwardingPhase.cpp
2 * Copyright (C) 2015 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 "DFGVarargsForwardingPhase.h"
31 #include "DFGArgumentsUtilities.h"
32 #include "DFGClobberize.h"
33 #include "DFGForAllKills.h"
36 #include "JSCInlines.h"
37 #include <wtf/ListDump.h>
39 namespace JSC
{ namespace DFG
{
45 class VarargsForwardingPhase
: public Phase
{
47 VarargsForwardingPhase(Graph
& graph
)
48 : Phase(graph
, "varargs forwarding")
54 DFG_ASSERT(m_graph
, nullptr, m_graph
.m_form
!= SSA
);
57 dataLog("Graph before varargs forwarding:\n");
62 for (BasicBlock
* block
: m_graph
.blocksInNaturalOrder())
68 void handleBlock(BasicBlock
* block
)
70 for (unsigned nodeIndex
= 0; nodeIndex
< block
->size(); ++nodeIndex
) {
71 Node
* node
= block
->at(nodeIndex
);
73 case CreateDirectArguments
:
74 case CreateClonedArguments
:
75 handleCandidate(block
, nodeIndex
);
83 void handleCandidate(BasicBlock
* block
, unsigned candidateNodeIndex
)
85 // We expect calls into this function to be rare. So, this is written in a simple O(n) manner.
87 Node
* candidate
= block
->at(candidateNodeIndex
);
89 dataLog("Handling candidate ", candidate
, "\n");
91 // Find the index of the last node in this block to use the candidate, and look for escaping
93 unsigned lastUserIndex
= candidateNodeIndex
;
94 Vector
<VirtualRegister
, 2> relevantLocals
; // This is a set. We expect it to be a small set.
95 for (unsigned nodeIndex
= candidateNodeIndex
+ 1; nodeIndex
< block
->size(); ++nodeIndex
) {
96 Node
* node
= block
->at(nodeIndex
);
100 if (node
->child1() != candidate
)
102 lastUserIndex
= nodeIndex
;
103 if (!relevantLocals
.contains(node
->unlinkedLocal()))
104 relevantLocals
.append(node
->unlinkedLocal());
108 bool sawEscape
= false;
109 m_graph
.doToChildren(
112 if (edge
== candidate
)
113 lastUserIndex
= nodeIndex
;
115 if (edge
.willNotHaveCheck())
118 if (alreadyChecked(edge
.useKind(), SpecObject
))
125 dataLog(" Escape at ", node
, "\n");
132 if (m_graph
.uses(node
, candidate
))
133 lastUserIndex
= nodeIndex
;
137 case ConstructVarargs
:
138 if (node
->child1() == candidate
|| node
->child3() == candidate
) {
140 dataLog(" Escape at ", node
, "\n");
143 if (node
->child2() == candidate
)
144 lastUserIndex
= nodeIndex
;
148 if (node
->child1() == candidate
&& node
->variableAccessData()->isLoadedFrom()) {
150 dataLog(" Escape at ", node
, "\n");
156 if (m_graph
.uses(node
, candidate
)) {
158 dataLog(" Escape at ", node
, "\n");
163 forAllKilledOperands(
164 m_graph
, node
, block
->tryAt(nodeIndex
+ 1),
165 [&] (VirtualRegister reg
) {
167 dataLog(" Killing ", reg
, " while we are interested in ", listDump(relevantLocals
), "\n");
168 for (unsigned i
= 0; i
< relevantLocals
.size(); ++i
) {
169 if (relevantLocals
[i
] == reg
) {
170 relevantLocals
[i
--] = relevantLocals
.last();
171 relevantLocals
.removeLast();
172 lastUserIndex
= nodeIndex
;
178 dataLog("Selected lastUserIndex = ", lastUserIndex
, ", ", block
->at(lastUserIndex
), "\n");
180 // We're still in business. Determine if between the candidate and the last user there is any
181 // effect that could interfere with sinking.
182 for (unsigned nodeIndex
= candidateNodeIndex
+ 1; nodeIndex
<= lastUserIndex
; ++nodeIndex
) {
183 Node
* node
= block
->at(nodeIndex
);
185 // We have our own custom switch to detect some interferences that clobberize() wouldn't know
186 // about, and also some of the common ones, too. In particular, clobberize() doesn't know
187 // that Flush, MovHint, ZombieHint, and KillStack are bad because it's not worried about
188 // what gets read on OSR exit.
189 switch (node
->op()) {
193 if (argumentsInvolveStackSlot(candidate
, node
->unlinkedLocal())) {
195 dataLog(" Interference at ", node
, "\n");
201 if (argumentsInvolveStackSlot(candidate
, node
->stackAccessData()->local
)) {
203 dataLog(" Interference at ", node
, "\n");
210 if (argumentsInvolveStackSlot(candidate
, node
->local())) {
212 dataLog(" Interference at ", node
, "\n");
218 bool doesInterfere
= false;
220 m_graph
, node
, NoOpClobberize(),
221 [&] (AbstractHeap heap
) {
222 if (heap
.kind() != Stack
) {
223 ASSERT(!heap
.overlaps(Stack
));
226 ASSERT(!heap
.payload().isTop());
227 VirtualRegister
reg(heap
.payload().value32());
228 if (argumentsInvolveStackSlot(candidate
, reg
))
229 doesInterfere
= true;
234 dataLog(" Interference at ", node
, "\n");
240 // We can make this work.
242 dataLog(" Will do forwarding!\n");
245 // Transform the program.
246 switch (candidate
->op()) {
247 case CreateDirectArguments
:
248 candidate
->setOpAndDefaultFlags(PhantomDirectArguments
);
251 case CreateClonedArguments
:
252 candidate
->setOpAndDefaultFlags(PhantomClonedArguments
);
256 DFG_CRASH(m_graph
, candidate
, "bad node type");
259 for (unsigned nodeIndex
= candidateNodeIndex
+ 1; nodeIndex
<= lastUserIndex
; ++nodeIndex
) {
260 Node
* node
= block
->at(nodeIndex
);
261 switch (node
->op()) {
265 // We don't need to change anything with these.
269 if (node
->child1() != candidate
)
271 node
->setOpAndDefaultFlags(ForwardVarargs
);
275 if (node
->child2() != candidate
)
277 node
->setOpAndDefaultFlags(CallForwardVarargs
);
280 case ConstructVarargs
:
281 if (node
->child2() != candidate
)
283 node
->setOpAndDefaultFlags(ConstructForwardVarargs
);
287 // This is super odd. We don't have to do anything here, since in DFG IR, the phantom
288 // arguments nodes do produce a JSValue. Also, we know that if this SetLocal referenecs a
289 // candidate then the SetLocal - along with all of its references - will die off pretty
290 // soon, since it has no real users. DCE will surely kill it. If we make it to SSA, then
291 // SSA conversion will kill it.
297 m_graph
.doToChildren(
300 DFG_ASSERT(m_graph
, node
, edge
!= candidate
);
310 } // anonymous namespace
312 bool performVarargsForwarding(Graph
& graph
)
314 SamplingRegion
samplingRegion("DFG Varargs Forwarding Phase");
315 return runPhase
<VarargsForwardingPhase
>(graph
);
318 } } // namespace JSC::DFG
320 #endif // ENABLE(DFG_JIT)