We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArgumentsEliminationPhase.cpp
1 /*
2  * Copyright (C) 2015-2018 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 "DFGArgumentsEliminationPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "ArrayPrototype.h"
32 #include "BytecodeLivenessAnalysisInlines.h"
33 #include "ClonedArguments.h"
34 #include "DFGArgumentsUtilities.h"
35 #include "DFGBasicBlockInlines.h"
36 #include "DFGBlockMapInlines.h"
37 #include "DFGClobberize.h"
38 #include "DFGCombinedLiveness.h"
39 #include "DFGForAllKills.h"
40 #include "DFGGraph.h"
41 #include "DFGInsertionSet.h"
42 #include "DFGLivenessAnalysisPhase.h"
43 #include "DFGOSRAvailabilityAnalysisPhase.h"
44 #include "DFGPhase.h"
45 #include "JSCInlines.h"
46 #include <wtf/HashSet.h>
47 #include <wtf/ListDump.h>
48 #include <wtf/RecursableLambda.h>
49
50 namespace JSC { namespace DFG {
51
52 namespace {
53
54 namespace DFGArgumentsEliminationPhaseInternal {
55 static const bool verbose = false;
56 }
57
58 class ArgumentsEliminationPhase : public Phase {
59 public:
60     ArgumentsEliminationPhase(Graph& graph)
61         : Phase(graph, "arguments elimination")
62     {
63     }
64     
65     bool run()
66     {
67         // For now this phase only works on SSA. This could be changed; we could have a block-local
68         // version over LoadStore.
69         DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA);
70         
71         if (DFGArgumentsEliminationPhaseInternal::verbose) {
72             dataLog("Graph before arguments elimination:\n");
73             m_graph.dump();
74         }
75         
76         identifyCandidates();
77         if (m_candidates.isEmpty())
78             return false;
79         
80         eliminateCandidatesThatEscape();
81         if (m_candidates.isEmpty())
82             return false;
83         
84         eliminateCandidatesThatInterfere();
85         if (m_candidates.isEmpty())
86             return false;
87         
88         transform();
89         
90         return true;
91     }
92
93 private:
94     // Just finds nodes that we know how to work with.
95     void identifyCandidates()
96     {
97         for (BasicBlock* block : m_graph.blocksInPreOrder()) {
98             for (Node* node : *block) {
99                 switch (node->op()) {
100                 case CreateDirectArguments:
101                 case CreateClonedArguments:
102                     m_candidates.add(node);
103                     break;
104
105                 case CreateRest:
106                     if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
107                         // If we're watching the HavingABadTime watchpoint it means that we will be invalidated
108                         // when it fires (it may or may not have actually fired yet). We don't try to eliminate
109                         // this allocation when we're not watching the watchpoint because it could entail calling
110                         // indexed accessors (and probably more crazy things) on out of bound accesses to the
111                         // rest parameter. It's also much easier to reason about this way.
112                         m_candidates.add(node);
113                     }
114                     break;
115
116                 case Spread:
117                     if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
118                         // We check ArrayUse here because ArrayUse indicates that the iterator
119                         // protocol for Arrays is non-observable by user code (e.g, it hasn't
120                         // been changed).
121                         if (node->child1().useKind() == ArrayUse) {
122                             if ((node->child1()->op() == CreateRest || node->child1()->op() == NewArrayBuffer) && m_candidates.contains(node->child1().node()))
123                                 m_candidates.add(node);
124                         }
125                     }
126                     break;
127
128                 case NewArrayWithSpread: {
129                     if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
130                         BitVector* bitVector = node->bitVector();
131                         // We only allow for Spreads to be of CreateRest or NewArrayBuffer nodes for now.
132                         bool isOK = true;
133                         for (unsigned i = 0; i < node->numChildren(); i++) {
134                             if (bitVector->get(i)) {
135                                 Node* child = m_graph.varArgChild(node, i).node();
136                                 isOK = child->op() == Spread && (child->child1()->op() == CreateRest || child->child1()->op() == NewArrayBuffer) && m_candidates.contains(child);
137                                 if (!isOK)
138                                     break;
139                             }
140                         }
141
142                         if (!isOK)
143                             break;
144
145                         m_candidates.add(node);
146                     }
147                     break;
148                 }
149
150                 case NewArrayBuffer: {
151                     if (m_graph.isWatchingHavingABadTimeWatchpoint(node) && !hasAnyArrayStorage(node->indexingMode()))
152                         m_candidates.add(node);
153                     break;
154                 }
155                     
156                 case CreateScopedArguments:
157                     // FIXME: We could handle this if it wasn't for the fact that scoped arguments are
158                     // always stored into the activation.
159                     // https://bugs.webkit.org/show_bug.cgi?id=143072 and
160                     // https://bugs.webkit.org/show_bug.cgi?id=143073
161                     break;
162                     
163                 default:
164                     break;
165                 }
166                 if (node->isPseudoTerminal())
167                     break;
168             }
169         }
170         
171         if (DFGArgumentsEliminationPhaseInternal::verbose)
172             dataLog("Candidates: ", listDump(m_candidates), "\n");
173     }
174
175     bool isStillValidCandidate(Node* candidate)
176     {
177         switch (candidate->op()) {
178         case Spread:
179             return m_candidates.contains(candidate->child1().node());
180
181         case NewArrayWithSpread: {
182             BitVector* bitVector = candidate->bitVector();
183             for (unsigned i = 0; i < candidate->numChildren(); i++) {
184                 if (bitVector->get(i)) {
185                     if (!m_candidates.contains(m_graph.varArgChild(candidate, i).node()))
186                         return false;
187                 }
188             }
189             return true;
190         }
191
192         default:
193             return true;
194         }
195
196         RELEASE_ASSERT_NOT_REACHED();
197         return false;
198     }
199
200     void removeInvalidCandidates()
201     {
202         bool changed;
203         do {
204             changed = false;
205             Vector<Node*, 1> toRemove;
206
207             for (Node* candidate : m_candidates) {
208                 if (!isStillValidCandidate(candidate))
209                     toRemove.append(candidate);
210             }
211
212             if (toRemove.size()) {
213                 changed = true;
214                 for (Node* node : toRemove)
215                     m_candidates.remove(node);
216             }
217
218         } while (changed);
219     }
220
221     void transitivelyRemoveCandidate(Node* node, Node* source = nullptr)
222     {
223         bool removed = m_candidates.remove(node);
224         if (removed && DFGArgumentsEliminationPhaseInternal::verbose && source)
225             dataLog("eliminating candidate: ", node, " because it escapes from: ", source, "\n");
226
227         if (removed)
228             removeInvalidCandidates();
229     }
230     
231     // Look for escaping sites, and remove from the candidates set if we see an escape.
232     void eliminateCandidatesThatEscape()
233     {
234         auto escape = [&] (Edge edge, Node* source) {
235             if (!edge)
236                 return;
237             transitivelyRemoveCandidate(edge.node(), source);
238         };
239         
240         auto escapeBasedOnArrayMode = [&] (ArrayMode mode, Edge edge, Node* source) {
241             switch (mode.type()) {
242             case Array::DirectArguments: {
243                 if (edge->op() != CreateDirectArguments) {
244                     escape(edge, source);
245                     break;
246                 }
247
248                 // Everything is fine if we're doing an in-bounds access.
249                 if (mode.isInBounds())
250                     break;
251
252                 // If we're out-of-bounds then we proceed only if the prototype chain
253                 // for the allocation is sane (i.e. doesn't have indexed properties).
254                 JSGlobalObject* globalObject = m_graph.globalObjectFor(edge->origin.semantic);
255                 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(m_graph.m_vm);
256                 if (objectPrototypeStructure->transitionWatchpointSetIsStillValid()
257                     && globalObject->objectPrototypeIsSane()) {
258                     m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
259                     break;
260                 }
261                 escape(edge, source);
262                 break;
263             }
264             
265             case Array::Contiguous: {
266                 if (edge->op() != CreateClonedArguments && edge->op() != CreateRest) {
267                     escape(edge, source);
268                     break;
269                 }
270             
271                 // Everything is fine if we're doing an in-bounds access.
272                 if (mode.isInBounds())
273                     break;
274                 
275                 // If we're out-of-bounds then we proceed only if the prototype chain
276                 // for the allocation is sane (i.e. doesn't have indexed properties).
277                 JSGlobalObject* globalObject = m_graph.globalObjectFor(edge->origin.semantic);
278                 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(m_graph.m_vm);
279                 if (edge->op() == CreateRest) {
280                     Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(m_graph.m_vm);
281                     if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
282                         && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
283                         && globalObject->arrayPrototypeChainIsSane()) {
284                         m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
285                         m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
286                         break;
287                     }
288                 } else {
289                     if (objectPrototypeStructure->transitionWatchpointSetIsStillValid()
290                         && globalObject->objectPrototypeIsSane()) {
291                         m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
292                         break;
293                     }
294                 }
295                 escape(edge, source);
296                 break;
297             }
298             
299             case Array::ForceExit:
300                 break;
301             
302             default:
303                 escape(edge, source);
304                 break;
305             }
306         };
307
308         removeInvalidCandidates();
309         
310         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
311             for (Node* node : *block) {
312                 switch (node->op()) {
313                 case GetFromArguments:
314                     break;
315                     
316                 case GetByVal:
317                     escapeBasedOnArrayMode(node->arrayMode(), m_graph.varArgChild(node, 0), node);
318                     escape(m_graph.varArgChild(node, 1), node);
319                     escape(m_graph.varArgChild(node, 2), node);
320                     break;
321
322                 case GetArrayLength:
323                     escape(node->child2(), node);
324                     // Computing the length of a NewArrayWithSpread can require some additions.
325                     // These additions can overflow if the array is sufficiently enormous, and in that case we will need to exit.
326                     if ((node->child1()->op() == NewArrayWithSpread) && !node->origin.exitOK)
327                         escape(node->child1(), node);
328                     break;
329
330                 case NewArrayWithSpread: {
331                     BitVector* bitVector = node->bitVector();
332                     bool isWatchingHavingABadTimeWatchpoint = m_graph.isWatchingHavingABadTimeWatchpoint(node); 
333                     for (unsigned i = 0; i < node->numChildren(); i++) {
334                         Edge child = m_graph.varArgChild(node, i);
335                         bool dontEscape;
336                         if (bitVector->get(i)) {
337                             dontEscape = child->op() == Spread
338                                 && child->child1().useKind() == ArrayUse
339                                 && (child->child1()->op() == CreateRest || child->child1()->op() == NewArrayBuffer)
340                                 && isWatchingHavingABadTimeWatchpoint;
341                         } else
342                             dontEscape = false;
343
344                         if (!dontEscape)
345                             escape(child, node);
346                     }
347
348                     break;
349                 }
350
351                 case Spread: {
352                     bool isOK = node->child1().useKind() == ArrayUse && (node->child1()->op() == CreateRest || node->child1()->op() == NewArrayBuffer);
353                     if (!isOK)
354                         escape(node->child1(), node);
355                     break;
356                 }
357
358                 case NewArrayBuffer:
359                     break;
360                     
361                 case LoadVarargs:
362                     if (node->loadVarargsData()->offset && (node->child1()->op() == NewArrayWithSpread || node->child1()->op() == Spread || node->child1()->op() == NewArrayBuffer))
363                         escape(node->child1(), node);
364                     break;
365                     
366                 case CallVarargs:
367                 case ConstructVarargs:
368                 case TailCallVarargs:
369                 case TailCallVarargsInlinedCaller:
370                     escape(node->child1(), node);
371                     escape(node->child2(), node);
372                     if (node->callVarargsData()->firstVarArgOffset && (node->child3()->op() == NewArrayWithSpread || node->child3()->op() == Spread || node->child1()->op() == NewArrayBuffer))
373                         escape(node->child3(), node);
374                     break;
375
376                 case Check:
377                 case CheckVarargs:
378                     m_graph.doToChildren(
379                         node,
380                         [&] (Edge edge) {
381                             if (edge.willNotHaveCheck())
382                                 return;
383                             
384                             if (alreadyChecked(edge.useKind(), SpecObject))
385                                 return;
386                             
387                             escape(edge, node);
388                         });
389                     break;
390                     
391                 case MovHint:
392                 case PutHint:
393                     break;
394                     
395                 case GetButterfly:
396                     // This barely works. The danger is that the GetButterfly is used by something that
397                     // does something escaping to a candidate. Fortunately, the only butterfly-using ops
398                     // that we exempt here also use the candidate directly. If there ever was a
399                     // butterfly-using op that we wanted to exempt, then we'd have to look at the
400                     // butterfly's child and check if it's a candidate.
401                     break;
402                     
403                 case FilterGetByIdStatus:
404                 case FilterPutByIdStatus:
405                 case FilterCallLinkStatus:
406                 case FilterInByIdStatus:
407                     break;
408
409                 case CheckArray:
410                     escapeBasedOnArrayMode(node->arrayMode(), node->child1(), node);
411                     break;
412
413                 case CheckStructureOrEmpty:
414                 case CheckStructure: {
415                     Node* target = node->child1().node();
416                     if (!m_candidates.contains(target))
417                         break;
418
419                     Structure* structure = nullptr;
420                     JSGlobalObject* globalObject = m_graph.globalObjectFor(target->origin.semantic);
421                     switch (target->op()) {
422                     case CreateDirectArguments:
423                         structure = globalObject->directArgumentsStructure();
424                         break;
425                     case CreateClonedArguments:
426                         structure = globalObject->clonedArgumentsStructure();
427                         break;
428                     case CreateRest:
429                         ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(target));
430                         structure = globalObject->restParameterStructure();
431                         break;
432                     case NewArrayWithSpread:
433                         ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(target));
434                         structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
435                         break;
436                     case NewArrayBuffer: {
437                         ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(target));
438                         IndexingType indexingMode = target->indexingMode();
439                         ASSERT(!hasAnyArrayStorage(indexingMode));
440                         structure = globalObject->originalArrayStructureForIndexingType(indexingMode);
441                         break;
442                     }
443                     default:
444                         RELEASE_ASSERT_NOT_REACHED();
445                     }
446                     ASSERT(structure);
447
448                     if (!node->structureSet().contains(m_graph.registerStructure(structure)))
449                         escape(node->child1(), node);
450                     break;
451                 }
452                     
453                 // FIXME: We should be able to handle GetById/GetByOffset on callee.
454                 // https://bugs.webkit.org/show_bug.cgi?id=143075
455
456                 case GetByOffset:
457                     if (node->child2()->op() == CreateClonedArguments && node->storageAccessData().offset == clonedArgumentsLengthPropertyOffset)
458                         break;
459                     FALLTHROUGH;
460                 default:
461                     m_graph.doToChildren(node, [&] (Edge edge) { return escape(edge, node); });
462                     break;
463                 }
464                 if (node->isPseudoTerminal())
465                     break;
466             }
467         }
468
469         if (DFGArgumentsEliminationPhaseInternal::verbose)
470             dataLog("After escape analysis: ", listDump(m_candidates), "\n");
471     }
472
473     // Anywhere that a candidate is live (in bytecode or in DFG), check if there is a chance of
474     // interference between the stack area that the arguments object copies from and the arguments
475     // object's payload. Conservatively this means that the stack region doesn't get stored to.
476     void eliminateCandidatesThatInterfere()
477     {
478         performLivenessAnalysis(m_graph);
479         performOSRAvailabilityAnalysis(m_graph);
480         m_graph.initializeNodeOwners();
481         CombinedLiveness combinedLiveness(m_graph);
482         
483         BlockMap<Operands<bool>> clobberedByBlock(m_graph);
484         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
485             Operands<bool>& clobberedByThisBlock = clobberedByBlock[block];
486             clobberedByThisBlock = Operands<bool>(OperandsLike, m_graph.block(0)->variablesAtHead);
487             for (Node* node : *block) {
488                 clobberize(
489                     m_graph, node, NoOpClobberize(),
490                     [&] (AbstractHeap heap) {
491                         if (heap.kind() != Stack) {
492                             ASSERT(!heap.overlaps(Stack));
493                             return;
494                         }
495                         ASSERT(!heap.payload().isTop());
496                         VirtualRegister reg(heap.payload().value32());
497                         // The register may not point to an argument or local, for example if we are looking at SetArgumentCountIncludingThis.
498                         if (!reg.isHeader())
499                             clobberedByThisBlock.operand(reg) = true;
500                     },
501                     NoOpClobberize());
502             }
503         }
504         
505         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
506             // Stop if we've already removed all candidates.
507             if (m_candidates.isEmpty())
508                 return;
509             
510             // Ignore blocks that don't write to the stack.
511             bool writesToStack = false;
512             for (unsigned i = clobberedByBlock[block].size(); i--;) {
513                 if (clobberedByBlock[block][i]) {
514                     writesToStack = true;
515                     break;
516                 }
517             }
518             if (!writesToStack)
519                 continue;
520             
521             forAllKillsInBlock(
522                 m_graph, combinedLiveness, block,
523                 [&] (unsigned nodeIndex, Node* candidate) {
524                     if (!m_candidates.contains(candidate))
525                         return;
526                     
527                     // Check if this block has any clobbers that affect this candidate. This is a fairly
528                     // fast check.
529                     bool isClobberedByBlock = false;
530                     Operands<bool>& clobberedByThisBlock = clobberedByBlock[block];
531                     
532                     if (InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame) {
533                         if (inlineCallFrame->isVarargs()) {
534                             isClobberedByBlock |= clobberedByThisBlock.operand(
535                                 inlineCallFrame->stackOffset + CallFrameSlot::argumentCount);
536                         }
537                         
538                         if (!isClobberedByBlock || inlineCallFrame->isClosureCall) {
539                             isClobberedByBlock |= clobberedByThisBlock.operand(
540                                 inlineCallFrame->stackOffset + CallFrameSlot::callee);
541                         }
542                         
543                         if (!isClobberedByBlock) {
544                             for (unsigned i = 0; i < inlineCallFrame->argumentCountIncludingThis - 1; ++i) {
545                                 VirtualRegister reg =
546                                     VirtualRegister(inlineCallFrame->stackOffset) +
547                                     CallFrame::argumentOffset(i);
548                                 if (clobberedByThisBlock.operand(reg)) {
549                                     isClobberedByBlock = true;
550                                     break;
551                                 }
552                             }
553                         }
554                     } else {
555                         // We don't include the ArgumentCount or Callee in this case because we can be
556                         // damn sure that this won't be clobbered.
557                         for (unsigned i = 1; i < static_cast<unsigned>(codeBlock()->numParameters()); ++i) {
558                             if (clobberedByThisBlock.argument(i)) {
559                                 isClobberedByBlock = true;
560                                 break;
561                             }
562                         }
563                     }
564                     
565                     if (!isClobberedByBlock)
566                         return;
567                     
568                     // Check if we can immediately eliminate this candidate. If the block has a clobber
569                     // for this arguments allocation, and we'd have to examine every node in the block,
570                     // then we can just eliminate the candidate.
571                     if (nodeIndex == block->size() && candidate->owner != block) {
572                         if (DFGArgumentsEliminationPhaseInternal::verbose)
573                             dataLog("eliminating candidate: ", candidate, " because it is clobbered by: ", block->at(nodeIndex), "\n");
574                         transitivelyRemoveCandidate(candidate);
575                         return;
576                     }
577                     
578                     // This loop considers all nodes up to the nodeIndex, excluding the nodeIndex.
579                     while (nodeIndex--) {
580                         Node* node = block->at(nodeIndex);
581                         if (node == candidate)
582                             break;
583                         
584                         bool found = false;
585                         clobberize(
586                             m_graph, node, NoOpClobberize(),
587                             [&] (AbstractHeap heap) {
588                                 if (heap.kind() == Stack && !heap.payload().isTop()) {
589                                     if (argumentsInvolveStackSlot(candidate, VirtualRegister(heap.payload().value32())))
590                                         found = true;
591                                     return;
592                                 }
593                                 if (heap.overlaps(Stack))
594                                     found = true;
595                             },
596                             NoOpClobberize());
597                         
598                         if (found) {
599                             if (DFGArgumentsEliminationPhaseInternal::verbose)
600                                 dataLog("eliminating candidate: ", candidate, " because it is clobbered by ", block->at(nodeIndex), "\n");
601                             transitivelyRemoveCandidate(candidate);
602                             return;
603                         }
604                     }
605                 });
606         }
607         
608         // Q: How do we handle OSR exit with a live PhantomArguments at a point where the inline call
609         // frame is dead?  A: Naively we could say that PhantomArguments must escape the stack slots. But
610         // that would break PutStack sinking, which in turn would break object allocation sinking, in
611         // cases where we have a varargs call to an otherwise pure method. So, we need something smarter.
612         // For the outermost arguments, we just have a PhantomArguments that magically knows that it
613         // should load the arguments from the call frame. For the inline arguments, we have the heap map
614         // in the availabiltiy map track each possible inline argument as a promoted heap location. If the
615         // PutStacks for those arguments aren't sunk, those heap locations will map to very trivial
616         // availabilities (they will be flush availabilities). But if sinking happens then those
617         // availabilities may become whatever. OSR exit should be able to handle this quite naturally,
618         // since those availabilities speak of the stack before the optimizing compiler stack frame is
619         // torn down.
620
621         if (DFGArgumentsEliminationPhaseInternal::verbose)
622             dataLog("After interference analysis: ", listDump(m_candidates), "\n");
623     }
624     
625     void transform()
626     {
627         InsertionSet insertionSet(m_graph);
628         
629         for (BasicBlock* block : m_graph.blocksInPreOrder()) {
630             for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
631                 Node* node = block->at(nodeIndex);
632                 
633                 auto getArrayLength = [&] (Node* candidate) -> Node* {
634                     return emitCodeToGetArgumentsArrayLength(
635                         insertionSet, candidate, nodeIndex, node->origin);
636                 };
637
638                 auto isEliminatedAllocation = [&] (Node* candidate) -> bool {
639                     if (!m_candidates.contains(candidate))
640                         return false;
641                     // We traverse in such a way that we are guaranteed to see a def before a use.
642                     // Therefore, we should have already transformed the allocation before the use
643                     // of an allocation.
644                     ASSERT(candidate->op() == PhantomCreateRest || candidate->op() == PhantomDirectArguments || candidate->op() == PhantomClonedArguments
645                         || candidate->op() == PhantomSpread || candidate->op() == PhantomNewArrayWithSpread || candidate->op() == PhantomNewArrayBuffer);
646                     return true;
647                 };
648
649                 switch (node->op()) {
650                 case CreateDirectArguments:
651                     if (!m_candidates.contains(node))
652                         break;
653                     
654                     node->setOpAndDefaultFlags(PhantomDirectArguments);
655                     break;
656
657                 case CreateRest:
658                     if (!m_candidates.contains(node))
659                         break;
660
661                     node->setOpAndDefaultFlags(PhantomCreateRest);
662                     // We don't need this parameter for OSR exit, we can find out all the information
663                     // we need via the static parameter count and the dynamic argument count.
664                     node->child1() = Edge(); 
665                     break;
666                     
667                 case CreateClonedArguments:
668                     if (!m_candidates.contains(node))
669                         break;
670                     
671                     node->setOpAndDefaultFlags(PhantomClonedArguments);
672                     break;
673
674                 case Spread:
675                     if (!m_candidates.contains(node))
676                         break;
677                     
678                     node->setOpAndDefaultFlags(PhantomSpread);
679                     break;
680
681                 case NewArrayWithSpread:
682                     if (!m_candidates.contains(node))
683                         break;
684                     
685                     node->setOpAndDefaultFlags(PhantomNewArrayWithSpread);
686                     break;
687
688                 case NewArrayBuffer:
689                     if (!m_candidates.contains(node))
690                         break;
691
692                     node->setOpAndDefaultFlags(PhantomNewArrayBuffer);
693                     node->child1() = Edge(insertionSet.insertConstant(nodeIndex, node->origin, node->cellOperand()));
694                     break;
695                     
696                 case GetFromArguments: {
697                     Node* candidate = node->child1().node();
698                     if (!isEliminatedAllocation(candidate))
699                         break;
700                     
701                     DFG_ASSERT(
702                         m_graph, node, node->child1()->op() == PhantomDirectArguments, node->child1()->op());
703                     VirtualRegister reg =
704                         virtualRegisterForArgument(node->capturedArgumentsOffset().offset() + 1) +
705                         node->origin.semantic.stackOffset();
706                     StackAccessData* data = m_graph.m_stackAccessData.add(reg, FlushedJSValue);
707                     node->convertToGetStack(data);
708                     break;
709                 }
710
711                 case GetByOffset: {
712                     Node* candidate = node->child2().node();
713                     if (!isEliminatedAllocation(candidate))
714                         break;
715
716                     ASSERT(candidate->op() == PhantomClonedArguments);
717                     ASSERT(node->storageAccessData().offset == clonedArgumentsLengthPropertyOffset);
718
719                     // Meh, this is kind of hackish - we use an Identity so that we can reuse the
720                     // getArrayLength() helper.
721                     node->convertToIdentityOn(getArrayLength(candidate));
722                     break;
723                 }
724                     
725                 case GetArrayLength: {
726                     Node* candidate = node->child1().node();
727                     if (!isEliminatedAllocation(candidate))
728                         break;
729                     
730                     node->convertToIdentityOn(getArrayLength(candidate));
731                     break;
732                 }
733
734                 case GetByVal: {
735                     // FIXME: For ClonedArguments, we would have already done a separate bounds check.
736                     // This code will cause us to have two bounds checks - the original one that we
737                     // already factored out in SSALoweringPhase, and the new one we insert here, which is
738                     // often implicitly part of GetMyArgumentByVal. B3 will probably eliminate the
739                     // second bounds check, but still - that's just silly.
740                     // https://bugs.webkit.org/show_bug.cgi?id=143076
741                     
742                     Node* candidate = m_graph.varArgChild(node, 0).node();
743                     if (!isEliminatedAllocation(candidate))
744                         break;
745
746                     unsigned numberOfArgumentsToSkip = 0;
747                     if (candidate->op() == PhantomCreateRest)
748                         numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
749                     
750                     Node* result = nullptr;
751                     if (m_graph.varArgChild(node, 1)->isInt32Constant()) {
752                         unsigned index = m_graph.varArgChild(node, 1)->asUInt32();
753                         InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
754                         index += numberOfArgumentsToSkip;
755                         
756                         bool safeToGetStack;
757                         if (inlineCallFrame)
758                             safeToGetStack = index < inlineCallFrame->argumentCountIncludingThis - 1;
759                         else {
760                             safeToGetStack =
761                                 index < static_cast<unsigned>(codeBlock()->numParameters()) - 1;
762                         }
763                         if (safeToGetStack) {
764                             StackAccessData* data;
765                             VirtualRegister arg = virtualRegisterForArgument(index + 1);
766                             if (inlineCallFrame)
767                                 arg += inlineCallFrame->stackOffset;
768                             data = m_graph.m_stackAccessData.add(arg, FlushedJSValue);
769                             
770                             if (!inlineCallFrame || inlineCallFrame->isVarargs()) {
771                                 insertionSet.insertNode(
772                                     nodeIndex, SpecNone, CheckInBounds, node->origin,
773                                     m_graph.varArgChild(node, 1), Edge(getArrayLength(candidate), Int32Use));
774                             }
775                             
776                             result = insertionSet.insertNode(
777                                 nodeIndex, node->prediction(), GetStack, node->origin, OpInfo(data));
778                         }
779                     }
780                     
781                     if (!result) {
782                         NodeType op;
783                         if (node->arrayMode().isInBounds())
784                             op = GetMyArgumentByVal;
785                         else
786                             op = GetMyArgumentByValOutOfBounds;
787                         result = insertionSet.insertNode(
788                             nodeIndex, node->prediction(), op, node->origin, OpInfo(numberOfArgumentsToSkip),
789                             m_graph.varArgChild(node, 0), m_graph.varArgChild(node, 1));
790                     }
791
792                     // Need to do this because we may have a data format conversion here.
793                     node->convertToIdentityOn(result);
794                     break;
795                 }
796                     
797                 case LoadVarargs: {
798                     Node* candidate = node->child1().node();
799                     if (!isEliminatedAllocation(candidate))
800                         break;
801                     
802                     // LoadVarargs can exit, so it better be exitOK.
803                     DFG_ASSERT(m_graph, node, node->origin.exitOK);
804                     bool canExit = true;
805                     LoadVarargsData* varargsData = node->loadVarargsData();
806
807                     auto storeArgumentCountIncludingThis = [&] (unsigned argumentCountIncludingThis) {
808                         Node* argumentCountIncludingThisNode = insertionSet.insertConstant(
809                             nodeIndex, node->origin.withExitOK(canExit),
810                             jsNumber(argumentCountIncludingThis));
811                         insertionSet.insertNode(
812                             nodeIndex, SpecNone, MovHint, node->origin.takeValidExit(canExit),
813                             OpInfo(varargsData->count.offset()), Edge(argumentCountIncludingThisNode));
814                         insertionSet.insertNode(
815                             nodeIndex, SpecNone, PutStack, node->origin.withExitOK(canExit),
816                             OpInfo(m_graph.m_stackAccessData.add(varargsData->count, FlushedInt32)),
817                             Edge(argumentCountIncludingThisNode, KnownInt32Use));
818                     };
819
820                     auto storeValue = [&] (Node* value, unsigned storeIndex) {
821                         VirtualRegister reg = varargsData->start + storeIndex;
822                         StackAccessData* data =
823                             m_graph.m_stackAccessData.add(reg, FlushedJSValue);
824                         
825                         insertionSet.insertNode(
826                             nodeIndex, SpecNone, MovHint, node->origin.takeValidExit(canExit),
827                             OpInfo(reg.offset()), Edge(value));
828                         insertionSet.insertNode(
829                             nodeIndex, SpecNone, PutStack, node->origin.withExitOK(canExit),
830                             OpInfo(data), Edge(value));
831                     };
832
833                     if (candidate->op() == PhantomNewArrayWithSpread || candidate->op() == PhantomNewArrayBuffer || candidate->op() == PhantomSpread) {
834                         auto canConvertToStaticLoadStores = recursableLambda([&] (auto self, Node* candidate) -> bool {
835                             if (candidate->op() == PhantomSpread)
836                                 return self(candidate->child1().node());
837
838                             if (candidate->op() == PhantomNewArrayWithSpread) {
839                                 BitVector* bitVector = candidate->bitVector();
840                                 for (unsigned i = 0; i < candidate->numChildren(); i++) {
841                                     if (bitVector->get(i)) {
842                                         if (!self(m_graph.varArgChild(candidate, i).node()))
843                                             return false;
844                                     }
845                                 }
846                                 return true;
847                             }
848
849                             // PhantomNewArrayBuffer only contains constants. It can always convert LoadVarargs to static load stores.
850                             if (candidate->op() == PhantomNewArrayBuffer)
851                                 return true;
852
853                             ASSERT(candidate->op() == PhantomCreateRest);
854                             InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
855                             return inlineCallFrame && !inlineCallFrame->isVarargs();
856                         });
857
858                         if (canConvertToStaticLoadStores(candidate)) {
859                             auto countNumberOfArguments = recursableLambda([&](auto self, Node* candidate) -> unsigned {
860                                 if (candidate->op() == PhantomSpread)
861                                     return self(candidate->child1().node());
862
863                                 if (candidate->op() == PhantomNewArrayWithSpread) {
864                                     BitVector* bitVector = candidate->bitVector();
865                                     unsigned result = 0;
866                                     for (unsigned i = 0; i < candidate->numChildren(); i++) {
867                                         if (bitVector->get(i))
868                                             result += self(m_graph.varArgChild(candidate, i).node());
869                                         else
870                                             ++result;
871                                     }
872                                     return result;
873                                 }
874
875                                 if (candidate->op() == PhantomNewArrayBuffer)
876                                     return candidate->castOperand<JSImmutableButterfly*>()->length();
877
878                                 ASSERT(candidate->op() == PhantomCreateRest);
879                                 unsigned numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
880                                 InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
881                                 unsigned frameArgumentCount = inlineCallFrame->argumentCountIncludingThis - 1;
882                                 if (frameArgumentCount >= numberOfArgumentsToSkip)
883                                     return frameArgumentCount - numberOfArgumentsToSkip;
884                                 return 0;
885                             });
886
887                             unsigned argumentCountIncludingThis = 1 + countNumberOfArguments(candidate); // |this|
888                             if (argumentCountIncludingThis <= varargsData->limit) {
889                                 storeArgumentCountIncludingThis(argumentCountIncludingThis);
890
891                                 DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum, varargsData->limit, varargsData->mandatoryMinimum);
892                                 // Define our limit to exclude "this", since that's a bit easier to reason about.
893                                 unsigned limit = varargsData->limit - 1;
894
895                                 auto forwardNode = recursableLambda([&](auto self, Node* candidate, unsigned storeIndex) -> unsigned {
896                                     if (candidate->op() == PhantomSpread)
897                                         return self(candidate->child1().node(), storeIndex);
898
899                                     if (candidate->op() == PhantomNewArrayWithSpread) {
900                                         BitVector* bitVector = candidate->bitVector();
901                                         for (unsigned i = 0; i < candidate->numChildren(); i++) {
902                                             if (bitVector->get(i))
903                                                 storeIndex = self(m_graph.varArgChild(candidate, i).node(), storeIndex);
904                                             else {
905                                                 Node* value = m_graph.varArgChild(candidate, i).node();
906                                                 storeValue(value, storeIndex++);
907                                             }
908                                         }
909                                         return storeIndex;
910                                     }
911
912                                     if (candidate->op() == PhantomNewArrayBuffer) {
913                                         auto* array = candidate->castOperand<JSImmutableButterfly*>();
914                                         for (unsigned index = 0; index < array->length(); ++index) {
915                                             JSValue constant;
916                                             if (candidate->indexingType() == ArrayWithDouble)
917                                                 constant = jsDoubleNumber(array->get(index).asNumber());
918                                             else
919                                                 constant = array->get(index);
920                                             Node* value = insertionSet.insertConstant(nodeIndex, node->origin.withExitOK(canExit), constant);
921                                             storeValue(value, storeIndex++);
922                                         }
923                                         return storeIndex;
924                                     }
925
926                                     ASSERT(candidate->op() == PhantomCreateRest);
927                                     unsigned numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
928                                     InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
929                                     unsigned frameArgumentCount = inlineCallFrame->argumentCountIncludingThis - 1;
930                                     for (unsigned loadIndex = numberOfArgumentsToSkip; loadIndex < frameArgumentCount; ++loadIndex) {
931                                         VirtualRegister reg = virtualRegisterForArgument(loadIndex + 1) + inlineCallFrame->stackOffset;
932                                         StackAccessData* data = m_graph.m_stackAccessData.add(reg, FlushedJSValue);
933                                         Node* value = insertionSet.insertNode(
934                                             nodeIndex, SpecNone, GetStack, node->origin.withExitOK(canExit),
935                                             OpInfo(data));
936                                         storeValue(value, storeIndex++);
937                                     }
938                                     return storeIndex;
939                                 });
940
941                                 unsigned storeIndex = forwardNode(candidate, 0);
942                                 RELEASE_ASSERT(storeIndex <= limit);
943                                 Node* undefined = nullptr;
944                                 for (; storeIndex < limit; ++storeIndex) {
945                                     if (!undefined) {
946                                         undefined = insertionSet.insertConstant(
947                                             nodeIndex, node->origin.withExitOK(canExit), jsUndefined());
948                                     }
949                                     storeValue(undefined, storeIndex);
950                                 }
951                                 
952                                 node->remove(m_graph);
953                                 node->origin.exitOK = canExit;
954                                 break;
955                             }
956                         }
957                     } else {
958                         unsigned numberOfArgumentsToSkip = 0;
959                         if (candidate->op() == PhantomCreateRest)
960                             numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
961                         varargsData->offset += numberOfArgumentsToSkip;
962
963                         InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
964
965                         if (inlineCallFrame
966                             && !inlineCallFrame->isVarargs()) {
967
968                             unsigned argumentCountIncludingThis = inlineCallFrame->argumentCountIncludingThis;
969                             if (argumentCountIncludingThis > varargsData->offset)
970                                 argumentCountIncludingThis -= varargsData->offset;
971                             else
972                                 argumentCountIncludingThis = 1;
973                             RELEASE_ASSERT(argumentCountIncludingThis >= 1);
974
975                             if (argumentCountIncludingThis <= varargsData->limit) {
976                                 
977                                 storeArgumentCountIncludingThis(argumentCountIncludingThis);
978
979                                 DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum, varargsData->limit, varargsData->mandatoryMinimum);
980                                 // Define our limit to exclude "this", since that's a bit easier to reason about.
981                                 unsigned limit = varargsData->limit - 1;
982                                 Node* undefined = nullptr;
983                                 for (unsigned storeIndex = 0; storeIndex < limit; ++storeIndex) {
984                                     // First determine if we have an element we can load, and load it if
985                                     // possible.
986                                     
987                                     Node* value = nullptr;
988                                     unsigned loadIndex = storeIndex + varargsData->offset;
989
990                                     if (loadIndex + 1 < inlineCallFrame->argumentCountIncludingThis) {
991                                         VirtualRegister reg = virtualRegisterForArgument(loadIndex + 1) + inlineCallFrame->stackOffset;
992                                         StackAccessData* data = m_graph.m_stackAccessData.add(
993                                             reg, FlushedJSValue);
994                                         
995                                         value = insertionSet.insertNode(
996                                             nodeIndex, SpecNone, GetStack, node->origin.withExitOK(canExit),
997                                             OpInfo(data));
998                                     } else {
999                                         // FIXME: We shouldn't have to store anything if
1000                                         // storeIndex >= varargsData->mandatoryMinimum, but we will still
1001                                         // have GetStacks in that range. So if we don't do the stores, we'll
1002                                         // have degenerate IR: we'll have GetStacks of something that didn't
1003                                         // have PutStacks.
1004                                         // https://bugs.webkit.org/show_bug.cgi?id=147434
1005                                         
1006                                         if (!undefined) {
1007                                             undefined = insertionSet.insertConstant(
1008                                                 nodeIndex, node->origin.withExitOK(canExit), jsUndefined());
1009                                         }
1010                                         value = undefined;
1011                                     }
1012                                     
1013                                     // Now that we have a value, store it.
1014                                     storeValue(value, storeIndex);
1015                                 }
1016                                 
1017                                 node->remove(m_graph);
1018                                 node->origin.exitOK = canExit;
1019                                 break;
1020                             }
1021                         }
1022                     }
1023
1024                     node->setOpAndDefaultFlags(ForwardVarargs);
1025                     break;
1026                 }
1027                     
1028                 case CallVarargs:
1029                 case ConstructVarargs:
1030                 case TailCallVarargs:
1031                 case TailCallVarargsInlinedCaller: {
1032                     Node* candidate = node->child3().node();
1033                     if (!isEliminatedAllocation(candidate))
1034                         break;
1035
1036                     auto convertToStaticArgumentCountCall = [&] (const Vector<Node*>& arguments) {
1037                         unsigned firstChild = m_graph.m_varArgChildren.size();
1038                         m_graph.m_varArgChildren.append(node->child1());
1039                         m_graph.m_varArgChildren.append(node->child2());
1040                         for (Node* argument : arguments)
1041                             m_graph.m_varArgChildren.append(Edge(argument));
1042                         switch (node->op()) {
1043                         case CallVarargs:
1044                             node->setOpAndDefaultFlags(Call);
1045                             break;
1046                         case ConstructVarargs:
1047                             node->setOpAndDefaultFlags(Construct);
1048                             break;
1049                         case TailCallVarargs:
1050                             node->setOpAndDefaultFlags(TailCall);
1051                             break;
1052                         case TailCallVarargsInlinedCaller:
1053                             node->setOpAndDefaultFlags(TailCallInlinedCaller);
1054                             break;
1055                         default:
1056                             RELEASE_ASSERT_NOT_REACHED();
1057                         }
1058                         node->children = AdjacencyList(
1059                             AdjacencyList::Variable,
1060                             firstChild, m_graph.m_varArgChildren.size() - firstChild);
1061                     };
1062
1063                     auto convertToForwardsCall = [&] () {
1064                         switch (node->op()) {
1065                         case CallVarargs:
1066                             node->setOpAndDefaultFlags(CallForwardVarargs);
1067                             break;
1068                         case ConstructVarargs:
1069                             node->setOpAndDefaultFlags(ConstructForwardVarargs);
1070                             break;
1071                         case TailCallVarargs:
1072                             node->setOpAndDefaultFlags(TailCallForwardVarargs);
1073                             break;
1074                         case TailCallVarargsInlinedCaller:
1075                             node->setOpAndDefaultFlags(TailCallForwardVarargsInlinedCaller);
1076                             break;
1077                         default:
1078                             RELEASE_ASSERT_NOT_REACHED();
1079                         }
1080                     };
1081                     
1082                     if (candidate->op() == PhantomNewArrayWithSpread || candidate->op() == PhantomNewArrayBuffer || candidate->op() == PhantomSpread) {
1083                         auto canTransformToStaticArgumentCountCall = recursableLambda([&](auto self, Node* candidate) -> bool {
1084                             if (candidate->op() == PhantomSpread)
1085                                 return self(candidate->child1().node());
1086
1087                             if (candidate->op() == PhantomNewArrayWithSpread) {
1088                                 BitVector* bitVector = candidate->bitVector();
1089                                 for (unsigned i = 0; i < candidate->numChildren(); i++) {
1090                                     if (bitVector->get(i)) {
1091                                         Node* spread = m_graph.varArgChild(candidate, i).node();
1092                                         if (!self(spread))
1093                                             return false;
1094                                     }
1095                                 }
1096                                 return true;
1097                             }
1098
1099                             // PhantomNewArrayBuffer only contains constants. It can always convert LoadVarargs to static load stores.
1100                             if (candidate->op() == PhantomNewArrayBuffer)
1101                                 return true;
1102
1103                             ASSERT(candidate->op() == PhantomCreateRest);
1104                             InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
1105                             return inlineCallFrame && !inlineCallFrame->isVarargs();
1106                         });
1107
1108                         if (canTransformToStaticArgumentCountCall(candidate)) {
1109                             Vector<Node*> arguments;
1110                             auto appendNode = recursableLambda([&](auto self, Node* candidate) -> void {
1111                                 if (candidate->op() == PhantomSpread) {
1112                                     self(candidate->child1().node());
1113                                     return;
1114                                 }
1115
1116                                 if (candidate->op() == PhantomNewArrayWithSpread) {
1117                                     BitVector* bitVector = candidate->bitVector();
1118                                     for (unsigned i = 0; i < candidate->numChildren(); i++) {
1119                                         Node* child = m_graph.varArgChild(candidate, i).node();
1120                                         if (bitVector->get(i))
1121                                             self(child);
1122                                         else
1123                                             arguments.append(child);
1124                                     }
1125                                     return;
1126                                 }
1127
1128                                 if (candidate->op() == PhantomNewArrayBuffer) {
1129                                     bool canExit = true;
1130                                     auto* array = candidate->castOperand<JSImmutableButterfly*>();
1131                                     for (unsigned index = 0; index < array->length(); ++index) {
1132                                         JSValue constant;
1133                                         if (candidate->indexingType() == ArrayWithDouble)
1134                                             constant = jsDoubleNumber(array->get(index).asNumber());
1135                                         else
1136                                             constant = array->get(index);
1137                                         arguments.append(insertionSet.insertConstant(nodeIndex, node->origin.withExitOK(canExit), constant));
1138                                     }
1139                                     return;
1140                                 }
1141
1142                                 ASSERT(candidate->op() == PhantomCreateRest);
1143                                 InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
1144                                 unsigned numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
1145                                 for (unsigned i = 1 + numberOfArgumentsToSkip; i < inlineCallFrame->argumentCountIncludingThis; ++i) {
1146                                     StackAccessData* data = m_graph.m_stackAccessData.add(
1147                                         virtualRegisterForArgument(i) + inlineCallFrame->stackOffset,
1148                                         FlushedJSValue);
1149
1150                                     Node* value = insertionSet.insertNode(
1151                                         nodeIndex, SpecNone, GetStack, node->origin, OpInfo(data));
1152
1153                                     arguments.append(value);
1154                                 }
1155                             });
1156
1157                             appendNode(candidate);
1158                             convertToStaticArgumentCountCall(arguments);
1159                         } else
1160                             convertToForwardsCall();
1161                     } else {
1162                         unsigned numberOfArgumentsToSkip = 0;
1163                         if (candidate->op() == PhantomCreateRest)
1164                             numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip();
1165                         CallVarargsData* varargsData = node->callVarargsData();
1166                         varargsData->firstVarArgOffset += numberOfArgumentsToSkip;
1167
1168                         InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame;
1169                         if (inlineCallFrame && !inlineCallFrame->isVarargs()) {
1170                             Vector<Node*> arguments;
1171                             for (unsigned i = 1 + varargsData->firstVarArgOffset; i < inlineCallFrame->argumentCountIncludingThis; ++i) {
1172                                 StackAccessData* data = m_graph.m_stackAccessData.add(
1173                                     virtualRegisterForArgument(i) + inlineCallFrame->stackOffset,
1174                                     FlushedJSValue);
1175                                 
1176                                 Node* value = insertionSet.insertNode(
1177                                     nodeIndex, SpecNone, GetStack, node->origin, OpInfo(data));
1178                                 
1179                                 arguments.append(value);
1180                             }
1181                             
1182                             convertToStaticArgumentCountCall(arguments);
1183                         } else
1184                             convertToForwardsCall();
1185                     }
1186
1187                     break;
1188                 }
1189                     
1190                 case CheckArray:
1191                 case GetButterfly:
1192                 case FilterGetByIdStatus:
1193                 case FilterPutByIdStatus:
1194                 case FilterCallLinkStatus:
1195                 case FilterInByIdStatus: {
1196                     if (!isEliminatedAllocation(node->child1().node()))
1197                         break;
1198                     node->remove(m_graph);
1199                     break;
1200                 }
1201
1202                 case CheckStructureOrEmpty:
1203                 case CheckStructure:
1204                     if (!isEliminatedAllocation(node->child1().node()))
1205                         break;
1206                     node->child1() = Edge(); // Remove the cell check since we've proven it's not needed and FTL lowering might botch this.
1207                     node->remove(m_graph);
1208                     break;
1209                     
1210                 default:
1211                     break;
1212                 }
1213                 if (node->isPseudoTerminal())
1214                     break;
1215             }
1216             
1217             insertionSet.execute(block);
1218         }
1219     }
1220     
1221     HashSet<Node*> m_candidates;
1222 };
1223
1224 } // anonymous namespace
1225
1226 bool performArgumentsElimination(Graph& graph)
1227 {
1228     return runPhase<ArgumentsEliminationPhase>(graph);
1229 }
1230
1231 } } // namespace JSC::DFG
1232
1233 #endif // ENABLE(DFG_JIT)
1234