Unreviewed, merge the arguments fix in r118138 to get bots green.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArgumentsSimplificationPhase.cpp
1 /*
2  * Copyright (C) 2012 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 "DFGArgumentsSimplificationPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGAbstractState.h"
32 #include "DFGBasicBlock.h"
33 #include "DFGGraph.h"
34 #include "DFGInsertionSet.h"
35 #include "DFGPhase.h"
36 #include "DFGValidate.h"
37 #include <wtf/HashSet.h>
38 #include <wtf/HashMap.h>
39
40 namespace JSC { namespace DFG {
41
42 namespace {
43
44 template<typename T>
45 struct NullableHashTraits : public HashTraits<T> {
46     static const bool emptyValueIsZero = false;
47     static T emptyValue() { return reinterpret_cast<T>(1); }
48 };
49
50 struct ArgumentsAliasingData {
51     InlineCallFrame* callContext;
52     bool callContextSet;
53     bool multipleCallContexts;
54     
55     bool assignedFromArguments;
56     bool assignedFromManyThings;
57     
58     bool escapes;
59     
60     ArgumentsAliasingData()
61         : callContext(0)
62         , callContextSet(false)
63         , multipleCallContexts(false)
64         , assignedFromArguments(false)
65         , assignedFromManyThings(false)
66         , escapes(false)
67     {
68     }
69     
70     void mergeCallContext(InlineCallFrame* newCallContext)
71     {
72         if (multipleCallContexts)
73             return;
74         
75         if (!callContextSet) {
76             callContext = newCallContext;
77             callContextSet = true;
78             return;
79         }
80         
81         if (callContext == newCallContext)
82             return;
83         
84         multipleCallContexts = true;
85     }
86     
87     bool callContextIsValid()
88     {
89         return callContextSet && !multipleCallContexts;
90     }
91     
92     void mergeArgumentsAssignment()
93     {
94         assignedFromArguments = true;
95     }
96     
97     void mergeNonArgumentsAssignment()
98     {
99         assignedFromManyThings = true;
100     }
101     
102     bool argumentsAssignmentIsValid()
103     {
104         return assignedFromArguments && !assignedFromManyThings;
105     }
106     
107     bool isValid()
108     {
109         return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
110     }
111 };
112
113 } // end anonymous namespace
114
115 class ArgumentsSimplificationPhase : public Phase {
116 public:
117     ArgumentsSimplificationPhase(Graph& graph)
118         : Phase(graph, "arguments simplification")
119     {
120     }
121     
122     bool run()
123     {
124         if (!m_graph.m_hasArguments)
125             return false;
126         
127         bool changed = false;
128         
129         // Record which arguments are known to escape no matter what.
130         for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;) {
131             InlineCallFrame* inlineCallFrame = &codeBlock()->inlineCallFrames()[i];
132             if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
133                     m_graph.executableFor(inlineCallFrame)))
134                 m_createsArguments.add(inlineCallFrame);
135         }
136         
137         // Create data for variable access datas that we will want to analyze.
138         for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
139             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
140             if (!variableAccessData->isRoot())
141                 continue;
142             if (variableAccessData->isCaptured())
143                 continue;
144             m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
145         }
146         
147         // Figure out which variables alias the arguments and nothing else, and are
148         // used only for GetByVal and GetArgumentsLength accesses. At the same time,
149         // identify uses of CreateArguments that are not consistent with the arguments
150         // being aliased only to variables that satisfy these constraints.
151         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
152             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
153             if (!block)
154                 continue;
155             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
156                 NodeIndex nodeIndex = block->at(indexInBlock);
157                 Node& node = m_graph[nodeIndex];
158                 if (!node.shouldGenerate())
159                     continue;
160                 switch (node.op()) {
161                 case CreateArguments: {
162                     // Ignore this op. If we see a lone CreateArguments then we want to
163                     // completely ignore it because:
164                     // 1) The default would be to see that the child is a GetLocal on the
165                     //    arguments register and conclude that we have an arguments escape.
166                     // 2) The fact that a CreateArguments exists does not mean that it
167                     //    will continue to exist after we're done with this phase. As far
168                     //    as this phase is concerned, a CreateArguments only "exists" if it
169                     //    is used in a manner that necessitates its existance.
170                     break;
171                 }
172                     
173                 case SetLocal: {
174                     Node& source = m_graph[node.child1()];
175                     VariableAccessData* variableAccessData = node.variableAccessData();
176                     if (source.op() != CreateArguments) {
177                         // Make sure that the source of the SetLocal knows that if it's
178                         // a variable that we think is aliased to the arguments, then it
179                         // may escape at this point. In future, we could track transitive
180                         // aliasing. But not yet.
181                         observeBadArgumentsUse(node.child1());
182                         
183                         if (variableAccessData->isCaptured())
184                             break;
185                         
186                         // Make sure that if it's a variable that we think is aliased to
187                         // the arguments, that we know that it might actually not be.
188                         ArgumentsAliasingData& data =
189                             m_argumentsAliasing.find(variableAccessData)->second;
190                         data.mergeNonArgumentsAssignment();
191                         data.mergeCallContext(node.codeOrigin.inlineCallFrame);
192                         break;
193                     }
194                     int argumentsRegister =
195                         m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
196                     if (variableAccessData->local() == argumentsRegister
197                         || variableAccessData->local() ==
198                             unmodifiedArgumentsRegister(argumentsRegister)) {
199                         if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame)
200                             break;
201                         m_createsArguments.add(source.codeOrigin.inlineCallFrame);
202                         break;
203                     }
204                     if (variableAccessData->isCaptured()) {
205                         m_createsArguments.add(source.codeOrigin.inlineCallFrame);
206                         break;
207                     }
208                     ArgumentsAliasingData& data =
209                         m_argumentsAliasing.find(variableAccessData)->second;
210                     data.mergeArgumentsAssignment();
211                     // This ensures that the variable's uses are in the same context as
212                     // the arguments it is aliasing.
213                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
214                     data.mergeCallContext(source.codeOrigin.inlineCallFrame);
215                     break;
216                 }
217                     
218                 case GetLocal:
219                 case Phi: {
220                     VariableAccessData* variableAccessData = node.variableAccessData();
221                     if (variableAccessData->isCaptured())
222                         break;
223                     ArgumentsAliasingData& data =
224                         m_argumentsAliasing.find(variableAccessData)->second;
225                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
226                     break;
227                 }
228                     
229                 case Flush: {
230                     VariableAccessData* variableAccessData = node.variableAccessData();
231                     if (variableAccessData->isCaptured())
232                         break;
233                     ArgumentsAliasingData& data =
234                         m_argumentsAliasing.find(variableAccessData)->second;
235                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
236                     
237                     // If a variable is used in a flush then by definition it escapes.
238                     data.escapes = true;
239                     break;
240                 }
241                     
242                 case SetArgument: {
243                     VariableAccessData* variableAccessData = node.variableAccessData();
244                     if (variableAccessData->isCaptured())
245                         break;
246                     ArgumentsAliasingData& data =
247                         m_argumentsAliasing.find(variableAccessData)->second;
248                     data.mergeNonArgumentsAssignment();
249                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
250                     break;
251                 }
252                     
253                 case GetByVal: {
254                     if (!node.prediction()
255                         || !m_graph[node.child1()].prediction()
256                         || !m_graph[node.child2()].prediction()) {
257                         observeBadArgumentsUses(node);
258                         break;
259                     }
260                     
261                     if (!isActionableArrayPrediction(m_graph[node.child1()].prediction())
262                         || !m_graph[node.child2()].shouldSpeculateInteger()) {
263                         observeBadArgumentsUses(node);
264                         break;
265                     }
266                     
267                     if (m_graph[node.child1()].shouldSpeculateArguments()) {
268                         // If arguments is used as an index, then it's an escaping use.
269                         // That's so awful and pretty much impossible since it would
270                         // imply that the arguments were predicted integer, but it's
271                         // good to be defensive and thorough.
272                         observeBadArgumentsUse(node.child2());
273                         observeProperArgumentsUse(node, node.child1());
274                         break;
275                     }
276                     
277                     observeBadArgumentsUses(node);
278                     break;
279                 }
280                     
281                 case GetArgumentsLength: {
282                     observeProperArgumentsUse(node, node.child1());
283                     break;
284                 }
285                     
286                 default:
287                     observeBadArgumentsUses(node);
288                     break;
289                 }
290             }
291         }
292
293         // Now we know which variables are aliased to arguments. But if any of them are
294         // found to have escaped, or were otherwise invalidated, then we need to mark
295         // the arguments as requiring creation. This is a property of SetLocals to
296         // variables that are neither the correct arguments register nor are marked as
297         // being arguments-aliased.
298         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
299             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
300             if (!block)
301                 continue;
302             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
303                 NodeIndex nodeIndex = block->at(indexInBlock);
304                 Node& node = m_graph[nodeIndex];
305                 if (!node.shouldGenerate())
306                     continue;
307                 if (node.op() != SetLocal)
308                     continue;
309                 Node& source = m_graph[node.child1()];
310                 if (source.op() != CreateArguments)
311                     continue;
312                 VariableAccessData* variableAccessData = node.variableAccessData();
313                 if (variableAccessData->isCaptured()) {
314                     // The captured case would have already been taken care of in the
315                     // previous pass.
316                     continue;
317                 }
318                 
319                 ArgumentsAliasingData& data =
320                     m_argumentsAliasing.find(variableAccessData)->second;
321                 if (data.isValid())
322                     continue;
323                 
324                 m_createsArguments.add(source.codeOrigin.inlineCallFrame);
325             }
326         }
327         
328 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
329         dataLog("Arguments aliasing states:\n");
330         for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
331             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
332             if (!variableAccessData->isRoot())
333                 continue;
334             dataLog("   r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
335             if (variableAccessData->isCaptured())
336                 dataLog("Captured");
337             else {
338                 ArgumentsAliasingData& data =
339                     m_argumentsAliasing.find(variableAccessData)->second;
340                 bool first = true;
341                 if (data.callContextIsValid()) {
342                     if (!first)
343                         dataLog(", ");
344                     dataLog("Have Call Context: %p", data.callContext);
345                     first = false;
346                     if (!m_createsArguments.contains(data.callContext))
347                         dataLog(" (Does Not Create Arguments)");
348                 }
349                 if (data.argumentsAssignmentIsValid()) {
350                     if (!first)
351                         dataLog(", ");
352                     dataLog("Arguments Assignment Is Valid");
353                     first = false;
354                 }
355                 if (!data.escapes) {
356                     if (!first)
357                         dataLog(", ");
358                     dataLog("Does Not Escape");
359                     first = false;
360                 }
361                 if (!first)
362                     dataLog(", ");
363                 if (data.isValid()) {
364                     if (m_createsArguments.contains(data.callContext))
365                         dataLog("VALID");
366                     else
367                         dataLog("INVALID (due to argument creation)");
368                 } else
369                     dataLog("INVALID (due to bad variable use)");
370             }
371             dataLog("\n");
372         }
373 #endif
374         
375         InsertionSet<NodeIndex> insertionSet;
376         
377         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
378             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
379             if (!block)
380                 continue;
381             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
382                 NodeIndex nodeIndex = block->at(indexInBlock);
383                 Node& node = m_graph[nodeIndex];
384                 if (!node.shouldGenerate())
385                     continue;
386                 
387                 switch (node.op()) {
388                 case SetLocal: {
389                     Node& source = m_graph[node.child1()];
390                     if (source.op() != CreateArguments)
391                         break;
392                     
393                     VariableAccessData* variableAccessData = node.variableAccessData();
394                     
395                     // If this is a store into the arguments register for an InlineCallFrame*
396                     // that does not create arguments, then kill it.
397                     int argumentsRegister =
398                         m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
399                     if ((variableAccessData->local() == argumentsRegister
400                          || variableAccessData->local()
401                              == unmodifiedArgumentsRegister(argumentsRegister))
402                         && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) {
403                         // Find the Flush. It should be the next instruction.
404                         Node& flush = m_graph[block->at(indexInBlock + 1)];
405                         ASSERT(flush.op() == Flush);
406                         ASSERT(flush.variableAccessData() == variableAccessData);
407                         ASSERT(flush.child1() == nodeIndex);
408                         // Be defensive in release mode.
409                         if (flush.op() != Flush
410                             || flush.variableAccessData() != variableAccessData
411                             || flush.child1() != nodeIndex)
412                             break;
413                         flush.setOpAndDefaultFlags(Nop);
414                         m_graph.clearAndDerefChild1(flush);
415                         flush.setRefCount(0);
416                         changed = true;
417                         break;
418                     }
419                     
420                     if (variableAccessData->isCaptured())
421                         break;
422                     
423                     // If this is a store into a VariableAccessData* that is marked as
424                     // arguments aliasing for an InlineCallFrame* that does not create
425                     // arguments, then flag the VariableAccessData as being an
426                     // arguments-aliased. This'll let the OSR exit machinery do the right
427                     // things. Note also that the SetLocal should become dead as soon as
428                     // we replace all uses of this variable with GetMyArgumentsLength and
429                     // GetMyArgumentByVal.
430                     if (m_argumentsAliasing.find(variableAccessData)->second.isValid()
431                         && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) {
432                         changed |= variableAccessData->mergeIsArgumentsAlias(true);
433                         break;
434                     }
435                     break;
436                 }
437                     
438                 case Phantom: {
439                     // It's highly likely that we will have a Phantom referencing either
440                     // CreateArguments, or a local op for the arguments register, or a
441                     // local op for an arguments-aliased variable. In any of those cases,
442                     // we should remove the phantom reference, since:
443                     // 1) Phantoms only exist to aid OSR exit. But arguments simplification
444                     //    has its own OSR exit story, which is to inform OSR exit to reify
445                     //    the arguments as necessary.
446                     // 2) The Phantom may keep the CreateArguments node alive, which is
447                     //    precisely what we don't want.
448                     for (unsigned i = 0; i < AdjacencyList::Size; ++i)
449                         removeArgumentsReferencingPhantomChild(node, i);
450                     break;
451                 }
452                     
453                 case GetByVal: {
454                     if (!node.prediction()
455                         || !m_graph[node.child1()].prediction()
456                         || !m_graph[node.child2()].prediction())
457                         break;
458                     
459                     if (!isActionableArrayPrediction(m_graph[node.child1()].prediction())
460                         || !m_graph[node.child2()].shouldSpeculateInteger())
461                         break;
462                     
463                     if (m_graph[node.child1()].shouldSpeculateArguments()) {
464                         // This can be simplified to GetMyArgumentByVal if we know that
465                         // it satisfies either condition (1) or (2):
466                         // 1) Its first child is a valid ArgumentsAliasingData and the
467                         //    InlineCallFrame* is not marked as creating arguments.
468                         // 2) Its first child is CreateArguments and its InlineCallFrame*
469                         //    is not marked as creating arguments.
470                         
471                         if (!isOKToOptimize(m_graph[node.child1()]))
472                             break;
473                         
474                         m_graph.deref(node.child1());
475                         node.children.child1() = node.children.child2();
476                         node.children.child2() = Edge();
477                         node.setOpAndDefaultFlags(GetMyArgumentByVal);
478                         changed = true;
479                         --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
480                         break;
481                     }
482                     break;
483                 }
484                     
485                 case GetArgumentsLength: {
486                     if (!isOKToOptimize(m_graph[node.child1()]))
487                         break;
488                     
489                     m_graph.deref(node.child1());
490                     node.children.child1() = Edge();
491                     node.setOpAndDefaultFlags(GetMyArgumentsLength);
492                     changed = true;
493                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
494                     break;
495                 }
496                     
497                 case GetMyArgumentsLength:
498                 case GetMyArgumentsLengthSafe: {
499                     if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
500                         ASSERT(node.op() == GetMyArgumentsLengthSafe);
501                         break;
502                     }
503                     if (node.op() == GetMyArgumentsLengthSafe) {
504                         node.setOp(GetMyArgumentsLength);
505                         changed = true;
506                     }
507                     if (!node.codeOrigin.inlineCallFrame)
508                         break;
509                     
510                     // We know exactly what this will return. But only after we have checked
511                     // that nobody has escaped our arguments.
512                     Node check(CheckArgumentsNotCreated, node.codeOrigin);
513                     check.ref();
514                     NodeIndex checkIndex = m_graph.size();
515                     m_graph.append(check);
516                     insertionSet.append(indexInBlock, checkIndex);
517                     
518                     m_graph.convertToConstant(
519                         nodeIndex, jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
520                     changed = true;
521                     break;
522                 }
523                     
524                 case GetMyArgumentByVal:
525                 case GetMyArgumentByValSafe: {
526                     if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
527                         ASSERT(node.op() == GetMyArgumentByValSafe);
528                         break;
529                     }
530                     if (node.op() == GetMyArgumentByValSafe) {
531                         node.setOp(GetMyArgumentByVal);
532                         changed = true;
533                     }
534                     if (!node.codeOrigin.inlineCallFrame)
535                         break;
536                     if (!m_graph[node.child1()].hasConstant())
537                         break;
538                     JSValue value = m_graph[node.child1()].valueOfJSConstant(codeBlock());
539                     if (!value.isInt32())
540                         break;
541                     int32_t index = value.asInt32();
542                     if (index < 0
543                         || static_cast<size_t>(index + 1) >=
544                             node.codeOrigin.inlineCallFrame->arguments.size())
545                         break;
546                     
547                     // We know which argument this is accessing. But only after we have checked
548                     // that nobody has escaped our arguments. We also need to ensure that the
549                     // index is kept alive. That's somewhat pointless since it's a constant, but
550                     // it's important because this is one of those invariants that we like to
551                     // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
552                     // here, since this is being done _after_ the prediction propagation phase
553                     // has run - therefore it makes little sense to link the GetLocal operation
554                     // into the VariableAccessData and Phi graphs.
555
556                     Node check(CheckArgumentsNotCreated, node.codeOrigin);
557                     check.ref();
558                     
559                     Node phantom(Phantom, node.codeOrigin);
560                     phantom.ref();
561                     phantom.children = node.children;
562                     
563                     node.convertToGetLocalUnlinked(
564                         static_cast<VirtualRegister>(
565                             node.codeOrigin.inlineCallFrame->stackOffset +
566                             argumentToOperand(index + 1)));
567                     
568                     NodeIndex checkNodeIndex = m_graph.size();
569                     m_graph.append(check);
570                     insertionSet.append(indexInBlock, checkNodeIndex);
571                     NodeIndex phantomNodeIndex = m_graph.size();
572                     m_graph.append(phantom);
573                     insertionSet.append(indexInBlock, phantomNodeIndex);
574                     
575                     changed = true;
576                     break;
577                 }
578                     
579                 default:
580                     break;
581                 }
582             }
583             insertionSet.execute(*block);
584         }
585         
586         if (changed)
587             m_graph.collectGarbage();
588         
589         return changed;
590     }
591     
592 private:
593     HashSet<InlineCallFrame*,
594             DefaultHash<InlineCallFrame*>::Hash,
595             NullableHashTraits<InlineCallFrame*> > m_createsArguments;
596     HashMap<VariableAccessData*, ArgumentsAliasingData,
597             DefaultHash<VariableAccessData*>::Hash,
598             NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
599
600     void observeBadArgumentsUse(Edge edge)
601     {
602         if (!edge)
603             return;
604         
605         Node& child = m_graph[edge];
606         switch (child.op()) {
607         case CreateArguments: {
608             m_createsArguments.add(child.codeOrigin.inlineCallFrame);
609             break;
610         }
611             
612         case GetLocal: {
613             if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)) {
614                 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
615                 break;
616             }
617             
618             VariableAccessData* variableAccessData = child.variableAccessData();
619             if (variableAccessData->isCaptured())
620                 break;
621             
622             ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
623             data.escapes = true;
624             break;
625         }
626             
627         default:
628             break;
629         }
630     }
631     
632     void observeBadArgumentsUses(Node& node)
633     {
634         for (unsigned i = m_graph.numChildren(node); i--;)
635             observeBadArgumentsUse(m_graph.child(node, i));
636     }
637     
638     void observeProperArgumentsUse(Node& node, Edge edge)
639     {
640         Node& child = m_graph[edge];
641         if (child.op() != GetLocal) {
642             // When can this happen? At least two cases that I can think
643             // of:
644             //
645             // 1) Aliased use of arguments in the same basic block,
646             //    like:
647             //
648             //    var a = arguments;
649             //    var x = arguments[i];
650             //
651             // 2) If we're accessing arguments we got from the heap!
652                             
653             if (child.op() == CreateArguments
654                 && node.codeOrigin.inlineCallFrame
655                    != child.codeOrigin.inlineCallFrame)
656                 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
657             
658             return;
659         }
660                         
661         VariableAccessData* variableAccessData = child.variableAccessData();
662         if (variableAccessData->isCaptured())
663             return;
664                         
665         ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
666         data.mergeCallContext(node.codeOrigin.inlineCallFrame);
667     }
668     
669     bool isOKToOptimize(Node& source)
670     {
671         switch (source.op()) {
672         case GetLocal: {
673             VariableAccessData* variableAccessData = source.variableAccessData();
674             if (variableAccessData->isCaptured())
675                 break;
676             ArgumentsAliasingData& data =
677                 m_argumentsAliasing.find(variableAccessData)->second;
678             if (!data.isValid())
679                 break;
680             if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
681                 break;
682                             
683             return true;
684         }
685                             
686         case CreateArguments: {
687             if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
688                 break;
689                             
690             return true;
691         }
692                             
693         default:
694             break;
695         }
696         
697         return false;
698     }
699     
700     void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex)
701     {
702         Edge edge = node.children.child(edgeIndex);
703         if (!edge)
704             return;
705         
706         Node& child = m_graph[edge];
707         switch (child.op()) {
708         case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
709         case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
710         case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
711             VariableAccessData* variableAccessData = child.variableAccessData();
712             bool isDeadArgumentsRegister =
713                 variableAccessData->local() ==
714                     m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
715                 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
716             bool isAliasedArgumentsRegister =
717                 !variableAccessData->isCaptured()
718                 && m_argumentsAliasing.find(variableAccessData)->second.isValid()
719                 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
720             if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
721                 break;
722             m_graph.deref(edge);
723             node.children.removeEdgeFromBag(edgeIndex);
724             break;
725         }
726             
727         case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
728             if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame))
729                 break;
730             m_graph.deref(edge);
731             node.children.removeEdgeFromBag(edgeIndex);
732             break;
733         }
734             
735         default:
736             break;
737         }
738     }
739 };
740
741 bool performArgumentsSimplification(Graph& graph)
742 {
743     return runPhase<ArgumentsSimplificationPhase>(graph);
744 }
745
746 } } // namespace JSC::DFG
747
748 #endif // ENABLE(DFG_JIT)
749
750