diff options
Diffstat (limited to 'src/proguard/optimize/peephole')
22 files changed, 2459 insertions, 346 deletions
diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java index 8f650bb..79499f1 100644 --- a/src/proguard/optimize/peephole/BranchTargetFinder.java +++ b/src/proguard/optimize/peephole/BranchTargetFinder.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -29,6 +29,8 @@ import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; +import java.util.Arrays; + /** * This AttributeVisitor finds all instruction offsets, branch targets, and * exception targets in the CodeAttribute objects that it visits. @@ -45,12 +47,15 @@ implements AttributeVisitor, //* private static final boolean DEBUG = false; /*/ - private static boolean DEBUG = true; + private static boolean DEBUG = System.getProperty("btf") != null; //*/ public static final int NONE = -2; public static final int AT_METHOD_ENTRY = -1; + public static final int UNKNOWN = -1; + public static final int NO_SUBROUTINE = -2; + private static final short INSTRUCTION = 1 << 0; private static final short BRANCH_ORIGIN = 1 << 1; private static final short BRANCH_TARGET = 1 << 2; @@ -70,9 +75,10 @@ implements AttributeVisitor, private int[] creationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private int superInitializationOffset; + private boolean containsSubroutines; + private boolean repeat; private int currentSubroutineStart; - private int currentSubroutineEnd; private int[] recentCreationOffsets = new int[MAXIMUM_CREATION_OFFSETS]; private int recentCreationOffsetIndex; private boolean isInitializer; @@ -189,7 +195,7 @@ implements AttributeVisitor, */ public boolean isSubroutine(int offset) { - return subroutineStarts[offset] != NONE; + return subroutineStarts[offset] >= 0; } @@ -289,6 +295,16 @@ implements AttributeVisitor, } + /** + * Returns whether the method contains subroutines, in the CodeAttribute + * that was visited most recently. + */ + public boolean containsSubroutines() + { + return containsSubroutines; + } + + // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} @@ -312,106 +328,98 @@ implements AttributeVisitor, initializationOffsets = new int[codeLength]; // Reset the arrays. - for (int index = 0; index < codeLength; index++) - { - subroutineStarts[index] = NONE; - subroutineEnds[index] = NONE; - creationOffsets[index] = NONE; - initializationOffsets[index] = NONE; - } + Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN); + Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN); + Arrays.fill(creationOffsets, 0, codeLength, NONE); + Arrays.fill(initializationOffsets, 0, codeLength, NONE); } else { // Reset the arrays. - for (int index = 0; index < codeLength; index++) - { - instructionMarks[index] = 0; - subroutineStarts[index] = NONE; - subroutineEnds[index] = NONE; - creationOffsets[index] = NONE; - initializationOffsets[index] = NONE; - } + Arrays.fill(instructionMarks, 0, codeLength, (short)0); + Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN); + Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN); + Arrays.fill(creationOffsets, 0, codeLength, NONE); + Arrays.fill(initializationOffsets, 0, codeLength, NONE); instructionMarks[codeLength] = 0; } superInitializationOffset = NONE; + containsSubroutines = false; - // We're assuming all subroutines are contiguous blocks of code. - // We're not starting in a subroutine. - currentSubroutineStart = NONE; - currentSubroutineEnd = NONE; + // Iterate until all subroutines have been fully marked. + do + { + repeat = false; + currentSubroutineStart = NO_SUBROUTINE; + recentCreationOffsetIndex = 0; - recentCreationOffsetIndex = 0; + // Initialize the stack of 'new' instruction offsets if this method + // is an instance initializer. + if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) + { + recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY; + } - // Initialize the stack of 'new' instruction offsets if this method is - // an instance initializer. - if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) - { - recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY; + // Mark branch targets by going over all instructions. + codeAttribute.instructionsAccept(clazz, method, this); } + while (repeat); // The end of the code is a branch target sentinel. instructionMarks[codeLength] = BRANCH_TARGET; - // Mark branch targets by going over all instructions. - codeAttribute.instructionsAccept(clazz, method, this); - // Mark branch targets in the exception table. codeAttribute.exceptionsAccept(clazz, method, this); - // Fill out any gaps in the subroutine starts and the subroutine ends - // and subroutine returning flags, working backward. - - // We're not starting in a subroutine. - int subroutineStart = NONE; - int subroutineEnd = codeLength; - boolean subroutineReturning = false; - - for (int index = codeLength - 1; index >= 0; index--) + if (containsSubroutines) { - if (isInstruction(index)) - { - // Are we inside a previously marked subroutine? - if (subroutineStarts[index] != NONE) - { - // Update the current subroutine start. - subroutineStart = subroutineStarts[index]; - } - else if (subroutineStart != NONE) - { - // Mark the subroutine start. - subroutineStarts[index] = subroutineStart; - } + // Set the subroutine returning flag and the subroutine end at each + // subroutine start. + int previousSubroutineStart = NO_SUBROUTINE; - // Did we reach the start of the subroutine. - if (isSubroutineStart(index)) - { - // Stop marking it. - subroutineStart = NONE; - } - - // Are we inside a subroutine? - if (isSubroutine(index)) + for (int offset = 0; offset < codeLength; offset++) + { + if (isInstruction(offset)) { - // Mark the subroutine end. - subroutineEnds[index] = subroutineEnd; + int subroutineStart = subroutineStarts[offset]; - // Update or mark the subroutine returning flag. - if (isSubroutineReturning(index)) + if (subroutineStart >= 0 && + isSubroutineReturning(offset)) { - subroutineReturning = true; + instructionMarks[subroutineStart] |= SUBROUTINE_RETURNING; } - else if (subroutineReturning) + + if (previousSubroutineStart >= 0) { - instructionMarks[index] |= SUBROUTINE_RETURNING; + subroutineEnds[previousSubroutineStart] = offset; } + + previousSubroutineStart = subroutineStart; } - else + } + + if (previousSubroutineStart >= 0) + { + subroutineEnds[previousSubroutineStart] = codeLength; + } + + // Set the subroutine returning flag and the subroutine end at each + // subroutine instruction, based on the marks at the subroutine + // start. + for (int offset = 0; offset < codeLength; offset++) + { + if (isSubroutine(offset)) { - // Update the subroutine end and returning flag. - subroutineEnd = index; - subroutineReturning = false; + int subroutineStart = subroutineStarts[offset]; + + if (isSubroutineReturning(subroutineStart)) + { + instructionMarks[offset] |= SUBROUTINE_RETURNING; + } + + subroutineEnds[offset] = subroutineEnds[subroutineStart]; } } } @@ -451,7 +459,7 @@ implements AttributeVisitor, // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; - // Check if this is the first instruction of a subroutine. + // Check if this is an instruction of a subroutine. checkSubroutine(offset); byte opcode = simpleInstruction.opcode; @@ -476,7 +484,7 @@ implements AttributeVisitor, // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; - // Check if this is the first instruction of a subroutine. + // Check if this is an instruction of a subroutine. checkSubroutine(offset); // Check if the instruction is a 'new' instruction. @@ -517,15 +525,18 @@ implements AttributeVisitor, // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; - // Check if this is the first instruction of a subroutine. + // Check if this is an instruction of a subroutine. checkSubroutine(offset); if (variableInstruction.opcode == InstructionConstants.OP_RET) { + // Mark the method. + containsSubroutines = true; + // Mark the branch origin. markBranchOrigin(offset); - // Mark the regular subroutine return. + // Mark the subroutine return at its return instruction. instructionMarks[offset] |= SUBROUTINE_RETURNING; // Mark the next instruction. @@ -536,28 +547,39 @@ implements AttributeVisitor, public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { + int branchOffset = branchInstruction.branchOffset; + int targetOffset = offset + branchOffset; + // Mark the branch origin. markBranchOrigin(offset); - // Check if this is the first instruction of a subroutine. + // Check if this is an instruction of a subroutine. checkSubroutine(offset); // Mark the branch target. - markBranchTarget(offset, branchInstruction.branchOffset); + markBranchTarget(offset, branchOffset); byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W) { + // Mark the method. + containsSubroutines = true; + // Mark the subroutine invocation. instructionMarks[offset] |= SUBROUTINE_INVOCATION; - // Mark the subroutine start. - int targetOffset = offset + branchInstruction.branchOffset; - subroutineStarts[targetOffset] = targetOffset; + // Mark the new subroutine start. + markBranchSubroutineStart(offset, branchOffset, targetOffset); } - else if (opcode == InstructionConstants.OP_GOTO || - opcode == InstructionConstants.OP_GOTO_W) + else if (currentSubroutineStart != UNKNOWN) + { + // Mark the continued subroutine start. + markBranchSubroutineStart(offset, branchOffset, currentSubroutineStart); + } + + if (opcode == InstructionConstants.OP_GOTO || + opcode == InstructionConstants.OP_GOTO_W) { // Mark the next instruction. markAfterBranchOrigin(offset + branchInstruction.length(offset)); @@ -570,15 +592,14 @@ implements AttributeVisitor, // Mark the branch origin. markBranchOrigin(offset); - // Check if this is the first instruction of a subroutine. + // Check if this is an instruction of a subroutine. checkSubroutine(offset); // Mark the branch targets of the default jump offset. - markBranchTarget(offset, switchInstruction.defaultOffset); + markBranch(offset, switchInstruction.defaultOffset); // Mark the branch targets of the jump offsets. - markBranchTargets(offset, - switchInstruction.jumpOffsets); + markBranches(offset, switchInstruction.jumpOffsets); // Mark the next instruction. markAfterBranchOrigin(offset + switchInstruction.length(offset)); @@ -610,19 +631,32 @@ implements AttributeVisitor, // Small utility methods. /** - * Marks the branch targets of the given jump offsets for the instruction - * at the given offset. + * Marks the branch targets and their subroutine starts at the given + * offsets. */ - private void markBranchTargets(int offset, int[] jumpOffsets) + private void markBranches(int offset, int[] jumpOffsets) { for (int index = 0; index < jumpOffsets.length; index++) { - markBranchTarget(offset, jumpOffsets[index]); + markBranch(offset, jumpOffsets[index]); } } /** + * Marks the branch target and its subroutine start at the given offset. + */ + private void markBranch(int offset, int jumpOffset) + { + markBranchTarget(offset, jumpOffset); + + if (currentSubroutineStart != UNKNOWN) + { + markBranchSubroutineStart(offset, jumpOffset, currentSubroutineStart); + } + } + + /** * Marks the branch origin at the given offset. */ private void markBranchOrigin(int offset) @@ -639,18 +673,37 @@ implements AttributeVisitor, int targetOffset = offset + jumpOffset; instructionMarks[targetOffset] |= BRANCH_TARGET; + } - // Are we inside a previously marked subroutine? - if (isSubroutine(offset)) - { - // Mark the subroutine start of the target. - subroutineStarts[targetOffset] = currentSubroutineStart; - // Update the current subroutine end. - if (currentSubroutineEnd < targetOffset) + /** + * Marks the subroutine start at the given offset, if applicable. + */ + private void markBranchSubroutineStart(int offset, + int jumpOffset, + int subroutineStart) + { + int targetOffset = offset + jumpOffset; + + // Are we marking a subroutine and branching to an offset that hasn't + // been marked yet? + if (subroutineStarts[targetOffset] == UNKNOWN) + { + // Is it a backward branch? + if (jumpOffset < 0) { - currentSubroutineEnd = targetOffset; + // Remember the smallest subroutine start. + if (subroutineStart > targetOffset) + { + subroutineStart = targetOffset; + } + + // We'll have to go over all instructions again. + repeat = true; } + + // Mark the subroutine start of the target. + subroutineStarts[targetOffset] = subroutineStart; } } @@ -662,12 +715,8 @@ implements AttributeVisitor, { instructionMarks[nextOffset] |= AFTER_BRANCH; - // Are we at the end of the current subroutine? - if (currentSubroutineEnd <= nextOffset) - { - // Reset the subroutine start. - currentSubroutineStart = NONE; - } + // Stop marking a subroutine. + currentSubroutineStart = UNKNOWN; } @@ -677,15 +726,23 @@ implements AttributeVisitor, private void checkSubroutine(int offset) { // Are we inside a previously marked subroutine? - if (isSubroutine(offset)) + if (subroutineStarts[offset] != UNKNOWN) { - // Update the current subroutine start. + // Start marking a subroutine. currentSubroutineStart = subroutineStarts[offset]; } - else + + // Are we marking a subroutine? + else if (currentSubroutineStart != UNKNOWN) { - // Mark the subroutine start (or NONE). + // Mark the subroutine start. subroutineStarts[offset] = currentSubroutineStart; + + if (currentSubroutineStart >= 0) + { + // Mark the subroutine end at the subroutine start. + subroutineEnds[currentSubroutineStart] = offset; + } } } } diff --git a/src/proguard/optimize/peephole/ClassFinalizer.java b/src/proguard/optimize/peephole/ClassFinalizer.java index b5e54f8..378f972 100644 --- a/src/proguard/optimize/peephole/ClassFinalizer.java +++ b/src/proguard/optimize/peephole/ClassFinalizer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/ClassMerger.java b/src/proguard/optimize/peephole/ClassMerger.java index 1e1a950..aa40c75 100644 --- a/src/proguard/optimize/peephole/ClassMerger.java +++ b/src/proguard/optimize/peephole/ClassMerger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -21,6 +21,7 @@ package proguard.optimize.peephole; import proguard.classfile.*; +import proguard.classfile.attribute.visitor.AttributeNameFilter; import proguard.classfile.constant.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; @@ -50,7 +51,7 @@ implements ClassVisitor, //* private static final boolean DEBUG = false; /*/ - private static boolean DEBUG = true; + private static boolean DEBUG = System.getProperty("cm") != null; //*/ @@ -59,6 +60,8 @@ implements ClassVisitor, private final boolean mergeInterfacesAggressively; private final ClassVisitor extraClassVisitor; + private final MemberVisitor fieldOptimizationInfoCopier = new FieldOptimizationInfoCopier(); + /** * Creates a new ClassMerger that will merge classes into the given target @@ -151,7 +154,7 @@ implements ClassVisitor, // infinite recursion. (programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 && - // Only merge classes if we can change the access permissioms, or + // Only merge classes if we can change the access permissions, or // if they are in the same package, or // if they are public and don't contain or invoke package visible // class members. @@ -196,12 +199,19 @@ implements ClassVisitor, !(DotClassMarker.isDotClassed(programClass) && DotClassMarker.isDotClassed(targetClass)) && + // The classes must not have clashing fields. + !haveAnyIdenticalFields(programClass, targetClass) && + // The two classes must not introduce any unwanted fields. !introducesUnwantedFields(programClass, targetClass) && !introducesUnwantedFields(targetClass, programClass) && - // The classes must not have clashing constructors. - !haveAnyIdenticalInitializers(programClass, targetClass) && + // The two classes must not shadow each others fields. + !shadowsAnyFields(programClass, targetClass) && + !shadowsAnyFields(targetClass, programClass) && + + // The classes must not have clashing methods. + !haveAnyIdenticalMethods(programClass, targetClass) && // The classes must not introduce abstract methods, unless // explicitly allowed. @@ -226,6 +236,10 @@ implements ClassVisitor, System.out.println(" Target subclasses ["+targetClass.subClasses+"]"); System.out.println(" Source superclass ["+programClass.getSuperClass().getName()+"]"); System.out.println(" Target superclass ["+targetClass.getSuperClass().getName()+"]"); + + //System.out.println("=== Before ==="); + //programClass.accept(new ClassPrinter()); + //targetClass.accept(new ClassPrinter()); } // Combine the access flags. @@ -235,11 +249,12 @@ implements ClassVisitor, targetClass.u2accessFlags = ((targetAccessFlags & sourceAccessFlags) & - (ClassConstants.INTERNAL_ACC_INTERFACE | + (ClassConstants.INTERNAL_ACC_INTERFACE | ClassConstants.INTERNAL_ACC_ABSTRACT)) | ((targetAccessFlags | sourceAccessFlags) & - (ClassConstants.INTERNAL_ACC_PUBLIC | + (ClassConstants.INTERNAL_ACC_PUBLIC | + ClassConstants.INTERNAL_ACC_SUPER | ClassConstants.INTERNAL_ACC_ANNOTATTION | ClassConstants.INTERNAL_ACC_ENUM)); @@ -260,14 +275,18 @@ implements ClassVisitor, // Copy over the class members. MemberAdder memberAdder = - new MemberAdder(targetClass); + new MemberAdder(targetClass, fieldOptimizationInfoCopier); programClass.fieldsAccept(memberAdder); programClass.methodsAccept(memberAdder); // Copy over the other attributes. programClass.attributesAccept( - new AttributeAdder(targetClass, true)); + new AttributeNameFilter(new NotMatcher(new OrMatcher(new OrMatcher( + new FixedStringMatcher(ClassConstants.ATTR_SourceFile), + new FixedStringMatcher(ClassConstants.ATTR_InnerClasses)), + new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))), + new AttributeAdder(targetClass, true))); // Update the optimization information of the target class. ClassOptimizationInfo info = @@ -280,6 +299,12 @@ implements ClassVisitor, // Remember to replace the inlined class by the target class. setTargetClass(programClass, targetClass); + //if (DEBUG) + //{ + // System.out.println("=== After ===="); + // targetClass.accept(new ClassPrinter()); + //} + // Visit the merged class, if required. if (extraClassVisitor != null) { @@ -336,10 +361,8 @@ implements ClassVisitor, // Visit all superclasses and interfaces, collecting the ones that have // static initializers. clazz.hierarchyAccept(true, true, true, false, - new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, - ClassConstants.INTERNAL_METHOD_TYPE_INIT, - new MemberToClassVisitor( - new ClassCollector(set)))); + new StaticInitializerContainingClassFilter( + new ClassCollector(set))); return set; } @@ -368,9 +391,16 @@ implements ClassVisitor, */ private Set caughtSuperClasses(Clazz clazz) { + // Don't bother if this isn't an exception at all. + if (!clazz.extends_(ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE)) + { + return Collections.EMPTY_SET; + } + + // Visit all superclasses, collecting the ones that are caught + // (plus java.lang.Object, in the current implementation). Set set = new HashSet(); - // Visit all superclasses, collecting the ones that are caught. clazz.hierarchyAccept(true, true, false, false, new CaughtClassFilter( new ClassCollector(set))); @@ -380,38 +410,82 @@ implements ClassVisitor, /** + * Returns whether the two given classes have class members with the same + * name and descriptor. + */ + private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass) + { + MemberCounter counter = new MemberCounter(); + + // Visit all fields, counting the with the same name and descriptor in + // the target class. + clazz.fieldsAccept(new SimilarMemberVisitor(targetClass, true, false, false, false, + counter)); + + return counter.getCount() > 0; + } + + + /** * Returns whether the given class would introduce any unwanted fields * in the target class. */ private boolean introducesUnwantedFields(ProgramClass programClass, ProgramClass targetClass) { - // The class must not have any fields, or it must not be instantiated, - // without any other subclasses. - return - programClass.u2fieldsCount != 0 && - (InstantiationClassMarker.isInstantiated(targetClass) || - (targetClass.subClasses != null && - !isOnlySubClass(programClass, targetClass))); + // It's ok if the target class is never instantiated, without any other + // subclasses except for maybe the source class. + if (!InstantiationClassMarker.isInstantiated(targetClass) && + (targetClass.subClasses == null || + isOnlySubClass(programClass, targetClass))) + { + return false; + } + + MemberCounter counter = new MemberCounter(); + + // Count all non-static fields in the the source class. + programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC, + counter)); + + return counter.getCount() > 0; + } + + + /** + * Returns whether the given class or its subclasses shadow any fields in + * the given target class. + */ + private boolean shadowsAnyFields(Clazz clazz, Clazz targetClass) + { + MemberCounter counter = new MemberCounter(); + + // Visit all fields, counting the ones that are shadowing non-private + // fields in the class hierarchy of the target class. + clazz.hierarchyAccept(true, false, false, true, + new AllFieldVisitor( + new SimilarMemberVisitor(targetClass, true, true, true, false, + new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, + counter)))); + + return counter.getCount() > 0; } /** - * Returns whether the two given classes have initializers with the same - * descriptors. + * Returns whether the two given classes have class members with the same + * name and descriptor. */ - private boolean haveAnyIdenticalInitializers(Clazz clazz, Clazz targetClass) + private boolean haveAnyIdenticalMethods(Clazz clazz, Clazz targetClass) { MemberCounter counter = new MemberCounter(); - // TODO: Currently checking shared methods, not just initializers. - // TODO: Allow identical methods. - // Visit all methods, counting the ones that are also present in the - // target class. - clazz.methodsAccept(//new MemberNameFilter(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT), + // Visit all non-abstract methods, counting the ones that are also + // present in the target class. + clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT, new SimilarMemberVisitor(targetClass, true, false, false, false, new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT, - counter))); + counter)))); return counter.getCount() > 0; } @@ -538,4 +612,30 @@ implements ClassVisitor, targetClass = clazz; } } + + + /** + * This MemberVisitor copies field optimization info from copied fields. + */ + private static class FieldOptimizationInfoCopier + extends SimplifiedVisitor + implements MemberVisitor + { + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + // Copy the optimization info from the field that was just copied. + ProgramField copiedField = (ProgramField)programField.getVisitorInfo(); + Object info = copiedField.getVisitorInfo(); + + programField.setVisitorInfo(info instanceof FieldOptimizationInfo ? + new FieldOptimizationInfo((FieldOptimizationInfo)info) : + info); + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + // Linked methods share their optimization info. + } + } }
\ No newline at end of file diff --git a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java index 4833275..3bfd98c 100644 --- a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java +++ b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -50,7 +50,7 @@ implements AttributeVisitor, private final InstructionVisitor extraInstructionVisitor; private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); - private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, false); /** @@ -123,10 +123,7 @@ implements AttributeVisitor, int deleteOffset = offset - delta; if (branchTargetFinder.isInstruction(deleteOffset)) { - codeAttributeEditor.replaceInstruction( deleteOffset, (Instruction)null); - codeAttributeEditor.insertBeforeInstruction(deleteOffset, (Instruction)null); - codeAttributeEditor.insertAfterInstruction( deleteOffset, (Instruction)null); - + codeAttributeEditor.clearModifications(deleteOffset); codeAttributeEditor.deleteInstruction(deleteOffset); } } @@ -136,7 +133,7 @@ implements AttributeVisitor, if (newBranchOffset != branchInstruction.length(offset)) { Instruction newGotoInstruction = - new BranchInstruction(opcode, newBranchOffset); + new BranchInstruction(opcode, newBranchOffset).shrink(); codeAttributeEditor.replaceInstruction(offset, newGotoInstruction); } diff --git a/src/proguard/optimize/peephole/GotoGotoReplacer.java b/src/proguard/optimize/peephole/GotoGotoReplacer.java index 7d7e66c..4a490a1 100644 --- a/src/proguard/optimize/peephole/GotoGotoReplacer.java +++ b/src/proguard/optimize/peephole/GotoGotoReplacer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -84,8 +84,9 @@ implements InstructionVisitor int branchOffset = branchInstruction.branchOffset; int targetOffset = offset + branchOffset; - if (branchOffset != branchInstruction.length(offset) && - !codeAttributeEditor.isModified(offset) && + if (branchOffset != 0 && + branchOffset != branchInstruction.length(offset) && + !codeAttributeEditor.isModified(offset) && !codeAttributeEditor.isModified(targetOffset)) { Instruction targetInstruction = diff --git a/src/proguard/optimize/peephole/GotoReturnReplacer.java b/src/proguard/optimize/peephole/GotoReturnReplacer.java index 5c3eb77..b6deec8 100644 --- a/src/proguard/optimize/peephole/GotoReturnReplacer.java +++ b/src/proguard/optimize/peephole/GotoReturnReplacer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/HorizontalClassMerger.java b/src/proguard/optimize/peephole/HorizontalClassMerger.java index a37b9a5..31d3d33 100644 --- a/src/proguard/optimize/peephole/HorizontalClassMerger.java +++ b/src/proguard/optimize/peephole/HorizontalClassMerger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/InstructionSequenceConstants.java b/src/proguard/optimize/peephole/InstructionSequenceConstants.java index b33204b..4ab9056 100644 --- a/src/proguard/optimize/peephole/InstructionSequenceConstants.java +++ b/src/proguard/optimize/peephole/InstructionSequenceConstants.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -20,81 +20,207 @@ */ package proguard.optimize.peephole; +import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.instruction.*; -import proguard.classfile.util.InstructionSequenceMatcher; +import proguard.classfile.visitor.ClassPrinter; /** * This class contains a set of instruction sequences and their suggested * replacements. * * @see InstructionSequencesReplacer + * @see InstructionSequenceReplacer * @author Eric Lafortune */ public class InstructionSequenceConstants { - public static final int X = InstructionSequenceMatcher.X; - public static final int Y = InstructionSequenceMatcher.Y; - public static final int Z = InstructionSequenceMatcher.Z; + private static final int X = InstructionSequenceReplacer.X; + private static final int Y = InstructionSequenceReplacer.Y; + private static final int Z = InstructionSequenceReplacer.Z; - public static final int A = InstructionSequenceMatcher.A; - public static final int B = InstructionSequenceMatcher.B; - public static final int C = InstructionSequenceMatcher.C; - public static final int D = InstructionSequenceMatcher.D; + private static final int A = InstructionSequenceReplacer.A; + private static final int B = InstructionSequenceReplacer.B; + private static final int C = InstructionSequenceReplacer.C; + private static final int D = InstructionSequenceReplacer.D; + private static final int STRING_A_LENGTH = InstructionSequenceReplacer.STRING_A_LENGTH; + private static final int BOOLEAN_A_STRING = InstructionSequenceReplacer.BOOLEAN_A_STRING; + private static final int CHAR_A_STRING = InstructionSequenceReplacer.CHAR_A_STRING; + private static final int INT_A_STRING = InstructionSequenceReplacer.INT_A_STRING; + private static final int LONG_A_STRING = InstructionSequenceReplacer.LONG_A_STRING; + private static final int FLOAT_A_STRING = InstructionSequenceReplacer.FLOAT_A_STRING; + private static final int DOUBLE_A_STRING = InstructionSequenceReplacer.DOUBLE_A_STRING; + private static final int STRING_A_STRING = InstructionSequenceReplacer.STRING_A_STRING; + private static final int BOOLEAN_B_STRING = InstructionSequenceReplacer.BOOLEAN_B_STRING; + private static final int CHAR_B_STRING = InstructionSequenceReplacer.CHAR_B_STRING; + private static final int INT_B_STRING = InstructionSequenceReplacer.INT_B_STRING; + private static final int LONG_B_STRING = InstructionSequenceReplacer.LONG_B_STRING; + private static final int FLOAT_B_STRING = InstructionSequenceReplacer.FLOAT_B_STRING; + private static final int DOUBLE_B_STRING = InstructionSequenceReplacer.DOUBLE_B_STRING; + private static final int STRING_B_STRING = InstructionSequenceReplacer.STRING_B_STRING; - private static final int I_32768 = 0; - private static final int I_65536 = 1; - private static final int I_16777216 = 2; + private static final int I_32768 = 0; + private static final int I_65536 = 1; + private static final int I_16777216 = 2; // private static final int I_0x000000ff - private static final int I_0x0000ff00 = 3; - private static final int I_0x00ff0000 = 4; - private static final int I_0xff000000 = 5; - private static final int I_0x0000ffff = 6; - private static final int I_0xffff0000 = 7; + private static final int I_0x0000ff00 = 3; + private static final int I_0x00ff0000 = 4; + private static final int I_0xff000000 = 5; + private static final int I_0x0000ffff = 6; + private static final int I_0xffff0000 = 7; - private static final int L_M1 = 8; - private static final int L_2 = 9; - private static final int L_4 = 10; - private static final int L_8 = 11; - private static final int L_16 = 12; - private static final int L_32 = 13; - private static final int L_64 = 14; - private static final int L_128 = 15; - private static final int L_256 = 16; - private static final int L_512 = 17; - private static final int L_1024 = 18; - private static final int L_2048 = 19; - private static final int L_4096 = 20; - private static final int L_8192 = 21; - private static final int L_16384 = 22; - private static final int L_32768 = 23; - private static final int L_65536 = 24; - private static final int L_16777216 = 25; - private static final int L_4294967296 = 26; + private static final int L_M1 = 8; + private static final int L_2 = 9; + private static final int L_4 = 10; + private static final int L_8 = 11; + private static final int L_16 = 12; + private static final int L_32 = 13; + private static final int L_64 = 14; + private static final int L_128 = 15; + private static final int L_256 = 16; + private static final int L_512 = 17; + private static final int L_1024 = 18; + private static final int L_2048 = 19; + private static final int L_4096 = 20; + private static final int L_8192 = 21; + private static final int L_16384 = 22; + private static final int L_32768 = 23; + private static final int L_65536 = 24; + private static final int L_16777216 = 25; + private static final int L_4294967296 = 26; - private static final int L_0x00000000ffffffff = 27; - private static final int L_0xffffffff00000000 = 28; + private static final int L_0x00000000ffffffff = 27; + private static final int L_0xffffffff00000000 = 28; - private static final int F_M1 = 29; + private static final int F_M1 = 29; - private static final int D_M1 = 30; + private static final int D_M1 = 30; - private static final int FIELD_I = 31; - private static final int FIELD_L = 32; - private static final int FIELD_F = 33; - private static final int FIELD_D = 34; + private static final int STRING_EMPTY = 31; - private static final int NAME_AND_TYPE_I = 35; - private static final int NAME_AND_TYPE_L = 36; - private static final int NAME_AND_TYPE_F = 37; - private static final int NAME_AND_TYPE_D = 38; + private static final int FIELD_I = 32; // Implicitly uses X and Y. + private static final int FIELD_L = 33; // Implicitly uses X and Y. + private static final int FIELD_F = 34; // Implicitly uses X and Y. + private static final int FIELD_D = 35; // Implicitly uses X and Y. - private static final int TYPE_I = 39; - private static final int TYPE_L = 40; - private static final int TYPE_F = 41; - private static final int TYPE_D = 42; + private static final int METHOD_STRING_EQUALS = 36; + private static final int METHOD_STRING_LENGTH = 37; + private static final int METHOD_STRING_VALUEOF_Z = 38; + private static final int METHOD_STRING_VALUEOF_C = 39; + private static final int METHOD_STRING_VALUEOF_I = 40; + private static final int METHOD_STRING_VALUEOF_J = 41; + private static final int METHOD_STRING_VALUEOF_F = 42; + private static final int METHOD_STRING_VALUEOF_D = 43; + private static final int METHOD_STRING_VALUEOF_OBJECT = 44; + private static final int METHOD_STRINGBUFFER_INIT = 45; + private static final int METHOD_STRINGBUFFER_INIT_STRING = 46; + private static final int METHOD_STRINGBUFFER_APPEND_Z = 47; + private static final int METHOD_STRINGBUFFER_APPEND_C = 48; + private static final int METHOD_STRINGBUFFER_APPEND_I = 49; + private static final int METHOD_STRINGBUFFER_APPEND_J = 50; + private static final int METHOD_STRINGBUFFER_APPEND_F = 51; + private static final int METHOD_STRINGBUFFER_APPEND_D = 52; + private static final int METHOD_STRINGBUFFER_APPEND_STRING = 53; + private static final int METHOD_STRINGBUFFER_APPEND_OBJECT = 54; + private static final int METHOD_STRINGBUFFER_LENGTH = 55; + private static final int METHOD_STRINGBUFFER_TOSTRING = 56; + private static final int METHOD_STRINGBUILDER_INIT = 57; + private static final int METHOD_STRINGBUILDER_INIT_STRING = 58; + private static final int METHOD_STRINGBUILDER_APPEND_Z = 59; + private static final int METHOD_STRINGBUILDER_APPEND_C = 60; + private static final int METHOD_STRINGBUILDER_APPEND_I = 61; + private static final int METHOD_STRINGBUILDER_APPEND_J = 62; + private static final int METHOD_STRINGBUILDER_APPEND_F = 63; + private static final int METHOD_STRINGBUILDER_APPEND_D = 64; + private static final int METHOD_STRINGBUILDER_APPEND_STRING = 65; + private static final int METHOD_STRINGBUILDER_APPEND_OBJECT = 66; + private static final int METHOD_STRINGBUILDER_LENGTH = 67; + private static final int METHOD_STRINGBUILDER_TOSTRING = 68; + + private static final int CLASS_STRING = 69; + private static final int CLASS_STRINGBUFFER = 70; + private static final int CLASS_STRINGBUILDER = 71; + + private static final int NAME_AND_TYPE_I = 72; // Implicitly uses Y. + private static final int NAME_AND_TYPE_L = 73; // Implicitly uses Y. + private static final int NAME_AND_TYPE_F = 74; // Implicitly uses Y. + private static final int NAME_AND_TYPE_D = 75; // Implicitly uses Y. + + private static final int NAME_AND_TYPE_EQUALS = 76; + private static final int NAME_AND_TYPE_LENGTH = 77; + private static final int NAME_AND_TYPE_VALUEOF_Z = 78; + private static final int NAME_AND_TYPE_VALUEOF_C = 79; + private static final int NAME_AND_TYPE_VALUEOF_I = 80; + private static final int NAME_AND_TYPE_VALUEOF_J = 81; + private static final int NAME_AND_TYPE_VALUEOF_F = 82; + private static final int NAME_AND_TYPE_VALUEOF_D = 83; + private static final int NAME_AND_TYPE_VALUEOF_OBJECT = 84; + private static final int NAME_AND_TYPE_INIT = 85; + private static final int NAME_AND_TYPE_INIT_STRING = 86; + private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUFFER = 87; + private static final int NAME_AND_TYPE_APPEND_C_STRINGBUFFER = 88; + private static final int NAME_AND_TYPE_APPEND_I_STRINGBUFFER = 89; + private static final int NAME_AND_TYPE_APPEND_J_STRINGBUFFER = 90; + private static final int NAME_AND_TYPE_APPEND_F_STRINGBUFFER = 91; + private static final int NAME_AND_TYPE_APPEND_D_STRINGBUFFER = 92; + private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER = 93; + private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER = 94; + private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUILDER = 95; + private static final int NAME_AND_TYPE_APPEND_C_STRINGBUILDER = 96; + private static final int NAME_AND_TYPE_APPEND_I_STRINGBUILDER = 97; + private static final int NAME_AND_TYPE_APPEND_J_STRINGBUILDER = 98; + private static final int NAME_AND_TYPE_APPEND_F_STRINGBUILDER = 99; + private static final int NAME_AND_TYPE_APPEND_D_STRINGBUILDER = 100; + private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER = 101; + private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER = 102; + private static final int NAME_AND_TYPE_TOSTRING = 103; + + private static final int UTF8_EMPTY = 104; + private static final int UTF8_I = 105; + private static final int UTF8_L = 106; + private static final int UTF8_F = 107; + private static final int UTF8_D = 108; + private static final int UTF8_STRING = 109; + private static final int UTF8_STRINGBUFFER = 110; + private static final int UTF8_STRINGBUILDER = 111; + private static final int UTF8_EQUALS = 112; + private static final int UTF8_OBJECT_Z = 113; + private static final int UTF8_LENGTH = 114; + private static final int UTF8__I = 115; + private static final int UTF8_VALUEOF = 116; + private static final int UTF8_Z_STRING = 117; + private static final int UTF8_C_STRING = 118; + private static final int UTF8_I_STRING = 119; + private static final int UTF8_J_STRING = 120; + private static final int UTF8_F_STRING = 121; + private static final int UTF8_D_STRING = 122; + private static final int UTF8_OBJECT_STRING = 123; + private static final int UTF8_INIT = 124; + private static final int UTF8__VOID = 125; + private static final int UTF8_STRING_VOID = 126; + private static final int UTF8_TOSTRING = 127; + private static final int UTF8__STRING = 128; + private static final int UTF8_APPEND = 129; + private static final int UTF8_Z_STRINGBUFFER = 130; + private static final int UTF8_C_STRINGBUFFER = 131; + private static final int UTF8_I_STRINGBUFFER = 132; + private static final int UTF8_J_STRINGBUFFER = 133; + private static final int UTF8_F_STRINGBUFFER = 134; + private static final int UTF8_D_STRINGBUFFER = 135; + private static final int UTF8_STRING_STRINGBUFFER = 136; + private static final int UTF8_OBJECT_STRINGBUFFER = 137; + private static final int UTF8_Z_STRINGBUILDER = 138; + private static final int UTF8_C_STRINGBUILDER = 139; + private static final int UTF8_I_STRINGBUILDER = 140; + private static final int UTF8_J_STRINGBUILDER = 141; + private static final int UTF8_F_STRINGBUILDER = 142; + private static final int UTF8_D_STRINGBUILDER = 143; + private static final int UTF8_STRING_STRINGBUILDER = 144; + private static final int UTF8_OBJECT_STRINGBUILDER = 145; + + private static final int SENTINEL = 146; public static final Constant[] CONSTANTS = new Constant[] @@ -136,23 +262,128 @@ public class InstructionSequenceConstants new DoubleConstant(-1d), + new StringConstant(UTF8_EMPTY, null, null), + new FieldrefConstant(X, NAME_AND_TYPE_I, null, null), new FieldrefConstant(X, NAME_AND_TYPE_L, null, null), new FieldrefConstant(X, NAME_AND_TYPE_F, null, null), new FieldrefConstant(X, NAME_AND_TYPE_D, null, null), - new NameAndTypeConstant(Y, TYPE_I), - new NameAndTypeConstant(Y, TYPE_L), - new NameAndTypeConstant(Y, TYPE_F), - new NameAndTypeConstant(Y, TYPE_D), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_EQUALS, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_LENGTH, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_Z, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_C, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_I, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_J, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_F, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_D, null, null), + new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_OBJECT, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT_STRING, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_Z_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_C_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_I_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_J_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_F_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_D_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_LENGTH, null, null), + new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_TOSTRING, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT_STRING, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_Z_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_C_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_I_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_J_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_F_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_D_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_LENGTH, null, null), + new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_TOSTRING, null, null), + + new ClassConstant(UTF8_STRING, null), + new ClassConstant(UTF8_STRINGBUFFER, null), + new ClassConstant(UTF8_STRINGBUILDER, null), + new NameAndTypeConstant(Y, UTF8_I), + new NameAndTypeConstant(Y, UTF8_L), + new NameAndTypeConstant(Y, UTF8_F), + new NameAndTypeConstant(Y, UTF8_D), + new NameAndTypeConstant(UTF8_EQUALS, UTF8_OBJECT_Z), + new NameAndTypeConstant(UTF8_LENGTH, UTF8__I), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_Z_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_C_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_I_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_J_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_F_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_D_STRING), + new NameAndTypeConstant(UTF8_VALUEOF, UTF8_OBJECT_STRING), + new NameAndTypeConstant(UTF8_INIT, UTF8__VOID), + new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_VOID), + new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUFFER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUILDER), + new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUILDER), + new NameAndTypeConstant(UTF8_TOSTRING, UTF8__STRING), + + new Utf8Constant(""), new Utf8Constant("I"), new Utf8Constant("J"), new Utf8Constant("F"), new Utf8Constant("D"), + new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING), + new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_EQUALS), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_EQUALS), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_LENGTH), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LENGTH), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_VALUEOF), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_CHAR), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_INT), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_LONG), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_FLOAT), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_OBJECT), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_INIT), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INIT), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_VOID), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_TOSTRING), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_TOSTRING), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_APPEND), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER), + new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER), }; - public static final Instruction[][][] VARIABLE = new Instruction[][][] { { // nop = nothing @@ -237,7 +468,7 @@ public class InstructionSequenceConstants { // a = a = nothing { new VariableInstruction(InstructionConstants.OP_ALOAD, X), - new SimpleInstruction(InstructionConstants.OP_POP), + new VariableInstruction(InstructionConstants.OP_ASTORE, X), },{ // Nothing. }, @@ -382,12 +613,12 @@ public class InstructionSequenceConstants }, { // c * i = i * c { - new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new VariableInstruction(InstructionConstants.OP_ILOAD, X), new SimpleInstruction(InstructionConstants.OP_IMUL), },{ new VariableInstruction(InstructionConstants.OP_ILOAD, X), - new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IMUL), }, }, @@ -548,7 +779,7 @@ public class InstructionSequenceConstants { // i = i + c = i += c { new VariableInstruction(InstructionConstants.OP_ILOAD, X), - new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new SimpleInstruction(InstructionConstants.OP_SIPUSH, A), new SimpleInstruction(InstructionConstants.OP_IADD), new VariableInstruction(InstructionConstants.OP_ISTORE, X), },{ @@ -651,22 +882,23 @@ public class InstructionSequenceConstants // Nothing. }, }, - { // ... + 0f = ... - { - new SimpleInstruction(InstructionConstants.OP_FCONST_0), - new SimpleInstruction(InstructionConstants.OP_FADD), - },{ - // Nothing. - }, - }, - { // ... + 0d = ... - { - new SimpleInstruction(InstructionConstants.OP_DCONST_0), - new SimpleInstruction(InstructionConstants.OP_DADD), - },{ - // Nothing. - }, - }, + // Not valid for -0.0. +// { // ... + 0f = ... +// { +// new SimpleInstruction(InstructionConstants.OP_FCONST_0), +// new SimpleInstruction(InstructionConstants.OP_FADD), +// },{ +// // Nothing. +// }, +// }, +// { // ... + 0d = ... +// { +// new SimpleInstruction(InstructionConstants.OP_DCONST_0), +// new SimpleInstruction(InstructionConstants.OP_DADD), +// },{ +// // Nothing. +// }, +// }, { // ... - 0 = ... { new SimpleInstruction(InstructionConstants.OP_ICONST_0), @@ -1072,7 +1304,8 @@ public class InstructionSequenceConstants new SimpleInstruction(InstructionConstants.OP_FNEG), }, }, -// { // ... * 0f = 0f (or NaN) + // Not valid for -0.0 and for NaN. +// { // ... * 0f = 0f // { // new SimpleInstruction(InstructionConstants.OP_FCONST_0), // new SimpleInstruction(InstructionConstants.OP_FMUL), @@ -1097,7 +1330,8 @@ public class InstructionSequenceConstants new SimpleInstruction(InstructionConstants.OP_DNEG), }, }, -// { // ... * 0d = 0d (or NaN) + // Not valid for -0.0 and for NaN. +// { // ... * 0d = 0d // { // new SimpleInstruction(InstructionConstants.OP_DCONST_0), // new SimpleInstruction(InstructionConstants.OP_DMUL), @@ -1504,6 +1738,7 @@ public class InstructionSequenceConstants new SimpleInstruction(InstructionConstants.OP_ICONST_0), }, }, + // Not valid for negative values. // { // ... % 2 = ... & 0x1 // { // new SimpleInstruction(InstructionConstants.OP_ICONST_2), @@ -3348,4 +3583,1508 @@ public class InstructionSequenceConstants // }, // } }; -}
\ No newline at end of file + + public static final Instruction[][][] STRING = new Instruction[][][] + { + { // "...".equals("...") = true + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_EQUALS), + },{ + new SimpleInstruction(InstructionConstants.OP_ICONST_1), + }, + }, + { // "...".length() = ... + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_LENGTH), + },{ + new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), + }, + }, + { // String.valueOf(Z) = ".... + { + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), + }, + }, + { // String.valueOf(C) = "...." + { + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + }, + }, + { // String.valueOf(Cc) = "...." + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + }, + }, + { // String.valueOf(I) = "...." + { + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + }, + }, + { // String.valueOf(Ic) = "...." + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + }, + }, + { // String.valueOf(J) = "...." + { + new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + }, + }, + { // String.valueOf(Jc) = "...." + { + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + }, + }, + { // String.valueOf(F) = "...." + { + new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + }, + }, + { // String.valueOf(Fc) = "...." + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + }, + }, + { // String.valueOf(D) = "...." + { + new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + }, + }, + { // String.valueOf(Dc) = "...." + { + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + }, + }, + + { // new StringBuffer("...").toString() = "..." (ignoring identity) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, A), + }, + }, + { // new StringBuffer(string).toString() = string (ignoring identity) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + }, + }, + { // new StringBuffer("...").length() = length + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_LENGTH), + },{ + new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), + }, + }, + { // new StringBuffer() (without dup) = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...") (without dup) = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + },{ + // Nothing. + }, + }, + { // new StringBuffer()/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...")/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(z)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(c)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(i)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(l)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_LLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(f)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_FLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(d)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_DLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuffer("...").append(s)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ALOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // StringBuffer#toString()/pop = pop + { + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + new SimpleInstruction(InstructionConstants.OP_POP), + }, + }, + { // StringBuffer#append("") = nothing + { + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + },{ + // Nothing. + }, + }, + { // new StringBuffer().append(Z) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(C) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(Cc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(I) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(Ic) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(J) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(Jc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(F) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(Fc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(D) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append(Dc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer().append("...") = new StringBuffer("...") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Z) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(C) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Cc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(I) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Ic) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(J) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Jc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(F) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Fc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(D) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append(Dc) = new StringBuffer("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // new StringBuffer("...").append("...") = new StringBuffer("......") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING), + }, + }, + { // StringBuffer#append("...").append(Z) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(C) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(Cc) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(I) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(Ic) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(J) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(Jc) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(F) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(Fc) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(D) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append(Dc) = StringBuffer#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // StringBuffer#append("...").append("...") = StringBuffer#append("......") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + }, + }, + { // new StringBuffer().append(z).toString() = String.valueOf(z) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), + }, + }, + { // new StringBuffer().append(c).toString() = String.valueOf(c) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), + }, + }, + { // new StringBuffer().append(i).toString() = String.valueOf(i) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), + }, + }, + { // new StringBuffer().append(j).toString() = String.valueOf(j) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_LLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_LLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), + }, + }, + { // new StringBuffer().append(f).toString() = String.valueOf(f) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_FLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_FLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), + }, + }, + { // new StringBuffer().append(d).toString() = String.valueOf(d) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_DLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_DLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), + }, + }, + { // new StringBuffer().append(string).toString() = string + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + }, + }, + { // new StringBuffer().append(object).toString() = String.valueOf(object) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_OBJECT), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT), + }, + }, + + { // new StringBuilder("...").toString() = "..." (ignoring identity) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, A), + }, + }, + { // new StringBuilder(string).toString() = string (ignoring identity) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + }, + }, + { // new StringBuilder("...").length() = length + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_LENGTH), + },{ + new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH), + }, + }, + { // new StringBuilder() (without dup) = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...") (without dup) = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + },{ + // Nothing. + }, + }, + { // new StringBuilder()/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...")/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(z)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(c)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(i)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ILOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(l)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_LLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(f)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_FLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(d)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_DLOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // new StringBuilder("...").append(s)/pop = nothing + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new VariableInstruction(InstructionConstants.OP_ALOAD, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + // Nothing. + }, + }, + { // StringBuilder#toString()/pop = pop + { + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + new SimpleInstruction(InstructionConstants.OP_POP), + },{ + new SimpleInstruction(InstructionConstants.OP_POP), + }, + }, + { // StringBuilder#append("") = nothing + { + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + },{ + // Nothing. + }, + }, + { // new StringBuilder().append(Z) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(C) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(Cc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(I) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(Ic) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(J) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(Jc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(F) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(Fc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(D) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append(Dc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder().append("...") = new StringBuilder("...") + { + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Z) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(C) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Cc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(I) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Ic) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(J) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Jc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(F) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Fc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(D) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append(Dc) = new StringBuilder("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // new StringBuilder("...").append("...") = new StringBuilder("......") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING), + }, + }, + { // StringBuilder#append("...").append(Z) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(C) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(Cc) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(I) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_ICONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(Ic) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(J) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_LCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(Jc) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(F) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_FCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(Fc) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(D) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new SimpleInstruction(InstructionConstants.OP_DCONST_0, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append(Dc) = StringBuilder#append("....") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC2_W, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // StringBuilder#append("...").append("...") = StringBuilder#append("......") + { + new ConstantInstruction(InstructionConstants.OP_LDC, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_LDC, B), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + },{ + new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + }, + }, + { // new StringBuilder().append(z).toString() = String.valueOf(z) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z), + }, + }, + { // new StringBuilder().append(c).toString() = String.valueOf(c) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C), + }, + }, + { // new StringBuilder().append(i).toString() = String.valueOf(i) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ILOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I), + }, + }, + { // new StringBuilder().append(j).toString() = String.valueOf(j) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_LLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_LLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J), + }, + }, + { // new StringBuilder().append(f).toString() = String.valueOf(f) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_FLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_FLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F), + }, + }, + { // new StringBuilder().append(d).toString() = String.valueOf(d) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_DLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_DLOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D), + }, + }, + { // new StringBuilder().append(string).toString() = string + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + }, + }, + { // new StringBuilder().append(object).toString() = String.valueOf(object) + { + new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER), + new SimpleInstruction(InstructionConstants.OP_DUP), + new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT), + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_OBJECT), + new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING), + },{ + new VariableInstruction(InstructionConstants.OP_ALOAD, A), + new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT), + }, + }, + }; + + + /** + * Prints out the constants and the instruction sequences. + */ + public static void main(String[] args) + { + ProgramClass clazz = new ProgramClass(); + clazz.constantPool = CONSTANTS; + + ClassPrinter printer = new ClassPrinter(); + + for (int index = 0; index < CONSTANTS.length; index++) + { + System.out.print("["+index+"] "); + try + { + CONSTANTS[index].accept(clazz, printer); + } + catch (Exception e) + { + System.out.println("("+e.getClass().getName()+")"); + } + } + + if (CONSTANTS.length != SENTINEL) + { + throw new IllegalStateException("Constants length ["+CONSTANTS.length+"] different from number of constant names ["+SENTINEL+"]"); + } + + Instruction[][][] sequences = STRING; + + for (int sequence = 0; sequence < sequences.length; sequence++) + { + System.out.println(); + Instruction[] instructions = sequences[sequence][0]; + for (int index = 0; index < instructions.length; index++) + { + Instruction instruction = instructions[index]; + try + { + instruction.accept(clazz, null, null, index, new ClassPrinter()); + } + catch (Exception e) {} + } + + System.out.println("=>"); + instructions = sequences[sequence][1]; + for (int index = 0; index < instructions.length; index++) + { + Instruction instruction = instructions[index]; + try + { + instruction.accept(clazz, null, null, index, new ClassPrinter()); + } + catch (Exception e) {} + } + } + } +} diff --git a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java index bce06e2..7ec1a95 100644 --- a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java +++ b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -22,9 +22,9 @@ package proguard.optimize.peephole; import proguard.classfile.*; import proguard.classfile.attribute.CodeAttribute; -import proguard.classfile.constant.Constant; +import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; -import proguard.classfile.editor.CodeAttributeEditor; +import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; @@ -42,10 +42,48 @@ extends SimplifiedVisitor implements InstructionVisitor, ConstantVisitor { + //* private static final boolean DEBUG = false; + /*/ + public static boolean DEBUG = true; + //*/ + + public static final int X = InstructionSequenceMatcher.X; + public static final int Y = InstructionSequenceMatcher.Y; + public static final int Z = InstructionSequenceMatcher.Z; + + public static final int A = InstructionSequenceMatcher.A; + public static final int B = InstructionSequenceMatcher.B; + public static final int C = InstructionSequenceMatcher.C; + public static final int D = InstructionSequenceMatcher.D; + + private static final int BOOLEAN_STRING = 0x1; + private static final int CHAR_STRING = 0x2; + private static final int INT_STRING = 0x3; + private static final int LONG_STRING = 0x4; + private static final int FLOAT_STRING = 0x5; + private static final int DOUBLE_STRING = 0x6; + private static final int STRING_STRING = 0x7; + + public static final int STRING_A_LENGTH = 0x20000000; + public static final int BOOLEAN_A_STRING = 0x20000001; + public static final int CHAR_A_STRING = 0x20000002; + public static final int INT_A_STRING = 0x20000003; + public static final int LONG_A_STRING = 0x20000004; + public static final int FLOAT_A_STRING = 0x20000005; + public static final int DOUBLE_A_STRING = 0x20000006; + public static final int STRING_A_STRING = 0x20000007; + public static final int BOOLEAN_B_STRING = 0x20000010; + public static final int CHAR_B_STRING = 0x20000020; + public static final int INT_B_STRING = 0x20000030; + public static final int LONG_B_STRING = 0x20000040; + public static final int FLOAT_B_STRING = 0x20000050; + public static final int DOUBLE_B_STRING = 0x20000060; + public static final int STRING_B_STRING = 0x20000070; private final InstructionSequenceMatcher instructionSequenceMatcher; + private final Constant[] patternConstants; private final Instruction[] replacementInstructions; private final BranchTargetFinder branchTargetFinder; private final CodeAttributeEditor codeAttributeEditor; @@ -101,6 +139,7 @@ implements InstructionVisitor, InstructionVisitor extraInstructionVisitor) { this.instructionSequenceMatcher = new InstructionSequenceMatcher(patternConstants, patternInstructions); + this.patternConstants = patternConstants; this.replacementInstructions = replacementInstructions; this.branchTargetFinder = branchTargetFinder; this.codeAttributeEditor = codeAttributeEditor; @@ -140,7 +179,7 @@ implements InstructionVisitor, for (int index = 0; index < replacementInstructions.length; index++) { int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index); - System.out.println(" "+replacementInstructionFactory.create(index).shrink().toString(matchedOffset)); + System.out.println(" "+replacementInstructionFactory.create(clazz, index).shrink().toString(matchedOffset)); } } @@ -148,7 +187,7 @@ implements InstructionVisitor, for (int index = 0; index < replacementInstructions.length; index++) { codeAttributeEditor.replaceInstruction(instructionSequenceMatcher.matchedInstructionOffset(index), - replacementInstructionFactory.create(index).shrink()); + replacementInstructionFactory.create(clazz, index)); } // Delete any remaining instructions in the from sequence. @@ -204,17 +243,17 @@ implements InstructionVisitor, * Creates the replacement instruction for the given index in the * instruction sequence. */ - public Instruction create(int index) + public Instruction create(Clazz clazz, int index) { // Create the instruction. - replacementInstructions[index].accept(null, + replacementInstructions[index].accept(clazz, null, null, instructionSequenceMatcher.matchedInstructionOffset(index), this); // Return it. - return replacementInstruction.shrink(); + return replacementInstruction; } @@ -224,7 +263,7 @@ implements InstructionVisitor, { replacementInstruction = new SimpleInstruction(simpleInstruction.opcode, - instructionSequenceMatcher.matchedArgument(simpleInstruction.constant)); + matchedArgument(clazz, simpleInstruction.constant)); } @@ -241,7 +280,8 @@ implements InstructionVisitor, { replacementInstruction = new ConstantInstruction(constantInstruction.opcode, - instructionSequenceMatcher.matchedConstantIndex(constantInstruction.constantIndex), + matchedConstantIndex((ProgramClass)clazz, + constantInstruction.constantIndex), instructionSequenceMatcher.matchedArgument(constantInstruction.constant)); } @@ -250,7 +290,8 @@ implements InstructionVisitor, { replacementInstruction = new BranchInstruction(branchInstruction.opcode, - instructionSequenceMatcher.matchedBranchOffset(offset, branchInstruction.branchOffset)); + instructionSequenceMatcher.matchedBranchOffset(offset, + branchInstruction.branchOffset)); } @@ -261,7 +302,8 @@ implements InstructionVisitor, instructionSequenceMatcher.matchedBranchOffset(offset, tableSwitchInstruction.defaultOffset), instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.lowCase), instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.highCase), - instructionSequenceMatcher.matchedJumpOffsets(offset, tableSwitchInstruction.jumpOffsets)); + instructionSequenceMatcher.matchedJumpOffsets(offset, + tableSwitchInstruction.jumpOffsets)); } @@ -274,5 +316,105 @@ implements InstructionVisitor, instructionSequenceMatcher.matchedArguments(lookUpSwitchInstruction.cases), instructionSequenceMatcher.matchedJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets)); } + + + /** + * Returns the matched argument for the given pattern argument. + */ + private int matchedArgument(Clazz clazz, int argument) + { + // Special case: do we have to compute the string length? + if (argument == STRING_A_LENGTH) + { + // Return the string length. + return clazz.getStringString(instructionSequenceMatcher.matchedArgument(A)).length(); + } + + // Otherwise, just return the matched argument. + return instructionSequenceMatcher.matchedArgument(argument); + } + + + /** + * Returns the matched or newly created constant index for the given + * pattern constant index. + */ + private int matchedConstantIndex(ProgramClass programClass, int constantIndex) + { + // Special case: do we have to create a concatenated string? + if (constantIndex >= BOOLEAN_A_STRING && + constantIndex <= (STRING_A_STRING | STRING_B_STRING)) + { + // Create a new string constant and return its index. + return new ConstantPoolEditor(programClass).addStringConstant( + argumentAsString(programClass, constantIndex & 0xf, A) + + argumentAsString(programClass, (constantIndex >>> 4) & 0xf, B), + null, + null); + } + + int matchedConstantIndex = + instructionSequenceMatcher.matchedConstantIndex(constantIndex); + + // Do we have a matched constant index? + if (matchedConstantIndex > 0) + { + // Return its index. + return matchedConstantIndex; + } + + // Otherwise, we still have to create a new constant. + // This currently only works for constants without any wildcards. + ProgramClass dummyClass = new ProgramClass(); + dummyClass.constantPool = patternConstants; + + return new ConstantAdder(programClass).addConstant(dummyClass, constantIndex); + } + + + private String argumentAsString(ProgramClass programClass, + int valueType, + int argument) + { + switch (valueType) + { + case BOOLEAN_STRING: + return Boolean.toString((instructionSequenceMatcher.wasConstant(argument) ? + ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument)) != 0); + + case CHAR_STRING: + return Character.toString((char)(instructionSequenceMatcher.wasConstant(argument) ? + ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument))); + + case INT_STRING: + return Integer.toString(instructionSequenceMatcher.wasConstant(argument) ? + ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument)); + + case LONG_STRING: + return Long.toString(instructionSequenceMatcher.wasConstant(argument) ? + ((LongConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument)); + + case FLOAT_STRING: + return Float.toString(instructionSequenceMatcher.wasConstant(argument) ? + ((FloatConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument)); + + case DOUBLE_STRING: + return Double.toString(instructionSequenceMatcher.wasConstant(argument) ? + ((DoubleConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() : + instructionSequenceMatcher.matchedArgument(argument)); + + case STRING_STRING: + return + programClass.getStringString(instructionSequenceMatcher.matchedConstantIndex(argument)); + + default: + return ""; + } + } } } diff --git a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java index f12b51a..22fb6cd 100644 --- a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java +++ b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/MemberPrivatizer.java b/src/proguard/optimize/peephole/MemberPrivatizer.java index 55b2f31..f57281c 100644 --- a/src/proguard/optimize/peephole/MemberPrivatizer.java +++ b/src/proguard/optimize/peephole/MemberPrivatizer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/MethodFinalizer.java b/src/proguard/optimize/peephole/MethodFinalizer.java index af1811b..89174ac 100644 --- a/src/proguard/optimize/peephole/MethodFinalizer.java +++ b/src/proguard/optimize/peephole/MethodFinalizer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/MethodInliner.java b/src/proguard/optimize/peephole/MethodInliner.java index 55f9ccb..947cd43 100644 --- a/src/proguard/optimize/peephole/MethodInliner.java +++ b/src/proguard/optimize/peephole/MethodInliner.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -29,10 +29,11 @@ import proguard.classfile.editor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; -import proguard.classfile.visitor.MemberVisitor; +import proguard.classfile.visitor.*; +import proguard.optimize.*; import proguard.optimize.info.*; -import java.util.Stack; +import java.util.*; /** * This AttributeVisitor inlines short methods or methods that are only invoked @@ -48,10 +49,8 @@ implements AttributeVisitor, MemberVisitor { private static final int MAXIMUM_INLINED_CODE_LENGTH = Integer.parseInt(System.getProperty("maximum.inlined.code.length", "8")); - private static final int MAXIMUM_RESULTING_CODE_LENGTH_JSE = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "8000")); + private static final int MAXIMUM_RESULTING_CODE_LENGTH_JSE = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "7000")); private static final int MAXIMUM_RESULTING_CODE_LENGTH_JME = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "2000")); - private static final int MAXIMUM_CODE_EXPANSION = 2; - private static final int MAXIMUM_EXTRA_CODE_LENGTH = 128; //* private static final boolean DEBUG = false; @@ -138,6 +137,42 @@ implements AttributeVisitor, public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { + // TODO: Remove this when the method inliner has stabilized. + // Catch any unexpected exceptions from the actual visiting method. + try + { + // Process the code. + visitCodeAttribute0(clazz, method, codeAttribute); + } + catch (RuntimeException ex) + { + System.err.println("Unexpected error while inlining method:"); + System.err.println(" Target class = ["+targetClass.getName()+"]"); + System.err.println(" Target method = ["+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); + if (inlining) + { + System.err.println(" Inlined class = ["+clazz.getName()+"]"); + System.err.println(" Inlined method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); + } + System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); + System.err.println("Not inlining this method"); + + if (DEBUG) + { + targetMethod.accept(targetClass, new ClassPrinter()); + if (inlining) + { + method.accept(clazz, new ClassPrinter()); + } + + throw ex; + } + } + } + + + public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) + { if (!inlining) { // codeAttributeComposer.DEBUG = DEBUG = @@ -278,7 +313,7 @@ implements AttributeVisitor, } codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1, - new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex).shrink()); + new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex)); } } @@ -286,7 +321,7 @@ implements AttributeVisitor, if (!isStatic) { codeAttributeComposer.appendInstruction(parameterSize, - new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset).shrink()); + new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset)); } codeAttributeComposer.endCodeFragment(); @@ -305,12 +340,12 @@ implements AttributeVisitor, // Copy the instructions. codeAttribute.instructionsAccept(clazz, method, this); - // Copy the exceptions. - codeAttribute.exceptionsAccept(clazz, method, exceptionInfoAdder); - // Append a label just after the code. codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); + // Copy the exceptions. + codeAttribute.exceptionsAccept(clazz, method, exceptionInfoAdder); + codeAttributeComposer.endCodeFragment(); } @@ -319,7 +354,7 @@ implements AttributeVisitor, public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { - codeAttributeComposer.appendInstruction(offset, instruction.shrink()); + codeAttributeComposer.appendInstruction(offset, instruction); } @@ -346,7 +381,7 @@ implements AttributeVisitor, codeAttribute.u4codeLength - offset); codeAttributeComposer.appendInstruction(offset, - branchInstruction.shrink()); + branchInstruction); } else { @@ -359,7 +394,7 @@ implements AttributeVisitor, } } - codeAttributeComposer.appendInstruction(offset, simpleInstruction.shrink()); + codeAttributeComposer.appendInstruction(offset, simpleInstruction); } @@ -372,7 +407,7 @@ implements AttributeVisitor, variableInstruction.variableIndex += variableOffset; } - codeAttributeComposer.appendInstruction(offset, variableInstruction.shrink()); + codeAttributeComposer.appendInstruction(offset, variableInstruction); } @@ -430,7 +465,7 @@ implements AttributeVisitor, constantAdder.addConstant(clazz, constantInstruction.constantIndex); } - codeAttributeComposer.appendInstruction(offset, constantInstruction.shrink()); + codeAttributeComposer.appendInstruction(offset, constantInstruction); } @@ -454,45 +489,48 @@ implements AttributeVisitor, { int accessFlags = programMethod.getAccessFlags(); - if (// Only inline the method if it is private, static, or final. + if (// Don't inline methods that must be preserved. + !KeepMarker.isKept(programMethod) && + + // Only inline the method if it is private, static, or final. (accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | - ClassConstants.INTERNAL_ACC_FINAL)) != 0 && + ClassConstants.INTERNAL_ACC_FINAL)) != 0 && // Only inline the method if it is not synchronized, etc. (accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED | ClassConstants.INTERNAL_ACC_NATIVE | ClassConstants.INTERNAL_ACC_INTERFACE | - ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 && + ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 && // Don't inline an <init> method, except in an <init> method in the // same class. // (!programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) || // (programClass.equals(targetClass) && // targetMethod.getName(targetClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) && - !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && + !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && // Don't inline a method into itself. (!programMethod.equals(targetMethod) || - !programClass.equals(targetClass)) && + !programClass.equals(targetClass)) && // Only inline the method if it isn't recursing. - !inliningMethods.contains(programMethod) && + !inliningMethods.contains(programMethod) && // Only inline the method if its target class has at least the // same version number as the source class, in order to avoid // introducing incompatible constructs. - targetClass.u4version >= programClass.u4version && + targetClass.u4version >= programClass.u4version && // Only inline the method if it doesn't invoke a super method, or if // it is in the same class. (!SuperInvocationMarker.invokesSuperMethods(programMethod) || - programClass.equals(targetClass)) && + programClass.equals(targetClass)) && // Only inline the method if it doesn't branch backward while there // are uninitialized objects. (!BackwardBranchMarker.branchesBackward(programMethod) || - uninitializedObjectCount == 0) && + uninitializedObjectCount == 0) && // Only inline if the code access of the inlined method allows it. (allowAccessModification || @@ -501,47 +539,24 @@ implements AttributeVisitor, (!AccessMethodMarker.accessesPackageCode(programMethod) || ClassUtil.internalPackageName(programClass.getName()).equals( - ClassUtil.internalPackageName(targetClass.getName()))))) && + ClassUtil.internalPackageName(targetClass.getName()))))) && // (!AccessMethodMarker.accessesProtectedCode(programMethod) || // targetClass.extends_(programClass) || // targetClass.implements_(programClass)) || (!AccessMethodMarker.accessesProtectedCode(programMethod) || - programClass.equals(targetClass)) && + programClass.equals(targetClass)) && // Only inline the method if it doesn't catch exceptions, or if it // is invoked with an empty stack. (!CatchExceptionMarker.catchesExceptions(programMethod) || - emptyInvokingStack) && + emptyInvokingStack) && - // Only inline the method if it comes from the same class or from - // a class with a static initializer. + // Only inline the method if it comes from the a class with at most + // a subset of the initialized superclasses. (programClass.equals(targetClass) || - programClass.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, - ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) == null)) - { -// System.out.print("MethodInliner: inlining "); -// programMethod.accept(programClass, new SimpleClassPrinter(true)); -// System.out.print(" in "); -// targetMethod.accept(targetClass, new SimpleClassPrinter(true)); -// -// System.out.println(" Private: "+ -// (!AccessMethodMarker.accessesPrivateCode(programMethod) || -// programClass.equals(targetClass))); -// -// System.out.println(" Package: "+ -// (!AccessMethodMarker.accessesPackageCode(programMethod) || -// ClassUtil.internalPackageName(programClass.getName()).equals( -// ClassUtil.internalPackageName(targetClass.getName())))); -// -// System.out.println(" Protected: "+ -// ((!AccessMethodMarker.accessesProtectedCode(programMethod) || -// targetClass.extends_(programClass) || -// targetClass.implements_(programClass)) || -// ClassUtil.internalPackageName(programClass.getName()).equals( -// ClassUtil.internalPackageName(targetClass.getName())))); - - boolean oldInlining = inlining; + initializedSuperClasses(targetClass).containsAll(initializedSuperClasses(programClass)))) + { boolean oldInlining = inlining; inlining = true; inliningMethods.push(programMethod); @@ -564,4 +579,21 @@ implements AttributeVisitor, uninitializedObjectCount--; } } + + + /** + * Returns the set of superclasses and interfaces that are initialized. + */ + private Set initializedSuperClasses(Clazz clazz) + { + Set set = new HashSet(); + + // Visit all superclasses and interfaces, collecting the ones that have + // static initializers. + clazz.hierarchyAccept(true, true, true, false, + new StaticInitializerContainingClassFilter( + new ClassCollector(set))); + + return set; + } } diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/peephole/NopRemover.java index 69adb30..9396c40 100644 --- a/src/proguard/optimize/peephole/NopRemover.java +++ b/src/proguard/optimize/peephole/NopRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/PeepholeOptimizer.java b/src/proguard/optimize/peephole/PeepholeOptimizer.java index 98f8e8d..2a602ee 100644 --- a/src/proguard/optimize/peephole/PeepholeOptimizer.java +++ b/src/proguard/optimize/peephole/PeepholeOptimizer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/ReachableCodeMarker.java b/src/proguard/optimize/peephole/ReachableCodeMarker.java index d9dbf2d..b6fcf18 100644 --- a/src/proguard/optimize/peephole/ReachableCodeMarker.java +++ b/src/proguard/optimize/peephole/ReachableCodeMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -27,6 +27,8 @@ import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; +import java.util.Arrays; + /** * This AttributeVisitor finds all instruction offsets, branch targets, and * exception targets in the CodeAttribute objects that it visits. @@ -91,10 +93,7 @@ implements AttributeVisitor, else { // Reset the array. - for (int index = 0; index < codeLength; index++) - { - isReachable[index] = false; - } + Arrays.fill(isReachable, 0, codeLength, false); } // Mark the code, starting at the entry point. diff --git a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java index 6707a12..a67c6ff 100644 --- a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java +++ b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -28,6 +28,8 @@ import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; +import java.util.Arrays; + /** * This ClassVisitor removes InnerClasses and EnclosingMethod attributes in * classes that are retargeted or that refer to classes that are retargeted. @@ -70,12 +72,9 @@ implements ClassVisitor, } // Clean up any remaining array elements. - for (int index = newAtributesCount; index < attributesCount; index++) - { - attributes[index] = null; - } + Arrays.fill(attributes, newAtributesCount, attributesCount, null); - // Update the number of attribuets. + // Update the number of attributes. programClass.u2attributesCount = newAtributesCount; } @@ -90,8 +89,39 @@ implements ClassVisitor, // Check whether the class itself is retargeted. checkTarget(clazz); - // Check whether the referenced classes are retargeted. - innerClassesAttribute.innerClassEntriesAccept(clazz, this); + if (!retargeted) + { + // Check whether the referenced classes are retargeted. + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + int classesCount = innerClassesAttribute.u2classesCount; + InnerClassesInfo[] classes = innerClassesAttribute.classes; + + int newClassesCount = 0; + + // Copy over all non-retargeted attributes. + for (int index = 0; index < classesCount; index++) + { + InnerClassesInfo classInfo = classes[index]; + + // Check if the outer class or inner class is a retargeted class. + retargeted = false; + classInfo.outerClassConstantAccept(clazz, this); + classInfo.innerClassConstantAccept(clazz, this); + if (!retargeted) + { + classes[newClassesCount++] = classInfo; + } + } + + // Clean up any remaining array elements. + Arrays.fill(classes, newClassesCount, classesCount, null); + + // Update the number of classes. + innerClassesAttribute.u2classesCount = newClassesCount; + + // Remove the attribute altogether if it's empty. + retargeted = newClassesCount == 0; + } } diff --git a/src/proguard/optimize/peephole/TargetClassChanger.java b/src/proguard/optimize/peephole/TargetClassChanger.java index 22fd83d..f997e03 100644 --- a/src/proguard/optimize/peephole/TargetClassChanger.java +++ b/src/proguard/optimize/peephole/TargetClassChanger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -51,13 +51,13 @@ implements ClassVisitor, AnnotationVisitor, ElementValueVisitor { + private static final boolean DEBUG = false; + + // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { - Clazz superClass = null; - Clazz[] interfaceClasses = null; - // Change the references of the constant pool. programClass.constantPoolEntriesAccept(this); @@ -80,34 +80,39 @@ implements ClassVisitor, programClass.getName(), programClass); + // This class will loose all its interfaces. + programClass.u2interfacesCount = 0; + // This class will loose all its subclasses. programClass.subClasses = null; } - - // Remove interface classes that are pointing to this class. - int newInterfacesCount = 0; - for (int index = 0; index < programClass.u2interfacesCount; index++) + else { - Clazz interfaceClass = programClass.getInterface(index); - if (!programClass.equals(interfaceClass)) + // Remove interface classes that are pointing to this class. + int newInterfacesCount = 0; + for (int index = 0; index < programClass.u2interfacesCount; index++) { - programClass.u2interfaces[newInterfacesCount++] = - programClass.u2interfaces[index]; + Clazz interfaceClass = programClass.getInterface(index); + if (!programClass.equals(interfaceClass)) + { + programClass.u2interfaces[newInterfacesCount++] = + programClass.u2interfaces[index]; + } } - } - programClass.u2interfacesCount = newInterfacesCount; + programClass.u2interfacesCount = newInterfacesCount; - // Update the subclasses of the superclass and interfaces of the - // target class. - ConstantVisitor subclassAdder = - new ReferencedClassVisitor( - new SubclassFilter(programClass, - new SubclassAdder(programClass))); + // Update the subclasses of the superclass and interfaces of the + // target class. + ConstantVisitor subclassAdder = + new ReferencedClassVisitor( + new SubclassFilter(programClass, + new SubclassAdder(programClass))); - programClass.superClassConstantAccept(subclassAdder); - programClass.interfaceConstantsAccept(subclassAdder); + programClass.superClassConstantAccept(subclassAdder); + programClass.interfaceConstantsAccept(subclassAdder); - // TODO: Maybe restore private method references. + // TODO: Maybe restore private method references. + } } @@ -188,6 +193,12 @@ implements ClassVisitor, Clazz newReferencedClass = updateReferencedClass(referencedClass); if (referencedClass != newReferencedClass) { + if (DEBUG) + { + System.out.println("TargetClassChanger:"); + System.out.println(" ["+clazz.getName()+"] changing reference from ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); + } + // Change the referenced class. refConstant.referencedClass = newReferencedClass; @@ -197,6 +208,11 @@ implements ClassVisitor, refConstant.getName(clazz), refConstant.getType(clazz), newReferencedClass); + + if (DEBUG) + { + System.out.println(" ["+clazz.getName()+"] to ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); + } } } diff --git a/src/proguard/optimize/peephole/UnreachableCodeRemover.java b/src/proguard/optimize/peephole/UnreachableCodeRemover.java index e8a99ab..570b3ca 100644 --- a/src/proguard/optimize/peephole/UnreachableCodeRemover.java +++ b/src/proguard/optimize/peephole/UnreachableCodeRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java index 048f5e3..8e77716 100644 --- a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java +++ b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/VariableShrinker.java b/src/proguard/optimize/peephole/VariableShrinker.java index 45b694f..6c05944 100644 --- a/src/proguard/optimize/peephole/VariableShrinker.java +++ b/src/proguard/optimize/peephole/VariableShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/VerticalClassMerger.java b/src/proguard/optimize/peephole/VerticalClassMerger.java index 29ed6ff..825de94 100644 --- a/src/proguard/optimize/peephole/VerticalClassMerger.java +++ b/src/proguard/optimize/peephole/VerticalClassMerger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free |