DFG::ArgumentsSimplificationPhase should assert that the PhantomArguments nodes it...
[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 TearOffArguments: {
174                     // Ignore arguments tear off, because it's only relevant if we actually
175                     // need to create the arguments.
176                     break;
177                 }
178                     
179                 case SetLocal: {
180                     Node& source = m_graph[node.child1()];
181                     VariableAccessData* variableAccessData = node.variableAccessData();
182                     int argumentsRegister =
183                         m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
184                     if (source.op() != CreateArguments) {
185                         // Make sure that the source of the SetLocal knows that if it's
186                         // a variable that we think is aliased to the arguments, then it
187                         // may escape at this point. In future, we could track transitive
188                         // aliasing. But not yet.
189                         observeBadArgumentsUse(node.child1());
190                         
191                         if (variableAccessData->isCaptured()) {
192                             // If this is an assignment to the arguments register, then
193                             // pretend as if the arguments were created. We don't want to
194                             // optimize code that explicitly assigns to the arguments,
195                             // because that seems too ugly.
196                             
197                             // But, before getting rid of CreateArguments, we will have
198                             // an assignment to the arguments registers with JSValue().
199                             // That's because CSE will refuse to get rid of the
200                             // init_lazy_reg since it treats CreateArguments as reading
201                             // local variables. That could be fixed, but it's easier to
202                             // work around this here.
203                             if (source.op() == JSConstant
204                                 && !source.valueOfJSConstant(codeBlock()))
205                                 break;
206                             
207                             if (argumentsRegister != InvalidVirtualRegister
208                                 && (variableAccessData->local() == argumentsRegister
209                                     || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister)))
210                                 m_createsArguments.add(node.codeOrigin.inlineCallFrame);
211                             break;
212                         }
213                         
214                         // Make sure that if it's a variable that we think is aliased to
215                         // the arguments, that we know that it might actually not be.
216                         ArgumentsAliasingData& data =
217                             m_argumentsAliasing.find(variableAccessData)->second;
218                         data.mergeNonArgumentsAssignment();
219                         data.mergeCallContext(node.codeOrigin.inlineCallFrame);
220                         break;
221                     }
222                     if (argumentsRegister != InvalidVirtualRegister
223                         && (variableAccessData->local() == argumentsRegister
224                             || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
225                         if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame)
226                             break;
227                         m_createsArguments.add(source.codeOrigin.inlineCallFrame);
228                         break;
229                     }
230                     if (variableAccessData->isCaptured()) {
231                         m_createsArguments.add(source.codeOrigin.inlineCallFrame);
232                         break;
233                     }
234                     ArgumentsAliasingData& data =
235                         m_argumentsAliasing.find(variableAccessData)->second;
236                     data.mergeArgumentsAssignment();
237                     // This ensures that the variable's uses are in the same context as
238                     // the arguments it is aliasing.
239                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
240                     data.mergeCallContext(source.codeOrigin.inlineCallFrame);
241                     break;
242                 }
243                     
244                 case GetLocal:
245                 case Phi: {
246                     VariableAccessData* variableAccessData = node.variableAccessData();
247                     if (variableAccessData->isCaptured())
248                         break;
249                     ArgumentsAliasingData& data =
250                         m_argumentsAliasing.find(variableAccessData)->second;
251                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
252                     break;
253                 }
254                     
255                 case Flush: {
256                     VariableAccessData* variableAccessData = node.variableAccessData();
257                     if (variableAccessData->isCaptured())
258                         break;
259                     ArgumentsAliasingData& data =
260                         m_argumentsAliasing.find(variableAccessData)->second;
261                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
262                     
263                     // If a variable is used in a flush then by definition it escapes.
264                     data.escapes = true;
265                     break;
266                 }
267                     
268                 case SetArgument: {
269                     VariableAccessData* variableAccessData = node.variableAccessData();
270                     if (variableAccessData->isCaptured())
271                         break;
272                     ArgumentsAliasingData& data =
273                         m_argumentsAliasing.find(variableAccessData)->second;
274                     data.mergeNonArgumentsAssignment();
275                     data.mergeCallContext(node.codeOrigin.inlineCallFrame);
276                     break;
277                 }
278                     
279                 case GetByVal: {
280                     if (!node.prediction()
281                         || !m_graph[node.child1()].prediction()
282                         || !m_graph[node.child2()].prediction()) {
283                         observeBadArgumentsUses(node);
284                         break;
285                     }
286                     
287                     if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
288                         || !m_graph[node.child2()].shouldSpeculateInteger()) {
289                         observeBadArgumentsUses(node);
290                         break;
291                     }
292                     
293                     if (m_graph[node.child1()].shouldSpeculateArguments()) {
294                         // If arguments is used as an index, then it's an escaping use.
295                         // That's so awful and pretty much impossible since it would
296                         // imply that the arguments were predicted integer, but it's
297                         // good to be defensive and thorough.
298                         observeBadArgumentsUse(node.child2());
299                         observeProperArgumentsUse(node, node.child1());
300                         break;
301                     }
302                     
303                     observeBadArgumentsUses(node);
304                     break;
305                 }
306                     
307                 case GetArgumentsLength: {
308                     observeProperArgumentsUse(node, node.child1());
309                     break;
310                 }
311                     
312                 case Phantom:
313                     // We don't care about phantom uses, since phantom uses are all about
314                     // just keeping things alive for OSR exit. If something - like the
315                     // CreateArguments - is just being kept alive, then this transformation
316                     // will not break this, since the Phantom will now just keep alive a
317                     // PhantomArguments and OSR exit will still do the right things.
318                     break;
319                     
320                 default:
321                     observeBadArgumentsUses(node);
322                     break;
323                 }
324             }
325         }
326
327         // Now we know which variables are aliased to arguments. But if any of them are
328         // found to have escaped, or were otherwise invalidated, then we need to mark
329         // the arguments as requiring creation. This is a property of SetLocals to
330         // variables that are neither the correct arguments register nor are marked as
331         // being arguments-aliased.
332         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
333             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
334             if (!block)
335                 continue;
336             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
337                 NodeIndex nodeIndex = block->at(indexInBlock);
338                 Node& node = m_graph[nodeIndex];
339                 if (!node.shouldGenerate())
340                     continue;
341                 if (node.op() != SetLocal)
342                     continue;
343                 Node& source = m_graph[node.child1()];
344                 if (source.op() != CreateArguments)
345                     continue;
346                 VariableAccessData* variableAccessData = node.variableAccessData();
347                 if (variableAccessData->isCaptured()) {
348                     // The captured case would have already been taken care of in the
349                     // previous pass.
350                     continue;
351                 }
352                 
353                 ArgumentsAliasingData& data =
354                     m_argumentsAliasing.find(variableAccessData)->second;
355                 if (data.isValid())
356                     continue;
357                 
358                 m_createsArguments.add(source.codeOrigin.inlineCallFrame);
359             }
360         }
361         
362 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
363         dataLog("Arguments aliasing states:\n");
364         for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
365             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
366             if (!variableAccessData->isRoot())
367                 continue;
368             dataLog("   r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
369             if (variableAccessData->isCaptured())
370                 dataLog("Captured");
371             else {
372                 ArgumentsAliasingData& data =
373                     m_argumentsAliasing.find(variableAccessData)->second;
374                 bool first = true;
375                 if (data.callContextIsValid()) {
376                     if (!first)
377                         dataLog(", ");
378                     dataLog("Have Call Context: %p", data.callContext);
379                     first = false;
380                     if (!m_createsArguments.contains(data.callContext))
381                         dataLog(" (Does Not Create Arguments)");
382                 }
383                 if (data.argumentsAssignmentIsValid()) {
384                     if (!first)
385                         dataLog(", ");
386                     dataLog("Arguments Assignment Is Valid");
387                     first = false;
388                 }
389                 if (!data.escapes) {
390                     if (!first)
391                         dataLog(", ");
392                     dataLog("Does Not Escape");
393                     first = false;
394                 }
395                 if (!first)
396                     dataLog(", ");
397                 if (data.isValid()) {
398                     if (m_createsArguments.contains(data.callContext))
399                         dataLog("VALID");
400                     else
401                         dataLog("INVALID (due to argument creation)");
402                 } else
403                     dataLog("INVALID (due to bad variable use)");
404             }
405             dataLog("\n");
406         }
407 #endif
408         
409         InsertionSet<NodeIndex> insertionSet;
410         
411         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
412             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
413             if (!block)
414                 continue;
415             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
416                 NodeIndex nodeIndex = block->at(indexInBlock);
417                 Node& node = m_graph[nodeIndex];
418                 if (!node.shouldGenerate())
419                     continue;
420                 
421                 switch (node.op()) {
422                 case SetLocal: {
423                     Node& source = m_graph[node.child1()];
424                     if (source.op() != CreateArguments)
425                         break;
426                     
427                     if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
428                         break;
429                     
430                     VariableAccessData* variableAccessData = node.variableAccessData();
431                     
432                     if (variableAccessData->isCaptured()) {
433                         ASSERT(m_graph.argumentsRegisterFor(node.codeOrigin) == variableAccessData->local()
434                                || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node.codeOrigin)) == variableAccessData->local());
435                         // The child of this store should really be the empty value.
436                         Node emptyJSValue(JSConstant, node.codeOrigin, OpInfo(codeBlock()->addOrFindConstant(JSValue())));
437                         emptyJSValue.ref();
438                         NodeIndex emptyJSValueIndex = m_graph.size();
439                         m_graph.deref(node.child1());
440                         node.children.child1() = Edge(emptyJSValueIndex);
441                         m_graph.append(emptyJSValue);
442                         insertionSet.append(indexInBlock, emptyJSValueIndex);
443                         changed = true;
444                         break;
445                     }
446                     
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)->second.isValid());
455                     changed |= variableAccessData->mergeIsArgumentsAlias(true);
456                     break;
457                 }
458                     
459                 case Phantom: {
460                     // It's highly likely that we will have a Phantom referencing either
461                     // CreateArguments, or a local op for the arguments register, or a
462                     // local op for an arguments-aliased variable. In any of those cases,
463                     // we should remove the phantom reference, since:
464                     // 1) Phantoms only exist to aid OSR exit. But arguments simplification
465                     //    has its own OSR exit story, which is to inform OSR exit to reify
466                     //    the arguments as necessary.
467                     // 2) The Phantom may keep the CreateArguments node alive, which is
468                     //    precisely what we don't want.
469                     for (unsigned i = 0; i < AdjacencyList::Size; ++i)
470                         removeArgumentsReferencingPhantomChild(node, i);
471                     break;
472                 }
473                     
474                 case GetByVal: {
475                     if (!node.prediction()
476                         || !m_graph[node.child1()].prediction()
477                         || !m_graph[node.child2()].prediction())
478                         break;
479                     
480                     if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
481                         || !m_graph[node.child2()].shouldSpeculateInteger())
482                         break;
483                     
484                     if (m_graph[node.child1()].shouldSpeculateArguments()) {
485                         // This can be simplified to GetMyArgumentByVal if we know that
486                         // it satisfies either condition (1) or (2):
487                         // 1) Its first child is a valid ArgumentsAliasingData and the
488                         //    InlineCallFrame* is not marked as creating arguments.
489                         // 2) Its first child is CreateArguments and its InlineCallFrame*
490                         //    is not marked as creating arguments.
491                         
492                         if (!isOKToOptimize(m_graph[node.child1()]))
493                             break;
494                         
495                         m_graph.deref(node.child1());
496                         node.children.child1() = node.children.child2();
497                         node.children.child2() = Edge();
498                         node.setOpAndDefaultFlags(GetMyArgumentByVal);
499                         changed = true;
500                         --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
501                         break;
502                     }
503                     break;
504                 }
505                     
506                 case GetArgumentsLength: {
507                     if (!isOKToOptimize(m_graph[node.child1()]))
508                         break;
509                     
510                     m_graph.deref(node.child1());
511                     node.children.child1() = Edge();
512                     node.setOpAndDefaultFlags(GetMyArgumentsLength);
513                     changed = true;
514                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
515                     break;
516                 }
517                     
518                 case GetMyArgumentsLength:
519                 case GetMyArgumentsLengthSafe: {
520                     if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
521                         ASSERT(node.op() == GetMyArgumentsLengthSafe);
522                         break;
523                     }
524                     if (node.op() == GetMyArgumentsLengthSafe) {
525                         node.setOp(GetMyArgumentsLength);
526                         changed = true;
527                     }
528                     
529                     CodeOrigin codeOrigin = node.codeOrigin;
530                     if (!codeOrigin.inlineCallFrame)
531                         break;
532                     
533                     // We know exactly what this will return. But only after we have checked
534                     // that nobody has escaped our arguments.
535                     Node check(CheckArgumentsNotCreated, codeOrigin);
536                     check.ref();
537                     NodeIndex checkIndex = m_graph.size();
538                     m_graph.append(check);
539                     insertionSet.append(indexInBlock, checkIndex);
540                     
541                     m_graph.convertToConstant(
542                         nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
543                     changed = true;
544                     break;
545                 }
546                     
547                 case GetMyArgumentByVal:
548                 case GetMyArgumentByValSafe: {
549                     if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
550                         ASSERT(node.op() == GetMyArgumentByValSafe);
551                         break;
552                     }
553                     if (node.op() == GetMyArgumentByValSafe) {
554                         node.setOp(GetMyArgumentByVal);
555                         changed = true;
556                     }
557                     if (!node.codeOrigin.inlineCallFrame)
558                         break;
559                     if (!m_graph[node.child1()].hasConstant())
560                         break;
561                     JSValue value = m_graph[node.child1()].valueOfJSConstant(codeBlock());
562                     if (!value.isInt32())
563                         break;
564                     int32_t index = value.asInt32();
565                     if (index < 0
566                         || static_cast<size_t>(index + 1) >=
567                             node.codeOrigin.inlineCallFrame->arguments.size())
568                         break;
569                     
570                     // We know which argument this is accessing. But only after we have checked
571                     // that nobody has escaped our arguments. We also need to ensure that the
572                     // index is kept alive. That's somewhat pointless since it's a constant, but
573                     // it's important because this is one of those invariants that we like to
574                     // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
575                     // here, since this is being done _after_ the prediction propagation phase
576                     // has run - therefore it makes little sense to link the GetLocal operation
577                     // into the VariableAccessData and Phi graphs.
578
579                     Node check(CheckArgumentsNotCreated, node.codeOrigin);
580                     check.ref();
581                     
582                     Node phantom(Phantom, node.codeOrigin);
583                     phantom.ref();
584                     phantom.children = node.children;
585                     
586                     node.convertToGetLocalUnlinked(
587                         static_cast<VirtualRegister>(
588                             node.codeOrigin.inlineCallFrame->stackOffset +
589                             argumentToOperand(index + 1)));
590                     
591                     NodeIndex checkNodeIndex = m_graph.size();
592                     m_graph.append(check);
593                     insertionSet.append(indexInBlock, checkNodeIndex);
594                     NodeIndex phantomNodeIndex = m_graph.size();
595                     m_graph.append(phantom);
596                     insertionSet.append(indexInBlock, phantomNodeIndex);
597                     
598                     changed = true;
599                     break;
600                 }
601                     
602                 case TearOffArguments: {
603                     if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
604                         continue;
605                     
606                     node.setOpAndDefaultFlags(Nop);
607                     m_graph.clearAndDerefChild1(node);
608                     node.setRefCount(0);
609                     break;
610                 }
611                     
612                 default:
613                     break;
614                 }
615             }
616             insertionSet.execute(*block);
617         }
618         
619         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
620             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
621             if (!block)
622                 continue;
623             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
624                 NodeIndex nodeIndex = block->at(indexInBlock);
625                 Node& node = m_graph[nodeIndex];
626                 if (node.op() != CreateArguments)
627                     continue;
628                 // If this is a CreateArguments for an InlineCallFrame* that does
629                 // not create arguments, then replace it with a PhantomArguments.
630                 // PhantomArguments is a non-executing node that just indicates
631                 // that the node should be reified as an arguments object on OSR
632                 // exit.
633                 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
634                     continue;
635                 if (node.shouldGenerate()) {
636                     Node phantom(Phantom, node.codeOrigin);
637                     phantom.children = node.children;
638                     phantom.ref();
639                     NodeIndex phantomNodeIndex = m_graph.size();
640                     m_graph.append(phantom);
641                     insertionSet.append(indexInBlock, phantomNodeIndex);
642                 }
643                 node.setOpAndDefaultFlags(PhantomArguments);
644                 node.children.reset();
645                 changed = true;
646             }
647             insertionSet.execute(*block);
648         }
649         
650         if (changed) {
651             m_graph.collectGarbage();
652             
653             // Verify that PhantomArguments nodes are not shouldGenerate().
654 #if !ASSERT_DISABLED
655             for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
656                 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
657                 if (!block)
658                     continue;
659                 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
660                     NodeIndex nodeIndex = block->at(indexInBlock);
661                     Node& node = m_graph[nodeIndex];
662                     if (node.op() != PhantomArguments)
663                         continue;
664                     ASSERT(!node.shouldGenerate());
665                 }
666             }
667 #endif
668         }
669         
670         return changed;
671     }
672     
673 private:
674     HashSet<InlineCallFrame*,
675             DefaultHash<InlineCallFrame*>::Hash,
676             NullableHashTraits<InlineCallFrame*> > m_createsArguments;
677     HashMap<VariableAccessData*, ArgumentsAliasingData,
678             DefaultHash<VariableAccessData*>::Hash,
679             NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
680
681     void observeBadArgumentsUse(Edge edge)
682     {
683         if (!edge)
684             return;
685         
686         Node& child = m_graph[edge];
687         switch (child.op()) {
688         case CreateArguments: {
689             m_createsArguments.add(child.codeOrigin.inlineCallFrame);
690             break;
691         }
692             
693         case GetLocal: {
694             int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin);
695             if (argumentsRegister != InvalidVirtualRegister
696                 && (child.local() == argumentsRegister
697                     || child.local() == unmodifiedArgumentsRegister(argumentsRegister))) {
698                 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
699                 break;
700             }
701             
702             VariableAccessData* variableAccessData = child.variableAccessData();
703             if (variableAccessData->isCaptured())
704                 break;
705             
706             ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
707             data.escapes = true;
708             break;
709         }
710             
711         default:
712             break;
713         }
714     }
715     
716     void observeBadArgumentsUses(Node& node)
717     {
718         for (unsigned i = m_graph.numChildren(node); i--;)
719             observeBadArgumentsUse(m_graph.child(node, i));
720     }
721     
722     void observeProperArgumentsUse(Node& node, Edge edge)
723     {
724         Node& child = m_graph[edge];
725         if (child.op() != GetLocal) {
726             // When can this happen? At least two cases that I can think
727             // of:
728             //
729             // 1) Aliased use of arguments in the same basic block,
730             //    like:
731             //
732             //    var a = arguments;
733             //    var x = arguments[i];
734             //
735             // 2) If we're accessing arguments we got from the heap!
736                             
737             if (child.op() == CreateArguments
738                 && node.codeOrigin.inlineCallFrame
739                    != child.codeOrigin.inlineCallFrame)
740                 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
741             
742             return;
743         }
744                         
745         VariableAccessData* variableAccessData = child.variableAccessData();
746         if (variableAccessData->isCaptured()) {
747             if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
748                 && node.codeOrigin.inlineCallFrame != child.codeOrigin.inlineCallFrame)
749                 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
750             return;
751         }
752         
753         ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
754         data.mergeCallContext(node.codeOrigin.inlineCallFrame);
755     }
756     
757     bool isOKToOptimize(Node& source)
758     {
759         if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
760             return false;
761         
762         switch (source.op()) {
763         case GetLocal: {
764             VariableAccessData* variableAccessData = source.variableAccessData();
765             if (variableAccessData->isCaptured()) {
766                 int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source.codeOrigin);
767                 if (argumentsRegister == InvalidVirtualRegister)
768                     break;
769                 if (argumentsRegister == variableAccessData->local())
770                     return true;
771                 if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
772                     return true;
773                 break;
774             }
775             ArgumentsAliasingData& data =
776                 m_argumentsAliasing.find(variableAccessData)->second;
777             if (!data.isValid())
778                 break;
779                             
780             return true;
781         }
782                             
783         case CreateArguments: {
784             return true;
785         }
786                             
787         default:
788             break;
789         }
790         
791         return false;
792     }
793     
794     void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex)
795     {
796         Edge edge = node.children.child(edgeIndex);
797         if (!edge)
798             return;
799         
800         Node& child = m_graph[edge];
801         switch (child.op()) {
802         case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
803         case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
804         case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
805             VariableAccessData* variableAccessData = child.variableAccessData();
806             bool isDeadArgumentsRegister =
807                 variableAccessData->local() ==
808                     m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
809                 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
810             bool isAliasedArgumentsRegister =
811                 !variableAccessData->isCaptured()
812                 && m_argumentsAliasing.find(variableAccessData)->second.isValid()
813                 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
814             if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
815                 break;
816             m_graph.deref(edge);
817             node.children.removeEdgeFromBag(edgeIndex);
818             break;
819         }
820             
821         case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
822             if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame))
823                 break;
824             m_graph.deref(edge);
825             node.children.removeEdgeFromBag(edgeIndex);
826             break;
827         }
828             
829         default:
830             break;
831         }
832     }
833 };
834
835 bool performArgumentsSimplification(Graph& graph)
836 {
837     return runPhase<ArgumentsSimplificationPhase>(graph);
838 }
839
840 } } // namespace JSC::DFG
841
842 #endif // ENABLE(DFG_JIT)
843
844