~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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