diff options
author | Ying Wang <wangying@google.com> | 2012-02-27 10:21:35 -0800 |
---|---|---|
committer | Ying Wang <wangying@google.com> | 2012-02-27 11:54:51 -0800 |
commit | cfead78069f3dc32998dc118ee08cab3867acea2 (patch) | |
tree | 9600f15eed62fa9ba63ce5894d1f09fe686d5997 /src/proguard/optimize | |
parent | 10aa7224f49abe49d123bde5d34346202d49aaca (diff) | |
download | android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.tar.gz android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.tar.bz2 android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.zip |
Upgrade from Progaurd 4.4 to 4.7.
Change-Id: Ie185d0be411a80cc6a330cafa8547252a7dc1d9c
You can find the changelog here
http://proguard.sourceforge.net/#downloads.html
Diffstat (limited to 'src/proguard/optimize')
77 files changed, 2975 insertions, 680 deletions
diff --git a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java new file mode 100644 index 0000000..70d031d --- /dev/null +++ b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java @@ -0,0 +1,103 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.optimize; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.annotation.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.editor.ConstantPoolEditor; +import proguard.classfile.util.*; +import proguard.classfile.visitor.MemberVisitor; +import proguard.optimize.info.*; +import proguard.optimize.peephole.VariableShrinker; + +/** + * This BootstrapMethodInfoVisitor removes unused constant arguments from + * bootstrap method entries that it visits. + * + * @see ParameterUsageMarker + * @see VariableUsageMarker + * @see VariableShrinker + * @author Eric Lafortune + */ +public class BootstrapMethodArgumentShrinker +extends SimplifiedVisitor +implements BootstrapMethodInfoVisitor, + ConstantVisitor, + MemberVisitor +{ + private long usedParameters; + + + // Implementations for BootstrapMethodInfoVisitor. + + public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) + { + // Check which method parameters are used. + usedParameters = -1L; + clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, this); + + // Remove the unused arguments. + int methodArgumentCount = bootstrapMethodInfo.u2methodArgumentCount; + int[] methodArguments = bootstrapMethodInfo.u2methodArguments; + + int newArgumentIndex = 0; + + for (int argumentIndex = 0; argumentIndex < methodArgumentCount; argumentIndex++) + { + if (argumentIndex >= 64 || + (usedParameters & (1L << argumentIndex)) != 0L) + { + methodArguments[newArgumentIndex++] = methodArguments[argumentIndex]; + } + } + + // Update the number of arguments. + bootstrapMethodInfo.u2methodArgumentCount = newArgumentIndex; + } + + + // Implementations for ConstantVisitor. + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + // Check the referenced bootstrap method. + clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); + } + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + // Check the referenced class member itself. + refConstant.referencedMemberAccept(this); + } + + + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + usedParameters = ParameterUsageMarker.getUsedParameters(programMethod); + } +} diff --git a/src/proguard/optimize/ChangedCodePrinter.java b/src/proguard/optimize/ChangedCodePrinter.java index 67a79ab..e0d00b8 100644 --- a/src/proguard/optimize/ChangedCodePrinter.java +++ b/src/proguard/optimize/ChangedCodePrinter.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-2011 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 @@ -54,6 +54,12 @@ implements AttributeVisitor } + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + attributeVisitor.visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute); + } + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { attributeVisitor.visitSourceFileAttribute(clazz, sourceFileAttribute); diff --git a/src/proguard/optimize/ConstantMemberFilter.java b/src/proguard/optimize/ConstantMemberFilter.java index 56437c3..d3a8207 100644 --- a/src/proguard/optimize/ConstantMemberFilter.java +++ b/src/proguard/optimize/ConstantMemberFilter.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-2011 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/ConstantParameterFilter.java b/src/proguard/optimize/ConstantParameterFilter.java index 24a7040..6920990 100644 --- a/src/proguard/optimize/ConstantParameterFilter.java +++ b/src/proguard/optimize/ConstantParameterFilter.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-2011 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/DuplicateInitializerFixer.java b/src/proguard/optimize/DuplicateInitializerFixer.java index 746d182..07b7d82 100644 --- a/src/proguard/optimize/DuplicateInitializerFixer.java +++ b/src/proguard/optimize/DuplicateInitializerFixer.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-2011 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 @@ -86,7 +86,7 @@ implements MemberVisitor, if (!programMethod.equals(similarMethod)) { // Should this initializer be preserved? - if (!KeepMarker.isKept(programMethod)) + if (KeepMarker.isKept(programMethod)) { // Fix the other initializer. programMethod = (ProgramMethod)similarMethod; @@ -95,12 +95,23 @@ implements MemberVisitor, int index = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); // Try to find a new, unique descriptor. - for (int typeIndex = 0; typeIndex < TYPES.length; typeIndex++) + int typeCounter = 0; + while (true) { - String newDescriptor = - descriptor.substring(0, index) + - TYPES[typeIndex] + - descriptor.substring(index); + // Construct the new descriptor by inserting a new type + // as an additional last argument. + StringBuffer newDescriptorBuffer = + new StringBuffer(descriptor.substring(0, index)); + + for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++) + { + newDescriptorBuffer.append(ClassConstants.INTERNAL_TYPE_ARRAY); + } + + newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]); + newDescriptorBuffer.append(descriptor.substring(index)); + + String newDescriptor = newDescriptorBuffer.toString(); // Is the new initializer descriptor unique? if (programClass.findMethod(name, newDescriptor) == null) @@ -108,7 +119,7 @@ implements MemberVisitor, if (DEBUG) { System.out.println("DuplicateInitializerFixer:"); - System.out.println(" ["+programClass.getName()+"]: "+name+descriptor+" -> "+newDescriptor); + System.out.println(" ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]"); } // Update the descriptor. @@ -130,12 +141,9 @@ implements MemberVisitor, // We're done with this constructor. return; } - } - throw new IllegalStateException("Can't find unique constructor descriptor for ["+ - programClass.getName()+"."+ - programMethod.getName(programClass)+ - programMethod.getDescriptor(programClass)+"]"); + typeCounter++; + } } } } diff --git a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java b/src/proguard/optimize/DuplicateInitializerInvocationFixer.java index ca24481..e900232 100644 --- a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java +++ b/src/proguard/optimize/DuplicateInitializerInvocationFixer.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-2011 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,7 +28,7 @@ import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.editor.CodeAttributeEditor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; -import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; /** @@ -48,12 +48,12 @@ implements AttributeVisitor, private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); - private String descriptor; - private boolean hasBeenFixed; + private String descriptor; + private int descriptorLengthDelta; /** - * Creates a new EvaluationSimplifier. + * Creates a new DuplicateInitializerInvocationFixer. */ public DuplicateInitializerInvocationFixer() { @@ -62,7 +62,7 @@ implements AttributeVisitor, /** - * Creates a new EvaluationSimplifier. + * Creates a new DuplicateInitializerInvocationFixer. * @param extraAddedInstructionVisitor an optional extra visitor for all * added instructions. */ @@ -102,21 +102,22 @@ implements AttributeVisitor, { if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL) { - hasBeenFixed = false; + descriptorLengthDelta = 0; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); - if (hasBeenFixed) + if (descriptorLengthDelta > 0) { Instruction extraInstruction = - new SimpleInstruction(InstructionConstants.OP_ICONST_0); + new SimpleInstruction(descriptorLengthDelta == 1 ? + InstructionConstants.OP_ICONST_0 : + InstructionConstants.OP_ACONST_NULL); codeAttributeEditor.insertBeforeInstruction(offset, extraInstruction); if (DEBUG) { - System.out.println("DuplicateInitializerInvocationFixer:"); - System.out.println(" Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset)); + System.out.println(" ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset)); } if (extraAddedInstructionVisitor != null) @@ -145,6 +146,16 @@ implements AttributeVisitor, public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { - hasBeenFixed = !descriptor.equals(programMethod.getDescriptor(programClass)); + descriptorLengthDelta = + programMethod.getDescriptor(programClass).length() - descriptor.length(); + + if (DEBUG) + { + if (descriptorLengthDelta > 0) + { + System.out.println("DuplicateInitializerInvocationFixer:"); + System.out.println(" ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") referenced by:"); + } + } } -}
\ No newline at end of file +} diff --git a/src/proguard/optimize/KeepMarker.java b/src/proguard/optimize/KeepMarker.java index 4297996..f8087be 100644 --- a/src/proguard/optimize/KeepMarker.java +++ b/src/proguard/optimize/KeepMarker.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-2011 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/KeptClassFilter.java b/src/proguard/optimize/KeptClassFilter.java new file mode 100644 index 0000000..4b9d090 --- /dev/null +++ b/src/proguard/optimize/KeptClassFilter.java @@ -0,0 +1,69 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.optimize; + +import proguard.classfile.*; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This ClassVisitor delegates all its method calls to another ClassVisitor, + * but only for Clazz objects that are marked as kept. + * + * @see KeepMarker + * + * @author Eric Lafortune + */ +public class KeptClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + /** + * Creates a new KeptClassFilter. + * @param classVisitor the class visitor to which the visiting will be + * delegated. + */ + public KeptClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (KeepMarker.isKept(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (KeepMarker.isKept(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +}
\ No newline at end of file diff --git a/src/proguard/optimize/KeptMemberFilter.java b/src/proguard/optimize/KeptMemberFilter.java new file mode 100644 index 0000000..5b25425 --- /dev/null +++ b/src/proguard/optimize/KeptMemberFilter.java @@ -0,0 +1,88 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.optimize; + +import proguard.classfile.*; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This MemberVisitor delegates all its method calls to another MemberVisitor, + * but only for Member objects that are marked as kept. + * + * @see KeepMarker + * + * @author Eric Lafortune + */ +public class KeptMemberFilter +implements MemberVisitor +{ + private final MemberVisitor memberVisitor; + + + /** + * Creates a new KeptMemberFilter. + * @param memberVisitor the member visitor to which the visiting will be + * delegated. + */ + public KeptMemberFilter(MemberVisitor memberVisitor) + { + this.memberVisitor = memberVisitor; + } + + + // Implementations for MemberVisitor. + + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + if (KeepMarker.isKept(programField)) + { + memberVisitor.visitProgramField(programClass, programField); + } + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + if (KeepMarker.isKept(programMethod)) + { + memberVisitor.visitProgramMethod(programClass, programMethod); + } + } + + + public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) + { + if (KeepMarker.isKept(libraryField)) + { + memberVisitor.visitLibraryField(libraryClass, libraryField); + } + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + if (KeepMarker.isKept(libraryMethod)) + { + memberVisitor.visitLibraryMethod(libraryClass, libraryMethod); + } + } +}
\ No newline at end of file diff --git a/src/proguard/optimize/MemberDescriptorSpecializer.java b/src/proguard/optimize/MemberDescriptorSpecializer.java index 0d0b841..7f051f5 100644 --- a/src/proguard/optimize/MemberDescriptorSpecializer.java +++ b/src/proguard/optimize/MemberDescriptorSpecializer.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-2011 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 @@ -39,7 +39,7 @@ public class MemberDescriptorSpecializer extends SimplifiedVisitor implements MemberVisitor { - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final MemberVisitor extraParameterMemberVisitor; diff --git a/src/proguard/optimize/MethodDescriptorShrinker.java b/src/proguard/optimize/MethodDescriptorShrinker.java index 48374e7..f4667ee 100644 --- a/src/proguard/optimize/MethodDescriptorShrinker.java +++ b/src/proguard/optimize/MethodDescriptorShrinker.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-2011 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 @@ -23,7 +23,7 @@ package proguard.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; -import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.attribute.visitor.*; import proguard.classfile.editor.ConstantPoolEditor; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; @@ -95,11 +95,9 @@ implements MemberVisitor, if (DEBUG) { System.out.println("MethodDescriptorShrinker:"); - System.out.println(" Class file = "+programClass.getName()); - System.out.println(" Method name = "+name); - System.out.println(" -> "+newName); - System.out.println(" Method descriptor = "+descriptor); - System.out.println(" -> "+newDescriptor); + System.out.println(" ["+programClass.getName()+"."+ + name+descriptor+"] -> ["+ + newName+newDescriptor+"]"); } ConstantPoolEditor constantPoolEditor = diff --git a/src/proguard/optimize/MethodStaticizer.java b/src/proguard/optimize/MethodStaticizer.java index 8dd11e1..9bd7b2a 100644 --- a/src/proguard/optimize/MethodStaticizer.java +++ b/src/proguard/optimize/MethodStaticizer.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-2011 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/OptimizationInfoMemberFilter.java b/src/proguard/optimize/OptimizationInfoMemberFilter.java index 8760aee..a6d3cc7 100644 --- a/src/proguard/optimize/OptimizationInfoMemberFilter.java +++ b/src/proguard/optimize/OptimizationInfoMemberFilter.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-2011 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/Optimizer.java b/src/proguard/optimize/Optimizer.java index a3e8a6e..c5db18b 100644 --- a/src/proguard/optimize/Optimizer.java +++ b/src/proguard/optimize/Optimizer.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-2011 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 @@ -23,7 +23,8 @@ package proguard.optimize; import proguard.*; import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; -import proguard.classfile.constant.visitor.AllConstantVisitor; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.instruction.visitor.*; import proguard.classfile.util.MethodLinker; @@ -66,6 +67,7 @@ public class Optimizer private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast"; private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field"; private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch"; + private static final String CODE_SIMPLIFICATION_STRING = "code/simplification/string"; private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced"; private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced"; private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple"; @@ -80,6 +82,7 @@ public class Optimizer CLASS_MERGING_VERTICAL, CLASS_MERGING_HORIZONTAL, FIELD_REMOVAL_WRITEONLY, + FIELD_MARKING_PRIVATE, FIELD_PROPAGATION_VALUE, METHOD_MARKING_PRIVATE, METHOD_MARKING_STATIC, @@ -96,6 +99,7 @@ public class Optimizer CODE_SIMPLIFICATION_CAST, CODE_SIMPLIFICATION_FIELD, CODE_SIMPLIFICATION_BRANCH, + CODE_SIMPLIFICATION_STRING, CODE_SIMPLIFICATION_ADVANCED, CODE_REMOVAL_ADVANCED, CODE_REMOVAL_SIMPLE, @@ -157,6 +161,7 @@ public class Optimizer boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST); boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD); boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH); + boolean codeSimplificationString = filter.matches(CODE_SIMPLIFICATION_STRING); boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED); boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED); boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE); @@ -186,13 +191,15 @@ public class Optimizer InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); + InstructionCounter codeSimplificationStringCounter = new InstructionCounter(); InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); InstructionCounter deletedCounter = new InstructionCounter(); InstructionCounter addedCounter = new InstructionCounter(); MemberCounter codeRemovalVariableCounter = new MemberCounter(); ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); MemberCounter codeAllocationVariableCounter = new MemberCounter(); - MemberCounter initializerFixCounter = new MemberCounter(); + MemberCounter initializerFixCounter1 = new MemberCounter(); + MemberCounter initializerFixCounter2 = new MemberCounter(); // Some optimizations are required by other optimizations. codeSimplificationAdvanced = @@ -250,10 +257,27 @@ public class Optimizer new AllInstructionVisitor( new DotClassClassVisitor(keepMarker))))); - // We also keep all classes that are involved in Class.forName constructs. + // We also keep all classes that are accessed dynamically. programClassPool.classesAccept( new AllConstantVisitor( - new ClassForNameClassVisitor(keepMarker))); + new ConstantTagFilter(ClassConstants.CONSTANT_String, + new ReferencedClassVisitor(keepMarker)))); + + // We also keep all class members that are accessed dynamically. + programClassPool.classesAccept( + new AllConstantVisitor( + new ConstantTagFilter(ClassConstants.CONSTANT_String, + new ReferencedMemberVisitor(keepMarker)))); + + // We also keep all bootstrap method signatures. + programClassPool.classesAccept( + new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_7, + new AllAttributeVisitor( + new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods, + new AllBootstrapMethodInfoVisitor( + new BootstrapMethodHandleTraveler( + new MethodrefTraveler( + new ReferencedMemberVisitor(keepMarker)))))))); // Attach some optimization info to all classes and class members, so // it can be filled out later. @@ -320,6 +344,9 @@ public class Optimizer new ParameterUsageMarker(!methodMarkingStatic, !methodRemovalParameter)))); + // Mark all classes that have static initializers. + programClassPool.classesAccept(new StaticInitializerContainingClassMarker()); + // Mark all methods that have side effects. programClassPool.accept(new SideEffectMethodMarker()); @@ -347,18 +374,29 @@ public class Optimizer new AllAttributeVisitor( new PartialEvaluator(valueFactory, storingInvocationUnit, false)))); - // Count the constant fields and methods. - programClassPool.classesAccept( - new MultiClassVisitor( - new ClassVisitor[] - { + if (fieldPropagationValue) + { + // Count the constant fields. + programClassPool.classesAccept( new AllFieldVisitor( - new ConstantMemberFilter(fieldPropagationValueCounter)), + new ConstantMemberFilter(fieldPropagationValueCounter))); + } + + if (methodPropagationParameter) + { + // Count the constant method parameters. + programClassPool.classesAccept( new AllMethodVisitor( - new ConstantParameterFilter(methodPropagationParameterCounter)), + new ConstantParameterFilter(methodPropagationParameterCounter))); + } + + if (methodPropagationReturnvalue) + { + // Count the constant method return values. + programClassPool.classesAccept( new AllMethodVisitor( - new ConstantMemberFilter(methodPropagationReturnvalueCounter)), - })); + new ConstantMemberFilter(methodPropagationReturnvalueCounter))); + } } InvocationUnit loadingInvocationUnit = @@ -418,6 +456,12 @@ public class Optimizer // This operation also updates the stack sizes. programClassPool.classesAccept( new MemberReferenceFixer()); + + // Remove unused bootstrap method arguments. + programClassPool.classesAccept( + new AllAttributeVisitor( + new AllBootstrapMethodInfoVisitor( + new BootstrapMethodArgumentShrinker()))); } if (methodRemovalParameter || @@ -441,17 +485,39 @@ public class Optimizer new StackSizeUpdater()))); } -// // Specializing the class member descriptors seems to increase the -// // class file size, on average. -// // Specialize all class member descriptors. -// programClassPool.classesAccept(new AllMemberVisitor( -// new OptimizationInfoMemberFilter( -// new MemberDescriptorSpecializer()))); -// -// // Fix all references to classes, for MemberDescriptorSpecializer. -// programClassPool.classesAccept(new AllMemberVisitor( -// new OptimizationInfoMemberFilter( -// new ClassReferenceFixer(true)))); + if (methodRemovalParameter && + methodRemovalParameterCounter.getCount() > 0) + { + // Tweak the descriptors of duplicate initializers, due to removed + // method parameters. + programClassPool.classesAccept( + new AllMethodVisitor( + new DuplicateInitializerFixer(initializerFixCounter1))); + + if (initializerFixCounter1.getCount() > 0) + { + // Fix all invocations of tweaked initializers. + programClassPool.classesAccept( + new AllMethodVisitor( + new AllAttributeVisitor( + new DuplicateInitializerInvocationFixer(addedCounter)))); + + // Fix all references to tweaked initializers. + programClassPool.classesAccept(new MemberReferenceFixer()); + } + } + + //// Specializing the class member descriptors seems to increase the + //// class file size, on average. + //// Specialize all class member descriptors. + //programClassPool.classesAccept(new AllMemberVisitor( + // new OptimizationInfoMemberFilter( + // new MemberDescriptorSpecializer()))); + // + //// Fix all references to classes, for MemberDescriptorSpecializer. + //programClassPool.classesAccept(new AllMemberVisitor( + // new OptimizationInfoMemberFilter( + // new ClassReferenceFixer(true)))); // Mark all classes with package visible members. // Mark all exception catches of methods. @@ -461,13 +527,13 @@ public class Optimizer new MultiClassVisitor( new ClassVisitor[] { + new PackageVisibleMemberContainingClassMarker(), new AllConstantVisitor( new PackageVisibleMemberInvokingClassMarker()), new AllMethodVisitor( new MultiMemberVisitor( new MemberVisitor[] { - new PackageVisibleMemberContainingClassMarker(), new AllAttributeVisitor( new MultiAttributeVisitor( new AttributeVisitor[] @@ -511,8 +577,8 @@ public class Optimizer classMergingHorizontalCounter)); } - if (classMergingVertical || - classMergingHorizontal) + if (classMergingVerticalCounter .getCount() > 0 || + classMergingHorizontalCounter.getCount() > 0) { // Clean up inner class attributes to avoid loops. programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); @@ -530,18 +596,20 @@ public class Optimizer new AllConstantVisitor( new AccessFixer())); } - } - if (methodRemovalParameter || - classMergingVertical || - classMergingHorizontal) - { - // Tweak the descriptors of duplicate initializers. + // Fix the access flags of the inner classes information. + programClassPool.classesAccept( + new AllAttributeVisitor( + new AllInnerClassesInfoVisitor( + new InnerClassesAccessFixer()))); + + // Tweak the descriptors of duplicate initializers, due to merged + // parameter classes. programClassPool.classesAccept( new AllMethodVisitor( - new DuplicateInitializerFixer(initializerFixCounter))); + new DuplicateInitializerFixer(initializerFixCounter2))); - if (initializerFixCounter.getCount() > 0) + if (initializerFixCounter2.getCount() > 0) { // Fix all invocations of tweaked initializers. programClassPool.classesAccept( @@ -595,14 +663,14 @@ public class Optimizer new NonPrivateMemberMarker()); } - if (fieldMarkingPrivate || - methodMarkingPrivate) + if (fieldMarkingPrivate) { // Make all non-private fields private, whereever possible. programClassPool.classesAccept( + new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, new AllFieldVisitor( new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, - new MemberPrivatizer(fieldMarkingPrivateCounter)))); + new MemberPrivatizer(fieldMarkingPrivateCounter))))); } if (methodMarkingPrivate) @@ -615,9 +683,9 @@ public class Optimizer new MemberPrivatizer(methodMarkingPrivateCounter))))); } - if ((methodInliningUnique || - methodInliningShort || - methodInliningTailrecursion) && + if ((methodInliningUniqueCounter .getCount() > 0 || + methodInliningShortCounter .getCount() > 0 || + methodInliningTailrecursionCounter.getCount() > 0) && configuration.allowAccessModification) { // Fix the access flags of referenced classes and class members, @@ -627,10 +695,10 @@ public class Optimizer new AccessFixer())); } - if (methodRemovalParameter || - classMergingVertical || - classMergingHorizontal || - methodMarkingPrivate) + if (methodRemovalParameterCounter .getCount() > 0 || + classMergingVerticalCounter .getCount() > 0 || + classMergingHorizontalCounter .getCount() > 0 || + methodMarkingPrivateCounter .getCount() > 0 ) { // Fix invocations of interface methods, of methods that have become // non-abstract or private, and of methods that have moved to a @@ -707,6 +775,15 @@ public class Optimizer new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); } + if (codeSimplificationString) + { + // Peephole optimizations involving branches. + peepholeOptimizations.add( + new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, + InstructionSequenceConstants.STRING, + branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter)); + } + if (!peepholeOptimizations.isEmpty()) { // Convert the list into an array. @@ -749,14 +826,6 @@ public class Optimizer new AllAttributeVisitor( new VariableShrinker(codeRemovalVariableCounter)))); } - else - { - // Clean up all unused local variables. - programClassPool.classesAccept( - new AllMethodVisitor( - new AllAttributeVisitor( - new VariableCleaner()))); - } if (codeAllocationVariable) { @@ -767,6 +836,11 @@ public class Optimizer new VariableOptimizer(false, codeAllocationVariableCounter)))); } + + // Remove unused constants. + programClassPool.classesAccept( + new ConstantPoolShrinker()); + int classMarkingFinalCount = classMarkingFinalCounter .getCount(); int classMergingVerticalCount = classMergingVerticalCounter .getCount(); int classMergingHorizontalCount = classMergingHorizontalCounter .getCount(); @@ -776,7 +850,7 @@ public class Optimizer int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount(); int methodMarkingStaticCount = methodMarkingStaticCounter .getCount(); int methodMarkingFinalCount = methodMarkingFinalCounter .getCount(); - int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter.getCount(); + int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount(); int methodPropagationParameterCount = methodPropagationParameterCounter .getCount(); int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); int methodInliningShortCount = methodInliningShortCounter .getCount(); @@ -788,12 +862,23 @@ public class Optimizer int codeSimplificationCastCount = codeSimplificationCastCounter .getCount(); int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount(); int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount(); + int codeSimplificationStringCount = codeSimplificationStringCounter .getCount(); int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount(); int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount(); int codeRemovalVariableCount = codeRemovalVariableCounter .getCount(); int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount(); int codeAllocationVariableCount = codeAllocationVariableCounter .getCount(); + // Forget about constant fields, parameters, and return values, if they + // didn't lead to any useful optimizations. We want to avoid fruitless + // additional optimization passes. + if (codeSimplificationAdvancedCount == 0) + { + fieldPropagationValueCount = 0; + methodPropagationParameterCount = 0; + methodPropagationReturnvalueCount = 0; + } + if (configuration.verbose) { System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); @@ -817,6 +902,7 @@ public class Optimizer System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); + System.out.println(" Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString)); System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); @@ -845,6 +931,7 @@ public class Optimizer codeSimplificationCastCount > 0 || codeSimplificationFieldCount > 0 || codeSimplificationBranchCount > 0 || + codeSimplificationStringCount > 0 || codeSimplificationAdvancedCount > 0 || codeRemovalCount > 0 || codeRemovalVariableCount > 0 || diff --git a/src/proguard/optimize/ParameterShrinker.java b/src/proguard/optimize/ParameterShrinker.java index a2bc6d3..2021861 100644 --- a/src/proguard/optimize/ParameterShrinker.java +++ b/src/proguard/optimize/ParameterShrinker.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-2011 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 @@ -23,7 +23,7 @@ package proguard.optimize; import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; -import proguard.classfile.editor.*; +import proguard.classfile.editor.VariableRemapper; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; import proguard.optimize.info.ParameterUsageMarker; diff --git a/src/proguard/optimize/TailRecursionSimplifier.java b/src/proguard/optimize/TailRecursionSimplifier.java index 0946b6a..f01dcd9 100644 --- a/src/proguard/optimize/TailRecursionSimplifier.java +++ b/src/proguard/optimize/TailRecursionSimplifier.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-2011 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 @@ -54,9 +54,9 @@ implements AttributeVisitor, private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); + private final MyRecursionChecker recursionChecker = new MyRecursionChecker(); private Method targetMethod; - private boolean recursive; private boolean inlinedAny; @@ -105,38 +105,31 @@ implements AttributeVisitor, // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); - targetMethod = method; - inlinedAny = false; + targetMethod = method; + inlinedAny = false; codeAttributeComposer.reset(); - // Append the body of the code. - copyCode(clazz, method, codeAttribute); + // The code may expand, due to expanding constant and variable + // instructions. + codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); + + // Copy the instructions. + codeAttribute.instructionsAccept(clazz, method, this); // Update the code attribute if any code has been inlined. if (inlinedAny) { - codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); - } - } - } + // Copy the exceptions. + codeAttribute.exceptionsAccept(clazz, method, this); + // Append a label just after the code. + codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); - /** - * Appends the code of the given code attribute. - */ - private void copyCode(Clazz clazz, Method method, CodeAttribute codeAttribute) - { - // The code may expand, due to expanding constant and variable - // instructions. - codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); - - // Copy the instructions. - codeAttribute.instructionsAccept(clazz, method, this); + codeAttributeComposer.endCodeFragment(); - // Append a label just after the code. - codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); - - codeAttributeComposer.endCodeFragment(); + codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); + } + } } @@ -159,9 +152,9 @@ implements AttributeVisitor, case InstructionConstants.OP_INVOKESTATIC: { // Is it a recursive call? - clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, recursionChecker); - if (recursive) + if (recursionChecker.isRecursive()) { // Is the next instruction a return? int nextOffset = @@ -180,13 +173,13 @@ implements AttributeVisitor, case InstructionConstants.OP_RETURN: { // Isn't the recursive call inside a try/catch block? - codeAttribute.exceptionsAccept(clazz, method, offset, this); + codeAttribute.exceptionsAccept(clazz, method, offset, recursionChecker); - if (recursive) + if (recursionChecker.isRecursive()) { if (DEBUG) { - System.out.println("TailRecursionSimplifier.visitConstantInstruction: ["+ + System.out.println("TailRecursionSimplifier: ["+ clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"], inlining "+constantInstruction.toString(offset)); } @@ -227,19 +220,52 @@ implements AttributeVisitor, } - // Implementations for ConstantVisitor. + // Implementations for ExceptionInfoVisitor. - public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) + public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { - recursive = targetMethod.equals(methodrefConstant.referencedMember); + codeAttributeComposer.appendException(new ExceptionInfo(exceptionInfo.u2startPC, + exceptionInfo.u2endPC, + exceptionInfo.u2handlerPC, + exceptionInfo.u2catchType)); } - // Implementations for ExceptionInfoVisitor. - - public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) + /** + * This ConstantVisitor and ExceptionInfoVisitor returns whether a method + * invocation can be treated as tail-recursive. + */ + private class MyRecursionChecker + extends SimplifiedVisitor + implements ConstantVisitor, + ExceptionInfoVisitor { - recursive = false; + private boolean recursive; + + + /** + * Returns whether the method invocation can be treated as + * tail-recursive. + */ + public boolean isRecursive() + { + return recursive; + } + + // Implementations for ConstantVisitor. + + public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) + { + recursive = targetMethod.equals(methodrefConstant.referencedMember); + } + + + // Implementations for ExceptionInfoVisitor. + + public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) + { + recursive = false; + } } @@ -257,7 +283,6 @@ implements AttributeVisitor, (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0; // Count the number of parameters, taking into account their categories. - int parameterCount = ClassUtil.internalMethodParameterCount(descriptor); int parameterSize = ClassUtil.internalMethodParameterSize(descriptor); int parameterOffset = isStatic ? 0 : 1; diff --git a/src/proguard/optimize/WriteOnlyFieldFilter.java b/src/proguard/optimize/WriteOnlyFieldFilter.java index 578beb2..4a0e095 100644 --- a/src/proguard/optimize/WriteOnlyFieldFilter.java +++ b/src/proguard/optimize/WriteOnlyFieldFilter.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-2011 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/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java index 1463feb..bc5f658 100644 --- a/src/proguard/optimize/evaluation/EvaluationShrinker.java +++ b/src/proguard/optimize/evaluation/EvaluationShrinker.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-2011 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 @@ -34,6 +34,8 @@ import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.info.*; +import java.util.Arrays; + /** * This AttributeVisitor simplifies the code attributes that it visits, based * on partial evaluation. @@ -55,13 +57,14 @@ implements AttributeVisitor private final InstructionVisitor extraDeletedInstructionVisitor; private final InstructionVisitor extraAddedInstructionVisitor; - private final PartialEvaluator partialEvaluator; - private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(); - private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); - private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier(); - private final MyProducerMarker producerMarker = new MyProducerMarker(); - private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer(); - private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); + private final PartialEvaluator partialEvaluator; + private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(); + private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true); + private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier(); + private final MyProducerMarker producerMarker = new MyProducerMarker(); + private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker(); + private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer(); + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE]; private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE]; @@ -276,18 +279,10 @@ implements AttributeVisitor if (partialEvaluator.isTraced(offset) && !isInstructionNecessary(offset)) { - // Is the corresponding variable necessary anywhere in the code, - // accoriding to a simple partial evaluation? - int variableIndex = partialEvaluator.initializedVariable(offset); - if (variableIndex >= 0 && - isVariableInitializationNecessary(clazz, - method, - codeAttribute, - offset, - variableIndex)) - { - markInstruction(offset); - } + Instruction instruction = InstructionFactory.create(codeAttribute.code, + offset); + + instruction.accept(clazz, method, codeAttribute, offset, variableInitializationMarker); } } if (DEBUG) System.out.println(); @@ -467,7 +462,9 @@ implements AttributeVisitor */ private class MyUnusedParameterSimplifier extends SimplifiedVisitor - implements InstructionVisitor, ConstantVisitor, MemberVisitor + implements InstructionVisitor, + ConstantVisitor, + MemberVisitor { private int invocationOffset; private ConstantInstruction invocationInstruction; @@ -657,6 +654,40 @@ implements AttributeVisitor /** + * This InstructionVisitor marks variable initializations that are + * necessary to appease the JVM. + */ + private class MyVariableInitializationMarker + extends SimplifiedVisitor + implements InstructionVisitor + { + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) + { + if (!variableInstruction.isLoad()) + { + int variableIndex = variableInstruction.variableIndex; + + if (isVariableInitialization(offset, + variableIndex) && + isVariableInitializationNecessary(clazz, + method, + codeAttribute, + offset, + variableIndex)) + { + markInstruction(offset); + } + } + } + } + + + /** * This InstructionVisitor fixes instructions locally, popping any unused * produced stack entries after marked instructions, and popping produced * stack entries and pushing missing stack entries instead of unmarked @@ -687,12 +718,23 @@ implements AttributeVisitor int requiredPushCount = 0; for (int stackIndex = 0; stackIndex < popCount; stackIndex++) { - // Is the stack entry required by other consumers? - if (!isStackSimplifiedBefore(offset, top - stackIndex) && - !isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex)) + InstructionOffsetValue producerOffsets = + tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(); + + if (!isStackSimplifiedBefore(offset, top - stackIndex)) { - // Remember to push it. - requiredPushCount++; + // Is the stack entry pushed by any producer, + // because it is required by other consumers? + if (isAnyStackEntryNecessaryAfter(producerOffsets, top - stackIndex)) + { + // Make sure it is pushed after all producers. + markStackEntriesAfter(producerOffsets, top - stackIndex); + } + else + { + // Remember to push it. + requiredPushCount++; + } } } @@ -757,9 +799,16 @@ implements AttributeVisitor int expectedPopCount = 0; for (int stackIndex = 0; stackIndex < popCount; stackIndex++) { - // Is the stack entry required by other consumers? - if (isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex)) + InstructionOffsetValue producerOffsets = + tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(); + + // Is the stack entry pushed by any producer, + // because it is required by other consumers? + if (isAnyStackEntryNecessaryAfter(producerOffsets, top - stackIndex)) { + // Make sure it is pushed after all producers. + markStackEntriesAfter(producerOffsets, top - stackIndex); + // Remember to pop it. expectedPopCount++; } @@ -1052,6 +1101,7 @@ implements AttributeVisitor byte oldOpcode = instruction.opcode; byte newOpcode = 0; + byte addOpcode = 0; // Simplify the popping instruction if possible. switch (oldOpcode) @@ -1232,9 +1282,20 @@ implements AttributeVisitor stackEntryPresent1) { // Will both elements be present? - if (stackEntryPresent0 && - stackEntryPresent1) + if (!stackEntryPresent1) { + // Pop the original top element (later bottom element). + newOpcode = InstructionConstants.OP_POP; + } + else if (!stackEntryPresent0) + { + // Swap both elements and pop the top one. + newOpcode = InstructionConstants.OP_SWAP; + addOpcode = InstructionConstants.OP_POP; + } + else + { + // Just swap both elements. newOpcode = InstructionConstants.OP_SWAP; } } @@ -1242,6 +1303,7 @@ implements AttributeVisitor } } + // Is there a replacement opcode? if (newOpcode == 0) { // Delete the instruction. @@ -1270,6 +1332,21 @@ implements AttributeVisitor if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(dupOffset)+" by "+replacementInstruction.toString()); } + + // Is there an additional opcode? + if (addOpcode != 0) + { + // Add the instruction. + Instruction additionalInstruction = new SimpleInstruction(addOpcode); + codeAttributeEditor.insertAfterInstruction(dupOffset, additionalInstruction); + + if (extraAddedInstructionVisitor != null) + { + extraAddedInstructionVisitor.visitSimpleInstruction(null, null, null, dupOffset, null); + } + + if (DEBUG) System.out.println(" Adding instruction "+additionalInstruction.toString(dupOffset)); + } } @@ -1596,10 +1673,7 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - for (int index = 0; index < maxLocals; index++) - { - variablesNecessaryAfter[offset][index] = false; - } + Arrays.fill(variablesNecessaryAfter[offset], 0, maxLocals, false); } } @@ -1612,10 +1686,7 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - for (int index = 0; index < maxStack; index++) - { - stacksNecessaryAfter[offset][index] = false; - } + Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false); } } @@ -1628,10 +1699,7 @@ implements AttributeVisitor { for (int offset = 0; offset < codeLength; offset++) { - for (int index = 0; index < maxStack; index++) - { - stacksSimplifiedBefore[offset][index] = false; - } + Arrays.fill(stacksSimplifiedBefore[offset], 0, maxStack, false); } } @@ -1641,10 +1709,7 @@ implements AttributeVisitor } else { - for (int index = 0; index < codeLength; index++) - { - instructionsNecessary[index] = false; - } + Arrays.fill(instructionsNecessary, 0, codeLength, false); } } @@ -1670,6 +1735,34 @@ implements AttributeVisitor /** + * Returns whether the specified variable is initialized at the specified + * offset. + */ + private boolean isVariableInitialization(int instructionOffset, + int variableIndex) + { + // Wasn't the variable set yet? + Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex); + if (valueBefore == null) + { + return true; + } + + // Is the computational type different now? + Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex); + if (valueAfter.computationalType() != valueBefore.computationalType()) + { + return true; + } + + // Was the producer an argument (which may be removed)? + Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex); + return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 && + producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY; + } + + + /** * Returns whether the specified variable must be initialized at the * specified offset, according to the verifier of the JVM. */ @@ -1686,8 +1779,8 @@ implements AttributeVisitor { if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); - // Lazily compute perform simple partial evaluation, the way the - // JVM preverifier would do it. + // Lazily perform simple partial evaluation, the way the JVM + // verifier would do it. simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]"); @@ -1695,7 +1788,7 @@ implements AttributeVisitor // Check if the variable is necessary elsewhere. for (int offset = 0; offset < codeLength; offset++) { - if (isInstructionNecessary(offset)) + if (partialEvaluator.isTraced(offset)) { Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex); if (producer != null) @@ -1708,16 +1801,22 @@ implements AttributeVisitor InstructionOffsetValue simpleProducerOffsets = simpleProducer.instructionOffsetValue(); - // Does the sophisticated partial evaluation have fewer - // producers than the simple one? - // And does the simple partial evaluation point to an - // initialization of the variable? - if (producerOffsets.instructionOffsetCount() < - simpleProducerOffsets.instructionOffsetCount() && - isVariableNecessaryAfterAny(producerOffsets, variableIndex) && - simpleProducerOffsets.contains(initializationOffset)) + if (DEBUG) { - // Then the initialization is necessary. + System.out.println(" ["+offset+"] producers ["+producerOffsets+"], simple producers ["+simpleProducerOffsets+"]"); + } + + // Is the variable being used without all of its + // immediate simple producers being marked? + if (isVariableNecessaryAfterAny(producerOffsets, variableIndex) && + !isVariableNecessaryAfterAll(simpleProducerOffsets, variableIndex)) + { + if (DEBUG) + { + System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] necessary"); + } + + // Then the initialization may be necessary. return true; } } @@ -1726,6 +1825,11 @@ implements AttributeVisitor } } + if (DEBUG) + { + System.out.println(" => initialization of variable v"+variableIndex+" at ["+initializationOffset+"] not necessary"); + } + return false; } @@ -1749,7 +1853,7 @@ implements AttributeVisitor /** * Returns whether the specified variable is ever necessary after any - * instruction in the specified block. + * instructions in the specified block. */ private boolean isVariableNecessaryAfterAny(int startOffset, int endOffset, @@ -1769,7 +1873,7 @@ implements AttributeVisitor /** * Returns whether the specified variable is ever necessary after any - * instruction in the specified set of instructions offsets. + * instructions in the specified set of instructions offsets. */ private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue, int variableIndex) @@ -1789,6 +1893,28 @@ implements AttributeVisitor } + /** + * Returns whether the specified variable is ever necessary after all + * instructions in the specified set of instructions offsets. + */ + private boolean isVariableNecessaryAfterAll(InstructionOffsetValue instructionOffsetValue, + int variableIndex) + { + int count = instructionOffsetValue.instructionOffsetCount(); + + for (int index = 0; index < count; index++) + { + if (!isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index), + variableIndex)) + { + return false; + } + } + + return true; + } + + private boolean isVariableNecessaryAfter(int instructionOffset, int variableIndex) { @@ -1797,6 +1923,36 @@ implements AttributeVisitor } + /** + * Marks the stack entries after the given offsets. + * @param instructionOffsets the offsets of the stack entries to be marked. + * @param stackIndex the index of the stack entries to be marked + * (counting from the bottom). + */ + private void markStackEntriesAfter(InstructionOffsetValue instructionOffsets, + int stackIndex) + { + if (instructionOffsets != null) + { + int offsetCount = instructionOffsets.instructionOffsetCount(); + for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++) + { + // Make sure the stack entry and the instruction are marked + // at the producing offset. + int offset = instructionOffsets.instructionOffset(offsetIndex); + + markStackEntryAfter(offset, stackIndex); + } + } + } + + + /** + * Marks the stack entry after the given offset. + * @param instructionOffset the offset of the stack entry to be marked. + * @param stackIndex the index of the stack entry to be marked + * (counting from the bottom). + */ private void markStackEntryAfter(int instructionOffset, int stackIndex) { @@ -1814,6 +1970,13 @@ implements AttributeVisitor } + /** + * Returns whether any of the stack entries after the given offsets are + * necessary. + * @param instructionOffsets the offsets of the stack entries to be checked. + * @param stackIndex the index of the stack entries to be checked + * (counting from the bottom). + */ private boolean isAnyStackEntryNecessaryAfter(InstructionOffsetValue instructionOffsets, int stackIndex) { @@ -1831,6 +1994,13 @@ implements AttributeVisitor } + /** + * Returns whether any of the stack entries after the given offset are + * necessary. + * @param instructionOffset the offset of the stack entry to be checked. + * @param stackIndex the index of the stack entry to be checked + * (counting from the bottom). + */ private boolean isStackEntryNecessaryAfter(int instructionOffset, int stackIndex) { diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/src/proguard/optimize/evaluation/EvaluationSimplifier.java index 0c3a9c7..b207108 100644 --- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java +++ b/src/proguard/optimize/evaluation/EvaluationSimplifier.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-2011 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 @@ -43,6 +43,9 @@ extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor { + private static int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f); + private static long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0); + //* private static final boolean DEBUG = false; /*/ @@ -559,10 +562,11 @@ implements AttributeVisitor, Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { + // Make sure to distinguish between +0.0 and -0.0. float value = pushedValue.floatValue().value(); - if (value == 0f || - value == 1f || - value == 2f) + if (value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS || + value == 1.0f || + value == 2.0f) { replaceConstantPushInstruction(clazz, offset, @@ -627,8 +631,9 @@ implements AttributeVisitor, Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0); if (pushedValue.isParticular()) { + // Make sure to distinguish between +0.0 and -0.0. double value = pushedValue.doubleValue().value(); - if (value == 0.0 || + if (value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS || value == 1.0) { replaceConstantPushInstruction(clazz, diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/src/proguard/optimize/evaluation/LivenessAnalyzer.java index 9915027..747f993 100644 --- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java +++ b/src/proguard/optimize/evaluation/LivenessAnalyzer.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-2011 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 @@ -79,6 +79,16 @@ implements AttributeVisitor, /** + * Returns whether the instruction at the given offset has ever been + * executed during the partial evaluation. + */ + public boolean isTraced(int instructionOffset) + { + return partialEvaluator.isTraced(instructionOffset); + } + + + /** * Returns whether the specified variable is alive before the instruction * at the given offset. */ diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java index 8379c57..578ece5 100644 --- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java +++ b/src/proguard/optimize/evaluation/LoadingInvocationUnit.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-2011 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 @@ -35,9 +35,9 @@ import proguard.evaluation.value.*; public class LoadingInvocationUnit extends BasicInvocationUnit { - private boolean loadFieldValues; - private boolean loadMethodParameterValues; - private boolean loadMethodReturnValues; + private final boolean loadFieldValues; + private final boolean loadMethodParameterValues; + private final boolean loadMethodReturnValues; /** @@ -84,8 +84,6 @@ extends BasicInvocationUnit value.isParticular()) { return value; -// // Make sure the value is refreshed. -// return refresh(value); } } } @@ -110,8 +108,6 @@ extends BasicInvocationUnit value.isParticular()) { return value; -// // Make sure the value is refreshed. -// return refresh(value); } } } @@ -134,8 +130,6 @@ extends BasicInvocationUnit value.isParticular()) { return value; -// // Make sure the value is refreshed. -// return refresh(value); } } @@ -163,8 +157,6 @@ extends BasicInvocationUnit value.isParticular()) { return value; -// // Make sure the value is refreshed. -// return refresh(value); } } } @@ -173,8 +165,8 @@ extends BasicInvocationUnit refConstant, type); } -// -// + + // // Small utility methods. // // private Value refresh(Value value) diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java index 5790a36..b2776d1 100644 --- a/src/proguard/optimize/evaluation/PartialEvaluator.java +++ b/src/proguard/optimize/evaluation/PartialEvaluator.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-2011 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 @@ -31,6 +31,8 @@ import proguard.evaluation.*; import proguard.evaluation.value.*; import proguard.optimize.peephole.BranchTargetFinder; +import java.util.Arrays; + /** * This AttributeVisitor performs partial evaluation on the code attributes * that it visits. @@ -68,7 +70,6 @@ implements AttributeVisitor, private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH]; private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH]; - private int[] initializedVariables = new int[ClassConstants.TYPICAL_CODE_LENGTH]; private boolean evaluateExceptions; private final BasicBranchUnit branchUnit; @@ -189,6 +190,47 @@ implements AttributeVisitor, if (DEBUG) { method.accept(clazz, new ClassPrinter()); + + System.out.println("Evaluation results:"); + + int offset = 0; + do + { + if (isBranchOrExceptionTarget(offset)) + { + System.out.println("Branch target from ["+branchOriginValues[offset]+"]:"); + if (isTraced(offset)) + { + System.out.println(" Vars: "+variablesBefore[offset]); + System.out.println(" Stack: "+stacksBefore[offset]); + } + } + + Instruction instruction = InstructionFactory.create(codeAttribute.code, + offset); + System.out.println(instruction.toString(offset)); + + if (isTraced(offset)) + { + int initializationOffset = branchTargetFinder.initializationOffset(offset); + if (initializationOffset != NONE) + { + System.out.println(" is to be initialized at ["+initializationOffset+"]"); + } + + InstructionOffsetValue branchTargets = branchTargets(offset); + if (branchTargets != null) + { + System.out.println(" has overall been branching to "+branchTargets); + } + + System.out.println(" Vars: "+variablesAfter[offset]); + System.out.println(" Stack: "+stacksAfter[offset]); + } + + offset += instruction.length(offset); + } + while (offset < codeAttribute.u4codeLength); } throw ex; @@ -212,7 +254,8 @@ implements AttributeVisitor, TracedStack stack = new TracedStack(codeAttribute.u2maxStack); // Initialize the reusable arrays and variables. - initializeVariables(clazz, method, codeAttribute, variables, stack); + initializeArrays(codeAttribute); + initializeParameters(clazz, method, codeAttribute, variables); // Find all instruction offsets,... codeAttribute.accept(clazz, method, branchTargetFinder); @@ -249,12 +292,6 @@ implements AttributeVisitor, if (isTraced(offset)) { - int variableIndex = initializedVariable(offset); - if (variableIndex >= 0) - { - System.out.println(" is initializing variable v"+variableIndex); - } - int initializationOffset = branchTargetFinder.initializationOffset(offset); if (initializationOffset != NONE) { @@ -479,16 +516,6 @@ implements AttributeVisitor, } - /** - * Returns the variable that is initialized at the given instruction offset, - * or <code>NONE</code> if no variable was initialized. - */ - public int initializedVariable(int instructionOffset) - { - return initializedVariables[instructionOffset]; - } - - // Utility methods to evaluate instruction blocks. /** @@ -702,9 +729,6 @@ implements AttributeVisitor, // Reset the trace value. InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE; - // Reset the initialization flag. - variables.resetInitialization(); - // Note that the instruction is only volatile. Instruction instruction = InstructionFactory.create(code, instructionOffset); @@ -743,9 +767,6 @@ implements AttributeVisitor, throw ex; } - // Collect the offsets of the instructions whose results were used. - initializedVariables[instructionOffset] = variables.getInitializationIndex(); - // Collect the branch targets from the branch unit. InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets(); int branchTargetCount = branchTargets.instructionOffsetCount(); @@ -896,11 +917,7 @@ implements AttributeVisitor, subroutinePartialEvaluator = new PartialEvaluator(this); - subroutinePartialEvaluator.initializeVariables(clazz, - method, - codeAttribute, - variables, - stack); + subroutinePartialEvaluator.initializeArrays(codeAttribute); } // Evaluate the subroutine. @@ -952,13 +969,12 @@ implements AttributeVisitor, if (evaluationCounts[offset] == 0) { - variablesBefore[offset] = other.variablesBefore[offset]; - stacksBefore[offset] = other.stacksBefore[offset]; - variablesAfter[offset] = other.variablesAfter[offset]; - stacksAfter[offset] = other.stacksAfter[offset]; - generalizedContexts[offset] = other.generalizedContexts[offset]; - evaluationCounts[offset] = other.evaluationCounts[offset]; - initializedVariables[offset] = other.initializedVariables[offset]; + variablesBefore[offset] = other.variablesBefore[offset]; + stacksBefore[offset] = other.stacksBefore[offset]; + variablesAfter[offset] = other.variablesAfter[offset]; + stacksAfter[offset] = other.stacksAfter[offset]; + generalizedContexts[offset] = other.generalizedContexts[offset]; + evaluationCounts[offset] = other.evaluationCounts[offset]; } else { @@ -968,7 +984,6 @@ implements AttributeVisitor, stacksAfter[offset] .generalize(other.stacksAfter[offset]); //generalizedContexts[offset] evaluationCounts[offset] += other.evaluationCounts[offset]; - //initializedVariables[offset] } } } @@ -1094,11 +1109,7 @@ implements AttributeVisitor, /** * Initializes the data structures for the variables, stack, etc. */ - private void initializeVariables(Clazz clazz, - Method method, - CodeAttribute codeAttribute, - TracedVariables variables, - TracedStack stack) + private void initializeArrays(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; @@ -1106,33 +1117,25 @@ implements AttributeVisitor, if (variablesAfter.length < codeLength) { // Create new arrays. - branchOriginValues = new InstructionOffsetValue[codeLength]; - branchTargetValues = new InstructionOffsetValue[codeLength]; - variablesBefore = new TracedVariables[codeLength]; - stacksBefore = new TracedStack[codeLength]; - variablesAfter = new TracedVariables[codeLength]; - stacksAfter = new TracedStack[codeLength]; - generalizedContexts = new boolean[codeLength]; - evaluationCounts = new int[codeLength]; - initializedVariables = new int[codeLength]; - - // Reset the arrays. - for (int index = 0; index < codeLength; index++) - { - initializedVariables[index] = NONE; - } + branchOriginValues = new InstructionOffsetValue[codeLength]; + branchTargetValues = new InstructionOffsetValue[codeLength]; + variablesBefore = new TracedVariables[codeLength]; + stacksBefore = new TracedStack[codeLength]; + variablesAfter = new TracedVariables[codeLength]; + stacksAfter = new TracedStack[codeLength]; + generalizedContexts = new boolean[codeLength]; + evaluationCounts = new int[codeLength]; } else { // Reset the arrays. + Arrays.fill(branchOriginValues, null); + Arrays.fill(branchTargetValues, null); + Arrays.fill(generalizedContexts, false); + Arrays.fill(evaluationCounts, 0); + for (int index = 0; index < codeLength; index++) { - branchOriginValues[index] = null; - branchTargetValues[index] = null; - generalizedContexts[index] = false; - evaluationCounts[index] = 0; - initializedVariables[index] = NONE; - if (variablesBefore[index] != null) { variablesBefore[index].reset(codeAttribute.u2maxLocals); @@ -1154,7 +1157,17 @@ implements AttributeVisitor, } } } + } + + /** + * Initializes the data structures for the variables, stack, etc. + */ + private void initializeParameters(Clazz clazz, + Method method, + CodeAttribute codeAttribute, + TracedVariables variables) + { // Create the method parameters. TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals); diff --git a/src/proguard/optimize/evaluation/StoringInvocationUnit.java b/src/proguard/optimize/evaluation/StoringInvocationUnit.java index bcbb69f..010dab0 100644 --- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java +++ b/src/proguard/optimize/evaluation/StoringInvocationUnit.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-2011 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/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java index fa5bb79..b7dd469 100644 --- a/src/proguard/optimize/evaluation/TracedBranchUnit.java +++ b/src/proguard/optimize/evaluation/TracedBranchUnit.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-2011 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/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java index b3ae81c..a824481 100644 --- a/src/proguard/optimize/evaluation/VariableOptimizer.java +++ b/src/proguard/optimize/evaluation/VariableOptimizer.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-2011 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,10 +21,10 @@ package proguard.optimize.evaluation; import proguard.classfile.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.editor.*; import proguard.classfile.visitor.MemberVisitor; import proguard.classfile.attribute.*; -import proguard.classfile.attribute.visitor.AttributeVisitor; -import proguard.classfile.editor.VariableRemapper; import proguard.classfile.util.*; /** @@ -35,7 +35,9 @@ import proguard.classfile.util.*; */ public class VariableOptimizer extends SimplifiedVisitor -implements AttributeVisitor +implements AttributeVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor { //* private static final boolean DEBUG = false; @@ -51,6 +53,7 @@ implements AttributeVisitor private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(); private final VariableRemapper variableRemapper = new VariableRemapper(); + private VariableCleaner variableCleaner = new VariableCleaner(); private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE]; @@ -101,6 +104,11 @@ implements AttributeVisitor // Analyze the liveness of the variables in the code. livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); + // Trim the variables in the local variable tables, because even + // clipping the tables individually may leave some inconsistencies + // between them. + codeAttribute.attributesAccept(clazz, method, this); + int startIndex = (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 || reuseThis ? 0 : 1; @@ -142,23 +150,19 @@ implements AttributeVisitor } } - // Remap the variables. + // Have we been able to remap any variables? if (remapping) { if (DEBUG) { - System.out.println("Remapping variables:"); - System.out.println(" Class "+ ClassUtil.externalClassName(clazz.getName())); - System.out.println(" Method "+ClassUtil.externalFullMethodDescription(clazz.getName(), - 0, - method.getName(clazz), - method.getDescriptor(clazz))); - for (int index = 0; index < variableSize; index++) + System.out.println("VariableOptimizer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); + for (int index= 0; index < variableSize; index++) { - System.out.println(" ["+index+"] -> ["+variableMap[index]+"]"); + System.out.println(" v"+index+" -> "+variableMap[index]); } } + // Remap the variables. variableRemapper.setVariableMap(variableMap); variableRemapper.visitCodeAttribute(clazz, method, codeAttribute); @@ -168,6 +172,59 @@ implements AttributeVisitor method.accept(clazz, extraVariableMemberVisitor); } } + else + { + // Just clean up any empty variables. + variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); + } + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + // Trim the variables in the local variable table. + localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + // Trim the variables in the local variable type table. + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + // Trim the local variable to the instructions at which it is alive. + int variable = localVariableInfo.u2index; + int startPC = localVariableInfo.u2startPC; + int endPC = startPC + localVariableInfo.u2length; + + startPC = firstLiveness(startPC, endPC, variable); + endPC = lastLiveness(startPC, endPC, variable); + + localVariableInfo.u2startPC = startPC; + localVariableInfo.u2length = endPC - startPC; + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + // Trim the local variable type to the instructions at which it is alive. + int variable = localVariableTypeInfo.u2index; + int startPC = localVariableTypeInfo.u2startPC; + int endPC = startPC + localVariableTypeInfo.u2length; + + startPC = firstLiveness(startPC, endPC, variable); + endPC = lastLiveness(startPC, endPC, variable); + + localVariableTypeInfo.u2startPC = startPC; + localVariableTypeInfo.u2length = endPC - startPC; } @@ -241,4 +298,48 @@ implements AttributeVisitor } } } + + + /** + * Returns the first instruction offset between the given offsets at which + * the given variable goes alive. + */ + private int firstLiveness(int startOffset, int endOffset, int variableIndex) + { + for (int offset = startOffset; offset < endOffset; offset++) + { + if (livenessAnalyzer.isTraced(offset) && + livenessAnalyzer.isAliveBefore(offset, variableIndex)) + { + return offset; + } + } + + return endOffset; + } + + + /** + * Returns the last instruction offset between the given offsets before + * which the given variable is still alive. + */ + private int lastLiveness(int startOffset, int endOffset, int variableIndex) + { + int previousOffset = endOffset; + + for (int offset = endOffset-1; offset >= startOffset; offset--) + { + if (livenessAnalyzer.isTraced(offset)) + { + if (livenessAnalyzer.isAliveBefore(offset, variableIndex)) + { + return previousOffset; + } + + previousOffset = offset; + } + } + + return endOffset; + } } diff --git a/src/proguard/optimize/info/AccessMethodMarker.java b/src/proguard/optimize/info/AccessMethodMarker.java index 6965cec..8d758ce 100644 --- a/src/proguard/optimize/info/AccessMethodMarker.java +++ b/src/proguard/optimize/info/AccessMethodMarker.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-2011 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,7 +21,8 @@ package proguard.optimize.info; import proguard.classfile.*; -import proguard.classfile.attribute.CodeAttribute; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; @@ -71,6 +72,20 @@ implements InstructionVisitor, } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + // Check the bootstrap method. + invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + // Check the method reference. + clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); + } + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { // Check the referenced class. diff --git a/src/proguard/optimize/info/BackwardBranchMarker.java b/src/proguard/optimize/info/BackwardBranchMarker.java index 9e09b0f..d53a5b2 100644 --- a/src/proguard/optimize/info/BackwardBranchMarker.java +++ b/src/proguard/optimize/info/BackwardBranchMarker.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-2011 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/info/CatchExceptionMarker.java b/src/proguard/optimize/info/CatchExceptionMarker.java index 3f2a06f..5d74047 100644 --- a/src/proguard/optimize/info/CatchExceptionMarker.java +++ b/src/proguard/optimize/info/CatchExceptionMarker.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-2011 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/info/CaughtClassFilter.java b/src/proguard/optimize/info/CaughtClassFilter.java index 5e17763..4f7caff 100644 --- a/src/proguard/optimize/info/CaughtClassFilter.java +++ b/src/proguard/optimize/info/CaughtClassFilter.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-2011 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/info/CaughtClassMarker.java b/src/proguard/optimize/info/CaughtClassMarker.java index 0cc350e..5a60aaf 100644 --- a/src/proguard/optimize/info/CaughtClassMarker.java +++ b/src/proguard/optimize/info/CaughtClassMarker.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-2011 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 @@ -25,8 +25,9 @@ import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; /** - * This InstructionVisitor marks all classes that are used in an 'instanceof' - * test by any of the instructions that it visits. + * This ClassVisitor marks all program classes that it visits as caught. + * This means that these classes are exception classes that occur in exception + * handlers. * * @author Eric Lafortune */ diff --git a/src/proguard/optimize/info/ClassOptimizationInfo.java b/src/proguard/optimize/info/ClassOptimizationInfo.java index 99b6e7b..e440eef 100644 --- a/src/proguard/optimize/info/ClassOptimizationInfo.java +++ b/src/proguard/optimize/info/ClassOptimizationInfo.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-2011 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 @@ -34,6 +34,7 @@ public class ClassOptimizationInfo private boolean isInstanceofed = false; private boolean isDotClassed = false; private boolean isCaught = false; + private boolean containsStaticInitializer = false; private boolean containsPackageVisibleMembers = false; private boolean invokesPackageVisibleMembers = false; private Clazz targetClass; @@ -87,6 +88,18 @@ public class ClassOptimizationInfo } + public void setContainsStaticInitializer() + { + containsStaticInitializer = true; + } + + + public boolean containsStaticInitializer() + { + return containsStaticInitializer; + } + + public void setContainsPackageVisibleMembers() { containsPackageVisibleMembers = true; @@ -129,6 +142,7 @@ public class ClassOptimizationInfo this.isInstanceofed |= other.isInstanceofed; this.isDotClassed |= other.isDotClassed; this.isCaught |= other.isCaught; + this.containsStaticInitializer |= other.containsStaticInitializer; this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers; this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers; } diff --git a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java index 9cb167c..bc58f2d 100644 --- a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java +++ b/src/proguard/optimize/info/ClassOptimizationInfoSetter.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-2011 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/info/DotClassFilter.java b/src/proguard/optimize/info/DotClassFilter.java index 8cbe7f0..c55925c 100644 --- a/src/proguard/optimize/info/DotClassFilter.java +++ b/src/proguard/optimize/info/DotClassFilter.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-2011 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/info/DotClassMarker.java b/src/proguard/optimize/info/DotClassMarker.java index b5f12a7..2819441 100644 --- a/src/proguard/optimize/info/DotClassMarker.java +++ b/src/proguard/optimize/info/DotClassMarker.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-2011 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/info/ExceptionInstructionChecker.java b/src/proguard/optimize/info/ExceptionInstructionChecker.java index 2792d90..40287f3 100644 --- a/src/proguard/optimize/info/ExceptionInstructionChecker.java +++ b/src/proguard/optimize/info/ExceptionInstructionChecker.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-2011 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 @@ -67,34 +67,39 @@ implements InstructionVisitor byte opcode = simpleInstruction.opcode; // Check for instructions that may throw exceptions. - if (opcode == InstructionConstants.OP_IDIV || - opcode == InstructionConstants.OP_LDIV || - opcode == InstructionConstants.OP_IREM || - opcode == InstructionConstants.OP_LREM || - opcode == InstructionConstants.OP_IALOAD || - opcode == InstructionConstants.OP_LALOAD || - opcode == InstructionConstants.OP_FALOAD || - opcode == InstructionConstants.OP_DALOAD || - opcode == InstructionConstants.OP_AALOAD || - opcode == InstructionConstants.OP_BALOAD || - opcode == InstructionConstants.OP_CALOAD || - opcode == InstructionConstants.OP_SALOAD || - opcode == InstructionConstants.OP_IASTORE || - opcode == InstructionConstants.OP_LASTORE || - opcode == InstructionConstants.OP_FASTORE || - opcode == InstructionConstants.OP_DASTORE || - opcode == InstructionConstants.OP_AASTORE || - opcode == InstructionConstants.OP_BASTORE || - opcode == InstructionConstants.OP_CASTORE || - opcode == InstructionConstants.OP_SASTORE || - opcode == InstructionConstants.OP_NEWARRAY || - opcode == InstructionConstants.OP_ARRAYLENGTH || - opcode == InstructionConstants.OP_ATHROW || - opcode == InstructionConstants.OP_MONITORENTER || - opcode == InstructionConstants.OP_MONITOREXIT) + // Note that monitorexit can not sensibly throw exceptions, except the + // broken and deprecated asynchronous ThreadDeath. Removing the + // artificial infinite looping exception blocks that recent compilers + // add does not strictly follow the JVM specs, but it does have the + // additional benefit of avoiding a bug in the JVM in JDK 1.1. + switch (opcode) { - // These instructions may throw exceptions. - mayThrowExceptions = true; + case InstructionConstants.OP_IDIV: + case InstructionConstants.OP_LDIV: + case InstructionConstants.OP_IREM: + case InstructionConstants.OP_LREM: + case InstructionConstants.OP_IALOAD: + case InstructionConstants.OP_LALOAD: + case InstructionConstants.OP_FALOAD: + case InstructionConstants.OP_DALOAD: + case InstructionConstants.OP_AALOAD: + case InstructionConstants.OP_BALOAD: + case InstructionConstants.OP_CALOAD: + case InstructionConstants.OP_SALOAD: + case InstructionConstants.OP_IASTORE: + case InstructionConstants.OP_LASTORE: + case InstructionConstants.OP_FASTORE: + case InstructionConstants.OP_DASTORE: + case InstructionConstants.OP_AASTORE: + case InstructionConstants.OP_BASTORE: + case InstructionConstants.OP_CASTORE: + case InstructionConstants.OP_SASTORE: + case InstructionConstants.OP_NEWARRAY: + case InstructionConstants.OP_ARRAYLENGTH: + case InstructionConstants.OP_ATHROW: + case InstructionConstants.OP_MONITORENTER: + // These instructions may throw exceptions. + mayThrowExceptions = true; } } @@ -105,31 +110,32 @@ implements InstructionVisitor byte opcode = constantInstruction.opcode; // Check for instructions that may throw exceptions. - if (opcode == InstructionConstants.OP_GETSTATIC || - opcode == InstructionConstants.OP_PUTSTATIC || - opcode == InstructionConstants.OP_GETFIELD || - opcode == InstructionConstants.OP_PUTFIELD || - opcode == InstructionConstants.OP_INVOKEVIRTUAL || - opcode == InstructionConstants.OP_INVOKESPECIAL || - opcode == InstructionConstants.OP_INVOKESTATIC || - opcode == InstructionConstants.OP_INVOKEINTERFACE || - opcode == InstructionConstants.OP_NEW || - opcode == InstructionConstants.OP_ANEWARRAY || - opcode == InstructionConstants.OP_CHECKCAST || - opcode == InstructionConstants.OP_MULTIANEWARRAY) + switch (opcode) { - // These instructions may throw exceptions. - mayThrowExceptions = true; + case InstructionConstants.OP_GETSTATIC: + case InstructionConstants.OP_PUTSTATIC: + case InstructionConstants.OP_GETFIELD: + case InstructionConstants.OP_PUTFIELD: + case InstructionConstants.OP_INVOKEVIRTUAL: + case InstructionConstants.OP_INVOKESPECIAL: + case InstructionConstants.OP_INVOKESTATIC: + case InstructionConstants.OP_INVOKEINTERFACE: + case InstructionConstants.OP_INVOKEDYNAMIC: + case InstructionConstants.OP_NEW: + case InstructionConstants.OP_ANEWARRAY: + case InstructionConstants.OP_CHECKCAST: + case InstructionConstants.OP_INSTANCEOF: + case InstructionConstants.OP_MULTIANEWARRAY: + // These instructions may throw exceptions. + mayThrowExceptions = true; } -// else -// if (opcode == InstructionConstants.OP_INVOKEVIRTUAL || -// opcode == InstructionConstants.OP_INVOKESPECIAL || -// opcode == InstructionConstants.OP_INVOKESTATIC || -// opcode == InstructionConstants.OP_INVOKEINTERFACE) -// { + +// case InstructionConstants.OP_INVOKEVIRTUAL: +// case InstructionConstants.OP_INVOKESPECIAL: +// case InstructionConstants.OP_INVOKESTATIC: +// case InstructionConstants.OP_INVOKEINTERFACE: // // Check if the invoking the method may throw an exception. // clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); -// } } diff --git a/src/proguard/optimize/info/FieldOptimizationInfo.java b/src/proguard/optimize/info/FieldOptimizationInfo.java index 7a2d068..6797a14 100644 --- a/src/proguard/optimize/info/FieldOptimizationInfo.java +++ b/src/proguard/optimize/info/FieldOptimizationInfo.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-2011 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,8 +21,11 @@ package proguard.optimize.info; import proguard.classfile.*; -import proguard.classfile.util.MethodLinker; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.attribute.*; +import proguard.classfile.util.*; import proguard.evaluation.value.*; +import proguard.evaluation.ConstantValueFactory; /** * This class stores some optimization information that can be attached to @@ -31,8 +34,11 @@ import proguard.evaluation.value.*; * @author Eric Lafortune */ public class FieldOptimizationInfo +extends SimplifiedVisitor +implements AttributeVisitor { - private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory(); + private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory(); + private static final ConstantValueFactory CONSTANT_VALUE_FACTORY = new ConstantValueFactory(VALUE_FACTORY); private boolean isWritten; private boolean isRead; @@ -43,9 +49,33 @@ public class FieldOptimizationInfo public FieldOptimizationInfo(Clazz clazz, Field field) { + int accessFlags = field.getAccessFlags(); + isWritten = - isRead = (field.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0; - value = initialValue(field.getDescriptor(clazz)); + isRead = (accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0; + + if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) + { + // See if we can initialize the static field with a constant value. + field.accept(clazz, new AllAttributeVisitor(this)); + } + + if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 && + value == null) + { + // Otherwise initialize the non-final field with the default value. + value = initialValue(field.getDescriptor(clazz)); + } + } + + + public FieldOptimizationInfo(FieldOptimizationInfo FieldOptimizationInfo) + { + this.isWritten = FieldOptimizationInfo.isWritten; + this.isRead = FieldOptimizationInfo.isRead; + this.canBeMadePrivate = FieldOptimizationInfo.canBeMadePrivate; + this.referencedClass = FieldOptimizationInfo.referencedClass; + this.value = FieldOptimizationInfo.value; } @@ -113,6 +143,18 @@ public class FieldOptimizationInfo } + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) + { + // Retrieve the initial static field value. + value = CONSTANT_VALUE_FACTORY.constantValue(clazz, constantValueAttribute.u2constantValueIndex); + } + + // Small utility methods. private Value initialValue(String type) @@ -147,13 +189,13 @@ public class FieldOptimizationInfo public static void setFieldOptimizationInfo(Clazz clazz, Field field) { - MethodLinker.lastMember(field).setVisitorInfo(new FieldOptimizationInfo(clazz, field)); + field.setVisitorInfo(new FieldOptimizationInfo(clazz, field)); } public static FieldOptimizationInfo getFieldOptimizationInfo(Field field) { - Object visitorInfo = MethodLinker.lastMember(field).getVisitorInfo(); + Object visitorInfo = field.getVisitorInfo(); return visitorInfo instanceof FieldOptimizationInfo ? (FieldOptimizationInfo)visitorInfo : diff --git a/src/proguard/optimize/info/InstanceofClassFilter.java b/src/proguard/optimize/info/InstanceofClassFilter.java index 35e1d77..955fe9e 100644 --- a/src/proguard/optimize/info/InstanceofClassFilter.java +++ b/src/proguard/optimize/info/InstanceofClassFilter.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-2011 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/info/InstanceofClassMarker.java b/src/proguard/optimize/info/InstanceofClassMarker.java index c60e1f8..6d2f8aa 100644 --- a/src/proguard/optimize/info/InstanceofClassMarker.java +++ b/src/proguard/optimize/info/InstanceofClassMarker.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-2011 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/info/InstantiationClassFilter.java b/src/proguard/optimize/info/InstantiationClassFilter.java index a24e617..e67e0b5 100644 --- a/src/proguard/optimize/info/InstantiationClassFilter.java +++ b/src/proguard/optimize/info/InstantiationClassFilter.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-2011 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/info/InstantiationClassMarker.java b/src/proguard/optimize/info/InstantiationClassMarker.java index 124c23b..dc623c2 100644 --- a/src/proguard/optimize/info/InstantiationClassMarker.java +++ b/src/proguard/optimize/info/InstantiationClassMarker.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-2011 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/info/MemberOptimizationInfoSetter.java b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java index a170a8e..d222d81 100644 --- a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java +++ b/src/proguard/optimize/info/MemberOptimizationInfoSetter.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-2011 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 @@ -38,22 +38,22 @@ implements MemberVisitor { // Implementations for MemberVisitor. - public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + public void visitProgramField(ProgramClass programClass, ProgramField programField) { - if (!KeepMarker.isKept(programMethod)) + if (!KeepMarker.isKept(programField)) { - MethodOptimizationInfo.setMethodOptimizationInfo(programClass, - programMethod); + FieldOptimizationInfo.setFieldOptimizationInfo(programClass, + programField); } } - public void visitProgramField(ProgramClass programClass, ProgramField programField) + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { - if (!KeepMarker.isKept(programField)) + if (!KeepMarker.isKept(programMethod)) { - FieldOptimizationInfo.setFieldOptimizationInfo(programClass, - programField); + MethodOptimizationInfo.setMethodOptimizationInfo(programClass, + programMethod); } } } diff --git a/src/proguard/optimize/info/MethodInvocationMarker.java b/src/proguard/optimize/info/MethodInvocationMarker.java index 2528c94..9d573b7 100644 --- a/src/proguard/optimize/info/MethodInvocationMarker.java +++ b/src/proguard/optimize/info/MethodInvocationMarker.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-2011 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/info/MethodOptimizationInfo.java b/src/proguard/optimize/info/MethodOptimizationInfo.java index d3b1bde..dd76f97 100644 --- a/src/proguard/optimize/info/MethodOptimizationInfo.java +++ b/src/proguard/optimize/info/MethodOptimizationInfo.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-2011 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 @@ -204,7 +204,7 @@ public class MethodOptimizationInfo public void setParameterUsed(int parameterIndex) { - usedParameters |= 1 << parameterIndex; + usedParameters |= 1L << parameterIndex; } @@ -216,7 +216,7 @@ public class MethodOptimizationInfo public boolean isParameterUsed(int parameterIndex) { - return parameterIndex >= 64 || (usedParameters & (1 << parameterIndex)) != 0; + return parameterIndex >= 64 || (usedParameters & (1L << parameterIndex)) != 0; } diff --git a/src/proguard/optimize/info/NoSideEffectMethodMarker.java b/src/proguard/optimize/info/NoSideEffectMethodMarker.java index 5c78408..2e0516b 100644 --- a/src/proguard/optimize/info/NoSideEffectMethodMarker.java +++ b/src/proguard/optimize/info/NoSideEffectMethodMarker.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-2011 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/info/NonPrivateMemberMarker.java b/src/proguard/optimize/info/NonPrivateMemberMarker.java index d451643..23e33a9 100644 --- a/src/proguard/optimize/info/NonPrivateMemberMarker.java +++ b/src/proguard/optimize/info/NonPrivateMemberMarker.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-2011 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 @@ -77,15 +77,9 @@ implements ClassVisitor, public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { - Clazz referencedClass = stringConstant.referencedClass; - - // Is it refering to another class or class member? - if (referencedClass != null && - !referencedClass.equals(clazz)) - { - // The referenced class member, if any, can never be made private. - stringConstant.referencedMemberAccept(this); - } + // The referenced class member, if any, can never be made private, + // even if it's in the same class. + stringConstant.referencedMemberAccept(this); } @@ -93,7 +87,7 @@ implements ClassVisitor, { Clazz referencedClass = refConstant.referencedClass; - // Is it refering to a class member in another class? + // Is it referring to a class member in another class? // The class member might be in another class, or // it may be referenced through another class. if (referencedClass != null && diff --git a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java index d40bc6b..85ff4b9 100644 --- a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java +++ b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.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-2011 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,18 +22,36 @@ package proguard.optimize.info; import proguard.classfile.*; import proguard.classfile.util.SimplifiedVisitor; -import proguard.classfile.visitor.MemberVisitor; +import proguard.classfile.visitor.*; /** - * This MemberVisitor marks all classes that contain visited package visible - * members. + * This ClassVisitor marks all classes that contain package visible members. * * @author Eric Lafortune */ public class PackageVisibleMemberContainingClassMarker extends SimplifiedVisitor -implements MemberVisitor +implements ClassVisitor, + MemberVisitor { + // Implementations for ClassVisitor. + + public void visitAnyClass(Clazz clazz) + { + // Check the class itself. + if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) + { + setPackageVisibleMembers(clazz); + } + else + { + // Check the members. + clazz.fieldsAccept(this); + clazz.methodsAccept(this); + } + } + + // Implementations for MemberVisitor. public void visitAnyMember(Clazz clazz, Member member) diff --git a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java index 9ec8ec6..42cc14f 100644 --- a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java +++ b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.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-2011 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 @@ -24,39 +24,87 @@ import proguard.classfile.*; import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.constant.*; import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; /** - * This ConstantVisitor marks all classes that invoke package visible members - * in other classes. + * This ConstantVisitor marks all classes that refer to package visible classes + * or class members. * * @author Eric Lafortune */ public class PackageVisibleMemberInvokingClassMarker extends SimplifiedVisitor -implements ConstantVisitor +implements ConstantVisitor, + ClassVisitor, + MemberVisitor { + private Clazz referencingClass; + + // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + // Check the referenced class and class member, if any. + if (stringConstant.referencedClass != clazz) + { + referencingClass = clazz; + + stringConstant.referencedClassAccept(this); + stringConstant.referencedMemberAccept(this); + } + } + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { - Clazz referencedClass = refConstant.referencedClass; - if (referencedClass != null && - (referencedClass.getAccessFlags() & + // Check the referenced class and class member. + if (refConstant.referencedClass != clazz) + { + referencingClass = clazz; + + refConstant.referencedClassAccept(this); + refConstant.referencedMemberAccept(this); + } + } + + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + // Check the referenced class. + if (classConstant.referencedClass != clazz) + { + referencingClass = clazz; + + classConstant.referencedClassAccept(this); + } + } + + + // Implementations for ClassVisitor. + + public void visitAnyClass(Clazz clazz) + { + if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) { - setInvokesPackageVisibleMembers(clazz); + setInvokesPackageVisibleMembers(referencingClass); } + } - Member referencedMember = refConstant.referencedMember; - if (referencedMember != null && - (referencedMember.getAccessFlags() & + + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz clazz, Member member) + { + if ((member.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PUBLIC | ClassConstants.INTERNAL_ACC_PRIVATE)) == 0) { - setInvokesPackageVisibleMembers(clazz); + setInvokesPackageVisibleMembers(referencingClass); } } diff --git a/src/proguard/optimize/info/ParameterUsageMarker.java b/src/proguard/optimize/info/ParameterUsageMarker.java index 15ce88a..abae946 100644 --- a/src/proguard/optimize/info/ParameterUsageMarker.java +++ b/src/proguard/optimize/info/ParameterUsageMarker.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-2011 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,14 +21,14 @@ package proguard.optimize.info; import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; -import proguard.classfile.attribute.visitor.AttributeVisitor; -import proguard.classfile.attribute.*; import proguard.classfile.util.*; import proguard.classfile.visitor.MemberVisitor; +import proguard.evaluation.value.Value; import proguard.optimize.evaluation.PartialEvaluator; -import proguard.evaluation.value.*; /** * This MemberVisitor counts the parameters and marks the used parameters diff --git a/src/proguard/optimize/info/ReadWriteFieldMarker.java b/src/proguard/optimize/info/ReadWriteFieldMarker.java index 57d8561..236cb17 100644 --- a/src/proguard/optimize/info/ReadWriteFieldMarker.java +++ b/src/proguard/optimize/info/ReadWriteFieldMarker.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-2011 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/info/SideEffectInstructionChecker.java b/src/proguard/optimize/info/SideEffectInstructionChecker.java index 8be9dc1..1444e5a 100644 --- a/src/proguard/optimize/info/SideEffectInstructionChecker.java +++ b/src/proguard/optimize/info/SideEffectInstructionChecker.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-2011 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,11 +29,14 @@ import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; +import java.util.*; + /** * This class can tell whether an instruction has any side effects. Return * instructions can be included or not. * * @see ReadWriteFieldMarker + * @see StaticInitializerContainingClassMarker * @see NoSideEffectMethodMarker * @see SideEffectMethodMarker * @author Eric Lafortune @@ -47,6 +50,7 @@ implements InstructionVisitor, private final boolean includeReturnInstructions; // A return value for the visitor methods. + private Clazz referencingClass; private boolean hasSideEffects; @@ -60,7 +64,7 @@ implements InstructionVisitor, { hasSideEffects = false; - instruction.accept(clazz, method, codeAttribute, offset, this); + instruction.accept(clazz, method, codeAttribute, offset, this); return hasSideEffects; } @@ -118,14 +122,16 @@ implements InstructionVisitor, public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { byte opcode = constantInstruction.opcode; - // Check for instructions that might cause side effects. - if (opcode == InstructionConstants.OP_PUTSTATIC || - opcode == InstructionConstants.OP_PUTFIELD || - opcode == InstructionConstants.OP_INVOKEVIRTUAL || - opcode == InstructionConstants.OP_INVOKESPECIAL || - opcode == InstructionConstants.OP_INVOKESTATIC || - opcode == InstructionConstants.OP_INVOKEINTERFACE) + if (opcode == InstructionConstants.OP_GETSTATIC || + opcode == InstructionConstants.OP_PUTSTATIC || + opcode == InstructionConstants.OP_GETFIELD || + opcode == InstructionConstants.OP_PUTFIELD || + opcode == InstructionConstants.OP_INVOKEVIRTUAL || + opcode == InstructionConstants.OP_INVOKESPECIAL || + opcode == InstructionConstants.OP_INVOKESTATIC || + opcode == InstructionConstants.OP_INVOKEINTERFACE || + opcode == InstructionConstants.OP_INVOKEDYNAMIC) { // Check if the field is write-only or volatile, or if the invoked // method is causing any side effects. @@ -150,48 +156,36 @@ implements InstructionVisitor, // Implementations for ConstantVisitor. + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + // We'll have to assume invoking an unknown method has side effects. + hasSideEffects = true; + } + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { + // Pass the referencing class. + referencingClass = clazz; + // We'll have to assume accessing an unknown field has side effects. hasSideEffects = true; - // Check the referenced field. + // Check the referenced field, if known. fieldrefConstant.referencedMemberAccept(this); } public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { - Member referencedMember = refConstant.referencedMember; + // Pass the referencing class. + referencingClass = clazz; - // Do we have a reference to the method? - if (referencedMember == null) - { - // We'll have to assume invoking the unknown method has side effects. - hasSideEffects = true; - } - else - { - // First check the referenced method itself. - refConstant.referencedMemberAccept(this); - - // If the result isn't conclusive, check down the hierarchy. - if (!hasSideEffects) - { - Clazz referencedClass = refConstant.referencedClass; - Method referencedMethod = (Method)referencedMember; - - // Check all other implementations of the method down the class - // hierarchy. - if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) == 0) - { - clazz.hierarchyAccept(false, false, false, true, - new NamedMethodVisitor(referencedMethod.getName(referencedClass), - referencedMethod.getDescriptor(referencedClass), - this)); - } - } - } + // We'll have to assume invoking an unknown method has side effects. + hasSideEffects = true; + + // Check the referenced method, if known. + refConstant.referencedMemberAccept(this); } @@ -199,14 +193,24 @@ implements InstructionVisitor, public void visitProgramField(ProgramClass programClass, ProgramField programField) { - hasSideEffects = ReadWriteFieldMarker.isRead(programField); + hasSideEffects = + (ReadWriteFieldMarker.isRead(programField) && + ReadWriteFieldMarker.isWritten(programField)) || + ((programField.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) || + (!programClass.equals(referencingClass) && + !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { - hasSideEffects = hasSideEffects || - SideEffectMethodMarker.hasSideEffects(programMethod); + // Note that side effects already include synchronization of some + // implementation of the method. + hasSideEffects = + !NoSideEffectMethodMarker.hasNoSideEffects(programMethod) && + (SideEffectMethodMarker.hasSideEffects(programMethod) || + (!programClass.equals(referencingClass) && + !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass)))); } @@ -218,7 +222,24 @@ implements InstructionVisitor, public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { - hasSideEffects = hasSideEffects || - !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod); + hasSideEffects = + !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod); + } + + + /** + * 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/info/SideEffectMethodMarker.java b/src/proguard/optimize/info/SideEffectMethodMarker.java index 25fda72..d73179e 100644 --- a/src/proguard/optimize/info/SideEffectMethodMarker.java +++ b/src/proguard/optimize/info/SideEffectMethodMarker.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-2011 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/info/StaticInitializerContainingClassFilter.java b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java new file mode 100644 index 0000000..197668d --- /dev/null +++ b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java @@ -0,0 +1,62 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.optimize.info; + +import proguard.classfile.*; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This ClassVisitor delegates all its method calls to another ClassVisitor, + * but only for Clazz objects that are instantiated. + * + * @author Eric Lafortune + */ +public class StaticInitializerContainingClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + public StaticInitializerContainingClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (StaticInitializerContainingClassMarker.containsStaticInitializer(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (StaticInitializerContainingClassMarker.containsStaticInitializer(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +}
\ No newline at end of file diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java new file mode 100644 index 0000000..a121250 --- /dev/null +++ b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java @@ -0,0 +1,65 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.optimize.info; + +import proguard.classfile.*; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +/** + * This ClassVisitor marks all classes that contain static initializers. + * + * @author Eric Lafortune + */ +public class StaticInitializerContainingClassMarker +extends SimplifiedVisitor +implements ClassVisitor +{ + // Implementations for ClassVisitor. + + public void visitAnyClass(Clazz clazz) + { + if (clazz.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, + ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) != null) + { + setStaticInitializer(clazz); + } + } + + + // Small utility methods. + + private static void setStaticInitializer(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setContainsStaticInitializer(); + } + } + + + public static boolean containsStaticInitializer(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.containsStaticInitializer(); + } +}
\ No newline at end of file diff --git a/src/proguard/optimize/info/SuperInvocationMarker.java b/src/proguard/optimize/info/SuperInvocationMarker.java index 6f3d3bd..07e33bb 100644 --- a/src/proguard/optimize/info/SuperInvocationMarker.java +++ b/src/proguard/optimize/info/SuperInvocationMarker.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-2011 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/info/VariableUsageMarker.java b/src/proguard/optimize/info/VariableUsageMarker.java index 660c4ba..a1c6a9a 100644 --- a/src/proguard/optimize/info/VariableUsageMarker.java +++ b/src/proguard/optimize/info/VariableUsageMarker.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-2011 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 marks the local variables that are used in the code * attributes that it visits. @@ -62,14 +64,13 @@ implements AttributeVisitor, // Try to reuse the previous array. if (variableUsed.length < maxLocals) { + // Create a new array. variableUsed = new boolean[maxLocals]; } else { - for (int index = 0; index < maxLocals; index++) - { - variableUsed[index] = false; - } + // Reset the array. + Arrays.fill(variableUsed, 0, maxLocals, false); } codeAttribute.instructionsAccept(clazz, method, this); diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java index 8f650bb..7e5a11f 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-2011 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. @@ -312,25 +314,19 @@ 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, NONE); + Arrays.fill(subroutineEnds, 0, codeLength, NONE); + 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, NONE); + Arrays.fill(subroutineEnds, 0, codeLength, NONE); + Arrays.fill(creationOffsets, 0, codeLength, NONE); + Arrays.fill(initializationOffsets, 0, codeLength, NONE); instructionMarks[codeLength] = 0; } diff --git a/src/proguard/optimize/peephole/ClassFinalizer.java b/src/proguard/optimize/peephole/ClassFinalizer.java index b5e54f8..063f254 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-2011 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..4971cab 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-2011 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.constant.ClassConstant; import proguard.classfile.constant.visitor.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; @@ -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. @@ -235,11 +238,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,7 +264,7 @@ implements ClassVisitor, // Copy over the class members. MemberAdder memberAdder = - new MemberAdder(targetClass); + new MemberAdder(targetClass, fieldOptimizationInfoCopier); programClass.fieldsAccept(memberAdder); programClass.methodsAccept(memberAdder); @@ -336,10 +340,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,12 +370,19 @@ 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))); + new ClassCollector(set))); return set; } @@ -538,4 +547,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..0dd93b1 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-2011 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/GotoGotoReplacer.java b/src/proguard/optimize/peephole/GotoGotoReplacer.java index 7d7e66c..d05d7b6 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-2011 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..cafda92 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-2011 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..d12c2c0 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-2011 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..eb24061 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-2011 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,179 @@ */ 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; + private static final int FIELD_L = 33; + private static final int FIELD_F = 34; + private static final int FIELD_D = 35; - 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_STRINGBUFFER_INIT = 38; + private static final int METHOD_STRINGBUFFER_INIT_STRING = 39; + private static final int METHOD_STRINGBUFFER_APPEND_BOOLEAN = 40; + private static final int METHOD_STRINGBUFFER_APPEND_CHAR = 41; + private static final int METHOD_STRINGBUFFER_APPEND_INTEGER = 42; + private static final int METHOD_STRINGBUFFER_APPEND_LONG = 43; + private static final int METHOD_STRINGBUFFER_APPEND_FLOAT = 44; + private static final int METHOD_STRINGBUFFER_APPEND_DOUBLE = 45; + private static final int METHOD_STRINGBUFFER_APPEND_STRING = 46; + private static final int METHOD_STRINGBUFFER_LENGTH = 47; + private static final int METHOD_STRINGBUFFER_TOSTRING = 48; + private static final int METHOD_STRINGBUILDER_INIT = 49; + private static final int METHOD_STRINGBUILDER_INIT_STRING = 50; + private static final int METHOD_STRINGBUILDER_APPEND_BOOLEAN = 51; + private static final int METHOD_STRINGBUILDER_APPEND_CHAR = 52; + private static final int METHOD_STRINGBUILDER_APPEND_INTEGER = 53; + private static final int METHOD_STRINGBUILDER_APPEND_LONG = 54; + private static final int METHOD_STRINGBUILDER_APPEND_FLOAT = 55; + private static final int METHOD_STRINGBUILDER_APPEND_DOUBLE = 56; + private static final int METHOD_STRINGBUILDER_APPEND_STRING = 57; + private static final int METHOD_STRINGBUILDER_LENGTH = 58; + private static final int METHOD_STRINGBUILDER_TOSTRING = 59; + + private static final int CLASS_STRING = 60; + private static final int CLASS_STRINGBUFFER = 61; + private static final int CLASS_STRINGBUILDER = 62; + + private static final int NAME_AND_TYPE_I = 63; + private static final int NAME_AND_TYPE_L = 64; + private static final int NAME_AND_TYPE_F = 65; + private static final int NAME_AND_TYPE_D = 66; + + private static final int NAME_AND_TYPE_EQUALS = 67; + private static final int NAME_AND_TYPE_LENGTH = 68; + private static final int NAME_AND_TYPE_INIT = 69; + private static final int NAME_AND_TYPE_INIT_STRING = 70; + private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUFFER = 71; + private static final int NAME_AND_TYPE_APPEND_C_STRINGBUFFER = 72; + private static final int NAME_AND_TYPE_APPEND_I_STRINGBUFFER = 73; + private static final int NAME_AND_TYPE_APPEND_J_STRINGBUFFER = 74; + private static final int NAME_AND_TYPE_APPEND_F_STRINGBUFFER = 75; + private static final int NAME_AND_TYPE_APPEND_D_STRINGBUFFER = 76; + private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER = 77; + private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUILDER = 78; + private static final int NAME_AND_TYPE_APPEND_C_STRINGBUILDER = 79; + private static final int NAME_AND_TYPE_APPEND_I_STRINGBUILDER = 80; + private static final int NAME_AND_TYPE_APPEND_J_STRINGBUILDER = 81; + private static final int NAME_AND_TYPE_APPEND_F_STRINGBUILDER = 82; + private static final int NAME_AND_TYPE_APPEND_D_STRINGBUILDER = 83; + private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER = 84; + private static final int NAME_AND_TYPE_TOSTRING = 85; + + private static final int UTF8_EMPTY = 86; + private static final int UTF8_I = 87; + private static final int UTF8_L = 88; + private static final int UTF8_F = 89; + private static final int UTF8_D = 90; + private static final int UTF8_STRING = 91; + private static final int UTF8_STRINGBUFFER = 92; + private static final int UTF8_STRINGBUILDER = 93; + private static final int UTF8_EQUALS = 94; + private static final int UTF8_OBJECT_Z = 95; + private static final int UTF8_LENGTH = 96; + private static final int UTF8__I = 97; + private static final int UTF8_INIT = 98; + private static final int UTF8__VOID = 99; + private static final int UTF8_STRING_VOID = 100; + private static final int UTF8_TOSTRING = 101; + private static final int UTF8__STRING = 102; + private static final int UTF8_APPEND = 103; + private static final int UTF8_Z_STRINGBUFFER = 104; + private static final int UTF8_C_STRINGBUFFER = 105; + private static final int UTF8_I_STRINGBUFFER = 106; + private static final int UTF8_J_STRINGBUFFER = 107; + private static final int UTF8_F_STRINGBUFFER = 108; + private static final int UTF8_D_STRINGBUFFER = 109; + private static final int UTF8_STRING_STRINGBUFFER = 110; + private static final int UTF8_Z_STRINGBUILDER = 111; + private static final int UTF8_C_STRINGBUILDER = 112; + private static final int UTF8_I_STRINGBUILDER = 113; + private static final int UTF8_J_STRINGBUILDER = 114; + private static final int UTF8_F_STRINGBUILDER = 115; + private static final int UTF8_D_STRINGBUILDER = 116; + private static final int UTF8_STRING_STRINGBUILDER = 117; + + private static final int SENTINEL = 118; public static final Constant[] CONSTANTS = new Constant[] @@ -136,23 +234,100 @@ 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_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_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_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_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_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_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_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_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), }; - public static final Instruction[][][] VARIABLE = new Instruction[][][] { { // nop = nothing @@ -237,7 +412,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 +557,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 +723,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 +826,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 +1248,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 +1274,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 +1682,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 +3527,898 @@ 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), + }, + }, + + { // 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("...").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), + }, + }, + { // 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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, STRING_A_STRING), + 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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 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("...").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), + }, + }, + { // 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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, STRING_A_STRING), + 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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_BOOLEAN), + },{ + 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_CHAR), + },{ + 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_CHAR), + },{ + 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_INTEGER), + },{ + 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_INTEGER), + },{ + 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_LONG), + },{ + 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_LONG), + },{ + 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_FLOAT), + },{ + 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_FLOAT), + },{ + 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_DOUBLE), + },{ + 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_DOUBLE), + },{ + 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), + }, + }, + }; + + /* + static + { + 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[] instructions = STRING[2][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(" "+instruction.toString(offset)); + } + } + } + //*/ +} diff --git a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java index bce06e2..be65b53 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-2011 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 { + /* + public static boolean DEBUG = true; + /*/ private static final boolean DEBUG = false; + //*/ + + 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).shrink()); } // Delete any remaining instructions in the from sequence. @@ -204,10 +243,10 @@ 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), @@ -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..72fc334 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-2011 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..254e968 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-2011 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..140a114 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-2011 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..8857202 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-2011 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,10 @@ 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.info.*; -import java.util.Stack; +import java.util.*; /** * This AttributeVisitor inlines short methods or methods that are only invoked @@ -48,7 +48,7 @@ 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; @@ -138,6 +138,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 = @@ -305,12 +341,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(); } @@ -457,42 +493,42 @@ implements AttributeVisitor, if (// 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 +537,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 +577,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..4c99f3a 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-2011 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..d865638 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-2011 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..cac1965 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-2011 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..254f748 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-2011 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,10 +72,7 @@ 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. 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..5fa4fac 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-2011 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..fcb8914 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-2011 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..f3ecf0b 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-2011 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..55f42ca 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-2011 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..721f2a5 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-2011 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 |