DFGCSEPhase.cpp 47.1 KB
Newer Older
1
/*
2
 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "DFGCSEPhase.h"

#if ENABLE(DFG_JIT)

31
#include "DFGEdgeUsesStructure.h"
32 33
#include "DFGGraph.h"
#include "DFGPhase.h"
34
#include "JSCellInlines.h"
35
#include <wtf/FastBitVector.h>
36 37 38

namespace JSC { namespace DFG {

39 40 41
enum CSEMode { NormalCSE, StoreElimination };

template<CSEMode cseMode>
42
class CSEPhase : public Phase {
43
public:
44
    CSEPhase(Graph& graph)
45
        : Phase(graph, cseMode == NormalCSE ? "common subexpression elimination" : "store elimination")
46 47 48
    {
    }
    
49
    bool run()
50
    {
51 52
        ASSERT(m_graph.m_fixpointState != BeforeFixpoint);
        
53
        m_changed = false;
54
        
55 56
        m_graph.clearReplacements();
        
fpizlo@apple.com's avatar
fpizlo@apple.com committed
57 58 59 60 61 62 63 64 65
        if (m_graph.m_form == SSA) {
            Vector<BasicBlock*> depthFirst;
            m_graph.getBlocksInDepthFirstOrder(depthFirst);
            for (unsigned i = 0; i < depthFirst.size(); ++i)
                performBlockCSE(depthFirst[i]);
        } else {
            for (unsigned blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
                performBlockCSE(m_graph.block(blockIndex));
        }
66
        
67
        return m_changed;
68 69 70 71
    }
    
private:
    
72
    unsigned endIndexForPureCSE()
73
    {
74
        unsigned result = m_lastSeen[m_currentNode->op()];
75
        if (result == UINT_MAX)
76 77 78
            result = 0;
        else
            result++;
79
        ASSERT(result <= m_indexInBlock);
80 81
        return result;
    }
82

83
    Node* pureCSE(Node* node)
84
    {
85 86 87
        Edge child1 = node->child1();
        Edge child2 = node->child2();
        Edge child3 = node->child3();
88
        
89
        for (unsigned i = endIndexForPureCSE(); i--;) {
90 91
            Node* otherNode = m_currentBlock->at(i);
            if (otherNode == child1 || otherNode == child2 || otherNode == child3)
92 93
                break;

94
            if (node->op() != otherNode->op())
95 96
                continue;
            
97
            if (node->arithNodeFlags() != otherNode->arithNodeFlags())
98 99
                continue;
            
100
            Edge otherChild = otherNode->child1();
101 102
            if (!otherChild)
                return otherNode;
103 104 105
            if (otherChild != child1)
                continue;
            
106
            otherChild = otherNode->child2();
107 108
            if (!otherChild)
                return otherNode;
109 110 111
            if (otherChild != child2)
                continue;
            
112
            otherChild = otherNode->child3();
113 114
            if (!otherChild)
                return otherNode;
115 116 117
            if (otherChild != child3)
                continue;
            
118
            return otherNode;
119
        }
120
        return 0;
121 122
    }
    
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    Node* int32ToDoubleCSE(Node* node)
    {
        for (unsigned i = m_indexInBlock; i--;) {
            Node* otherNode = m_currentBlock->at(i);
            if (otherNode == node->child1())
                return 0;
            switch (otherNode->op()) {
            case Int32ToDouble:
                if (otherNode->child1() == node->child1())
                    return otherNode;
                break;
            default:
                break;
            }
        }
        return 0;
    }
    
141
    Node* constantCSE(Node* node)
142 143
    {
        for (unsigned i = endIndexForPureCSE(); i--;) {
144 145
            Node* otherNode = m_currentBlock->at(i);
            if (otherNode->op() != JSConstant)
146 147
                continue;
            
148 149 150 151
            if (otherNode->constantNumber() != node->constantNumber())
                continue;
            
            return otherNode;
152
        }
153
        return 0;
154 155
    }
    
156
    Node* weakConstantCSE(Node* node)
157 158
    {
        for (unsigned i = endIndexForPureCSE(); i--;) {
159 160 161 162 163
            Node* otherNode = m_currentBlock->at(i);
            if (otherNode->op() != WeakJSConstant)
                continue;
            
            if (otherNode->weakConstant() != node->weakConstant())
164 165
                continue;
            
166
            return otherNode;
167
        }
168
        return 0;
169 170
    }
    
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    Node* constantStoragePointerCSE(Node* node)
    {
        for (unsigned i = endIndexForPureCSE(); i--;) {
            Node* otherNode = m_currentBlock->at(i);
            if (otherNode->op() != ConstantStoragePointer)
                continue;
            
            if (otherNode->storagePointer() != node->storagePointer())
                continue;
            
            return otherNode;
        }
        return 0;
    }
    
186
    Node* getCalleeLoadElimination()
187 188
    {
        for (unsigned i = m_indexInBlock; i--;) {
189 190
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
191
            case GetCallee:
192
                return node;
193 194 195 196
            default:
                break;
            }
        }
197
        return 0;
198 199
    }
    
200
    Node* getArrayLengthElimination(Node* array)
201
    {
202
        for (unsigned i = m_indexInBlock; i--;) {
203 204
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
205
            case GetArrayLength:
206 207
                if (node->child1() == array)
                    return node;
208 209
                break;
                
210
            case PutByValDirect:
211 212
            case PutByVal:
                if (!m_graph.byValIsPure(node))
213 214 215
                    return 0;
                if (node->arrayMode().mayStoreToHole())
                    return 0;
216
                break;
217 218
                
            default:
219 220
                if (m_graph.clobbersWorld(node))
                    return 0;
221
            }
222
        }
223
        return 0;
224 225
    }
    
226
    Node* globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer)
227
    {
228
        for (unsigned i = m_indexInBlock; i--;) {
229 230
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
231
            case GetGlobalVar:
232 233
                if (node->registerPointer() == registerPointer)
                    return node;
234 235
                break;
            case PutGlobalVar:
236 237
                if (node->registerPointer() == registerPointer)
                    return node->child1().node();
238 239 240 241
                break;
            default:
                break;
            }
242
            if (m_graph.clobbersWorld(node))
243 244
                break;
        }
245
        return 0;
246 247
    }
    
fpizlo@apple.com's avatar
fpizlo@apple.com committed
248
    Node* scopedVarLoadElimination(Node* registers, int varNumber)
249 250
    {
        for (unsigned i = m_indexInBlock; i--;) {
251 252
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
253
            case GetClosureVar: {
254 255
                if (node->child1() == registers && node->varNumber() == varNumber)
                    return node;
256 257
                break;
            } 
258
            case PutClosureVar: {
259 260 261
                if (node->varNumber() != varNumber)
                    break;
                if (node->child2() == registers)
262
                    return node->child3().node();
263
                return 0;
264
            }
265
            case SetLocal: {
266
                VariableAccessData* variableAccessData = node->variableAccessData();
267 268
                if (variableAccessData->isCaptured()
                    && variableAccessData->local() == static_cast<VirtualRegister>(varNumber))
269
                    return 0;
270 271
                break;
            }
272 273 274
            default:
                break;
            }
275
            if (m_graph.clobbersWorld(node))
276 277
                break;
        }
278
        return 0;
279 280
    }
    
281 282 283 284 285 286 287 288 289 290 291
    bool varInjectionWatchpointElimination()
    {
        for (unsigned i = m_indexInBlock; i--;) {
            Node* node = m_currentBlock->at(i);
            if (node->op() == VarInjectionWatchpoint)
                return true;
            if (m_graph.clobbersWorld(node))
                break;
        }
        return false;
    }
292
    
293
    Node* globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer)
294 295
    {
        for (unsigned i = m_indexInBlock; i--;) {
296 297
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
298
            case PutGlobalVar:
299 300
                if (node->registerPointer() == registerPointer)
                    return node;
301 302 303
                break;
                
            case GetGlobalVar:
304 305
                if (node->registerPointer() == registerPointer)
                    return 0;
306 307 308 309 310
                break;
                
            default:
                break;
            }
311 312
            if (m_graph.clobbersWorld(node) || node->canExit())
                return 0;
313
        }
314
        return 0;
315 316
    }
    
fpizlo@apple.com's avatar
fpizlo@apple.com committed
317
    Node* scopedVarStoreElimination(Node* scope, Node* registers, int varNumber)
318 319
    {
        for (unsigned i = m_indexInBlock; i--;) {
320 321
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
322
            case PutClosureVar: {
323 324 325
                if (node->varNumber() != varNumber)
                    break;
                if (node->child1() == scope && node->child2() == registers)
326
                    return node;
327
                return 0;
328 329
            }
                
330
            case GetClosureVar: {
331
                // Let's be conservative.
332 333
                if (node->varNumber() == varNumber)
                    return 0;
334 335
                break;
            }
336
                
fpizlo@apple.com's avatar
fpizlo@apple.com committed
337 338
            case GetLocal:
            case SetLocal: {
339
                VariableAccessData* variableAccessData = node->variableAccessData();
340 341
                if (variableAccessData->isCaptured()
                    && variableAccessData->local() == static_cast<VirtualRegister>(varNumber))
342
                    return 0;
343 344
                break;
            }
345 346 347 348

            default:
                break;
            }
349 350
            if (m_graph.clobbersWorld(node) || node->canExit())
                return 0;
351
        }
352
        return 0;
353 354
    }
    
355
    Node* getByValLoadElimination(Node* child1, Node* child2, ArrayMode arrayMode)
356
    {
357
        for (unsigned i = m_indexInBlock; i--;) {
358
            Node* node = m_currentBlock->at(i);
359
            if (node == child1 || node == child2) 
360 361
                break;

362
            switch (node->op()) {
363
            case GetByVal:
364
                if (!m_graph.byValIsPure(node))
365
                    return 0;
366 367 368
                if (node->child1() == child1
                    && node->child2() == child2
                    && node->arrayMode().type() == arrayMode.type())
369
                    return node;
370
                break;
371 372
                    
            case PutByValDirect:
373
            case PutByVal:
374
            case PutByValAlias: {
375
                if (!m_graph.byValIsPure(node))
376
                    return 0;
377 378 379 380 381 382
                // Typed arrays 
                if (arrayMode.typedArrayType() != NotTypedArray)
                    return 0;
                if (m_graph.varArgChild(node, 0) == child1
                    && m_graph.varArgChild(node, 1) == child2
                    && node->arrayMode().type() == arrayMode.type())
383
                    return m_graph.varArgChild(node, 2).node();
384 385 386
                // We must assume that the PutByVal will clobber the location we're getting from.
                // FIXME: We can do better; if we know that the PutByVal is accessing an array of a
                // different type than the GetByVal, then we know that they won't clobber each other.
387 388
                // ... except of course for typed arrays, where all typed arrays clobber all other
                // typed arrays!  An Int32Array can alias a Float64Array for example, and so on.
389
                return 0;
390
            }
391
            default:
392 393
                if (m_graph.clobbersWorld(node))
                    return 0;
394 395 396
                break;
            }
        }
397
        return 0;
398 399
    }

400
    bool checkFunctionElimination(JSCell* function, Node* child1)
401
    {
402
        for (unsigned i = endIndexForPureCSE(); i--;) {
403 404
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
405 406
                break;

407
            if (node->op() == CheckFunction && node->child1() == child1 && node->function() == function)
408 409 410 411
                return true;
        }
        return false;
    }
412
    
413
    bool checkExecutableElimination(ExecutableBase* executable, Node* child1)
414 415
    {
        for (unsigned i = endIndexForPureCSE(); i--;) {
416 417
            Node* node = m_currentBlock->at(i);
            if (node == child1)
418 419
                break;

420
            if (node->op() == CheckExecutable && node->child1() == child1 && node->executable() == executable)
421 422 423 424
                return true;
        }
        return false;
    }
425

426
    bool checkStructureElimination(const StructureSet& structureSet, Node* child1)
427
    {
428
        for (unsigned i = m_indexInBlock; i--;) {
429 430
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
431 432
                break;

433
            switch (node->op()) {
434
            case CheckStructure:
435 436
                if (node->child1() == child1
                    && structureSet.isSupersetOf(node->structureSet()))
437 438 439
                    return true;
                break;
                
440
            case StructureTransitionWatchpoint:
441 442
                if (node->child1() == child1
                    && structureSet.contains(node->structure()))
443 444 445
                    return true;
                break;
                
446
            case PutStructure:
447 448
                if (node->child1() == child1
                    && structureSet.contains(node->structureTransitionData().newStructure))
449
                    return true;
450
                if (structureSet.contains(node->structureTransitionData().previousStructure))
451 452 453 454 455 456
                    return false;
                break;
                
            case PutByOffset:
                // Setting a property cannot change the structure.
                break;
457 458
                    
            case PutByValDirect:
459 460
            case PutByVal:
            case PutByValAlias:
461
                if (m_graph.byValIsPure(node)) {
462 463 464 465 466 467 468
                    // If PutByVal speculates that it's accessing an array with an
                    // integer index, then it's impossible for it to cause a structure
                    // change.
                    break;
                }
                return false;
                
469 470 471 472 473 474
            case Arrayify:
            case ArrayifyToStructure:
                // We could check if the arrayification could affect our structures.
                // But that seems like it would take Effort.
                return false;
                
475
            default:
476
                if (m_graph.clobbersWorld(node))
477 478 479 480 481 482 483
                    return false;
                break;
            }
        }
        return false;
    }
    
484
    bool structureTransitionWatchpointElimination(Structure* structure, Node* child1)
485 486
    {
        for (unsigned i = m_indexInBlock; i--;) {
487 488
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
489 490
                break;

491
            switch (node->op()) {
492
            case CheckStructure:
493 494
                if (node->child1() == child1
                    && node->structureSet().containsOnly(structure))
495 496 497 498
                    return true;
                break;
                
            case PutStructure:
499
                ASSERT(node->structureTransitionData().previousStructure != structure);
500 501 502 503 504
                break;
                
            case PutByOffset:
                // Setting a property cannot change the structure.
                break;
505 506
                    
            case PutByValDirect:
507 508 509 510 511 512 513 514 515 516 517
            case PutByVal:
            case PutByValAlias:
                if (m_graph.byValIsPure(node)) {
                    // If PutByVal speculates that it's accessing an array with an
                    // integer index, then it's impossible for it to cause a structure
                    // change.
                    break;
                }
                return false;
                
            case StructureTransitionWatchpoint:
518
                if (node->structure() == structure && node->child1() == child1)
519 520 521
                    return true;
                break;
                
522 523 524 525 526 527
            case Arrayify:
            case ArrayifyToStructure:
                // We could check if the arrayification could affect our structures.
                // But that seems like it would take Effort.
                return false;
                
528
            default:
529
                if (m_graph.clobbersWorld(node))
530 531 532 533 534 535 536
                    return false;
                break;
            }
        }
        return false;
    }
    
537
    Node* putStructureStoreElimination(Node* child1)
538 539
    {
        for (unsigned i = m_indexInBlock; i--;) {
540 541
            Node* node = m_currentBlock->at(i);
            if (node == child1)
542
                break;
543
            switch (node->op()) {
544
            case CheckStructure:
545
                return 0;
546 547
                
            case PhantomPutStructure:
548 549
                if (node->child1() == child1) // No need to retrace our steps.
                    return 0;
550 551 552
                break;
                
            case PutStructure:
553 554
                if (node->child1() == child1)
                    return node;
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
                break;
                
            // PutStructure needs to execute if we GC. Hence this needs to
            // be careful with respect to nodes that GC.
            case CreateArguments:
            case TearOffArguments:
            case NewFunctionNoCheck:
            case NewFunction:
            case NewFunctionExpression:
            case CreateActivation:
            case TearOffActivation:
            case ToPrimitive:
            case NewRegexp:
            case NewArrayBuffer:
            case NewArray:
            case NewObject:
            case CreateThis:
572 573
            case AllocatePropertyStorage:
            case ReallocatePropertyStorage:
574
            case TypeOf:
575 576
            case ToString:
            case NewStringObject:
577
            case MakeRope:
578
            case NewTypedArray:
579
                return 0;
580
                
581 582 583 584 585 586
            // This either exits, causes a GC (lazy string allocation), or clobbers
            // the world. The chances of it not doing any of those things are so
            // slim that we might as well not even try to reason about it.
            case GetByVal:
                return 0;
                
587
            case GetIndexedPropertyStorage:
588 589
                if (node->arrayMode().getIndexedPropertyStorageMayTriggerGC())
                    return 0;
590 591
                break;
                
592 593 594
            default:
                break;
            }
595 596
            if (m_graph.clobbersWorld(node) || node->canExit())
                return 0;
597 598
            if (edgesUseStructure(m_graph, node))
                return 0;
599
        }
600
        return 0;
601 602
    }
    
603
    Node* getByOffsetLoadElimination(unsigned identifierNumber, Node* child1)
604
    {
605
        for (unsigned i = m_indexInBlock; i--;) {
606 607
            Node* node = m_currentBlock->at(i);
            if (node == child1)
608 609
                break;

610
            switch (node->op()) {
611
            case GetByOffset:
612 613 614
                if (node->child1() == child1
                    && m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber)
                    return node;
615 616 617
                break;
                
            case PutByOffset:
618 619 620 621
                if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) {
                    if (node->child1() == child1) // Must be same property storage.
                        return node->child3().node();
                    return 0;
622 623
                }
                break;
624 625
                    
            case PutByValDirect:
626 627
            case PutByVal:
            case PutByValAlias:
628
                if (m_graph.byValIsPure(node)) {
629 630 631 632 633
                    // If PutByVal speculates that it's accessing an array with an
                    // integer index, then it's impossible for it to cause a structure
                    // change.
                    break;
                }
634
                return 0;
635 636
                
            default:
637 638
                if (m_graph.clobbersWorld(node))
                    return 0;
639 640 641
                break;
            }
        }
642
        return 0;
643 644
    }
    
645
    Node* putByOffsetStoreElimination(unsigned identifierNumber, Node* child1)
646 647
    {
        for (unsigned i = m_indexInBlock; i--;) {
648 649
            Node* node = m_currentBlock->at(i);
            if (node == child1)
650 651
                break;

652
            switch (node->op()) {
653
            case GetByOffset:
654 655
                if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber)
                    return 0;
656 657 658
                break;
                
            case PutByOffset:
659 660 661 662
                if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) {
                    if (node->child1() == child1) // Must be same property storage.
                        return node;
                    return 0;
663 664
                }
                break;
665 666
                    
            case PutByValDirect:
667 668 669 670 671 672 673 674 675
            case PutByVal:
            case PutByValAlias:
            case GetByVal:
                if (m_graph.byValIsPure(node)) {
                    // If PutByVal speculates that it's accessing an array with an
                    // integer index, then it's impossible for it to cause a structure
                    // change.
                    break;
                }
676
                return 0;
677 678
                
            default:
679 680
                if (m_graph.clobbersWorld(node))
                    return 0;
681 682
                break;
            }
683 684
            if (node->canExit())
                return 0;
685
        }
686
        return 0;
687 688
    }
    
689
    Node* getPropertyStorageLoadElimination(Node* child1)
690
    {
691
        for (unsigned i = m_indexInBlock; i--;) {
692 693
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
694 695
                break;

696
            switch (node->op()) {
697
            case GetButterfly:
698 699
                if (node->child1() == child1)
                    return node;
700
                break;
701 702 703 704 705

            case AllocatePropertyStorage:
            case ReallocatePropertyStorage:
                // If we can cheaply prove this is a change to our object's storage, we
                // can optimize and use its result.
706 707
                if (node->child1() == child1)
                    return node;
708 709 710
                // Otherwise, we currently can't prove that this doesn't change our object's
                // storage, so we conservatively assume that it may change the storage
                // pointer of any object, including ours.
711
                return 0;
712 713
                    
            case PutByValDirect:
714 715
            case PutByVal:
            case PutByValAlias:
716
                if (m_graph.byValIsPure(node)) {
717 718 719 720 721
                    // If PutByVal speculates that it's accessing an array with an
                    // integer index, then it's impossible for it to cause a structure
                    // change.
                    break;
                }
722
                return 0;
723
                
724 725 726 727
            case Arrayify:
            case ArrayifyToStructure:
                // We could check if the arrayification could affect our butterfly.
                // But that seems like it would take Effort.
728
                return 0;
729
                
730
            default:
731 732
                if (m_graph.clobbersWorld(node))
                    return 0;
733 734 735
                break;
            }
        }
736
        return 0;
737
    }
738
    
739
    bool checkArrayElimination(Node* child1, ArrayMode arrayMode)
740 741
    {
        for (unsigned i = m_indexInBlock; i--;) {
742 743
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
744
                break;
745

746
            switch (node->op()) {
747
            case CheckArray:
748
                if (node->child1() == child1 && node->arrayMode() == arrayMode)
749 750 751
                    return true;
                break;
                
752 753 754 755 756 757
            case Arrayify:
            case ArrayifyToStructure:
                // We could check if the arrayification could affect our array.
                // But that seems like it would take Effort.
                return false;
                
758
            default:
759
                if (m_graph.clobbersWorld(node))
760 761 762 763 764 765 766
                    return false;
                break;
            }
        }
        return false;
    }

767
    Node* getIndexedPropertyStorageLoadElimination(Node* child1, ArrayMode arrayMode)
768
    {
769
        for (unsigned i = m_indexInBlock; i--;) {
770 771
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
772 773
                break;

774
            switch (node->op()) {
775
            case GetIndexedPropertyStorage: {
776 777
                if (node->child1() == child1 && node->arrayMode() == arrayMode)
                    return node;
778 779 780
                break;
            }

781 782 783
            default:
                if (m_graph.clobbersWorld(node))
                    return 0;
784
                break;
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
            }
        }
        return 0;
    }
    
    Node* getTypedArrayByteOffsetLoadElimination(Node* child1)
    {
        for (unsigned i = m_indexInBlock; i--;) {
            Node* node = m_currentBlock->at(i);
            if (node == child1) 
                break;

            switch (node->op()) {
            case GetTypedArrayByteOffset: {
                if (node->child1() == child1)
                    return node;
                break;
            }

804
            default:
805 806
                if (m_graph.clobbersWorld(node))
                    return 0;
807 808 809
                break;
            }
        }
810
        return 0;
811 812
    }
    
813
    Node* getMyScopeLoadElimination()
814
    {
815
        for (unsigned i = m_indexInBlock; i--;) {
816 817
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
818 819
            case CreateActivation:
                // This may cause us to return a different scope.
820
                return 0;
821
            case GetMyScope:
822
                return node;
823 824 825
            default:
                break;
            }
826
        }
827
        return 0;
828
    }
829
    
830
    Node* getLocalLoadElimination(VirtualRegister local, Node*& relevantLocalOp, bool careAboutClobbering)
831
    {
832
        relevantLocalOp = 0;
833
        
834
        for (unsigned i = m_indexInBlock; i--;) {
835 836
            Node* node = m_currentBlock->at(i);
            switch (node->op()) {
837
            case GetLocal: