c22e69e0a9b50336d66332398899e17debab04f2
[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 "Operations.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 (unsigned i = m_graph.m_inlineCallFrames->size(); i--;)
126             pruneObviousArgumentCreations(m_graph.m_inlineCallFrames->at(i));
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->codeOrigin);
193                     if (source->op() != CreateArguments && source->op() != PhantomArguments) {
194                         // Make sure that the source of the SetLocal knows that if it's
195                         // a variable that we think is aliased to the arguments, then it
196                         // may escape at this point. In future, we could track transitive
197                         // aliasing. But not yet.
198                         observeBadArgumentsUse(source);
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->codeOrigin.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->codeOrigin.inlineCallFrame);
235                         break;
236                     }
237                     if (argumentsRegister.isValid()
238                         && (variableAccessData->local() == argumentsRegister
239                             || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
240                         if (node->codeOrigin.inlineCallFrame == source->codeOrigin.inlineCallFrame)
241                             break;
242                         m_createsArguments.add(source->codeOrigin.inlineCallFrame);
243                         break;
244                     }
245                     if (variableAccessData->isCaptured()) {
246                         m_createsArguments.add(source->codeOrigin.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->codeOrigin.inlineCallFrame);
255                     data.mergeCallContext(source->codeOrigin.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->codeOrigin.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->codeOrigin.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->codeOrigin.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                     // We don't care about phantom uses, since phantom uses are all about
320                     // just keeping things alive for OSR exit. If something - like the
321                     // CreateArguments - is just being kept alive, then this transformation
322                     // will not break this, since the Phantom will now just keep alive a
323                     // PhantomArguments and OSR exit will still do the right things.
324                     break;
325                     
326                 case CheckStructure:
327                 case StructureTransitionWatchpoint:
328                 case CheckArray:
329                     // We don't care about these because if we get uses of the relevant
330                     // variable then we can safely get rid of these, too. This of course
331                     // relies on there not being any information transferred by the CFA
332                     // from a CheckStructure on one variable to the information about the
333                     // structures of another variable.
334                     break;
335                     
336                 default:
337                     observeBadArgumentsUses(node);
338                     break;
339                 }
340             }
341         }
342
343         // Now we know which variables are aliased to arguments. But if any of them are
344         // found to have escaped, or were otherwise invalidated, then we need to mark
345         // the arguments as requiring creation. This is a property of SetLocals to
346         // variables that are neither the correct arguments register nor are marked as
347         // being arguments-aliased.
348         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
349             BasicBlock* block = m_graph.block(blockIndex);
350             if (!block)
351                 continue;
352             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
353                 Node* node = block->at(indexInBlock);
354                 if (node->op() != SetLocal)
355                     continue;
356                 Node* source = node->child1().node();
357                 if (source->op() != CreateArguments)
358                     continue;
359                 VariableAccessData* variableAccessData = node->variableAccessData();
360                 if (variableAccessData->isCaptured()) {
361                     // The captured case would have already been taken care of in the
362                     // previous pass.
363                     continue;
364                 }
365                 
366                 ArgumentsAliasingData& data =
367                     m_argumentsAliasing.find(variableAccessData)->value;
368                 if (data.isValid())
369                     continue;
370                 
371                 m_createsArguments.add(source->codeOrigin.inlineCallFrame);
372             }
373         }
374         
375 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
376         dataLogF("Arguments aliasing states:\n");
377         for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
378             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
379             if (!variableAccessData->isRoot())
380                 continue;
381             dataLog("   r", variableAccessData->local(), "(", VariableAccessDataDump(m_graph, variableAccessData), "): ");
382             if (variableAccessData->isCaptured())
383                 dataLogF("Captured");
384             else {
385                 ArgumentsAliasingData& data =
386                     m_argumentsAliasing.find(variableAccessData)->value;
387                 bool first = true;
388                 if (data.callContextIsValid()) {
389                     if (!first)
390                         dataLogF(", ");
391                     dataLogF("Have Call Context: %p", data.callContext);
392                     first = false;
393                     if (!m_createsArguments.contains(data.callContext))
394                         dataLogF(" (Does Not Create Arguments)");
395                 }
396                 if (data.argumentsAssignmentIsValid()) {
397                     if (!first)
398                         dataLogF(", ");
399                     dataLogF("Arguments Assignment Is Valid");
400                     first = false;
401                 }
402                 if (!data.escapes) {
403                     if (!first)
404                         dataLogF(", ");
405                     dataLogF("Does Not Escape");
406                     first = false;
407                 }
408                 if (!first)
409                     dataLogF(", ");
410                 if (data.isValid()) {
411                     if (m_createsArguments.contains(data.callContext))
412                         dataLogF("VALID");
413                     else
414                         dataLogF("INVALID (due to argument creation)");
415                 } else
416                     dataLogF("INVALID (due to bad variable use)");
417             }
418             dataLogF("\n");
419         }
420 #endif
421         
422         InsertionSet insertionSet(m_graph);
423         
424         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
425             BasicBlock* block = m_graph.block(blockIndex);
426             if (!block)
427                 continue;
428             for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) {
429                 Node* node = block->at(indexInBlock);
430                 switch (node->op()) {
431                 case SetLocal: {
432                     Node* source = node->child1().node();
433                     if (source->op() != CreateArguments)
434                         break;
435                     
436                     if (m_createsArguments.contains(source->codeOrigin.inlineCallFrame))
437                         break;
438                     
439                     VariableAccessData* variableAccessData = node->variableAccessData();
440                     
441                     if (m_graph.argumentsRegisterFor(node->codeOrigin) == variableAccessData->local()
442                         || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node->codeOrigin)) == variableAccessData->local())
443                         break;
444
445                     ASSERT(!variableAccessData->isCaptured());
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)->value.isValid());
455                     if (variableAccessData->mergeIsArgumentsAlias(true)) {
456                         changed = true;
457                         
458                         // Make sure that the variable knows, that it may now hold non-cell values.
459                         variableAccessData->predict(SpecEmpty);
460                     }
461                     
462                     // Make sure that the SetLocal doesn't check that the input is a Cell.
463                     if (node->child1().useKind() != UntypedUse) {
464                         node->child1().setUseKind(UntypedUse);
465                         changed = true;
466                     }
467                     break;
468                 }
469                     
470                 case PhantomLocal: {
471                     VariableAccessData* variableAccessData = node->variableAccessData();
472                     
473                     if (variableAccessData->isCaptured()
474                         || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
475                         || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
476                         break;
477                     
478                     // Turn PhantomLocals into just GetLocals. This will preserve the threading
479                     // of the local through to this point, but will allow it to die, causing
480                     // only OSR to know about it.
481
482                     node->setOpAndDefaultFlags(GetLocal);
483                     break;
484                 }
485
486                 case Flush: {
487                     VariableAccessData* variableAccessData = node->variableAccessData();
488                     
489                     if (variableAccessData->isCaptured()
490                         || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
491                         || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
492                         break;
493                     
494                     RELEASE_ASSERT_NOT_REACHED();
495                     break;
496                 }
497                     
498                 case Phantom: {
499                     // It's highly likely that we will have a Phantom referencing either
500                     // CreateArguments, or a local op for the arguments register, or a
501                     // local op for an arguments-aliased variable. In any of those cases,
502                     // we should remove the phantom reference, since:
503                     // 1) Phantoms only exist to aid OSR exit. But arguments simplification
504                     //    has its own OSR exit story, which is to inform OSR exit to reify
505                     //    the arguments as necessary.
506                     // 2) The Phantom may keep the CreateArguments node alive, which is
507                     //    precisely what we don't want.
508                     for (unsigned i = 0; i < AdjacencyList::Size; ++i)
509                         removeArgumentsReferencingPhantomChild(node, i);
510                     break;
511                 }
512                     
513                 case CheckStructure:
514                 case StructureTransitionWatchpoint:
515                 case CheckArray: {
516                     // We can just get rid of this node, if it references a phantom argument.
517                     if (!isOKToOptimize(node->child1().node()))
518                         break;
519                     node->convertToPhantom();
520                     node->children.setChild1(Edge());
521                     break;
522                 }
523                     
524                 case GetByVal: {
525                     if (node->arrayMode().type() != Array::Arguments)
526                         break;
527
528                     // This can be simplified to GetMyArgumentByVal if we know that
529                     // it satisfies either condition (1) or (2):
530                     // 1) Its first child is a valid ArgumentsAliasingData and the
531                     //    InlineCallFrame* is not marked as creating arguments.
532                     // 2) Its first child is CreateArguments and its InlineCallFrame*
533                     //    is not marked as creating arguments.
534                     
535                     if (!isOKToOptimize(node->child1().node()))
536                         break;
537                     
538                     node->children.child1() = node->children.child2();
539                     node->children.child2() = Edge();
540                     node->setOpAndDefaultFlags(GetMyArgumentByVal);
541                     changed = true;
542                     --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
543                     break;
544                 }
545                     
546                 case GetArrayLength: {
547                     if (node->arrayMode().type() != Array::Arguments)
548                         break;
549                     
550                     if (!isOKToOptimize(node->child1().node()))
551                         break;
552                     
553                     node->children.child1() = Edge();
554                     node->setOpAndDefaultFlags(GetMyArgumentsLength);
555                     changed = true;
556                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
557                     break;
558                 }
559                     
560                 case GetMyArgumentsLength:
561                 case GetMyArgumentsLengthSafe: {
562                     if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame)) {
563                         ASSERT(node->op() == GetMyArgumentsLengthSafe);
564                         break;
565                     }
566                     if (node->op() == GetMyArgumentsLengthSafe) {
567                         node->setOp(GetMyArgumentsLength);
568                         changed = true;
569                     }
570                     
571                     CodeOrigin codeOrigin = node->codeOrigin;
572                     if (!codeOrigin.inlineCallFrame)
573                         break;
574                     
575                     // We know exactly what this will return. But only after we have checked
576                     // that nobody has escaped our arguments.
577                     insertionSet.insertNode(
578                         indexInBlock, SpecNone, CheckArgumentsNotCreated, codeOrigin);
579                     
580                     m_graph.convertToConstant(
581                         node, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
582                     changed = true;
583                     break;
584                 }
585                     
586                 case GetMyArgumentByVal:
587                 case GetMyArgumentByValSafe: {
588                     if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame)) {
589                         ASSERT(node->op() == GetMyArgumentByValSafe);
590                         break;
591                     }
592                     if (node->op() == GetMyArgumentByValSafe) {
593                         node->setOp(GetMyArgumentByVal);
594                         changed = true;
595                     }
596                     if (!node->codeOrigin.inlineCallFrame)
597                         break;
598                     if (!node->child1()->hasConstant())
599                         break;
600                     JSValue value = node->child1()->valueOfJSConstant(codeBlock());
601                     if (!value.isInt32())
602                         break;
603                     int32_t index = value.asInt32();
604                     if (index < 0
605                         || static_cast<size_t>(index + 1) >=
606                             node->codeOrigin.inlineCallFrame->arguments.size())
607                         break;
608                     
609                     // We know which argument this is accessing. But only after we have checked
610                     // that nobody has escaped our arguments. We also need to ensure that the
611                     // index is kept alive. That's somewhat pointless since it's a constant, but
612                     // it's important because this is one of those invariants that we like to
613                     // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
614                     // here, since this is being done _after_ the prediction propagation phase
615                     // has run - therefore it makes little sense to link the GetLocal operation
616                     // into the VariableAccessData and Phi graphs.
617
618                     CodeOrigin codeOrigin = node->codeOrigin;
619                     AdjacencyList children = node->children;
620                     
621                     node->convertToGetLocalUnlinked(
622                         VirtualRegister(
623                             node->codeOrigin.inlineCallFrame->stackOffset +
624                             m_graph.baselineCodeBlockFor(node->codeOrigin)->argumentIndexAfterCapture(index)));
625
626                     insertionSet.insertNode(
627                         indexInBlock, SpecNone, CheckArgumentsNotCreated,
628                         codeOrigin);
629                     insertionSet.insertNode(
630                         indexInBlock, SpecNone, Phantom, codeOrigin,
631                         children);
632                     
633                     changed = true;
634                     break;
635                 }
636                     
637                 case TearOffArguments: {
638                     if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
639                         continue;
640                     
641                     node->setOpAndDefaultFlags(Phantom);
642                     node->children.reset();
643                     break;
644                 }
645                     
646                 default:
647                     break;
648                 }
649             }
650             insertionSet.execute(block);
651         }
652         
653         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
654             BasicBlock* block = m_graph.block(blockIndex);
655             if (!block)
656                 continue;
657             for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
658                 Node* node = block->at(indexInBlock);
659                 if (node->op() != CreateArguments)
660                     continue;
661                 // If this is a CreateArguments for an InlineCallFrame* that does
662                 // not create arguments, then replace it with a PhantomArguments.
663                 // PhantomArguments is a non-executing node that just indicates
664                 // that the node should be reified as an arguments object on OSR
665                 // exit.
666                 if (m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
667                     continue;
668                 insertionSet.insertNode(
669                     indexInBlock, SpecNone, Phantom, node->codeOrigin, node->children);
670                 node->setOpAndDefaultFlags(PhantomArguments);
671                 node->children.reset();
672                 changed = true;
673             }
674             insertionSet.execute(block);
675         }
676         
677         if (changed) {
678             m_graph.dethread();
679             m_graph.m_form = LoadStore;
680         }
681         
682         return changed;
683     }
684     
685 private:
686     HashSet<InlineCallFrame*,
687             DefaultHash<InlineCallFrame*>::Hash,
688             NullableHashTraits<InlineCallFrame*> > m_createsArguments;
689     HashMap<VariableAccessData*, ArgumentsAliasingData,
690             DefaultHash<VariableAccessData*>::Hash,
691             NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
692     HashSet<VariableAccessData*> m_isLive;
693
694     void pruneObviousArgumentCreations(InlineCallFrame* inlineCallFrame)
695     {
696         ScriptExecutable* executable = m_graph.executableFor(inlineCallFrame);
697         if (m_graph.m_executablesWhoseArgumentsEscaped.contains(executable)
698             || executable->isStrictMode())
699             m_createsArguments.add(inlineCallFrame);
700     }
701     
702     void observeBadArgumentsUse(Node* node)
703     {
704         if (!node)
705             return;
706         
707         switch (node->op()) {
708         case CreateArguments: {
709             m_createsArguments.add(node->codeOrigin.inlineCallFrame);
710             break;
711         }
712             
713         case GetLocal: {
714             VirtualRegister argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(node->codeOrigin);
715             if (argumentsRegister.isValid()
716                 && (node->local() == argumentsRegister
717                     || node->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
718                 m_createsArguments.add(node->codeOrigin.inlineCallFrame);
719                 break;
720             }
721             
722             VariableAccessData* variableAccessData = node->variableAccessData();
723             if (variableAccessData->isCaptured())
724                 break;
725             
726             ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
727             data.escapes = true;
728             break;
729         }
730             
731         default:
732             break;
733         }
734     }
735     
736     void observeBadArgumentsUses(Node* node)
737     {
738         for (unsigned i = m_graph.numChildren(node); i--;)
739             observeBadArgumentsUse(m_graph.child(node, i).node());
740     }
741     
742     void observeProperArgumentsUse(Node* node, Edge edge)
743     {
744         if (edge->op() != GetLocal) {
745             // When can this happen? At least two cases that I can think
746             // of:
747             //
748             // 1) Aliased use of arguments in the same basic block,
749             //    like:
750             //
751             //    var a = arguments;
752             //    var x = arguments[i];
753             //
754             // 2) If we're accessing arguments we got from the heap!
755                             
756             if (edge->op() == CreateArguments
757                 && node->codeOrigin.inlineCallFrame
758                     != edge->codeOrigin.inlineCallFrame)
759                 m_createsArguments.add(edge->codeOrigin.inlineCallFrame);
760             
761             return;
762         }
763                         
764         VariableAccessData* variableAccessData = edge->variableAccessData();
765         if (edge->local() == m_graph.uncheckedArgumentsRegisterFor(edge->codeOrigin)
766             && node->codeOrigin.inlineCallFrame != edge->codeOrigin.inlineCallFrame) {
767             m_createsArguments.add(edge->codeOrigin.inlineCallFrame);
768             return;
769         }
770
771         if (variableAccessData->isCaptured())
772             return;
773         
774         ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
775         data.mergeCallContext(node->codeOrigin.inlineCallFrame);
776     }
777     
778     bool isOKToOptimize(Node* source)
779     {
780         if (m_createsArguments.contains(source->codeOrigin.inlineCallFrame))
781             return false;
782         
783         switch (source->op()) {
784         case GetLocal: {
785             VariableAccessData* variableAccessData = source->variableAccessData();
786             VirtualRegister argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source->codeOrigin);
787             if (!argumentsRegister.isValid())
788                 break;
789             if (argumentsRegister == variableAccessData->local())
790                 return true;
791             if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
792                 return true;
793             if (variableAccessData->isCaptured())
794                 break;
795             ArgumentsAliasingData& data =
796                 m_argumentsAliasing.find(variableAccessData)->value;
797             if (!data.isValid())
798                 break;
799                             
800             return true;
801         }
802                             
803         case CreateArguments: {
804             return true;
805         }
806                             
807         default:
808             break;
809         }
810         
811         return false;
812     }
813     
814     void removeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
815     {
816         Edge edge = node->children.child(edgeIndex);
817         if (!edge)
818             return;
819         
820         switch (edge->op()) {
821         case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
822         case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
823         case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
824             VariableAccessData* variableAccessData = edge->variableAccessData();
825             bool isDeadArgumentsRegister =
826                 variableAccessData->local() ==
827                     m_graph.uncheckedArgumentsRegisterFor(edge->codeOrigin)
828                 && !m_createsArguments.contains(edge->codeOrigin.inlineCallFrame);
829             bool isAliasedArgumentsRegister =
830                 !variableAccessData->isCaptured()
831                 && m_argumentsAliasing.find(variableAccessData)->value.isValid()
832                 && !m_createsArguments.contains(edge->codeOrigin.inlineCallFrame);
833             if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
834                 break;
835             node->children.removeEdge(edgeIndex);
836             break;
837         }
838             
839         case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
840             if (m_createsArguments.contains(edge->codeOrigin.inlineCallFrame))
841                 break;
842             node->children.removeEdge(edgeIndex);
843             break;
844         }
845             
846         default:
847             break;
848         }
849     }
850 };
851
852 bool performArgumentsSimplification(Graph& graph)
853 {
854     SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
855     return runPhase<ArgumentsSimplificationPhase>(graph);
856 }
857
858 } } // namespace JSC::DFG
859
860 #endif // ENABLE(DFG_JIT)
861
862