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 "DFGBasicBlock.h"
33 #include "DFGInsertionSet.h"
35 #include "DFGValidate.h"
36 #include "DFGVariableAccessDataDump.h"
37 #include "Operations.h"
38 #include <wtf/HashSet.h>
39 #include <wtf/HashMap.h>
41 namespace JSC { namespace DFG {
45 struct ArgumentsAliasingData {
46 InlineCallFrame* callContext;
48 bool multipleCallContexts;
50 bool assignedFromArguments;
51 bool assignedFromManyThings;
55 ArgumentsAliasingData()
57 , callContextSet(false)
58 , multipleCallContexts(false)
59 , assignedFromArguments(false)
60 , assignedFromManyThings(false)
65 void mergeCallContext(InlineCallFrame* newCallContext)
67 if (multipleCallContexts)
70 if (!callContextSet) {
71 callContext = newCallContext;
72 callContextSet = true;
76 if (callContext == newCallContext)
79 multipleCallContexts = true;
82 bool callContextIsValid()
84 return callContextSet && !multipleCallContexts;
87 void mergeArgumentsAssignment()
89 assignedFromArguments = true;
92 void mergeNonArgumentsAssignment()
94 assignedFromManyThings = true;
97 bool argumentsAssignmentIsValid()
99 return assignedFromArguments && !assignedFromManyThings;
104 return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
108 } // end anonymous namespace
110 class ArgumentsSimplificationPhase : public Phase {
112 ArgumentsSimplificationPhase(Graph& graph)
113 : Phase(graph, "arguments simplification")
119 if (!m_graph.m_hasArguments)
122 bool changed = false;
124 // Record which arguments are known to escape no matter what.
125 for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;)
126 pruneObviousArgumentCreations(&codeBlock()->inlineCallFrames()[i]);
127 pruneObviousArgumentCreations(0); // the machine call frame.
129 // Create data for variable access datas that we will want to analyze.
130 for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
131 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
132 if (!variableAccessData->isRoot())
134 if (variableAccessData->isCaptured())
136 m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
139 // Figure out which variables are live, using a conservative approximation of
141 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
142 BasicBlock* block = m_graph.block(blockIndex);
145 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
146 Node* node = block->at(indexInBlock);
147 switch (node->op()) {
151 m_isLive.add(node->variableAccessData());
159 // Figure out which variables alias the arguments and nothing else, and are
160 // used only for GetByVal and GetArrayLength accesses. At the same time,
161 // identify uses of CreateArguments that are not consistent with the arguments
162 // being aliased only to variables that satisfy these constraints.
163 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
164 BasicBlock* block = m_graph.block(blockIndex);
167 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
168 Node* node = block->at(indexInBlock);
169 switch (node->op()) {
170 case CreateArguments: {
171 // Ignore this op. If we see a lone CreateArguments then we want to
172 // completely ignore it because:
173 // 1) The default would be to see that the child is a GetLocal on the
174 // arguments register and conclude that we have an arguments escape.
175 // 2) The fact that a CreateArguments exists does not mean that it
176 // will continue to exist after we're done with this phase. As far
177 // as this phase is concerned, a CreateArguments only "exists" if it
178 // is used in a manner that necessitates its existance.
182 case TearOffArguments: {
183 // Ignore arguments tear off, because it's only relevant if we actually
184 // need to create the arguments.
189 Node* source = node->child1().node();
190 VariableAccessData* variableAccessData = node->variableAccessData();
191 int argumentsRegister =
192 m_graph.uncheckedArgumentsRegisterFor(node->codeOrigin);
193 if (source->op() != CreateArguments && source->op() != PhantomArguments) {
194 // Make sure that the source of the SetLocal knows that if it's
195 // a variable that we think is aliased to the arguments, then it
196 // may escape at this point. In future, we could track transitive
197 // aliasing. But not yet.
198 observeBadArgumentsUse(source);
200 // If this is an assignment to the arguments register, then
201 // pretend as if the arguments were created. We don't want to
202 // optimize code that explicitly assigns to the arguments,
203 // because that seems too ugly.
205 // But, before getting rid of CreateArguments, we will have
206 // an assignment to the arguments registers with JSValue().
207 // That's because CSE will refuse to get rid of the
208 // init_lazy_reg since it treats CreateArguments as reading
209 // local variables. That could be fixed, but it's easier to
210 // work around this here.
211 if (source->op() == JSConstant
212 && !source->valueOfJSConstant(codeBlock()))
215 // If the variable is totally dead, then ignore it.
216 if (!m_isLive.contains(variableAccessData))
219 if (argumentsRegister != InvalidVirtualRegister
220 && (variableAccessData->local() == argumentsRegister
221 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
222 m_createsArguments.add(node->codeOrigin.inlineCallFrame);
226 if (variableAccessData->isCaptured())
229 // Make sure that if it's a variable that we think is aliased to
230 // the arguments, that we know that it might actually not be.
231 ArgumentsAliasingData& data =
232 m_argumentsAliasing.find(variableAccessData)->value;
233 data.mergeNonArgumentsAssignment();
234 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
237 if (argumentsRegister != InvalidVirtualRegister
238 && (variableAccessData->local() == argumentsRegister
239 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
240 if (node->codeOrigin.inlineCallFrame == source->codeOrigin.inlineCallFrame)
242 m_createsArguments.add(source->codeOrigin.inlineCallFrame);
245 if (variableAccessData->isCaptured()) {
246 m_createsArguments.add(source->codeOrigin.inlineCallFrame);
249 ArgumentsAliasingData& data =
250 m_argumentsAliasing.find(variableAccessData)->value;
251 data.mergeArgumentsAssignment();
252 // This ensures that the variable's uses are in the same context as
253 // the arguments it is aliasing.
254 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
255 data.mergeCallContext(source->codeOrigin.inlineCallFrame);
260 case Phi: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ {
261 VariableAccessData* variableAccessData = node->variableAccessData();
262 if (variableAccessData->isCaptured())
264 ArgumentsAliasingData& data =
265 m_argumentsAliasing.find(variableAccessData)->value;
266 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
271 VariableAccessData* variableAccessData = node->variableAccessData();
272 if (variableAccessData->isCaptured())
274 ArgumentsAliasingData& data =
275 m_argumentsAliasing.find(variableAccessData)->value;
276 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
278 // If a variable is used in a flush then by definition it escapes.
284 VariableAccessData* variableAccessData = node->variableAccessData();
285 if (variableAccessData->isCaptured())
287 ArgumentsAliasingData& data =
288 m_argumentsAliasing.find(variableAccessData)->value;
289 data.mergeNonArgumentsAssignment();
290 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
295 if (node->arrayMode().type() != Array::Arguments) {
296 observeBadArgumentsUses(node);
300 // That's so awful and pretty much impossible since it would
301 // imply that the arguments were predicted integer, but it's
302 // good to be defensive and thorough.
303 observeBadArgumentsUse(node->child2().node());
304 observeProperArgumentsUse(node, node->child1());
308 case GetArrayLength: {
309 if (node->arrayMode().type() != Array::Arguments) {
310 observeBadArgumentsUses(node);
314 observeProperArgumentsUse(node, node->child1());
319 // We don't care about phantom uses, since phantom uses are all about
320 // just keeping things alive for OSR exit. If something - like the
321 // CreateArguments - is just being kept alive, then this transformation
322 // will not break this, since the Phantom will now just keep alive a
323 // PhantomArguments and OSR exit will still do the right things.
327 case StructureTransitionWatchpoint:
329 // We don't care about these because if we get uses of the relevant
330 // variable then we can safely get rid of these, too. This of course
331 // relies on there not being any information transferred by the CFA
332 // from a CheckStructure on one variable to the information about the
333 // structures of another variable.
337 observeBadArgumentsUses(node);
343 // Now we know which variables are aliased to arguments. But if any of them are
344 // found to have escaped, or were otherwise invalidated, then we need to mark
345 // the arguments as requiring creation. This is a property of SetLocals to
346 // variables that are neither the correct arguments register nor are marked as
347 // being arguments-aliased.
348 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
349 BasicBlock* block = m_graph.block(blockIndex);
352 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
353 Node* node = block->at(indexInBlock);
354 if (node->op() != SetLocal)
356 Node* source = node->child1().node();
357 if (source->op() != CreateArguments)
359 VariableAccessData* variableAccessData = node->variableAccessData();
360 if (variableAccessData->isCaptured()) {
361 // The captured case would have already been taken care of in the
366 ArgumentsAliasingData& data =
367 m_argumentsAliasing.find(variableAccessData)->value;
371 m_createsArguments.add(source->codeOrigin.inlineCallFrame);
375 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
376 dataLogF("Arguments aliasing states:\n");
377 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
378 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
379 if (!variableAccessData->isRoot())
381 dataLog(" r", variableAccessData->local(), "(", VariableAccessDataDump(m_graph, variableAccessData), "): ");
382 if (variableAccessData->isCaptured())
383 dataLogF("Captured");
385 ArgumentsAliasingData& data =
386 m_argumentsAliasing.find(variableAccessData)->value;
388 if (data.callContextIsValid()) {
391 dataLogF("Have Call Context: %p", data.callContext);
393 if (!m_createsArguments.contains(data.callContext))
394 dataLogF(" (Does Not Create Arguments)");
396 if (data.argumentsAssignmentIsValid()) {
399 dataLogF("Arguments Assignment Is Valid");
405 dataLogF("Does Not Escape");
410 if (data.isValid()) {
411 if (m_createsArguments.contains(data.callContext))
414 dataLogF("INVALID (due to argument creation)");
416 dataLogF("INVALID (due to bad variable use)");
422 InsertionSet insertionSet(m_graph);
424 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
425 BasicBlock* block = m_graph.block(blockIndex);
428 for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) {
429 Node* node = block->at(indexInBlock);
430 switch (node->op()) {
432 Node* source = node->child1().node();
433 if (source->op() != CreateArguments)
436 if (m_createsArguments.contains(source->codeOrigin.inlineCallFrame))
439 VariableAccessData* variableAccessData = node->variableAccessData();
441 if (m_graph.argumentsRegisterFor(node->codeOrigin) == variableAccessData->local()
442 || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node->codeOrigin)) == variableAccessData->local())
445 ASSERT(!variableAccessData->isCaptured());
447 // If this is a store into a VariableAccessData* that is marked as
448 // arguments aliasing for an InlineCallFrame* that does not create
449 // arguments, then flag the VariableAccessData as being an
450 // arguments-aliased. This'll let the OSR exit machinery do the right
451 // things. Note also that the SetLocal should become dead as soon as
452 // we replace all uses of this variable with GetMyArgumentsLength and
453 // GetMyArgumentByVal.
454 ASSERT(m_argumentsAliasing.find(variableAccessData)->value.isValid());
455 if (variableAccessData->mergeIsArgumentsAlias(true)) {
458 // Make sure that the variable knows, that it may now hold non-cell values.
459 variableAccessData->predict(SpecEmpty);
462 // Make sure that the SetLocal doesn't check that the input is a Cell.
463 if (node->child1().useKind() != UntypedUse) {
464 node->child1().setUseKind(UntypedUse);
471 VariableAccessData* variableAccessData = node->variableAccessData();
473 if (variableAccessData->isCaptured()
474 || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
475 || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
478 // Turn PhantomLocals into just GetLocals. This will preserve the threading
479 // of the local through to this point, but will allow it to die, causing
480 // only OSR to know about it.
482 node->setOpAndDefaultFlags(GetLocal);
487 VariableAccessData* variableAccessData = node->variableAccessData();
489 if (variableAccessData->isCaptured()
490 || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
491 || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
494 RELEASE_ASSERT_NOT_REACHED();
499 // It's highly likely that we will have a Phantom referencing either
500 // CreateArguments, or a local op for the arguments register, or a
501 // local op for an arguments-aliased variable. In any of those cases,
502 // we should remove the phantom reference, since:
503 // 1) Phantoms only exist to aid OSR exit. But arguments simplification
504 // has its own OSR exit story, which is to inform OSR exit to reify
505 // the arguments as necessary.
506 // 2) The Phantom may keep the CreateArguments node alive, which is
507 // precisely what we don't want.
508 for (unsigned i = 0; i < AdjacencyList::Size; ++i)
509 removeArgumentsReferencingPhantomChild(node, i);
514 case StructureTransitionWatchpoint:
516 // We can just get rid of this node, if it references a phantom argument.
517 if (!isOKToOptimize(node->child1().node()))
519 node->convertToPhantom();
520 node->children.setChild1(Edge());
525 if (node->arrayMode().type() != Array::Arguments)
528 // This can be simplified to GetMyArgumentByVal if we know that
529 // it satisfies either condition (1) or (2):
530 // 1) Its first child is a valid ArgumentsAliasingData and the
531 // InlineCallFrame* is not marked as creating arguments.
532 // 2) Its first child is CreateArguments and its InlineCallFrame*
533 // is not marked as creating arguments.
535 if (!isOKToOptimize(node->child1().node()))
538 node->children.child1() = node->children.child2();
539 node->children.child2() = Edge();
540 node->setOpAndDefaultFlags(GetMyArgumentByVal);
542 --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
546 case GetArrayLength: {
547 if (node->arrayMode().type() != Array::Arguments)
550 if (!isOKToOptimize(node->child1().node()))
553 node->children.child1() = Edge();
554 node->setOpAndDefaultFlags(GetMyArgumentsLength);
556 --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
560 case GetMyArgumentsLength:
561 case GetMyArgumentsLengthSafe: {
562 if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame)) {
563 ASSERT(node->op() == GetMyArgumentsLengthSafe);
566 if (node->op() == GetMyArgumentsLengthSafe) {
567 node->setOp(GetMyArgumentsLength);
571 CodeOrigin codeOrigin = node->codeOrigin;
572 if (!codeOrigin.inlineCallFrame)
575 // We know exactly what this will return. But only after we have checked
576 // that nobody has escaped our arguments.
577 insertionSet.insertNode(
578 indexInBlock, SpecNone, CheckArgumentsNotCreated, codeOrigin);
580 m_graph.convertToConstant(
581 node, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
586 case GetMyArgumentByVal:
587 case GetMyArgumentByValSafe: {
588 if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame)) {
589 ASSERT(node->op() == GetMyArgumentByValSafe);
592 if (node->op() == GetMyArgumentByValSafe) {
593 node->setOp(GetMyArgumentByVal);
596 if (!node->codeOrigin.inlineCallFrame)
598 if (!node->child1()->hasConstant())
600 JSValue value = node->child1()->valueOfJSConstant(codeBlock());
601 if (!value.isInt32())
603 int32_t index = value.asInt32();
605 || static_cast<size_t>(index + 1) >=
606 node->codeOrigin.inlineCallFrame->arguments.size())
609 // We know which argument this is accessing. But only after we have checked
610 // that nobody has escaped our arguments. We also need to ensure that the
611 // index is kept alive. That's somewhat pointless since it's a constant, but
612 // it's important because this is one of those invariants that we like to
613 // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
614 // here, since this is being done _after_ the prediction propagation phase
615 // has run - therefore it makes little sense to link the GetLocal operation
616 // into the VariableAccessData and Phi graphs.
618 CodeOrigin codeOrigin = node->codeOrigin;
619 AdjacencyList children = node->children;
621 node->convertToGetLocalUnlinked(
622 static_cast<VirtualRegister>(
623 node->codeOrigin.inlineCallFrame->stackOffset +
624 m_graph.baselineCodeBlockFor(node->codeOrigin)->argumentIndexAfterCapture(index)));
626 insertionSet.insertNode(
627 indexInBlock, SpecNone, CheckArgumentsNotCreated,
629 insertionSet.insertNode(
630 indexInBlock, SpecNone, Phantom, codeOrigin,
637 case TearOffArguments: {
638 if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
641 node->setOpAndDefaultFlags(Phantom);
642 node->children.reset();
650 insertionSet.execute(block);
653 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
654 BasicBlock* block = m_graph.block(blockIndex);
657 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
658 Node* node = block->at(indexInBlock);
659 if (node->op() != CreateArguments)
661 // If this is a CreateArguments for an InlineCallFrame* that does
662 // not create arguments, then replace it with a PhantomArguments.
663 // PhantomArguments is a non-executing node that just indicates
664 // that the node should be reified as an arguments object on OSR
666 if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
668 insertionSet.insertNode(
669 indexInBlock, SpecNone, Phantom, node->codeOrigin, node->children);
670 node->setOpAndDefaultFlags(PhantomArguments);
671 node->children.reset();
674 insertionSet.execute(block);
679 m_graph.m_form = LoadStore;
686 HashSet<InlineCallFrame*,
687 DefaultHash<InlineCallFrame*>::Hash,
688 NullableHashTraits<InlineCallFrame*> > m_createsArguments;
689 HashMap<VariableAccessData*, ArgumentsAliasingData,
690 DefaultHash<VariableAccessData*>::Hash,
691 NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
692 HashSet<VariableAccessData*> m_isLive;
694 void pruneObviousArgumentCreations(InlineCallFrame* inlineCallFrame)
696 ScriptExecutable* executable = m_graph.executableFor(inlineCallFrame);
697 if (m_graph.m_executablesWhoseArgumentsEscaped.contains(executable)
698 || executable->isStrictMode())
699 m_createsArguments.add(inlineCallFrame);
702 void observeBadArgumentsUse(Node* node)
707 switch (node->op()) {
708 case CreateArguments: {
709 m_createsArguments.add(node->codeOrigin.inlineCallFrame);
714 int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(node->codeOrigin);
715 if (argumentsRegister != InvalidVirtualRegister
716 && (node->local() == argumentsRegister
717 || node->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
718 m_createsArguments.add(node->codeOrigin.inlineCallFrame);
722 VariableAccessData* variableAccessData = node->variableAccessData();
723 if (variableAccessData->isCaptured())
726 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
736 void observeBadArgumentsUses(Node* node)
738 for (unsigned i = m_graph.numChildren(node); i--;)
739 observeBadArgumentsUse(m_graph.child(node, i).node());
742 void observeProperArgumentsUse(Node* node, Edge edge)
744 if (edge->op() != GetLocal) {
745 // When can this happen? At least two cases that I can think
748 // 1) Aliased use of arguments in the same basic block,
751 // var a = arguments;
752 // var x = arguments[i];
754 // 2) If we're accessing arguments we got from the heap!
756 if (edge->op() == CreateArguments
757 && node->codeOrigin.inlineCallFrame
758 != edge->codeOrigin.inlineCallFrame)
759 m_createsArguments.add(edge->codeOrigin.inlineCallFrame);
764 VariableAccessData* variableAccessData = edge->variableAccessData();
765 if (edge->local() == m_graph.uncheckedArgumentsRegisterFor(edge->codeOrigin)
766 && node->codeOrigin.inlineCallFrame != edge->codeOrigin.inlineCallFrame) {
767 m_createsArguments.add(edge->codeOrigin.inlineCallFrame);
771 if (variableAccessData->isCaptured())
774 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
775 data.mergeCallContext(node->codeOrigin.inlineCallFrame);
778 bool isOKToOptimize(Node* source)
780 if (m_createsArguments.contains(source->codeOrigin.inlineCallFrame))
783 switch (source->op()) {
785 VariableAccessData* variableAccessData = source->variableAccessData();
786 int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source->codeOrigin);
787 if (argumentsRegister == InvalidVirtualRegister)
789 if (argumentsRegister == variableAccessData->local())
791 if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
793 if (variableAccessData->isCaptured())
795 ArgumentsAliasingData& data =
796 m_argumentsAliasing.find(variableAccessData)->value;
803 case CreateArguments: {
814 void removeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
816 Edge edge = node->children.child(edgeIndex);
820 switch (edge->op()) {
821 case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
822 case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
823 case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
824 VariableAccessData* variableAccessData = edge->variableAccessData();
825 bool isDeadArgumentsRegister =
826 variableAccessData->local() ==
827 m_graph.uncheckedArgumentsRegisterFor(edge->codeOrigin)
828 && !m_createsArguments.contains(edge->codeOrigin.inlineCallFrame);
829 bool isAliasedArgumentsRegister =
830 !variableAccessData->isCaptured()
831 && m_argumentsAliasing.find(variableAccessData)->value.isValid()
832 && !m_createsArguments.contains(edge->codeOrigin.inlineCallFrame);
833 if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
835 node->children.removeEdge(edgeIndex);
839 case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
840 if (m_createsArguments.contains(edge->codeOrigin.inlineCallFrame))
842 node->children.removeEdge(edgeIndex);
852 bool performArgumentsSimplification(Graph& graph)
854 SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
855 return runPhase<ArgumentsSimplificationPhase>(graph);
858 } } // namespace JSC::DFG
860 #endif // ENABLE(DFG_JIT)