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 InlineCallFrame
* inlineCallFrame
= &codeBlock()->inlineCallFrames()[i
];
131 if (m_graph
.m_executablesWhoseArgumentsEscaped
.contains(
132 m_graph
.executableFor(inlineCallFrame
)))
133 m_createsArguments
.add(inlineCallFrame
);
136 // Create data for variable access datas that we will want to analyze.
137 for (unsigned i
= m_graph
.m_variableAccessData
.size(); i
--;) {
138 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
139 if (!variableAccessData
->isRoot())
141 if (variableAccessData
->isCaptured())
143 m_argumentsAliasing
.add(variableAccessData
, ArgumentsAliasingData());
146 // Figure out which variables are live, using a conservative approximation of
148 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
149 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
152 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
153 Node
* node
= block
->at(indexInBlock
);
154 switch (node
->op()) {
158 m_isLive
.add(node
->variableAccessData());
166 // Figure out which variables alias the arguments and nothing else, and are
167 // used only for GetByVal and GetArrayLength accesses. At the same time,
168 // identify uses of CreateArguments that are not consistent with the arguments
169 // being aliased only to variables that satisfy these constraints.
170 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
171 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
174 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
175 Node
* node
= block
->at(indexInBlock
);
176 switch (node
->op()) {
177 case CreateArguments
: {
178 // Ignore this op. If we see a lone CreateArguments then we want to
179 // completely ignore it because:
180 // 1) The default would be to see that the child is a GetLocal on the
181 // arguments register and conclude that we have an arguments escape.
182 // 2) The fact that a CreateArguments exists does not mean that it
183 // will continue to exist after we're done with this phase. As far
184 // as this phase is concerned, a CreateArguments only "exists" if it
185 // is used in a manner that necessitates its existance.
189 case TearOffArguments
: {
190 // Ignore arguments tear off, because it's only relevant if we actually
191 // need to create the arguments.
196 Node
* source
= node
->child1().node();
197 VariableAccessData
* variableAccessData
= node
->variableAccessData();
198 int argumentsRegister
=
199 m_graph
.uncheckedArgumentsRegisterFor(node
->codeOrigin
);
200 if (source
->op() != CreateArguments
&& source
->op() != PhantomArguments
) {
201 // Make sure that the source of the SetLocal knows that if it's
202 // a variable that we think is aliased to the arguments, then it
203 // may escape at this point. In future, we could track transitive
204 // aliasing. But not yet.
205 observeBadArgumentsUse(source
);
207 // If this is an assignment to the arguments register, then
208 // pretend as if the arguments were created. We don't want to
209 // optimize code that explicitly assigns to the arguments,
210 // because that seems too ugly.
212 // But, before getting rid of CreateArguments, we will have
213 // an assignment to the arguments registers with JSValue().
214 // That's because CSE will refuse to get rid of the
215 // init_lazy_reg since it treats CreateArguments as reading
216 // local variables. That could be fixed, but it's easier to
217 // work around this here.
218 if (source
->op() == JSConstant
219 && !source
->valueOfJSConstant(codeBlock()))
222 // If the variable is totally dead, then ignore it.
223 if (!m_isLive
.contains(variableAccessData
))
226 if (argumentsRegister
!= InvalidVirtualRegister
227 && (variableAccessData
->local() == argumentsRegister
228 || variableAccessData
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
229 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
233 if (variableAccessData
->isCaptured())
236 // Make sure that if it's a variable that we think is aliased to
237 // the arguments, that we know that it might actually not be.
238 ArgumentsAliasingData
& data
=
239 m_argumentsAliasing
.find(variableAccessData
)->value
;
240 data
.mergeNonArgumentsAssignment();
241 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
244 if (argumentsRegister
!= InvalidVirtualRegister
245 && (variableAccessData
->local() == argumentsRegister
246 || variableAccessData
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
247 if (node
->codeOrigin
.inlineCallFrame
== source
->codeOrigin
.inlineCallFrame
)
249 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
252 if (variableAccessData
->isCaptured()) {
253 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
256 ArgumentsAliasingData
& data
=
257 m_argumentsAliasing
.find(variableAccessData
)->value
;
258 data
.mergeArgumentsAssignment();
259 // This ensures that the variable's uses are in the same context as
260 // the arguments it is aliasing.
261 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
262 data
.mergeCallContext(source
->codeOrigin
.inlineCallFrame
);
267 case Phi
: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ {
268 VariableAccessData
* variableAccessData
= node
->variableAccessData();
269 if (variableAccessData
->isCaptured())
271 ArgumentsAliasingData
& data
=
272 m_argumentsAliasing
.find(variableAccessData
)->value
;
273 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
278 VariableAccessData
* variableAccessData
= node
->variableAccessData();
279 if (variableAccessData
->isCaptured())
281 ArgumentsAliasingData
& data
=
282 m_argumentsAliasing
.find(variableAccessData
)->value
;
283 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
285 // If a variable is used in a flush then by definition it escapes.
291 VariableAccessData
* variableAccessData
= node
->variableAccessData();
292 if (variableAccessData
->isCaptured())
294 ArgumentsAliasingData
& data
=
295 m_argumentsAliasing
.find(variableAccessData
)->value
;
296 data
.mergeNonArgumentsAssignment();
297 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
302 if (node
->arrayMode().type() != Array::Arguments
) {
303 observeBadArgumentsUses(node
);
307 // That's so awful and pretty much impossible since it would
308 // imply that the arguments were predicted integer, but it's
309 // good to be defensive and thorough.
310 observeBadArgumentsUse(node
->child2().node());
311 observeProperArgumentsUse(node
, node
->child1());
315 case GetArrayLength
: {
316 if (node
->arrayMode().type() != Array::Arguments
) {
317 observeBadArgumentsUses(node
);
321 observeProperArgumentsUse(node
, node
->child1());
326 // We don't care about phantom uses, since phantom uses are all about
327 // just keeping things alive for OSR exit. If something - like the
328 // CreateArguments - is just being kept alive, then this transformation
329 // will not break this, since the Phantom will now just keep alive a
330 // PhantomArguments and OSR exit will still do the right things.
334 case ForwardCheckStructure
:
335 case StructureTransitionWatchpoint
:
336 case ForwardStructureTransitionWatchpoint
:
338 // We don't care about these because if we get uses of the relevant
339 // variable then we can safely get rid of these, too. This of course
340 // relies on there not being any information transferred by the CFA
341 // from a CheckStructure on one variable to the information about the
342 // structures of another variable.
346 observeBadArgumentsUses(node
);
352 // Now we know which variables are aliased to arguments. But if any of them are
353 // found to have escaped, or were otherwise invalidated, then we need to mark
354 // the arguments as requiring creation. This is a property of SetLocals to
355 // variables that are neither the correct arguments register nor are marked as
356 // being arguments-aliased.
357 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
358 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
361 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
362 Node
* node
= block
->at(indexInBlock
);
363 if (node
->op() != SetLocal
)
365 Node
* source
= node
->child1().node();
366 if (source
->op() != CreateArguments
)
368 VariableAccessData
* variableAccessData
= node
->variableAccessData();
369 if (variableAccessData
->isCaptured()) {
370 // The captured case would have already been taken care of in the
375 ArgumentsAliasingData
& data
=
376 m_argumentsAliasing
.find(variableAccessData
)->value
;
380 m_createsArguments
.add(source
->codeOrigin
.inlineCallFrame
);
384 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
385 dataLogF("Arguments aliasing states:\n");
386 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
387 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
388 if (!variableAccessData
->isRoot())
390 dataLog(" r", variableAccessData
->local(), "(", VariableAccessDataDump(m_graph
, variableAccessData
), "): ");
391 if (variableAccessData
->isCaptured())
392 dataLogF("Captured");
394 ArgumentsAliasingData
& data
=
395 m_argumentsAliasing
.find(variableAccessData
)->value
;
397 if (data
.callContextIsValid()) {
400 dataLogF("Have Call Context: %p", data
.callContext
);
402 if (!m_createsArguments
.contains(data
.callContext
))
403 dataLogF(" (Does Not Create Arguments)");
405 if (data
.argumentsAssignmentIsValid()) {
408 dataLogF("Arguments Assignment Is Valid");
414 dataLogF("Does Not Escape");
419 if (data
.isValid()) {
420 if (m_createsArguments
.contains(data
.callContext
))
423 dataLogF("INVALID (due to argument creation)");
425 dataLogF("INVALID (due to bad variable use)");
431 InsertionSet
insertionSet(m_graph
);
433 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
434 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
437 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); indexInBlock
++) {
438 Node
* node
= block
->at(indexInBlock
);
439 switch (node
->op()) {
441 Node
* source
= node
->child1().node();
442 if (source
->op() != CreateArguments
)
445 if (m_createsArguments
.contains(source
->codeOrigin
.inlineCallFrame
))
448 VariableAccessData
* variableAccessData
= node
->variableAccessData();
450 if (m_graph
.argumentsRegisterFor(node
->codeOrigin
) == variableAccessData
->local()
451 || unmodifiedArgumentsRegister(m_graph
.argumentsRegisterFor(node
->codeOrigin
)) == variableAccessData
->local())
454 ASSERT(!variableAccessData
->isCaptured());
456 // If this is a store into a VariableAccessData* that is marked as
457 // arguments aliasing for an InlineCallFrame* that does not create
458 // arguments, then flag the VariableAccessData as being an
459 // arguments-aliased. This'll let the OSR exit machinery do the right
460 // things. Note also that the SetLocal should become dead as soon as
461 // we replace all uses of this variable with GetMyArgumentsLength and
462 // GetMyArgumentByVal.
463 ASSERT(m_argumentsAliasing
.find(variableAccessData
)->value
.isValid());
464 if (variableAccessData
->mergeIsArgumentsAlias(true)) {
467 // Make sure that the variable knows, that it may now hold non-cell values.
468 variableAccessData
->predict(SpecEmpty
);
471 // Make sure that the SetLocal doesn't check that the input is a Cell.
472 if (node
->child1().useKind() != UntypedUse
) {
473 node
->child1().setUseKind(UntypedUse
);
480 VariableAccessData
* variableAccessData
= node
->variableAccessData();
482 if (variableAccessData
->isCaptured()
483 || !m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
484 || m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
487 // Turn PhantomLocals into just GetLocals. This will preserve the threading
488 // of the local through to this point, but will allow it to die, causing
489 // only OSR to know about it.
491 node
->setOpAndDefaultFlags(GetLocal
);
496 VariableAccessData
* variableAccessData
= node
->variableAccessData();
498 if (variableAccessData
->isCaptured()
499 || !m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
500 || m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
503 RELEASE_ASSERT_NOT_REACHED();
508 // It's highly likely that we will have a Phantom referencing either
509 // CreateArguments, or a local op for the arguments register, or a
510 // local op for an arguments-aliased variable. In any of those cases,
511 // we should remove the phantom reference, since:
512 // 1) Phantoms only exist to aid OSR exit. But arguments simplification
513 // has its own OSR exit story, which is to inform OSR exit to reify
514 // the arguments as necessary.
515 // 2) The Phantom may keep the CreateArguments node alive, which is
516 // precisely what we don't want.
517 for (unsigned i
= 0; i
< AdjacencyList::Size
; ++i
)
518 removeArgumentsReferencingPhantomChild(node
, i
);
523 case ForwardCheckStructure
:
524 case StructureTransitionWatchpoint
:
525 case ForwardStructureTransitionWatchpoint
:
527 // We can just get rid of this node, if it references a phantom argument.
528 if (!isOKToOptimize(node
->child1().node()))
530 node
->convertToPhantom();
531 node
->children
.setChild1(Edge());
536 if (node
->arrayMode().type() != Array::Arguments
)
539 // This can be simplified to GetMyArgumentByVal if we know that
540 // it satisfies either condition (1) or (2):
541 // 1) Its first child is a valid ArgumentsAliasingData and the
542 // InlineCallFrame* is not marked as creating arguments.
543 // 2) Its first child is CreateArguments and its InlineCallFrame*
544 // is not marked as creating arguments.
546 if (!isOKToOptimize(node
->child1().node()))
549 node
->children
.child1() = node
->children
.child2();
550 node
->children
.child2() = Edge();
551 node
->setOpAndDefaultFlags(GetMyArgumentByVal
);
553 --indexInBlock
; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
557 case GetArrayLength
: {
558 if (node
->arrayMode().type() != Array::Arguments
)
561 if (!isOKToOptimize(node
->child1().node()))
564 node
->children
.child1() = Edge();
565 node
->setOpAndDefaultFlags(GetMyArgumentsLength
);
567 --indexInBlock
; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
571 case GetMyArgumentsLength
:
572 case GetMyArgumentsLengthSafe
: {
573 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
)) {
574 ASSERT(node
->op() == GetMyArgumentsLengthSafe
);
577 if (node
->op() == GetMyArgumentsLengthSafe
) {
578 node
->setOp(GetMyArgumentsLength
);
582 CodeOrigin codeOrigin
= node
->codeOrigin
;
583 if (!codeOrigin
.inlineCallFrame
)
586 // We know exactly what this will return. But only after we have checked
587 // that nobody has escaped our arguments.
588 insertionSet
.insertNode(
589 indexInBlock
, SpecNone
, CheckArgumentsNotCreated
, codeOrigin
);
591 m_graph
.convertToConstant(
592 node
, jsNumber(codeOrigin
.inlineCallFrame
->arguments
.size() - 1));
597 case GetMyArgumentByVal
:
598 case GetMyArgumentByValSafe
: {
599 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
)) {
600 ASSERT(node
->op() == GetMyArgumentByValSafe
);
603 if (node
->op() == GetMyArgumentByValSafe
) {
604 node
->setOp(GetMyArgumentByVal
);
607 if (!node
->codeOrigin
.inlineCallFrame
)
609 if (!node
->child1()->hasConstant())
611 JSValue value
= node
->child1()->valueOfJSConstant(codeBlock());
612 if (!value
.isInt32())
614 int32_t index
= value
.asInt32();
616 || static_cast<size_t>(index
+ 1) >=
617 node
->codeOrigin
.inlineCallFrame
->arguments
.size())
620 // We know which argument this is accessing. But only after we have checked
621 // that nobody has escaped our arguments. We also need to ensure that the
622 // index is kept alive. That's somewhat pointless since it's a constant, but
623 // it's important because this is one of those invariants that we like to
624 // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
625 // here, since this is being done _after_ the prediction propagation phase
626 // has run - therefore it makes little sense to link the GetLocal operation
627 // into the VariableAccessData and Phi graphs.
629 CodeOrigin codeOrigin
= node
->codeOrigin
;
630 AdjacencyList children
= node
->children
;
632 node
->convertToGetLocalUnlinked(
633 static_cast<VirtualRegister
>(
634 node
->codeOrigin
.inlineCallFrame
->stackOffset
+
635 m_graph
.baselineCodeBlockFor(node
->codeOrigin
)->argumentIndexAfterCapture(index
)));
637 insertionSet
.insertNode(
638 indexInBlock
, SpecNone
, CheckArgumentsNotCreated
,
640 insertionSet
.insertNode(
641 indexInBlock
, SpecNone
, Phantom
, codeOrigin
,
648 case TearOffArguments
: {
649 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
652 node
->setOpAndDefaultFlags(Nop
);
653 m_graph
.clearAndDerefChild1(node
);
654 m_graph
.clearAndDerefChild2(node
);
662 insertionSet
.execute(block
);
665 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
666 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
669 for (unsigned indexInBlock
= 0; indexInBlock
< block
->size(); ++indexInBlock
) {
670 Node
* node
= block
->at(indexInBlock
);
671 if (node
->op() != CreateArguments
)
673 // If this is a CreateArguments for an InlineCallFrame* that does
674 // not create arguments, then replace it with a PhantomArguments.
675 // PhantomArguments is a non-executing node that just indicates
676 // that the node should be reified as an arguments object on OSR
678 if (m_createsArguments
.contains(node
->codeOrigin
.inlineCallFrame
))
680 insertionSet
.insertNode(
681 indexInBlock
, SpecNone
, Phantom
, node
->codeOrigin
, node
->children
);
682 node
->setOpAndDefaultFlags(PhantomArguments
);
683 node
->children
.reset();
686 insertionSet
.execute(block
);
691 m_graph
.m_form
= LoadStore
;
698 HashSet
<InlineCallFrame
*,
699 DefaultHash
<InlineCallFrame
*>::Hash
,
700 NullableHashTraits
<InlineCallFrame
*> > m_createsArguments
;
701 HashMap
<VariableAccessData
*, ArgumentsAliasingData
,
702 DefaultHash
<VariableAccessData
*>::Hash
,
703 NullableHashTraits
<VariableAccessData
*> > m_argumentsAliasing
;
704 HashSet
<VariableAccessData
*> m_isLive
;
706 void observeBadArgumentsUse(Node
* node
)
711 switch (node
->op()) {
712 case CreateArguments
: {
713 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
718 int argumentsRegister
= m_graph
.uncheckedArgumentsRegisterFor(node
->codeOrigin
);
719 if (argumentsRegister
!= InvalidVirtualRegister
720 && (node
->local() == argumentsRegister
721 || node
->local() == unmodifiedArgumentsRegister(argumentsRegister
))) {
722 m_createsArguments
.add(node
->codeOrigin
.inlineCallFrame
);
726 VariableAccessData
* variableAccessData
= node
->variableAccessData();
727 if (variableAccessData
->isCaptured())
730 ArgumentsAliasingData
& data
= m_argumentsAliasing
.find(variableAccessData
)->value
;
740 void observeBadArgumentsUses(Node
* node
)
742 for (unsigned i
= m_graph
.numChildren(node
); i
--;)
743 observeBadArgumentsUse(m_graph
.child(node
, i
).node());
746 void observeProperArgumentsUse(Node
* node
, Edge edge
)
748 if (edge
->op() != GetLocal
) {
749 // When can this happen? At least two cases that I can think
752 // 1) Aliased use of arguments in the same basic block,
755 // var a = arguments;
756 // var x = arguments[i];
758 // 2) If we're accessing arguments we got from the heap!
760 if (edge
->op() == CreateArguments
761 && node
->codeOrigin
.inlineCallFrame
762 != edge
->codeOrigin
.inlineCallFrame
)
763 m_createsArguments
.add(edge
->codeOrigin
.inlineCallFrame
);
768 VariableAccessData
* variableAccessData
= edge
->variableAccessData();
769 if (edge
->local() == m_graph
.uncheckedArgumentsRegisterFor(edge
->codeOrigin
)
770 && node
->codeOrigin
.inlineCallFrame
!= edge
->codeOrigin
.inlineCallFrame
) {
771 m_createsArguments
.add(edge
->codeOrigin
.inlineCallFrame
);
775 if (variableAccessData
->isCaptured())
778 ArgumentsAliasingData
& data
= m_argumentsAliasing
.find(variableAccessData
)->value
;
779 data
.mergeCallContext(node
->codeOrigin
.inlineCallFrame
);
782 bool isOKToOptimize(Node
* source
)
784 if (m_createsArguments
.contains(source
->codeOrigin
.inlineCallFrame
))
787 switch (source
->op()) {
789 VariableAccessData
* variableAccessData
= source
->variableAccessData();
790 int argumentsRegister
= m_graph
.uncheckedArgumentsRegisterFor(source
->codeOrigin
);
791 if (argumentsRegister
== InvalidVirtualRegister
)
793 if (argumentsRegister
== variableAccessData
->local())
795 if (unmodifiedArgumentsRegister(argumentsRegister
) == variableAccessData
->local())
797 if (variableAccessData
->isCaptured())
799 ArgumentsAliasingData
& data
=
800 m_argumentsAliasing
.find(variableAccessData
)->value
;
807 case CreateArguments
: {
818 void removeArgumentsReferencingPhantomChild(Node
* node
, unsigned edgeIndex
)
820 Edge edge
= node
->children
.child(edgeIndex
);
824 switch (edge
->op()) {
825 case Phi
: // Arises if we had CSE on a GetLocal of the arguments register.
826 case GetLocal
: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
827 case SetLocal
: { // Arises if we had CSE on a GetLocal of the arguments register.
828 VariableAccessData
* variableAccessData
= edge
->variableAccessData();
829 bool isDeadArgumentsRegister
=
830 variableAccessData
->local() ==
831 m_graph
.uncheckedArgumentsRegisterFor(edge
->codeOrigin
)
832 && !m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
);
833 bool isAliasedArgumentsRegister
=
834 !variableAccessData
->isCaptured()
835 && m_argumentsAliasing
.find(variableAccessData
)->value
.isValid()
836 && !m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
);
837 if (!isDeadArgumentsRegister
&& !isAliasedArgumentsRegister
)
839 node
->children
.removeEdge(edgeIndex
);
843 case CreateArguments
: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
844 if (m_createsArguments
.contains(edge
->codeOrigin
.inlineCallFrame
))
846 node
->children
.removeEdge(edgeIndex
);
856 bool performArgumentsSimplification(Graph
& graph
)
858 SamplingRegion
samplingRegion("DFG Arguments Simplification Phase");
859 return runPhase
<ArgumentsSimplificationPhase
>(graph
);
862 } } // namespace JSC::DFG
864 #endif // ENABLE(DFG_JIT)