Move back primary header includes next to config.h
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArgumentsSimplificationPhase.cpp
1 /*
2  * Copyright (C) 2012, 2013 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 "DFGBasicBlock.h"
32 #include "DFGGraph.h"
33 #include "DFGInsertionSet.h"
34 #include "DFGPhase.h"
35 #include "DFGValidate.h"
36 #include "DFGVariableAccessDataDump.h"
37 #include "JSCInlines.h"
38 #include <wtf/HashSet.h>
39 #include <wtf/HashMap.h>
40
41 namespace JSC { namespace DFG {
42
43 namespace {
44
45 struct ArgumentsAliasingData {
46     InlineCallFrame* callContext;
47     bool callContextSet;
48     bool multipleCallContexts;
49     
50     bool assignedFromArguments;
51     bool assignedFromManyThings;
52     
53     bool escapes;
54     
55     ArgumentsAliasingData()
56         : callContext(0)
57         , callContextSet(false)
58         , multipleCallContexts(false)
59         , assignedFromArguments(false)
60         , assignedFromManyThings(false)
61         , escapes(false)
62     {
63     }
64     
65     void mergeCallContext(InlineCallFrame* newCallContext)
66     {
67         if (multipleCallContexts)
68             return;
69         
70         if (!callContextSet) {
71             callContext = newCallContext;
72             callContextSet = true;
73             return;
74         }
75         
76         if (callContext == newCallContext)
77             return;
78         
79         multipleCallContexts = true;
80     }
81     
82     bool callContextIsValid()
83     {
84         return callContextSet && !multipleCallContexts;
85     }
86     
87     void mergeArgumentsAssignment()
88     {
89         assignedFromArguments = true;
90     }
91     
92     void mergeNonArgumentsAssignment()
93     {
94         assignedFromManyThings = true;
95     }
96     
97     bool argumentsAssignmentIsValid()
98     {
99         return assignedFromArguments && !assignedFromManyThings;
100     }
101     
102     bool isValid()
103     {
104         return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
105     }
106 };
107
108 } // end anonymous namespace
109
110 class ArgumentsSimplificationPhase : public Phase {
111 public:
112     ArgumentsSimplificationPhase(Graph& graph)
113         : Phase(graph, "arguments simplification")
114     {
115     }
116     
117     bool run()
118     {
119         if (!m_graph.m_hasArguments)
120             return false;
121         
122         bool changed = false;
123         
124         // Record which arguments are known to escape no matter what.
125         for (InlineCallFrameSet::iterator iter = m_graph.m_inlineCallFrames->begin(); !!iter; ++iter)
126             pruneObviousArgumentCreations(*iter);
127         pruneObviousArgumentCreations(0); // the machine call frame.
128         
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())
133                 continue;
134             if (variableAccessData->isCaptured())
135                 continue;
136             m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
137         }
138         
139         // Figure out which variables are live, using a conservative approximation of
140         // liveness.
141         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
142             BasicBlock* block = m_graph.block(blockIndex);
143             if (!block)
144                 continue;
145             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
146                 Node* node = block->at(indexInBlock);
147                 switch (node->op()) {
148                 case GetLocal:
149                 case Flush:
150                 case PhantomLocal:
151                     m_isLive.add(node->variableAccessData());
152                     break;
153                 default:
154                     break;
155                 }
156             }
157         }
158         
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);
165             if (!block)
166                 continue;
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.
179                     break;
180                 }
181                     
182                 case TearOffArguments: {
183                     // Ignore arguments tear off, because it's only relevant if we actually
184                     // need to create the arguments.
185                     break;
186                 }
187                     
188                 case SetLocal: {
189                     Node* source = node->child1().node();
190                     VariableAccessData* variableAccessData = node->variableAccessData();
191                     VirtualRegister argumentsRegister =
192                         m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic);
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);
199                         
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.
204                         
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()))
213                             break;
214                         
215                         // If the variable is totally dead, then ignore it.
216                         if (!m_isLive.contains(variableAccessData))
217                             break;
218                         
219                         if (argumentsRegister.isValid()
220                             && (variableAccessData->local() == argumentsRegister
221                                 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
222                             m_createsArguments.add(node->origin.semantic.inlineCallFrame);
223                             break;
224                         }
225
226                         if (variableAccessData->isCaptured())
227                             break;
228                         
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->origin.semantic.inlineCallFrame);
235                         break;
236                     }
237                     if (argumentsRegister.isValid()
238                         && (variableAccessData->local() == argumentsRegister
239                             || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
240                         if (node->origin.semantic.inlineCallFrame == source->origin.semantic.inlineCallFrame)
241                             break;
242                         m_createsArguments.add(source->origin.semantic.inlineCallFrame);
243                         break;
244                     }
245                     if (variableAccessData->isCaptured()) {
246                         m_createsArguments.add(source->origin.semantic.inlineCallFrame);
247                         break;
248                     }
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->origin.semantic.inlineCallFrame);
255                     data.mergeCallContext(source->origin.semantic.inlineCallFrame);
256                     break;
257                 }
258                     
259                 case GetLocal:
260                 case Phi: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ {
261                     VariableAccessData* variableAccessData = node->variableAccessData();
262                     if (variableAccessData->isCaptured())
263                         break;
264                     ArgumentsAliasingData& data =
265                         m_argumentsAliasing.find(variableAccessData)->value;
266                     data.mergeCallContext(node->origin.semantic.inlineCallFrame);
267                     break;
268                 }
269                     
270                 case Flush: {
271                     VariableAccessData* variableAccessData = node->variableAccessData();
272                     if (variableAccessData->isCaptured())
273                         break;
274                     ArgumentsAliasingData& data =
275                         m_argumentsAliasing.find(variableAccessData)->value;
276                     data.mergeCallContext(node->origin.semantic.inlineCallFrame);
277                     
278                     // If a variable is used in a flush then by definition it escapes.
279                     data.escapes = true;
280                     break;
281                 }
282                     
283                 case SetArgument: {
284                     VariableAccessData* variableAccessData = node->variableAccessData();
285                     if (variableAccessData->isCaptured())
286                         break;
287                     ArgumentsAliasingData& data =
288                         m_argumentsAliasing.find(variableAccessData)->value;
289                     data.mergeNonArgumentsAssignment();
290                     data.mergeCallContext(node->origin.semantic.inlineCallFrame);
291                     break;
292                 }
293                     
294                 case GetByVal: {
295                     if (node->arrayMode().type() != Array::Arguments) {
296                         observeBadArgumentsUses(node);
297                         break;
298                     }
299
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());
305                     break;
306                 }
307                     
308                 case GetArrayLength: {
309                     if (node->arrayMode().type() != Array::Arguments) {
310                         observeBadArgumentsUses(node);
311                         break;
312                     }
313                         
314                     observeProperArgumentsUse(node, node->child1());
315                     break;
316                 }
317                     
318                 case Phantom:
319                 case HardPhantom:
320                     // We don't care about phantom uses, since phantom uses are all about
321                     // just keeping things alive for OSR exit. If something - like the
322                     // CreateArguments - is just being kept alive, then this transformation
323                     // will not break this, since the Phantom will now just keep alive a
324                     // PhantomArguments and OSR exit will still do the right things.
325                     break;
326                     
327                 case CheckStructure:
328                 case StructureTransitionWatchpoint:
329                 case CheckArray:
330                     // We don't care about these because if we get uses of the relevant
331                     // variable then we can safely get rid of these, too. This of course
332                     // relies on there not being any information transferred by the CFA
333                     // from a CheckStructure on one variable to the information about the
334                     // structures of another variable.
335                     break;
336                     
337                 case MovHint:
338                     // We don't care about MovHints at all, since they represent what happens
339                     // in bytecode. We rematerialize arguments objects on OSR exit anyway.
340                     break;
341                     
342                 default:
343                     observeBadArgumentsUses(node);
344                     break;
345                 }
346             }
347         }
348
349         // Now we know which variables are aliased to arguments. But if any of them are
350         // found to have escaped, or were otherwise invalidated, then we need to mark
351         // the arguments as requiring creation. This is a property of SetLocals to
352         // variables that are neither the correct arguments register nor are marked as
353         // being arguments-aliased.
354         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
355             BasicBlock* block = m_graph.block(blockIndex);
356             if (!block)
357                 continue;
358             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
359                 Node* node = block->at(indexInBlock);
360                 if (node->op() != SetLocal)
361                     continue;
362                 Node* source = node->child1().node();
363                 if (source->op() != CreateArguments)
364                     continue;
365                 VariableAccessData* variableAccessData = node->variableAccessData();
366                 if (variableAccessData->isCaptured()) {
367                     // The captured case would have already been taken care of in the
368                     // previous pass.
369                     continue;
370                 }
371                 
372                 ArgumentsAliasingData& data =
373                     m_argumentsAliasing.find(variableAccessData)->value;
374                 if (data.isValid())
375                     continue;
376                 
377                 m_createsArguments.add(source->origin.semantic.inlineCallFrame);
378             }
379         }
380         
381         InsertionSet insertionSet(m_graph);
382         
383         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
384             BasicBlock* block = m_graph.block(blockIndex);
385             if (!block)
386                 continue;
387             for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) {
388                 Node* node = block->at(indexInBlock);
389                 switch (node->op()) {
390                 case SetLocal: {
391                     Node* source = node->child1().node();
392                     if (source->op() != CreateArguments)
393                         break;
394                     
395                     if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame))
396                         break;
397                     
398                     VariableAccessData* variableAccessData = node->variableAccessData();
399                     
400                     if (m_graph.argumentsRegisterFor(node->origin.semantic) == variableAccessData->local()
401                         || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node->origin.semantic)) == variableAccessData->local())
402                         break;
403
404                     if (variableAccessData->mergeIsArgumentsAlias(true)) {
405                         changed = true;
406                         
407                         // Make sure that the variable knows, that it may now hold non-cell values.
408                         variableAccessData->predict(SpecEmpty);
409                     }
410                     
411                     // Make sure that the SetLocal doesn't check that the input is a Cell.
412                     if (node->child1().useKind() != UntypedUse) {
413                         node->child1().setUseKind(UntypedUse);
414                         changed = true;
415                     }
416                     break;
417                 }
418                     
419                 case Flush: {
420                     VariableAccessData* variableAccessData = node->variableAccessData();
421                     
422                     if (variableAccessData->isCaptured()
423                         || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
424                         || m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
425                         break;
426                     
427                     RELEASE_ASSERT_NOT_REACHED();
428                     break;
429                 }
430                     
431                 case Phantom:
432                 case HardPhantom: {
433                     // It's highly likely that we will have a Phantom referencing either
434                     // CreateArguments, or a local op for the arguments register, or a
435                     // local op for an arguments-aliased variable. In any of those cases,
436                     // we should remove the phantom reference, since:
437                     // 1) Phantoms only exist to aid OSR exit. But arguments simplification
438                     //    has its own OSR exit story, which is to inform OSR exit to reify
439                     //    the arguments as necessary.
440                     // 2) The Phantom may keep the CreateArguments node alive, which is
441                     //    precisely what we don't want.
442                     for (unsigned i = 0; i < AdjacencyList::Size; ++i)
443                         detypeArgumentsReferencingPhantomChild(node, i);
444                     break;
445                 }
446                     
447                 case CheckStructure:
448                 case StructureTransitionWatchpoint:
449                 case CheckArray: {
450                     // We can just get rid of this node, if it references a phantom argument.
451                     if (!isOKToOptimize(node->child1().node()))
452                         break;
453                     node->convertToPhantom();
454                     break;
455                 }
456                     
457                 case GetByVal: {
458                     if (node->arrayMode().type() != Array::Arguments)
459                         break;
460
461                     // This can be simplified to GetMyArgumentByVal if we know that
462                     // it satisfies either condition (1) or (2):
463                     // 1) Its first child is a valid ArgumentsAliasingData and the
464                     //    InlineCallFrame* is not marked as creating arguments.
465                     // 2) Its first child is CreateArguments and its InlineCallFrame*
466                     //    is not marked as creating arguments.
467                     
468                     if (!isOKToOptimize(node->child1().node()))
469                         break;
470                     
471                     insertionSet.insertNode(
472                         indexInBlock, SpecNone, Phantom, node->origin, node->child1());
473                     
474                     node->child1() = node->child2();
475                     node->child2() = Edge();
476                     node->setOpAndDefaultFlags(GetMyArgumentByVal);
477                     changed = true;
478                     --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
479                     break;
480                 }
481                     
482                 case GetArrayLength: {
483                     if (node->arrayMode().type() != Array::Arguments)
484                         break;
485                     
486                     if (!isOKToOptimize(node->child1().node()))
487                         break;
488                     
489                     insertionSet.insertNode(
490                         indexInBlock, SpecNone, Phantom, node->origin, node->child1());
491                     
492                     node->child1() = Edge();
493                     node->setOpAndDefaultFlags(GetMyArgumentsLength);
494                     changed = true;
495                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
496                     break;
497                 }
498                     
499                 case GetMyArgumentsLength:
500                 case GetMyArgumentsLengthSafe: {
501                     if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) {
502                         ASSERT(node->op() == GetMyArgumentsLengthSafe);
503                         break;
504                     }
505                     if (node->op() == GetMyArgumentsLengthSafe) {
506                         node->setOp(GetMyArgumentsLength);
507                         changed = true;
508                     }
509                     
510                     NodeOrigin origin = node->origin;
511                     if (!origin.semantic.inlineCallFrame)
512                         break;
513                     
514                     // We know exactly what this will return. But only after we have checked
515                     // that nobody has escaped our arguments.
516                     insertionSet.insertNode(
517                         indexInBlock, SpecNone, CheckArgumentsNotCreated, origin);
518                     
519                     m_graph.convertToConstant(
520                         node, jsNumber(origin.semantic.inlineCallFrame->arguments.size() - 1));
521                     changed = true;
522                     break;
523                 }
524                     
525                 case GetMyArgumentByVal:
526                 case GetMyArgumentByValSafe: {
527                     if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) {
528                         ASSERT(node->op() == GetMyArgumentByValSafe);
529                         break;
530                     }
531                     if (node->op() == GetMyArgumentByValSafe) {
532                         node->setOp(GetMyArgumentByVal);
533                         changed = true;
534                     }
535                     if (!node->origin.semantic.inlineCallFrame)
536                         break;
537                     if (!node->child1()->hasConstant())
538                         break;
539                     JSValue value = node->child1()->valueOfJSConstant(codeBlock());
540                     if (!value.isInt32())
541                         break;
542                     int32_t index = value.asInt32();
543                     if (index < 0
544                         || static_cast<size_t>(index + 1) >=
545                             node->origin.semantic.inlineCallFrame->arguments.size())
546                         break;
547                     
548                     // We know which argument this is accessing. But only after we have checked
549                     // that nobody has escaped our arguments. We also need to ensure that the
550                     // index is kept alive. That's somewhat pointless since it's a constant, but
551                     // it's important because this is one of those invariants that we like to
552                     // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
553                     // here, since this is being done _after_ the prediction propagation phase
554                     // has run - therefore it makes little sense to link the GetLocal operation
555                     // into the VariableAccessData and Phi graphs.
556
557                     NodeOrigin origin = node->origin;
558                     AdjacencyList children = node->children;
559                     
560                     node->convertToGetLocalUnlinked(
561                         VirtualRegister(
562                             origin.semantic.inlineCallFrame->stackOffset +
563                             m_graph.baselineCodeBlockFor(origin.semantic)->argumentIndexAfterCapture(index)));
564
565                     insertionSet.insertNode(
566                         indexInBlock, SpecNone, CheckArgumentsNotCreated, origin);
567                     insertionSet.insertNode(
568                         indexInBlock, SpecNone, Phantom, origin, children);
569                     
570                     changed = true;
571                     break;
572                 }
573                     
574                 case TearOffArguments: {
575                     if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
576                         continue;
577                     
578                     node->convertToPhantom();
579                     break;
580                 }
581                     
582                 default:
583                     break;
584                 }
585             }
586             insertionSet.execute(block);
587         }
588         
589         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
590             BasicBlock* block = m_graph.block(blockIndex);
591             if (!block)
592                 continue;
593             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
594                 Node* node = block->at(indexInBlock);
595                 if (node->op() != CreateArguments)
596                     continue;
597                 // If this is a CreateArguments for an InlineCallFrame* that does
598                 // not create arguments, then replace it with a PhantomArguments.
599                 // PhantomArguments is a non-executing node that just indicates
600                 // that the node should be reified as an arguments object on OSR
601                 // exit.
602                 if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
603                     continue;
604                 insertionSet.insertNode(
605                     indexInBlock, SpecNone, Phantom, node->origin, node->children);
606                 node->setOpAndDefaultFlags(PhantomArguments);
607                 node->children.reset();
608                 changed = true;
609             }
610             insertionSet.execute(block);
611         }
612         
613         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
614             BasicBlock* block = m_graph.block(blockIndex);
615             if (!block)
616                 continue;
617             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
618                 Node* node = block->at(indexInBlock);
619                 if (node->op() != Phantom)
620                     continue;
621                 for (unsigned i = 0; i < AdjacencyList::Size; ++i)
622                     detypeArgumentsReferencingPhantomChild(node, i);
623             }
624         }
625         
626         if (changed) {
627             m_graph.dethread();
628             m_graph.m_form = LoadStore;
629         }
630         
631         return changed;
632     }
633     
634 private:
635     HashSet<InlineCallFrame*,
636             DefaultHash<InlineCallFrame*>::Hash,
637             NullableHashTraits<InlineCallFrame*>> m_createsArguments;
638     HashMap<VariableAccessData*, ArgumentsAliasingData,
639             DefaultHash<VariableAccessData*>::Hash,
640             NullableHashTraits<VariableAccessData*>> m_argumentsAliasing;
641     HashSet<VariableAccessData*> m_isLive;
642
643     void pruneObviousArgumentCreations(InlineCallFrame* inlineCallFrame)
644     {
645         ScriptExecutable* executable = m_graph.executableFor(inlineCallFrame);
646         if (m_graph.m_executablesWhoseArgumentsEscaped.contains(executable)
647             || executable->isStrictMode())
648             m_createsArguments.add(inlineCallFrame);
649     }
650     
651     void observeBadArgumentsUse(Node* node)
652     {
653         if (!node)
654             return;
655         
656         switch (node->op()) {
657         case CreateArguments: {
658             m_createsArguments.add(node->origin.semantic.inlineCallFrame);
659             break;
660         }
661             
662         case GetLocal: {
663             VirtualRegister argumentsRegister =
664                 m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic);
665             if (argumentsRegister.isValid()
666                 && (node->local() == argumentsRegister
667                     || node->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
668                 m_createsArguments.add(node->origin.semantic.inlineCallFrame);
669                 break;
670             }
671             
672             VariableAccessData* variableAccessData = node->variableAccessData();
673             if (variableAccessData->isCaptured())
674                 break;
675             
676             ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
677             data.escapes = true;
678             break;
679         }
680             
681         default:
682             break;
683         }
684     }
685     
686     void observeBadArgumentsUses(Node* node)
687     {
688         for (unsigned i = m_graph.numChildren(node); i--;)
689             observeBadArgumentsUse(m_graph.child(node, i).node());
690     }
691     
692     void observeProperArgumentsUse(Node* node, Edge edge)
693     {
694         if (edge->op() != GetLocal) {
695             // When can this happen? At least two cases that I can think
696             // of:
697             //
698             // 1) Aliased use of arguments in the same basic block,
699             //    like:
700             //
701             //    var a = arguments;
702             //    var x = arguments[i];
703             //
704             // 2) If we're accessing arguments we got from the heap!
705                             
706             if (edge->op() == CreateArguments
707                 && node->origin.semantic.inlineCallFrame
708                     != edge->origin.semantic.inlineCallFrame)
709                 m_createsArguments.add(edge->origin.semantic.inlineCallFrame);
710             
711             return;
712         }
713                         
714         VariableAccessData* variableAccessData = edge->variableAccessData();
715         if (edge->local() == m_graph.uncheckedArgumentsRegisterFor(edge->origin.semantic)
716             && node->origin.semantic.inlineCallFrame != edge->origin.semantic.inlineCallFrame) {
717             m_createsArguments.add(edge->origin.semantic.inlineCallFrame);
718             return;
719         }
720
721         if (variableAccessData->isCaptured())
722             return;
723         
724         ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
725         data.mergeCallContext(node->origin.semantic.inlineCallFrame);
726     }
727     
728     bool isOKToOptimize(Node* source)
729     {
730         if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame))
731             return false;
732         
733         switch (source->op()) {
734         case GetLocal: {
735             VariableAccessData* variableAccessData = source->variableAccessData();
736             VirtualRegister argumentsRegister =
737                 m_graph.uncheckedArgumentsRegisterFor(source->origin.semantic);
738             if (!argumentsRegister.isValid())
739                 break;
740             if (argumentsRegister == variableAccessData->local())
741                 return true;
742             if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
743                 return true;
744             if (variableAccessData->isCaptured())
745                 break;
746             ArgumentsAliasingData& data =
747                 m_argumentsAliasing.find(variableAccessData)->value;
748             if (!data.isValid())
749                 break;
750                             
751             return true;
752         }
753                             
754         case CreateArguments: {
755             return true;
756         }
757                             
758         default:
759             break;
760         }
761         
762         return false;
763     }
764     
765     void detypeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
766     {
767         Edge edge = node->children.child(edgeIndex);
768         if (!edge)
769             return;
770         
771         switch (edge->op()) {
772         case GetLocal: {
773             VariableAccessData* variableAccessData = edge->variableAccessData();
774             if (!variableAccessData->isArgumentsAlias())
775                 break;
776             node->children.child(edgeIndex).setUseKind(UntypedUse);
777             break;
778         }
779             
780         case PhantomArguments: {
781             node->children.child(edgeIndex).setUseKind(UntypedUse);
782             break;
783         }
784             
785         default:
786             break;
787         }
788     }
789 };
790
791 bool performArgumentsSimplification(Graph& graph)
792 {
793     SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
794     return runPhase<ArgumentsSimplificationPhase>(graph);
795 }
796
797 } } // namespace JSC::DFG
798
799 #endif // ENABLE(DFG_JIT)
800
801