1/*
2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DFGArgumentsSimplificationPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGBasicBlock.h"
32#include "DFGGraph.h"
33#include "DFGInsertionSet.h"
34#include "DFGPhase.h"
35#include "DFGValidate.h"
36#include "DFGVariableAccessDataDump.h"
37#include "JSCInlines.h"
38#include <wtf/HashSet.h>
39#include <wtf/HashMap.h>
40
41namespace JSC { namespace DFG {
42
43namespace {
44
45struct 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
110class ArgumentsSimplificationPhase : public Phase {
111public:
112    ArgumentsSimplificationPhase(Graph& graph)
113        : Phase(graph, "arguments simplification")
114    {
115    }
116
117    bool run()
118    {
119        if (!m_graph.m_hasArguments)
120            return false;
121
122        bool changed = false;
123
124        // Record which arguments are known to escape no matter what.
125        for (InlineCallFrameSet::iterator iter = m_graph.m_plan.inlineCallFrames->begin(); !!iter; ++iter)
126            pruneObviousArgumentCreations(*iter);
127        pruneObviousArgumentCreations(0); // the machine call frame.
128
129        // Create data for variable access datas that we will want to analyze.
130        for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
131            VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
132            if (!variableAccessData->isRoot())
133                continue;
134            if (variableAccessData->isCaptured())
135                continue;
136            m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
137        }
138
139        // Figure out which variables are live, using a conservative approximation of
140        // liveness.
141        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
142            BasicBlock* block = m_graph.block(blockIndex);
143            if (!block)
144                continue;
145            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
146                Node* node = block->at(indexInBlock);
147                switch (node->op()) {
148                case GetLocal:
149                case Flush:
150                case PhantomLocal:
151                    m_isLive.add(node->variableAccessData());
152                    break;
153                default:
154                    break;
155                }
156            }
157        }
158
159        // Figure out which variables alias the arguments and nothing else, and are
160        // used only for GetByVal and GetArrayLength accesses. At the same time,
161        // identify uses of CreateArguments that are not consistent with the arguments
162        // being aliased only to variables that satisfy these constraints.
163        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
164            BasicBlock* block = m_graph.block(blockIndex);
165            if (!block)
166                continue;
167            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
168                Node* node = block->at(indexInBlock);
169                switch (node->op()) {
170                case CreateArguments: {
171                    // Ignore this op. If we see a lone CreateArguments then we want to
172                    // completely ignore it because:
173                    // 1) The default would be to see that the child is a GetLocal on the
174                    //    arguments register and conclude that we have an arguments escape.
175                    // 2) The fact that a CreateArguments exists does not mean that it
176                    //    will continue to exist after we're done with this phase. As far
177                    //    as this phase is concerned, a CreateArguments only "exists" if it
178                    //    is used in a manner that necessitates its existance.
179                    break;
180                }
181
182                case TearOffArguments: {
183                    // Ignore arguments tear off, because it's only relevant if we actually
184                    // need to create the arguments.
185                    break;
186                }
187
188                case SetLocal: {
189                    Node* source = node->child1().node();
190                    VariableAccessData* variableAccessData = node->variableAccessData();
191                    VirtualRegister argumentsRegister =
192                        m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic);
193                    if (source->op() != CreateArguments && source->op() != PhantomArguments) {
194                        // Make sure that the source of the SetLocal knows that if it's
195                        // a variable that we think is aliased to the arguments, then it
196                        // may escape at this point. In future, we could track transitive
197                        // aliasing. But not yet.
198                        observeBadArgumentsUse(source);
199
200                        // If this is an assignment to the arguments register, then
201                        // pretend as if the arguments were created. We don't want to
202                        // optimize code that explicitly assigns to the arguments,
203                        // because that seems too ugly.
204
205                        // But, before getting rid of CreateArguments, we will have
206                        // an assignment to the arguments registers with JSValue().
207                        // That's because CSE will refuse to get rid of the
208                        // init_lazy_reg since it treats CreateArguments as reading
209                        // local variables. That could be fixed, but it's easier to
210                        // work around this here.
211                        if (source->op() == JSConstant
212                            && !source->valueOfJSConstant(codeBlock()))
213                            break;
214
215                        // If the variable is totally dead, then ignore it.
216                        if (!m_isLive.contains(variableAccessData))
217                            break;
218
219                        if (argumentsRegister.isValid()
220                            && (variableAccessData->local() == argumentsRegister
221                                || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
222                            m_createsArguments.add(node->origin.semantic.inlineCallFrame);
223                            break;
224                        }
225
226                        if (variableAccessData->isCaptured())
227                            break;
228
229                        // Make sure that if it's a variable that we think is aliased to
230                        // the arguments, that we know that it might actually not be.
231                        ArgumentsAliasingData& data =
232                            m_argumentsAliasing.find(variableAccessData)->value;
233                        data.mergeNonArgumentsAssignment();
234                        data.mergeCallContext(node->origin.semantic.inlineCallFrame);
235                        break;
236                    }
237                    if (argumentsRegister.isValid()
238                        && (variableAccessData->local() == argumentsRegister
239                            || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
240                        if (node->origin.semantic.inlineCallFrame == source->origin.semantic.inlineCallFrame)
241                            break;
242                        m_createsArguments.add(source->origin.semantic.inlineCallFrame);
243                        break;
244                    }
245                    if (variableAccessData->isCaptured()) {
246                        m_createsArguments.add(source->origin.semantic.inlineCallFrame);
247                        break;
248                    }
249                    ArgumentsAliasingData& data =
250                        m_argumentsAliasing.find(variableAccessData)->value;
251                    data.mergeArgumentsAssignment();
252                    // This ensures that the variable's uses are in the same context as
253                    // the arguments it is aliasing.
254                    data.mergeCallContext(node->origin.semantic.inlineCallFrame);
255                    data.mergeCallContext(source->origin.semantic.inlineCallFrame);
256                    break;
257                }
258
259                case GetLocal:
260                case Phi: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ {
261                    VariableAccessData* variableAccessData = node->variableAccessData();
262                    if (variableAccessData->isCaptured())
263                        break;
264                    ArgumentsAliasingData& data =
265                        m_argumentsAliasing.find(variableAccessData)->value;
266                    data.mergeCallContext(node->origin.semantic.inlineCallFrame);
267                    break;
268                }
269
270                case Flush: {
271                    VariableAccessData* variableAccessData = node->variableAccessData();
272                    if (variableAccessData->isCaptured())
273                        break;
274                    ArgumentsAliasingData& data =
275                        m_argumentsAliasing.find(variableAccessData)->value;
276                    data.mergeCallContext(node->origin.semantic.inlineCallFrame);
277
278                    // If a variable is used in a flush then by definition it escapes.
279                    data.escapes = true;
280                    break;
281                }
282
283                case SetArgument: {
284                    VariableAccessData* variableAccessData = node->variableAccessData();
285                    if (variableAccessData->isCaptured())
286                        break;
287                    ArgumentsAliasingData& data =
288                        m_argumentsAliasing.find(variableAccessData)->value;
289                    data.mergeNonArgumentsAssignment();
290                    data.mergeCallContext(node->origin.semantic.inlineCallFrame);
291                    break;
292                }
293
294                case GetByVal: {
295                    if (node->arrayMode().type() != Array::Arguments) {
296                        observeBadArgumentsUses(node);
297                        break;
298                    }
299
300                    // That's so awful and pretty much impossible since it would
301                    // imply that the arguments were predicted integer, but it's
302                    // good to be defensive and thorough.
303                    observeBadArgumentsUse(node->child2().node());
304                    observeProperArgumentsUse(node, node->child1());
305                    break;
306                }
307
308                case GetArrayLength: {
309                    if (node->arrayMode().type() != Array::Arguments) {
310                        observeBadArgumentsUses(node);
311                        break;
312                    }
313
314                    observeProperArgumentsUse(node, node->child1());
315                    break;
316                }
317
318                case Phantom:
319                case HardPhantom:
320                    // We don't care about phantom uses, since phantom uses are all about
321                    // just keeping things alive for OSR exit. If something - like the
322                    // CreateArguments - is just being kept alive, then this transformation
323                    // will not break this, since the Phantom will now just keep alive a
324                    // PhantomArguments and OSR exit will still do the right things.
325                    break;
326
327                case CheckStructure:
328                case StructureTransitionWatchpoint:
329                case CheckArray:
330                    // We don't care about these because if we get uses of the relevant
331                    // variable then we can safely get rid of these, too. This of course
332                    // relies on there not being any information transferred by the CFA
333                    // from a CheckStructure on one variable to the information about the
334                    // structures of another variable.
335                    break;
336
337                case MovHint:
338                    // We don't care about MovHints at all, since they represent what happens
339                    // in bytecode. We rematerialize arguments objects on OSR exit anyway.
340                    break;
341
342                default:
343                    observeBadArgumentsUses(node);
344                    break;
345                }
346            }
347        }
348
349        // Now we know which variables are aliased to arguments. But if any of them are
350        // found to have escaped, or were otherwise invalidated, then we need to mark
351        // the arguments as requiring creation. This is a property of SetLocals to
352        // variables that are neither the correct arguments register nor are marked as
353        // being arguments-aliased.
354        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
355            BasicBlock* block = m_graph.block(blockIndex);
356            if (!block)
357                continue;
358            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
359                Node* node = block->at(indexInBlock);
360                if (node->op() != SetLocal)
361                    continue;
362                Node* source = node->child1().node();
363                if (source->op() != CreateArguments)
364                    continue;
365                VariableAccessData* variableAccessData = node->variableAccessData();
366                if (variableAccessData->isCaptured()) {
367                    // The captured case would have already been taken care of in the
368                    // previous pass.
369                    continue;
370                }
371
372                ArgumentsAliasingData& data =
373                    m_argumentsAliasing.find(variableAccessData)->value;
374                if (data.isValid())
375                    continue;
376
377                m_createsArguments.add(source->origin.semantic.inlineCallFrame);
378            }
379        }
380
381        InsertionSet insertionSet(m_graph);
382
383        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
384            BasicBlock* block = m_graph.block(blockIndex);
385            if (!block)
386                continue;
387            for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) {
388                Node* node = block->at(indexInBlock);
389                switch (node->op()) {
390                case SetLocal: {
391                    Node* source = node->child1().node();
392                    if (source->op() != CreateArguments)
393                        break;
394
395                    if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame))
396                        break;
397
398                    VariableAccessData* variableAccessData = node->variableAccessData();
399
400                    if (variableAccessData->mergeIsArgumentsAlias(true)) {
401                        changed = true;
402
403                        // Make sure that the variable knows, that it may now hold non-cell values.
404                        variableAccessData->predict(SpecEmpty);
405                    }
406
407                    // Make sure that the SetLocal doesn't check that the input is a Cell.
408                    if (node->child1().useKind() != UntypedUse) {
409                        node->child1().setUseKind(UntypedUse);
410                        changed = true;
411                    }
412                    break;
413                }
414
415                case Flush: {
416                    VariableAccessData* variableAccessData = node->variableAccessData();
417
418                    if (variableAccessData->isCaptured()
419                        || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
420                        || m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
421                        break;
422
423                    RELEASE_ASSERT_NOT_REACHED();
424                    break;
425                }
426
427                case Phantom:
428                case HardPhantom: {
429                    // It's highly likely that we will have a Phantom referencing either
430                    // CreateArguments, or a local op for the arguments register, or a
431                    // local op for an arguments-aliased variable. In any of those cases,
432                    // we should remove the phantom reference, since:
433                    // 1) Phantoms only exist to aid OSR exit. But arguments simplification
434                    //    has its own OSR exit story, which is to inform OSR exit to reify
435                    //    the arguments as necessary.
436                    // 2) The Phantom may keep the CreateArguments node alive, which is
437                    //    precisely what we don't want.
438                    for (unsigned i = 0; i < AdjacencyList::Size; ++i)
439                        detypeArgumentsReferencingPhantomChild(node, i);
440                    break;
441                }
442
443                case CheckStructure:
444                case StructureTransitionWatchpoint:
445                case CheckArray: {
446                    // We can just get rid of this node, if it references a phantom argument.
447                    if (!isOKToOptimize(node->child1().node()))
448                        break;
449                    node->convertToPhantom();
450                    break;
451                }
452
453                case GetByVal: {
454                    if (node->arrayMode().type() != Array::Arguments)
455                        break;
456
457                    // This can be simplified to GetMyArgumentByVal if we know that
458                    // it satisfies either condition (1) or (2):
459                    // 1) Its first child is a valid ArgumentsAliasingData and the
460                    //    InlineCallFrame* is not marked as creating arguments.
461                    // 2) Its first child is CreateArguments and its InlineCallFrame*
462                    //    is not marked as creating arguments.
463
464                    if (!isOKToOptimize(node->child1().node()))
465                        break;
466
467                    insertionSet.insertNode(
468                        indexInBlock, SpecNone, Phantom, node->origin, node->child1());
469
470                    node->child1() = node->child2();
471                    node->child2() = Edge();
472                    node->setOpAndDefaultFlags(GetMyArgumentByVal);
473                    changed = true;
474                    --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
475                    break;
476                }
477
478                case GetArrayLength: {
479                    if (node->arrayMode().type() != Array::Arguments)
480                        break;
481
482                    if (!isOKToOptimize(node->child1().node()))
483                        break;
484
485                    insertionSet.insertNode(
486                        indexInBlock, SpecNone, Phantom, node->origin, node->child1());
487
488                    node->child1() = Edge();
489                    node->setOpAndDefaultFlags(GetMyArgumentsLength);
490                    changed = true;
491                    --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
492                    break;
493                }
494
495                case GetMyArgumentsLength:
496                case GetMyArgumentsLengthSafe: {
497                    if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) {
498                        ASSERT(node->op() == GetMyArgumentsLengthSafe);
499                        break;
500                    }
501                    if (node->op() == GetMyArgumentsLengthSafe) {
502                        node->setOp(GetMyArgumentsLength);
503                        changed = true;
504                    }
505
506                    NodeOrigin origin = node->origin;
507                    if (!origin.semantic.inlineCallFrame)
508                        break;
509
510                    // We know exactly what this will return. But only after we have checked
511                    // that nobody has escaped our arguments.
512                    insertionSet.insertNode(
513                        indexInBlock, SpecNone, CheckArgumentsNotCreated, origin);
514
515                    m_graph.convertToConstant(
516                        node, jsNumber(origin.semantic.inlineCallFrame->arguments.size() - 1));
517                    changed = true;
518                    break;
519                }
520
521                case GetMyArgumentByVal:
522                case GetMyArgumentByValSafe: {
523                    if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) {
524                        ASSERT(node->op() == GetMyArgumentByValSafe);
525                        break;
526                    }
527                    if (node->op() == GetMyArgumentByValSafe) {
528                        node->setOp(GetMyArgumentByVal);
529                        changed = true;
530                    }
531                    if (!node->origin.semantic.inlineCallFrame)
532                        break;
533                    if (!node->child1()->hasConstant())
534                        break;
535                    JSValue value = node->child1()->valueOfJSConstant(codeBlock());
536                    if (!value.isInt32())
537                        break;
538                    int32_t index = value.asInt32();
539                    if (index < 0
540                        || static_cast<size_t>(index + 1) >=
541                            node->origin.semantic.inlineCallFrame->arguments.size())
542                        break;
543
544                    // We know which argument this is accessing. But only after we have checked
545                    // that nobody has escaped our arguments. We also need to ensure that the
546                    // index is kept alive. That's somewhat pointless since it's a constant, but
547                    // it's important because this is one of those invariants that we like to
548                    // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
549                    // here, since this is being done _after_ the prediction propagation phase
550                    // has run - therefore it makes little sense to link the GetLocal operation
551                    // into the VariableAccessData and Phi graphs.
552
553                    NodeOrigin origin = node->origin;
554                    AdjacencyList children = node->children;
555
556                    node->convertToGetLocalUnlinked(
557                        VirtualRegister(
558                            origin.semantic.inlineCallFrame->stackOffset +
559                            m_graph.baselineCodeBlockFor(origin.semantic)->argumentIndexAfterCapture(index)));
560
561                    insertionSet.insertNode(
562                        indexInBlock, SpecNone, CheckArgumentsNotCreated, origin);
563                    insertionSet.insertNode(
564                        indexInBlock, SpecNone, Phantom, origin, children);
565
566                    changed = true;
567                    break;
568                }
569
570                case TearOffArguments: {
571                    if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
572                        continue;
573
574                    node->convertToPhantom();
575                    break;
576                }
577
578                default:
579                    break;
580                }
581            }
582            insertionSet.execute(block);
583        }
584
585        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
586            BasicBlock* block = m_graph.block(blockIndex);
587            if (!block)
588                continue;
589            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
590                Node* node = block->at(indexInBlock);
591                if (node->op() != CreateArguments)
592                    continue;
593                // If this is a CreateArguments for an InlineCallFrame* that does
594                // not create arguments, then replace it with a PhantomArguments.
595                // PhantomArguments is a non-executing node that just indicates
596                // that the node should be reified as an arguments object on OSR
597                // exit.
598                if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame))
599                    continue;
600                insertionSet.insertNode(
601                    indexInBlock, SpecNone, Phantom, node->origin, node->children);
602                node->setOpAndDefaultFlags(PhantomArguments);
603                node->children.reset();
604                changed = true;
605            }
606            insertionSet.execute(block);
607        }
608
609        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
610            BasicBlock* block = m_graph.block(blockIndex);
611            if (!block)
612                continue;
613            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
614                Node* node = block->at(indexInBlock);
615                if (node->op() != Phantom)
616                    continue;
617                for (unsigned i = 0; i < AdjacencyList::Size; ++i)
618                    detypeArgumentsReferencingPhantomChild(node, i);
619            }
620        }
621
622        if (changed) {
623            m_graph.dethread();
624            m_graph.m_form = LoadStore;
625        }
626
627        return changed;
628    }
629
630private:
631    HashSet<InlineCallFrame*,
632            DefaultHash<InlineCallFrame*>::Hash,
633            NullableHashTraits<InlineCallFrame*>> m_createsArguments;
634    HashMap<VariableAccessData*, ArgumentsAliasingData,
635            DefaultHash<VariableAccessData*>::Hash,
636            NullableHashTraits<VariableAccessData*>> m_argumentsAliasing;
637    HashSet<VariableAccessData*> m_isLive;
638
639    void pruneObviousArgumentCreations(InlineCallFrame* inlineCallFrame)
640    {
641        ScriptExecutable* executable = m_graph.executableFor(inlineCallFrame);
642        if (m_graph.m_executablesWhoseArgumentsEscaped.contains(executable)
643            || executable->isStrictMode())
644            m_createsArguments.add(inlineCallFrame);
645    }
646
647    void observeBadArgumentsUse(Node* node)
648    {
649        if (!node)
650            return;
651
652        switch (node->op()) {
653        case CreateArguments: {
654            m_createsArguments.add(node->origin.semantic.inlineCallFrame);
655            break;
656        }
657
658        case GetLocal: {
659            VirtualRegister argumentsRegister =
660                m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic);
661            if (argumentsRegister.isValid()
662                && (node->local() == argumentsRegister
663                    || node->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
664                m_createsArguments.add(node->origin.semantic.inlineCallFrame);
665                break;
666            }
667
668            VariableAccessData* variableAccessData = node->variableAccessData();
669            if (variableAccessData->isCaptured())
670                break;
671
672            ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
673            data.escapes = true;
674            break;
675        }
676
677        default:
678            break;
679        }
680    }
681
682    void observeBadArgumentsUses(Node* node)
683    {
684        for (unsigned i = m_graph.numChildren(node); i--;)
685            observeBadArgumentsUse(m_graph.child(node, i).node());
686    }
687
688    void observeProperArgumentsUse(Node* node, Edge edge)
689    {
690        if (edge->op() != GetLocal) {
691            // When can this happen? At least two cases that I can think
692            // of:
693            //
694            // 1) Aliased use of arguments in the same basic block,
695            //    like:
696            //
697            //    var a = arguments;
698            //    var x = arguments[i];
699            //
700            // 2) If we're accessing arguments we got from the heap!
701
702            if (edge->op() == CreateArguments
703                && node->origin.semantic.inlineCallFrame
704                    != edge->origin.semantic.inlineCallFrame)
705                m_createsArguments.add(edge->origin.semantic.inlineCallFrame);
706
707            return;
708        }
709
710        VariableAccessData* variableAccessData = edge->variableAccessData();
711        if (edge->local() == m_graph.uncheckedArgumentsRegisterFor(edge->origin.semantic)
712            && node->origin.semantic.inlineCallFrame != edge->origin.semantic.inlineCallFrame) {
713            m_createsArguments.add(edge->origin.semantic.inlineCallFrame);
714            return;
715        }
716
717        if (variableAccessData->isCaptured())
718            return;
719
720        ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
721        data.mergeCallContext(node->origin.semantic.inlineCallFrame);
722    }
723
724    bool isOKToOptimize(Node* source)
725    {
726        if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame))
727            return false;
728
729        switch (source->op()) {
730        case GetLocal: {
731            VariableAccessData* variableAccessData = source->variableAccessData();
732            VirtualRegister argumentsRegister =
733                m_graph.uncheckedArgumentsRegisterFor(source->origin.semantic);
734            if (!argumentsRegister.isValid())
735                break;
736            if (argumentsRegister == variableAccessData->local())
737                return true;
738            if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
739                return true;
740            if (variableAccessData->isCaptured())
741                break;
742            ArgumentsAliasingData& data =
743                m_argumentsAliasing.find(variableAccessData)->value;
744            if (!data.isValid())
745                break;
746
747            return true;
748        }
749
750        case CreateArguments: {
751            return true;
752        }
753
754        default:
755            break;
756        }
757
758        return false;
759    }
760
761    void detypeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
762    {
763        Edge edge = node->children.child(edgeIndex);
764        if (!edge)
765            return;
766
767        switch (edge->op()) {
768        case GetLocal: {
769            VariableAccessData* variableAccessData = edge->variableAccessData();
770            if (!variableAccessData->isArgumentsAlias())
771                break;
772            node->children.child(edgeIndex).setUseKind(UntypedUse);
773            break;
774        }
775
776        case PhantomArguments: {
777            node->children.child(edgeIndex).setUseKind(UntypedUse);
778            break;
779        }
780
781        default:
782            break;
783        }
784    }
785};
786
787bool performArgumentsSimplification(Graph& graph)
788{
789    SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
790    return runPhase<ArgumentsSimplificationPhase>(graph);
791}
792
793} } // namespace JSC::DFG
794
795#endif // ENABLE(DFG_JIT)
796
797
798