2 * Copyright (C) 2012, 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 "DFGArgumentsSimplificationPhase.h"
31 #include "DFGAbstractState.h"
32 #include "DFGBasicBlock.h"
34 #include "DFGInsertionSet.h"
36 #include "DFGValidate.h"
37 #include "DFGVariableAccessDataDump.h"
38 #include <wtf/HashSet.h>
39 #include <wtf/HashMap.h>
42 #include "Operations.h"
45 namespace JSC
{ namespace DFG
{
49 struct ArgumentsAliasingData
{
50 InlineCallFrame
* callContext
;
52 bool multipleCallContexts
;
54 bool assignedFromArguments
;
55 bool assignedFromManyThings
;
59 ArgumentsAliasingData()
61 , callContextSet(false)
62 , multipleCallContexts(false)
63 , assignedFromArguments(false)
64 , assignedFromManyThings(false)
69 void mergeCallContext(InlineCallFrame
* newCallContext
)
71 if (multipleCallContexts
)
74 if (!callContextSet
) {
75 callContext
= newCallContext
;
76 callContextSet
= true;
80 if (callContext
== newCallContext
)
83 multipleCallContexts
= true;
86 bool callContextIsValid()
88 return callContextSet
&& !multipleCallContexts
;
91 void mergeArgumentsAssignment()
93 assignedFromArguments
= true;
96 void mergeNonArgumentsAssignment()
98 assignedFromManyThings
= true;
101 bool argumentsAssignmentIsValid()
103 return assignedFromArguments
&& !assignedFromManyThings
;
108 return callContextIsValid() && argumentsAssignmentIsValid() && !escapes
;
112 } // end anonymous namespace
114 class ArgumentsSimplificationPhase
: public Phase
{
116 ArgumentsSimplificationPhase(Graph
& graph
)
117 : Phase(graph
, "arguments simplification")
123 if (!m_graph
.m_hasArguments
)
126 bool changed
= false;
128 // Record which arguments are known to escape no matter what.
129 for (unsigned i
= codeBlock()->inlineCallFrames().size(); i
--;)
130 pruneObviousArgumentCreations(&codeBlock()->inlineCallFrames()[i
]);
131 pruneObviousArgumentCreations(0); // the machine call frame.
133 // Create data for variable access datas that we will want to analyze.
134 for (unsigned i
= m_graph
.m_variableAccessData
.size(); i
--;) {
135 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
136 if (!variableAccessData
->isRoot())
138 if (variableAccessData
->isCaptured())
140 m_argumentsAliasing
.add(variableAccessData
, ArgumentsAliasingData());
143 // Figure out which variables are live, using a conservative approximation of
145 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
146 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
149 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
150 Node
* node
= block
->at(indexInBlock
);
151 switch (node
->op()) {
155 m_isLive
.add(node
->variableAccessData());
163 // Figure out which variables alias the arguments and nothing else, and are
164 // used only for GetByVal and GetArrayLength accesses. At the same time,
165 // identify uses of CreateArguments that are not consistent with the arguments
166 // being aliased only to variables that satisfy these constraints.
167 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
168 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
171 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
172 Node
* node
= block
->at(indexInBlock
);
173 switch (node
->op()) {
174 case CreateArguments
: {
175 // Ignore this op. If we see a lone CreateArguments then we want to
176 // completely ignore it because:
177 // 1) The default would be to see that the child is a GetLocal on the
178 // arguments register and conclude that we have an arguments escape.
179 // 2) The fact that a CreateArguments exists does not mean that it
180 // will continue to exist after we're done with this phase. As far
181 // as this phase is concerned, a CreateArguments only "exists" if it
182 // is used in a manner that necessitates its existance.
186 case TearOffArguments
: {
187 // Ignore arguments tear off, because it's only relevant if we actually
188 // need to create the arguments.
193 Node
* source
= node
->child1().node();
194 VariableAccessData
* variableAccessData
= node
->variableAccessData();
195 int argumentsRegister
=
196 m_graph
.uncheckedArgumentsRegisterFor(node
->codeOrigin
);
197 if (source
->op() != CreateArguments
&& source
->op() != PhantomArguments
) {
198 // Make sure that the source of the SetLocal knows that if it's
199 // a variable that we think is aliased to the arguments, then it
200 // may escape at this point. In future, we could track transitive
201 // aliasing. But not yet.
202 observeBadArgumentsUse(source
);
204 // If this is an assignment to the arguments register, then
205 // pretend as if the arguments were created. We don't want to
206 // optimize code that explicitly assigns to the arguments,
207 // because that seems too ugly.
209 // But, before getting rid of CreateArguments, we will have
210 // an assignment to the arguments registers with JSValue().
211 // That's because CSE will refuse to get rid of the
212 // init_lazy_reg since it treats CreateArguments as reading
213 // local variables. That could be fixed, but it's easier to
214 // work around this here.
215 if (source
->op() == JSConstant
216 && !source
->valueOfJSConstant(codeBlock()))
219 // If the variable is totally dead, then ignore it.
220 if (!m_isLive
.contains(variableAccessData
))
223 if (argumentsRegister
!= InvalidVirtualRegister
224 && (variableAccessData
->local() == argumentsRegister
225 || variableAccessData
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
226 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
230 if (variableAccessData
->isCaptured())
233 // Make sure that if it's a variable that we think is aliased to
234 // the arguments, that we know that it might actually not be.
235 ArgumentsAliasingData
& data
=
236 m_argumentsAliasing
.find(variableAccessData
)->value
;
237 data
.mergeNonArgumentsAssignment();
238 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
241 if (argumentsRegister
!= InvalidVirtualRegister
242 && (variableAccessData
->local() == argumentsRegister
243 || variableAccessData
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
244 if (node
->codeOrigin
.inlineCallFrame
== source
->codeOrigin
.inlineCallFrame
)
246 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
249 if (variableAccessData
->isCaptured()) {
250 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
253 ArgumentsAliasingData
& data
=
254 m_argumentsAliasing
.find(variableAccessData
)->value
;
255 data
.mergeArgumentsAssignment();
256 // This ensures that the variable's uses are in the same context as
257 // the arguments it is aliasing.
258 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
259 data
.mergeCallContext(source
->codeOrigin
.inlineCallFrame
);
264 case Phi
: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ {
265 VariableAccessData
* variableAccessData
= node
->variableAccessData();
266 if (variableAccessData
->isCaptured())
268 ArgumentsAliasingData
& data
=
269 m_argumentsAliasing
.find(variableAccessData
)->value
;
270 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
275 VariableAccessData
* variableAccessData
= node
->variableAccessData();
276 if (variableAccessData
->isCaptured())
278 ArgumentsAliasingData
& data
=
279 m_argumentsAliasing
.find(variableAccessData
)->value
;
280 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
282 // If a variable is used in a flush then by definition it escapes.
288 VariableAccessData
* variableAccessData
= node
->variableAccessData();
289 if (variableAccessData
->isCaptured())
291 ArgumentsAliasingData
& data
=
292 m_argumentsAliasing
.find(variableAccessData
)->value
;
293 data
.mergeNonArgumentsAssignment();
294 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
299 if (node
->arrayMode().type() != Array::Arguments
) {
300 observeBadArgumentsUses(node
);
304 // That's so awful and pretty much impossible since it would
305 // imply that the arguments were predicted integer, but it's
306 // good to be defensive and thorough.
307 observeBadArgumentsUse(node
->child2().node());
308 observeProperArgumentsUse(node
, node
->child1());
312 case GetArrayLength
: {
313 if (node
->arrayMode().type() != Array::Arguments
) {
314 observeBadArgumentsUses(node
);
318 observeProperArgumentsUse(node
, node
->child1());
323 // We don't care about phantom uses, since phantom uses are all about
324 // just keeping things alive for OSR exit. If something - like the
325 // CreateArguments - is just being kept alive, then this transformation
326 // will not break this, since the Phantom will now just keep alive a
327 // PhantomArguments and OSR exit will still do the right things.
331 case ForwardCheckStructure
:
332 case StructureTransitionWatchpoint
:
333 case ForwardStructureTransitionWatchpoint
:
335 // We don't care about these because if we get uses of the relevant
336 // variable then we can safely get rid of these, too. This of course
337 // relies on there not being any information transferred by the CFA
338 // from a CheckStructure on one variable to the information about the
339 // structures of another variable.
343 observeBadArgumentsUses(node
);
349 // Now we know which variables are aliased to arguments. But if any of them are
350 // found to have escaped, or were otherwise invalidated, then we need to mark
351 // the arguments as requiring creation. This is a property of SetLocals to
352 // variables that are neither the correct arguments register nor are marked as
353 // being arguments-aliased.
354 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
355 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
358 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
359 Node
* node
= block
->at(indexInBlock
);
360 if (node
->op() != SetLocal
)
362 Node
* source
= node
->child1().node();
363 if (source
->op() != CreateArguments
)
365 VariableAccessData
* variableAccessData
= node
->variableAccessData();
366 if (variableAccessData
->isCaptured()) {
367 // The captured case would have already been taken care of in the
372 ArgumentsAliasingData
& data
=
373 m_argumentsAliasing
.find(variableAccessData
)->value
;
377 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
381 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
382 dataLogF("Arguments aliasing states:\n");
383 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
384 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
385 if (!variableAccessData
->isRoot())
387 dataLog(" r", variableAccessData
->local(), "(", VariableAccessDataDump(m_graph
, variableAccessData
), "): ");
388 if (variableAccessData
->isCaptured())
389 dataLogF("Captured");
391 ArgumentsAliasingData
& data
=
392 m_argumentsAliasing
.find(variableAccessData
)->value
;
394 if (data
.callContextIsValid()) {
397 dataLogF("Have Call Context: %p", data
.callContext
);
399 if (!m_createsArguments
.contains(data
.callContext
))
400 dataLogF(" (Does Not Create Arguments)");
402 if (data
.argumentsAssignmentIsValid()) {
405 dataLogF("Arguments Assignment Is Valid");
411 dataLogF("Does Not Escape");
416 if (data
.isValid()) {
417 if (m_createsArguments
.contains(data
.callContext
))
420 dataLogF("INVALID (due to argument creation)");
422 dataLogF("INVALID (due to bad variable use)");
428 InsertionSet
insertionSet(m_graph
);
430 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
431 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
434 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); indexInBlock
++) {
435 Node
* node
= block
->at(indexInBlock
);
436 switch (node
->op()) {
438 Node
* source
= node
->child1().node();
439 if (source
->op() != CreateArguments
)
442 if (m_createsArguments
.contains(source
->codeOrigin
.inlineCallFrame
))
445 VariableAccessData
* variableAccessData
= node
->variableAccessData();
447 if (m_graph
.argumentsRegisterFor(node
->codeOrigin
) == variableAccessData
->local()
448 || unmodifiedArgumentsRegister(m_graph
.argumentsRegisterFor(node
->codeOrigin
)) == variableAccessData
->local())
451 ASSERT(!variableAccessData
->isCaptured());
453 // If this is a store into a VariableAccessData* that is marked as
454 // arguments aliasing for an InlineCallFrame* that does not create
455 // arguments, then flag the VariableAccessData as being an
456 // arguments-aliased. This'll let the OSR exit machinery do the right
457 // things. Note also that the SetLocal should become dead as soon as
458 // we replace all uses of this variable with GetMyArgumentsLength and
459 // GetMyArgumentByVal.
460 ASSERT(m_argumentsAliasing
.find(variableAccessData
)->value
.isValid());
461 if (variableAccessData
->mergeIsArgumentsAlias(true)) {
464 // Make sure that the variable knows, that it may now hold non-cell values.
465 variableAccessData
->predict(SpecEmpty
);
468 // Make sure that the SetLocal doesn't check that the input is a Cell.
469 if (node
->child1().useKind() != UntypedUse
) {
470 node
->child1().setUseKind(UntypedUse
);
477 VariableAccessData
* variableAccessData
= node
->variableAccessData();
479 if (variableAccessData
->isCaptured()
480 || !m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
481 || m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
484 // Turn PhantomLocals into just GetLocals. This will preserve the threading
485 // of the local through to this point, but will allow it to die, causing
486 // only OSR to know about it.
488 node
->setOpAndDefaultFlags(GetLocal
);
493 VariableAccessData
* variableAccessData
= node
->variableAccessData();
495 if (variableAccessData
->isCaptured()
496 || !m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
497 || m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
500 RELEASE_ASSERT_NOT_REACHED();
505 // It's highly likely that we will have a Phantom referencing either
506 // CreateArguments, or a local op for the arguments register, or a
507 // local op for an arguments-aliased variable. In any of those cases,
508 // we should remove the phantom reference, since:
509 // 1) Phantoms only exist to aid OSR exit. But arguments simplification
510 // has its own OSR exit story, which is to inform OSR exit to reify
511 // the arguments as necessary.
512 // 2) The Phantom may keep the CreateArguments node alive, which is
513 // precisely what we don't want.
514 for (unsigned i
= 0; i
< AdjacencyList::Size
; ++i
)
515 removeArgumentsReferencingPhantomChild(node
, i
);
520 case ForwardCheckStructure
:
521 case StructureTransitionWatchpoint
:
522 case ForwardStructureTransitionWatchpoint
:
524 // We can just get rid of this node, if it references a phantom argument.
525 if (!isOKToOptimize(node
->child1().node()))
527 node
->convertToPhantom();
528 node
->children
.setChild1(Edge());
533 if (node
->arrayMode().type() != Array::Arguments
)
536 // This can be simplified to GetMyArgumentByVal if we know that
537 // it satisfies either condition (1) or (2):
538 // 1) Its first child is a valid ArgumentsAliasingData and the
539 // InlineCallFrame* is not marked as creating arguments.
540 // 2) Its first child is CreateArguments and its InlineCallFrame*
541 // is not marked as creating arguments.
543 if (!isOKToOptimize(node
->child1().node()))
546 node
->children
.child1() = node
->children
.child2();
547 node
->children
.child2() = Edge();
548 node
->setOpAndDefaultFlags(GetMyArgumentByVal
);
550 --indexInBlock
; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
554 case GetArrayLength
: {
555 if (node
->arrayMode().type() != Array::Arguments
)
558 if (!isOKToOptimize(node
->child1().node()))
561 node
->children
.child1() = Edge();
562 node
->setOpAndDefaultFlags(GetMyArgumentsLength
);
564 --indexInBlock
; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
568 case GetMyArgumentsLength
:
569 case GetMyArgumentsLengthSafe
: {
570 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
)) {
571 ASSERT(node
->op() == GetMyArgumentsLengthSafe
);
574 if (node
->op() == GetMyArgumentsLengthSafe
) {
575 node
->setOp(GetMyArgumentsLength
);
579 CodeOrigin codeOrigin
= node
->codeOrigin
;
580 if (!codeOrigin
.inlineCallFrame
)
583 // We know exactly what this will return. But only after we have checked
584 // that nobody has escaped our arguments.
585 insertionSet
.insertNode(
586 indexInBlock
, SpecNone
, CheckArgumentsNotCreated
, codeOrigin
);
588 m_graph
.convertToConstant(
589 node
, jsNumber(codeOrigin
.inlineCallFrame
->arguments
.size() - 1));
594 case GetMyArgumentByVal
:
595 case GetMyArgumentByValSafe
: {
596 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
)) {
597 ASSERT(node
->op() == GetMyArgumentByValSafe
);
600 if (node
->op() == GetMyArgumentByValSafe
) {
601 node
->setOp(GetMyArgumentByVal
);
604 if (!node
->codeOrigin
.inlineCallFrame
)
606 if (!node
->child1()->hasConstant())
608 JSValue value
= node
->child1()->valueOfJSConstant(codeBlock());
609 if (!value
.isInt32())
611 int32_t index
= value
.asInt32();
613 || static_cast<size_t>(index
+ 1) >=
614 node
->codeOrigin
.inlineCallFrame
->arguments
.size())
617 // We know which argument this is accessing. But only after we have checked
618 // that nobody has escaped our arguments. We also need to ensure that the
619 // index is kept alive. That's somewhat pointless since it's a constant, but
620 // it's important because this is one of those invariants that we like to
621 // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
622 // here, since this is being done _after_ the prediction propagation phase
623 // has run - therefore it makes little sense to link the GetLocal operation
624 // into the VariableAccessData and Phi graphs.
626 CodeOrigin codeOrigin
= node
->codeOrigin
;
627 AdjacencyList children
= node
->children
;
629 node
->convertToGetLocalUnlinked(
630 static_cast<VirtualRegister
>(
631 node
->codeOrigin
.inlineCallFrame
->stackOffset
+
632 m_graph
.baselineCodeBlockFor(node
->codeOrigin
)->argumentIndexAfterCapture(index
)));
634 insertionSet
.insertNode(
635 indexInBlock
, SpecNone
, CheckArgumentsNotCreated
,
637 insertionSet
.insertNode(
638 indexInBlock
, SpecNone
, Phantom
, codeOrigin
,
645 case TearOffArguments
: {
646 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
649 node
->setOpAndDefaultFlags(Nop
);
650 m_graph
.clearAndDerefChild1(node
);
651 m_graph
.clearAndDerefChild2(node
);
659 insertionSet
.execute(block
);
662 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
663 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
666 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
667 Node
* node
= block
->at(indexInBlock
);
668 if (node
->op() != CreateArguments
)
670 // If this is a CreateArguments for an InlineCallFrame* that does
671 // not create arguments, then replace it with a PhantomArguments.
672 // PhantomArguments is a non-executing node that just indicates
673 // that the node should be reified as an arguments object on OSR
675 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
677 insertionSet
.insertNode(
678 indexInBlock
, SpecNone
, Phantom
, node
->codeOrigin
, node
->children
);
679 node
->setOpAndDefaultFlags(PhantomArguments
);
680 node
->children
.reset();
683 insertionSet
.execute(block
);
688 m_graph
.m_form
= LoadStore
;
695 HashSet
<InlineCallFrame
*,
696 DefaultHash
<InlineCallFrame
*>::Hash
,
697 NullableHashTraits
<InlineCallFrame
*> > m_createsArguments
;
698 HashMap
<VariableAccessData
*, ArgumentsAliasingData
,
699 DefaultHash
<VariableAccessData
*>::Hash
,
700 NullableHashTraits
<VariableAccessData
*> > m_argumentsAliasing
;
701 HashSet
<VariableAccessData
*> m_isLive
;
703 void pruneObviousArgumentCreations(InlineCallFrame
* inlineCallFrame
)
705 ScriptExecutable
* executable
= jsCast
<ScriptExecutable
*>(m_graph
.executableFor(inlineCallFrame
));
706 if (m_graph
.m_executablesWhoseArgumentsEscaped
.contains(executable
)
707 || executable
->isStrictMode())
708 m_createsArguments
.add(inlineCallFrame
);
711 void observeBadArgumentsUse(Node
* node
)
716 switch (node
->op()) {
717 case CreateArguments
: {
718 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
723 int argumentsRegister
= m_graph
.uncheckedArgumentsRegisterFor(node
->codeOrigin
);
724 if (argumentsRegister
!= InvalidVirtualRegister
725 && (node
->local() == argumentsRegister
726 || node
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
727 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
731 VariableAccessData
* variableAccessData
= node
->variableAccessData();
732 if (variableAccessData
->isCaptured())
735 ArgumentsAliasingData
& data
= m_argumentsAliasing
.find(variableAccessData
)->value
;
745 void observeBadArgumentsUses(Node
* node
)
747 for (unsigned i
= m_graph
.numChildren(node
); i
--;)
748 observeBadArgumentsUse(m_graph
.child(node
, i
).node());
751 void observeProperArgumentsUse(Node
* node
, Edge edge
)
753 if (edge
->op() != GetLocal
) {
754 // When can this happen? At least two cases that I can think
757 // 1) Aliased use of arguments in the same basic block,
760 // var a = arguments;
761 // var x = arguments[i];
763 // 2) If we're accessing arguments we got from the heap!
765 if (edge
->op() == CreateArguments
766 && node
->codeOrigin
.inlineCallFrame
767 != edge
->codeOrigin
.inlineCallFrame
)
768 m_createsArguments
.add(edge
->codeOrigin
.inlineCallFrame
);
773 VariableAccessData
* variableAccessData
= edge
->variableAccessData();
774 if (edge
->local() == m_graph
.uncheckedArgumentsRegisterFor(edge
->codeOrigin
)
775 && node
->codeOrigin
.inlineCallFrame
!= edge
->codeOrigin
.inlineCallFrame
) {
776 m_createsArguments
.add(edge
->codeOrigin
.inlineCallFrame
);
780 if (variableAccessData
->isCaptured())
783 ArgumentsAliasingData
& data
= m_argumentsAliasing
.find(variableAccessData
)->value
;
784 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
787 bool isOKToOptimize(Node
* source
)
789 if (m_createsArguments
.contains(source
->codeOrigin
.inlineCallFrame
))
792 switch (source
->op()) {
794 VariableAccessData
* variableAccessData
= source
->variableAccessData();
795 int argumentsRegister
= m_graph
.uncheckedArgumentsRegisterFor(source
->codeOrigin
);
796 if (argumentsRegister
== InvalidVirtualRegister
)
798 if (argumentsRegister
== variableAccessData
->local())
800 if (unmodifiedArgumentsRegister(argumentsRegister
) == variableAccessData
->local())
802 if (variableAccessData
->isCaptured())
804 ArgumentsAliasingData
& data
=
805 m_argumentsAliasing
.find(variableAccessData
)->value
;
812 case CreateArguments
: {
823 void removeArgumentsReferencingPhantomChild(Node
* node
, unsigned edgeIndex
)
825 Edge edge
= node
->children
.child(edgeIndex
);
829 switch (edge
->op()) {
830 case Phi
: // Arises if we had CSE on a GetLocal of the arguments register.
831 case GetLocal
: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
832 case SetLocal
: { // Arises if we had CSE on a GetLocal of the arguments register.
833 VariableAccessData
* variableAccessData
= edge
->variableAccessData();
834 bool isDeadArgumentsRegister
=
835 variableAccessData
->local() ==
836 m_graph
.uncheckedArgumentsRegisterFor(edge
->codeOrigin
)
837 && !m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
);
838 bool isAliasedArgumentsRegister
=
839 !variableAccessData
->isCaptured()
840 && m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
841 && !m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
);
842 if (!isDeadArgumentsRegister
&& !isAliasedArgumentsRegister
)
844 node
->children
.removeEdge(edgeIndex
);
848 case CreateArguments
: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
849 if (m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
))
851 node
->children
.removeEdge(edgeIndex
);
861 bool performArgumentsSimplification(Graph
& graph
)
863 SamplingRegion
samplingRegion("DFG Arguments Simplification Phase");
864 return runPhase
<ArgumentsSimplificationPhase
>(graph
);
867 } } // namespace JSC::DFG
869 #endif // ENABLE(DFG_JIT)