~ubuntu-branches/ubuntu/wily/proguard/wily

« back to all changes in this revision

Viewing changes to src/proguard/optimize/evaluation/EvaluationShrinker.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2014-04-10 13:58:11 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20140410135811-ddwzt2avu94rnolt
Tags: 4.11-1
* Team upload.
* New upstream release
* Removed the non-free documentation from the package (Closes: #719706)
* Removed the pre-built jars from the upstream tarball
* debian/control:
  - The package is now co-maintained with the Java Team
  - Standards-Version updated to 3.9.5 (no changes)
  - Added the Vcs-* fields
  - Added the Homepage field
* Switch to debhelper level 9
* Use XZ compression for the upstream tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3
3
 *             of Java bytecode.
4
4
 *
5
 
 * Copyright (c) 2002-2012 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
7
7
 * This program is free software; you can redistribute it and/or modify it
8
8
 * under the terms of the GNU General Public License as published by the Free
30
30
import proguard.classfile.instruction.visitor.InstructionVisitor;
31
31
import proguard.classfile.util.*;
32
32
import proguard.classfile.visitor.*;
33
 
import proguard.evaluation.*;
 
33
import proguard.evaluation.TracedStack;
34
34
import proguard.evaluation.value.*;
35
35
import proguard.optimize.info.*;
36
36
 
50
50
    private static final boolean DEBUG_RESULTS  = false;
51
51
    private static final boolean DEBUG          = false;
52
52
    /*/
53
 
    private static boolean DEBUG_RESULTS  = true;
54
 
    private static boolean DEBUG          = true;
 
53
    private static boolean DEBUG          = System.getProperty("es") != null;
 
54
    private static boolean DEBUG_RESULTS  = DEBUG;
55
55
    //*/
56
56
 
57
57
    private static final int UNSUPPORTED      = -1;
93
93
 
94
94
    private final PartialEvaluator               partialEvaluator;
95
95
    private final PartialEvaluator               simplePartialEvaluator       = new PartialEvaluator();
96
 
    private final SideEffectInstructionChecker   sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
 
96
    private final SideEffectInstructionChecker   sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
97
97
    private final MyUnusedParameterSimplifier    unusedParameterSimplifier    = new MyUnusedParameterSimplifier();
98
98
    private final MyProducerMarker               producerMarker               = new MyProducerMarker();
99
99
    private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker();
100
100
    private final MyStackConsistencyFixer        stackConsistencyFixer        = new MyStackConsistencyFixer();
101
 
    private final CodeAttributeEditor            codeAttributeEditor          = new CodeAttributeEditor(false);
 
101
    private final CodeAttributeEditor            codeAttributeEditor          = new CodeAttributeEditor(false, false);
102
102
 
103
 
    private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE];
104
 
    private boolean[][] stacksNecessaryAfter    = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
105
 
    private boolean[][] stacksSimplifiedBefore  = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
106
 
    private boolean[]   instructionsNecessary   = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
 
103
    private boolean[][] stacksNecessaryAfter   = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
 
104
    private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
 
105
    private boolean[]   instructionsNecessary  = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
107
106
 
108
107
    private int maxMarkedOffset;
109
108
 
178
177
        if (DEBUG_RESULTS)
179
178
        {
180
179
            System.out.println();
181
 
            System.out.println("Class "+ClassUtil.externalClassName(clazz.getName()));
182
 
            System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(),
183
 
                                                                                 0,
184
 
                                                                                 method.getName(clazz),
185
 
                                                                                 method.getDescriptor(clazz)));
 
180
            System.out.println("EvaluationShrinker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
186
181
        }
187
182
 
188
183
        // Initialize the necessary array.
191
186
        // Evaluate the method.
192
187
        partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
193
188
 
 
189
        // Evaluate the method the way the JVM verifier would do it.
 
190
        simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
 
191
 
194
192
        int codeLength = codeAttribute.u4codeLength;
195
193
 
196
194
        // Reset the code changes.
309
307
 
310
308
        for (int offset = 0; offset < codeLength; offset++)
311
309
        {
312
 
            // Is it a variable initialization that hasn't been marked yet?
313
 
            if (partialEvaluator.isTraced(offset) &&
314
 
                !isInstructionNecessary(offset))
 
310
            if (isInstructionNecessary(offset))
315
311
            {
 
312
                // Mark initializations of the required instruction.
316
313
                Instruction instruction = InstructionFactory.create(codeAttribute.code,
317
314
                                                                    offset);
318
315
 
412
409
                                                                offset);
413
410
            if (!isInstructionNecessary(offset))
414
411
            {
 
412
                codeAttributeEditor.clearModifications(offset);
415
413
                codeAttributeEditor.deleteInstruction(offset);
416
414
 
417
 
                codeAttributeEditor.insertBeforeInstruction(offset, (Instruction)null);
418
 
                codeAttributeEditor.replaceInstruction(offset,      (Instruction)null);
419
 
                codeAttributeEditor.insertAfterInstruction(offset,  (Instruction)null);
420
 
 
421
415
                // Visit the instruction, if required.
422
416
                if (extraDeletedInstructionVisitor != null)
423
417
                {
645
639
 
646
640
        public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
647
641
        {
648
 
            // Is the variable being loaded (or incremented)?
649
 
            if (variableInstruction.opcode < InstructionConstants.OP_ISTORE)
 
642
            // Is the variable being loaded or incremented?
 
643
            if (variableInstruction.isLoad())
650
644
            {
651
645
                markVariableProducers(offset, variableInstruction.variableIndex);
652
646
            }
702
696
 
703
697
        public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
704
698
        {
705
 
            if (!variableInstruction.isLoad())
 
699
            // Is the variable being loaded or incremented?
 
700
            if (variableInstruction.isLoad())
706
701
            {
707
 
                int variableIndex = variableInstruction.variableIndex;
708
 
 
709
 
                if (isVariableInitialization(offset,
710
 
                                             variableIndex) &&
711
 
                    isVariableInitializationNecessary(clazz,
712
 
                                                      method,
713
 
                                                      codeAttribute,
714
 
                                                      offset,
715
 
                                                      variableIndex))
716
 
                {
717
 
                    markInstruction(offset);
718
 
                }
 
702
                // Mark any variable initializations for this variable load that
 
703
                // are required according to the JVM.
 
704
                markVariableInitializersBefore(offset, variableInstruction.variableIndex);
719
705
            }
720
706
        }
721
707
    }
739
725
            if (isInstructionNecessary(offset))
740
726
            {
741
727
                // Check all stack entries that are popped.
 
728
                // Unusual case: an exception handler with an exception that is
 
729
                // no longer consumed directly by a method.
742
730
                // Typical case: a freshly marked variable initialization that
743
731
                // requires some value on the stack.
744
732
                int popCount = instruction.stackPopCount(clazz);
749
737
 
750
738
                    int stackSize = tracedStack.size();
751
739
 
 
740
                    int requiredPopCount  = 0;
752
741
                    int requiredPushCount = 0;
753
742
                    for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
754
743
                    {
755
 
                        if (!isStackSimplifiedBefore(offset, stackIndex))
 
744
                        boolean stackSimplifiedBefore =
 
745
                            isStackSimplifiedBefore(offset, stackIndex);
 
746
                        boolean stackEntryPresentBefore =
 
747
                            isStackEntryPresentBefore(offset, stackIndex);
 
748
 
 
749
                        if (stackSimplifiedBefore)
 
750
                        {
 
751
                            // Is this stack entry pushed by any producer
 
752
                            // (maybe an exception in an exception handler)?
 
753
                            if (isStackEntryPresentBefore(offset, stackIndex))
 
754
                            {
 
755
                                // Mark all produced stack entries.
 
756
                                markStackEntryProducers(offset, stackIndex);
 
757
 
 
758
                                // Remember to pop it.
 
759
                                requiredPopCount++;
 
760
                            }
 
761
                        }
 
762
                        else
756
763
                        {
757
764
                            // Is this stack entry pushed by any producer
758
765
                            // (because it is required by other consumers)?
759
 
                            if (isStackEntryPresentBefore(offset, stackIndex))
 
766
                            if (stackEntryPresentBefore)
760
767
                            {
761
768
                                // Mark all produced stack entries.
762
769
                                markStackEntryProducers(offset, stackIndex);
769
776
                        }
770
777
                    }
771
778
 
 
779
                    // Pop some unnecessary stack entries.
 
780
                    if (requiredPopCount > 0)
 
781
                    {
 
782
                        if (DEBUG) System.out.println("  Inserting before marked consumer "+instruction.toString(offset));
 
783
 
 
784
                        insertPopInstructions(offset, false, true, popCount);
 
785
                    }
 
786
 
772
787
                    // Push some necessary stack entries.
773
788
                    if (requiredPushCount > 0)
774
789
                    {
776
791
 
777
792
                        if (requiredPushCount > (instruction.isCategory2() ? 2 : 1))
778
793
                        {
779
 
                            throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"]");
 
794
                            throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]");
780
795
                        }
781
796
 
782
 
                        insertPushInstructions(offset, false, tracedStack.getTop(0).computationalType());
 
797
                        insertPushInstructions(offset, false, true, tracedStack.getTop(0).computationalType());
783
798
                    }
784
799
                }
785
800
 
836
851
                    {
837
852
                        if (DEBUG) System.out.println("  Inserting after marked producer "+instruction.toString(offset));
838
853
 
839
 
                        insertPopInstructions(offset, false, requiredPopCount);
 
854
                        insertPopInstructions(offset, false, false, requiredPopCount);
840
855
                    }
841
856
                }
842
857
            }
873
888
                    {
874
889
                        if (DEBUG) System.out.println("  Replacing unmarked consumer "+instruction.toString(offset));
875
890
 
876
 
                        insertPopInstructions(offset, true, expectedPopCount);
 
891
                        insertPopInstructions(offset, true, false, expectedPopCount);
877
892
                    }
878
893
                }
879
894
 
903
918
                    {
904
919
                        if (DEBUG) System.out.println("  Replacing unmarked producer "+instruction.toString(offset));
905
920
 
906
 
                        insertPushInstructions(offset, true, tracedStack.getTop(0).computationalType());
 
921
                        insertPushInstructions(offset, true, false, tracedStack.getTop(0).computationalType());
907
922
                    }
908
923
                }
909
924
            }
910
925
        }
911
926
 
912
 
        
 
927
 
913
928
        public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
914
929
        {
915
930
            if (isInstructionNecessary(offset) &&
1065
1080
                    stackEntryNecessary1 ? DUP : // ...O -> ...OO
1066
1081
                                           NOP : // ...O -> ...O
1067
1082
                stackEntryNecessary1     ? NOP : // ...O -> ...O
1068
 
                stackEntryPresent0       ? POP : // ...O -> ...  
 
1083
                stackEntryPresent0       ? POP : // ...O -> ...
1069
1084
                                           NOP;  // ...  -> ...
1070
1085
        }
1071
1086
 
1211
1226
            boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
1212
1227
            boolean stackEntryNecessary3 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 3);
1213
1228
 
1214
 
            return 
 
1229
            return
1215
1230
                stackEntryNecessary3 ?
1216
1231
                    stackEntryNecessary2 ?
1217
1232
                        stackEntryNecessary1 ?
1417
1432
    // Small utility methods.
1418
1433
 
1419
1434
    /**
1420
 
     * Marks the variable and the corresponding producing instructions
1421
 
     * of the consumer at the given offset.
1422
 
     * @param consumerOffset the offset of the consumer.
1423
 
     * @param variableIndex  the index of the variable to be marked.
 
1435
     * Marks the producing instructions of the variable consumer at the given
 
1436
     * offset.
 
1437
     * @param consumerOffset the offset of the variable consumer.
 
1438
     * @param variableIndex  the index of the variable that is loaded.
1424
1439
     */
1425
1440
    private void markVariableProducers(int consumerOffset,
1426
1441
                                       int variableIndex)
1427
1442
    {
1428
 
        TracedVariables tracedVariables =
1429
 
            partialEvaluator.getVariablesBefore(consumerOffset);
1430
 
 
1431
 
        // Mark the producer of the loaded value.
1432
 
        markVariableProducers(tracedVariables.getProducerValue(variableIndex).instructionOffsetValue(),
1433
 
                              variableIndex);
1434
 
    }
1435
 
 
1436
 
 
1437
 
    /**
1438
 
     * Marks the variable and its producing instructions at the given offsets.
1439
 
     * @param producerOffsets the offsets of the producers to be marked.
1440
 
     * @param variableIndex   the index of the variable to be marked.
1441
 
     */
1442
 
    private void markVariableProducers(InstructionOffsetValue producerOffsets,
1443
 
                                       int                    variableIndex)
1444
 
    {
 
1443
        InstructionOffsetValue producerOffsets =
 
1444
            partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
 
1445
 
1445
1446
        if (producerOffsets != null)
1446
1447
        {
1447
1448
            int offsetCount = producerOffsets.instructionOffsetCount();
1451
1452
                // at the producing offset.
1452
1453
                int offset = producerOffsets.instructionOffset(offsetIndex);
1453
1454
 
1454
 
                markVariableAfter(offset, variableIndex);
1455
1455
                markInstruction(offset);
1456
1456
            }
1457
1457
        }
1459
1459
 
1460
1460
 
1461
1461
    /**
 
1462
     * Ensures that the given variable is initialized before the specified
 
1463
     * consumer of that variable, in the JVM's view.
 
1464
     * @param consumerOffset the instruction offset before which the variable
 
1465
     *                       needs to be initialized.
 
1466
     * @param variableIndex  the index of the variable.
 
1467
     */
 
1468
    private void markVariableInitializersBefore(int consumerOffset,
 
1469
                                                int variableIndex)
 
1470
    {
 
1471
        // Make sure the variable is initialized after all producers.
 
1472
        // Use the simple evaluator, to get the JVM's view of what is
 
1473
        // initialized.
 
1474
        InstructionOffsetValue producerOffsets =
 
1475
            simplePartialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
 
1476
 
 
1477
        int offsetCount = producerOffsets.instructionOffsetCount();
 
1478
        for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
 
1479
        {
 
1480
            // Avoid infinite loops by only looking at producers before
 
1481
            // the consumer.
 
1482
            int producerOffset =
 
1483
                producerOffsets.instructionOffset(offsetIndex);
 
1484
            if (producerOffset < consumerOffset)
 
1485
            {
 
1486
                markVariableInitializersAfter(producerOffset, variableIndex);
 
1487
            }
 
1488
        }
 
1489
    }
 
1490
 
 
1491
 
 
1492
    /**
 
1493
     * Ensures that the given variable is initialized after the specified
 
1494
     * producer of that variable, in the JVM's view.
 
1495
     * @param producerOffset the instruction offset after which the variable
 
1496
     *                       needs to be initialized.
 
1497
     * @param variableIndex  the index of the variable.
 
1498
     */
 
1499
    private void markVariableInitializersAfter(int producerOffset,
 
1500
                                               int variableIndex)
 
1501
    {
 
1502
        // No problem if the producer has already been marked.
 
1503
        if (!isInstructionNecessary(producerOffset))
 
1504
        {
 
1505
            // Is the unmarked producer a variable initialization?
 
1506
            if (isVariableInitialization(producerOffset, variableIndex))
 
1507
            {
 
1508
                // Mark the producer.
 
1509
                if (DEBUG) System.out.print("  Marking initialization of v"+variableIndex+" at ");
 
1510
 
 
1511
                markInstruction(producerOffset);
 
1512
 
 
1513
                if (DEBUG) System.out.println();
 
1514
            }
 
1515
            else
 
1516
            {
 
1517
                // Don't mark the producer, but recursively look at the
 
1518
                // preceding producers of the same variable. Their values
 
1519
                // will fall through, replacing this producer.
 
1520
                markVariableInitializersBefore(producerOffset, variableIndex);
 
1521
            }
 
1522
        }
 
1523
    }
 
1524
 
 
1525
 
 
1526
    /**
1462
1527
     * Marks the stack entries and their producing instructions of the
1463
1528
     * consumer at the given offset.
1464
1529
     * @param clazz          the containing class.
1635
1700
     */
1636
1701
    private void insertPushInstructions(int     offset,
1637
1702
                                        boolean replace,
 
1703
                                        boolean before,
1638
1704
                                        int     computationalType)
1639
1705
    {
1640
1706
        // Mark this instruction.
1647
1713
        if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset));
1648
1714
 
1649
1715
        // Replace or insert the push instruction.
1650
 
        if (replace)
1651
 
        {
1652
 
            // Replace the push instruction.
1653
 
            codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
1654
 
        }
1655
 
        else
1656
 
        {
1657
 
            // Insert the push instruction.
1658
 
            codeAttributeEditor.insertBeforeInstruction(offset, replacementInstruction);
1659
 
 
1660
 
            if (extraAddedInstructionVisitor != null)
1661
 
            {
1662
 
                replacementInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
1663
 
            }
1664
 
        }
 
1716
        insertInstruction(offset, replace, before, replacementInstruction);
1665
1717
    }
1666
1718
 
1667
1719
 
1690
1742
     * Pops the given number of stack entries at or after the given offset.
1691
1743
     * The instructions are marked as necessary.
1692
1744
     */
1693
 
    private void insertPopInstructions(int offset, boolean replace, int popCount)
 
1745
    private void insertPopInstructions(int     offset,
 
1746
                                       boolean replace,
 
1747
                                       boolean before,
 
1748
                                       int     popCount)
1694
1749
    {
1695
1750
        // Mark this instruction.
1696
1751
        markInstruction(offset);
1703
1758
                Instruction popInstruction =
1704
1759
                    new SimpleInstruction(InstructionConstants.OP_POP);
1705
1760
 
1706
 
                if (replace)
1707
 
                {
1708
 
                    codeAttributeEditor.replaceInstruction(offset, popInstruction);
1709
 
                }
1710
 
                else
1711
 
                {
1712
 
                    codeAttributeEditor.insertAfterInstruction(offset, popInstruction);
1713
 
 
1714
 
                    if (extraAddedInstructionVisitor != null)
1715
 
                    {
1716
 
                        popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
1717
 
                    }
1718
 
                }
 
1761
                insertInstruction(offset, replace, before, popInstruction);
1719
1762
                break;
1720
1763
            }
1721
1764
            case 2:
1724
1767
                Instruction popInstruction =
1725
1768
                    new SimpleInstruction(InstructionConstants.OP_POP2);
1726
1769
 
1727
 
                if (replace)
1728
 
                {
1729
 
                    codeAttributeEditor.replaceInstruction(offset, popInstruction);
1730
 
                }
1731
 
                else
1732
 
                {
1733
 
                    codeAttributeEditor.insertAfterInstruction(offset, popInstruction);
1734
 
 
1735
 
                    if (extraAddedInstructionVisitor != null)
1736
 
                    {
1737
 
                        popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
1738
 
                    }
1739
 
                }
 
1770
                insertInstruction(offset, replace, before, popInstruction);
1740
1771
                break;
1741
1772
            }
1742
1773
            default:
1761
1792
                    popInstructions[popCount / 2] = popInstruction;
1762
1793
                }
1763
1794
 
1764
 
                if (replace)
1765
 
                {
1766
 
                    codeAttributeEditor.replaceInstruction(offset, popInstructions);
1767
 
 
1768
 
                    for (int index = 1; index < popInstructions.length; index++)
1769
 
                    {
1770
 
                        if (extraAddedInstructionVisitor != null)
1771
 
                        {
1772
 
                            popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1773
 
                        }
1774
 
                    }
1775
 
                }
1776
 
                else
1777
 
                {
1778
 
                    codeAttributeEditor.insertAfterInstruction(offset, popInstructions);
1779
 
 
1780
 
                    for (int index = 0; index < popInstructions.length; index++)
1781
 
                    {
1782
 
                        if (extraAddedInstructionVisitor != null)
1783
 
                        {
1784
 
                            popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
1785
 
                        }
1786
 
                    }
1787
 
                }
 
1795
                insertInstructions(offset,
 
1796
                                   replace,
 
1797
                                   before,
 
1798
                                   popInstruction,
 
1799
                                   popInstructions);
1788
1800
                break;
1789
1801
            }
1790
1802
        }
1792
1804
 
1793
1805
 
1794
1806
    /**
 
1807
     * Inserts or replaces the given instruction at the given offset.
 
1808
     */
 
1809
    private void insertInstruction(int         offset,
 
1810
                                   boolean     replace,
 
1811
                                   boolean     before,
 
1812
                                   Instruction instruction)
 
1813
    {
 
1814
        if (replace)
 
1815
        {
 
1816
            codeAttributeEditor.replaceInstruction(offset, instruction);
 
1817
        }
 
1818
        else
 
1819
        {
 
1820
            if (before)
 
1821
            {
 
1822
                codeAttributeEditor.insertBeforeInstruction(offset, instruction);
 
1823
            }
 
1824
            else
 
1825
            {
 
1826
                codeAttributeEditor.insertAfterInstruction(offset, instruction);
 
1827
            }
 
1828
 
 
1829
            if (extraAddedInstructionVisitor != null)
 
1830
            {
 
1831
                instruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
 
1832
            }
 
1833
        }
 
1834
    }
 
1835
 
 
1836
 
 
1837
    /**
 
1838
     * Inserts or replaces the given instruction at the given offset.
 
1839
     */
 
1840
    private void insertInstructions(int           offset,
 
1841
                                    boolean       replace,
 
1842
                                    boolean       before,
 
1843
                                    Instruction   instruction,
 
1844
                                    Instruction[] instructions)
 
1845
    {
 
1846
        if (replace)
 
1847
        {
 
1848
            codeAttributeEditor.replaceInstruction(offset, instructions);
 
1849
 
 
1850
            if (extraAddedInstructionVisitor != null)
 
1851
            {
 
1852
                for (int index = 1; index < instructions.length; index++)
 
1853
                {
 
1854
                    instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
 
1855
                }
 
1856
            }
 
1857
        }
 
1858
        else
 
1859
        {
 
1860
            if (before)
 
1861
            {
 
1862
                codeAttributeEditor.insertBeforeInstruction(offset, instructions);
 
1863
            }
 
1864
            else
 
1865
            {
 
1866
                codeAttributeEditor.insertAfterInstruction(offset, instructions);
 
1867
            }
 
1868
 
 
1869
            for (int index = 0; index < instructions.length; index++)
 
1870
            {
 
1871
                if (extraAddedInstructionVisitor != null)
 
1872
                {
 
1873
                    instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
 
1874
                }
 
1875
            }
 
1876
        }
 
1877
    }
 
1878
 
 
1879
 
 
1880
    /**
1795
1881
     * Replaces the instruction at a given offset by a static invocation.
1796
1882
     */
1797
1883
    private void replaceByStaticInvocation(Clazz               clazz,
1801
1887
        // Remember the replacement instruction.
1802
1888
        Instruction replacementInstruction =
1803
1889
             new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
1804
 
                                     constantInstruction.constantIndex).shrink();
 
1890
                                     constantInstruction.constantIndex);
1805
1891
 
1806
1892
        if (DEBUG) System.out.println("  Replacing by static invocation "+constantInstruction.toString(offset)+" -> "+replacementInstruction.toString());
1807
1893
 
1943
2029
        int maxStack   = codeAttribute.u2maxStack;
1944
2030
 
1945
2031
        // Create new arrays for storing information at each instruction offset.
1946
 
        if (variablesNecessaryAfter.length    < codeLength ||
1947
 
            variablesNecessaryAfter[0].length < maxLocals)
1948
 
        {
1949
 
            variablesNecessaryAfter = new boolean[codeLength][maxLocals];
1950
 
        }
1951
 
        else
1952
 
        {
1953
 
            for (int offset = 0; offset < codeLength; offset++)
1954
 
            {
1955
 
                Arrays.fill(variablesNecessaryAfter[offset], 0, maxLocals, false);
1956
 
            }
1957
 
        }
1958
 
 
1959
2032
        if (stacksNecessaryAfter.length    < codeLength ||
1960
2033
            stacksNecessaryAfter[0].length < maxStack)
1961
2034
        {
2014
2087
            return true;
2015
2088
        }
2016
2089
 
 
2090
        // Is the reference type different now?
 
2091
        if (valueAfter.computationalType() == Value.TYPE_REFERENCE &&
 
2092
            (valueAfter.referenceValue().isNull() == Value.ALWAYS ||
 
2093
             !valueAfter.referenceValue().getType().equals(valueBefore.referenceValue().getType())))
 
2094
        {
 
2095
            return true;
 
2096
        }
 
2097
 
2017
2098
        // Was the producer an argument (which may be removed)?
2018
2099
        Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex);
2019
2100
        return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 &&
2022
2103
 
2023
2104
 
2024
2105
    /**
2025
 
     * Returns whether the specified variable must be initialized at the
2026
 
     * specified offset, according to the verifier of the JVM.
2027
 
     */
2028
 
    private boolean isVariableInitializationNecessary(Clazz         clazz,
2029
 
                                                      Method        method,
2030
 
                                                      CodeAttribute codeAttribute,
2031
 
                                                      int           initializationOffset,
2032
 
                                                      int           variableIndex)
2033
 
    {
2034
 
        int codeLength = codeAttribute.u4codeLength;
2035
 
 
2036
 
        // Is the variable necessary anywhere at all?
2037
 
        if (isVariableNecessaryAfterAny(0, codeLength, variableIndex))
2038
 
        {
2039
 
            if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
2040
 
 
2041
 
            // Lazily perform simple partial evaluation, the way the JVM
2042
 
            // verifier would do it.
2043
 
            simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
2044
 
 
2045
 
            if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
2046
 
 
2047
 
            // Check if the variable is necessary elsewhere.
2048
 
            for (int offset = 0; offset < codeLength; offset++)
2049
 
            {
2050
 
                if (partialEvaluator.isTraced(offset))
2051
 
                {
2052
 
                    Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
2053
 
                    if (producer != null)
2054
 
                    {
2055
 
                        Value simpleProducer = simplePartialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
2056
 
                        if (simpleProducer != null)
2057
 
                        {
2058
 
                            InstructionOffsetValue producerOffsets =
2059
 
                                producer.instructionOffsetValue();
2060
 
                            InstructionOffsetValue simpleProducerOffsets =
2061
 
                                simpleProducer.instructionOffsetValue();
2062
 
 
2063
 
                            if (DEBUG)
2064
 
                            {
2065
 
                                System.out.println("  ["+offset+"] producers ["+producerOffsets+"], simple producers ["+simpleProducerOffsets+"]");
2066
 
                            }
2067
 
 
2068
 
                            // Is the variable being used without all of its
2069
 
                            // immediate simple producers being marked?
2070
 
                            if (isVariableNecessaryAfterAny(producerOffsets, variableIndex) &&
2071
 
                                !isVariableNecessaryAfterAll(simpleProducerOffsets, variableIndex))
2072
 
                            {
2073
 
                                if (DEBUG)
2074
 
                                {
2075
 
                                    System.out.println("    => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] necessary");
2076
 
                                }
2077
 
 
2078
 
                                // Then the initialization may be necessary.
2079
 
                                return true;
2080
 
                            }
2081
 
                        }
2082
 
                    }
2083
 
                }
2084
 
            }
2085
 
        }
2086
 
 
2087
 
        if (DEBUG)
2088
 
        {
2089
 
            System.out.println("    => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] not necessary");
2090
 
        }
2091
 
 
2092
 
        return false;
2093
 
    }
2094
 
 
2095
 
 
2096
 
    private void markVariableAfter(int instructionOffset,
2097
 
                                   int variableIndex)
2098
 
    {
2099
 
        if (!isVariableNecessaryAfter(instructionOffset, variableIndex))
2100
 
        {
2101
 
            if (DEBUG) System.out.print("["+instructionOffset+".v"+variableIndex+"],");
2102
 
 
2103
 
            variablesNecessaryAfter[instructionOffset][variableIndex] = true;
2104
 
 
2105
 
            if (maxMarkedOffset < instructionOffset)
2106
 
            {
2107
 
                maxMarkedOffset = instructionOffset;
2108
 
            }
2109
 
        }
2110
 
    }
2111
 
 
2112
 
 
2113
 
    /**
2114
 
     * Returns whether the specified variable is ever necessary after any
2115
 
     * instructions in the specified block.
2116
 
     */
2117
 
    private boolean isVariableNecessaryAfterAny(int startOffset,
2118
 
                                                int endOffset,
2119
 
                                                int variableIndex)
2120
 
    {
2121
 
        for (int offset = startOffset; offset < endOffset; offset++)
2122
 
        {
2123
 
            if (isVariableNecessaryAfter(offset, variableIndex))
2124
 
            {
2125
 
                return true;
2126
 
            }
2127
 
        }
2128
 
 
2129
 
        return false;
2130
 
    }
2131
 
 
2132
 
 
2133
 
    /**
2134
 
     * Returns whether the specified variable is ever necessary after any
2135
 
     * instructions in the specified set of instructions offsets.
2136
 
     */
2137
 
    private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue,
2138
 
                                                int                    variableIndex)
2139
 
    {
2140
 
        int count = instructionOffsetValue.instructionOffsetCount();
2141
 
 
2142
 
        for (int index = 0; index < count; index++)
2143
 
        {
2144
 
            if (isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index),
2145
 
                                         variableIndex))
2146
 
            {
2147
 
                return true;
2148
 
            }
2149
 
        }
2150
 
 
2151
 
        return false;
2152
 
    }
2153
 
 
2154
 
 
2155
 
    /**
2156
 
     * Returns whether the specified variable is ever necessary after all
2157
 
     * instructions in the specified set of instructions offsets.
2158
 
     */
2159
 
    private boolean isVariableNecessaryAfterAll(InstructionOffsetValue instructionOffsetValue,
2160
 
                                                int                    variableIndex)
2161
 
    {
2162
 
        int count = instructionOffsetValue.instructionOffsetCount();
2163
 
 
2164
 
        for (int index = 0; index < count; index++)
2165
 
        {
2166
 
            if (!isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index),
2167
 
                                          variableIndex))
2168
 
            {
2169
 
                return false;
2170
 
            }
2171
 
        }
2172
 
 
2173
 
        return true;
2174
 
    }
2175
 
 
2176
 
 
2177
 
    private boolean isVariableNecessaryAfter(int instructionOffset,
2178
 
                                             int variableIndex)
2179
 
    {
2180
 
        return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
2181
 
               variablesNecessaryAfter[instructionOffset][variableIndex];
2182
 
    }
2183
 
 
2184
 
 
2185
 
    /**
2186
2106
     * Marks the stack entry after the given offset.
2187
2107
     * @param instructionOffset the offset of the stack entry to be marked.
2188
2108
     * @param stackIndex        the index of the stack entry to be marked
2375
2295
        return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
2376
2296
               instructionsNecessary[instructionOffset];
2377
2297
    }
2378
 
}
 
 
b'\\ No newline at end of file'
 
2298
}