From b72c5c2e5482cf10117b2b25f642f7616b2326c3 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 31 Aug 2009 10:12:00 -0700 Subject: ProGuard 4.4 --- src/proguard/optimize/info/AccessMethodMarker.java | 187 +++++++++++++ .../optimize/info/BackwardBranchMarker.java | 90 ++++++ .../optimize/info/CatchExceptionMarker.java | 69 +++++ src/proguard/optimize/info/CaughtClassFilter.java | 63 +++++ src/proguard/optimize/info/CaughtClassMarker.java | 63 +++++ .../optimize/info/ClassOptimizationInfo.java | 151 +++++++++++ .../optimize/info/ClassOptimizationInfoSetter.java | 47 ++++ src/proguard/optimize/info/DotClassFilter.java | 63 +++++ src/proguard/optimize/info/DotClassMarker.java | 96 +++++++ .../optimize/info/ExceptionInstructionChecker.java | 187 +++++++++++++ .../optimize/info/FieldOptimizationInfo.java | 162 +++++++++++ .../optimize/info/InstanceofClassFilter.java | 63 +++++ .../optimize/info/InstanceofClassMarker.java | 93 +++++++ .../optimize/info/InstantiationClassFilter.java | 62 +++++ .../optimize/info/InstantiationClassMarker.java | 93 +++++++ .../info/MemberOptimizationInfoSetter.java | 59 ++++ .../optimize/info/MethodInvocationMarker.java | 107 ++++++++ .../optimize/info/MethodOptimizationInfo.java | 302 +++++++++++++++++++++ .../optimize/info/NoSideEffectMethodMarker.java | 91 +++++++ .../optimize/info/NonPrivateMemberMarker.java | 177 ++++++++++++ .../PackageVisibleMemberContainingClassMarker.java | 67 +++++ .../PackageVisibleMemberInvokingClassMarker.java | 81 ++++++ .../optimize/info/ParameterUsageMarker.java | 285 +++++++++++++++++++ .../optimize/info/ReadWriteFieldMarker.java | 163 +++++++++++ .../info/SideEffectInstructionChecker.java | 224 +++++++++++++++ .../optimize/info/SideEffectMethodMarker.java | 175 ++++++++++++ .../optimize/info/SuperInvocationMarker.java | 93 +++++++ .../optimize/info/VariableUsageMarker.java | 95 +++++++ src/proguard/optimize/info/package.html | 4 + 29 files changed, 3412 insertions(+) create mode 100644 src/proguard/optimize/info/AccessMethodMarker.java create mode 100644 src/proguard/optimize/info/BackwardBranchMarker.java create mode 100644 src/proguard/optimize/info/CatchExceptionMarker.java create mode 100644 src/proguard/optimize/info/CaughtClassFilter.java create mode 100644 src/proguard/optimize/info/CaughtClassMarker.java create mode 100644 src/proguard/optimize/info/ClassOptimizationInfo.java create mode 100644 src/proguard/optimize/info/ClassOptimizationInfoSetter.java create mode 100644 src/proguard/optimize/info/DotClassFilter.java create mode 100644 src/proguard/optimize/info/DotClassMarker.java create mode 100644 src/proguard/optimize/info/ExceptionInstructionChecker.java create mode 100644 src/proguard/optimize/info/FieldOptimizationInfo.java create mode 100644 src/proguard/optimize/info/InstanceofClassFilter.java create mode 100644 src/proguard/optimize/info/InstanceofClassMarker.java create mode 100644 src/proguard/optimize/info/InstantiationClassFilter.java create mode 100644 src/proguard/optimize/info/InstantiationClassMarker.java create mode 100644 src/proguard/optimize/info/MemberOptimizationInfoSetter.java create mode 100644 src/proguard/optimize/info/MethodInvocationMarker.java create mode 100644 src/proguard/optimize/info/MethodOptimizationInfo.java create mode 100644 src/proguard/optimize/info/NoSideEffectMethodMarker.java create mode 100644 src/proguard/optimize/info/NonPrivateMemberMarker.java create mode 100644 src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java create mode 100644 src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java create mode 100644 src/proguard/optimize/info/ParameterUsageMarker.java create mode 100644 src/proguard/optimize/info/ReadWriteFieldMarker.java create mode 100644 src/proguard/optimize/info/SideEffectInstructionChecker.java create mode 100644 src/proguard/optimize/info/SideEffectMethodMarker.java create mode 100644 src/proguard/optimize/info/SuperInvocationMarker.java create mode 100644 src/proguard/optimize/info/VariableUsageMarker.java create mode 100644 src/proguard/optimize/info/package.html (limited to 'src/proguard/optimize/info') diff --git a/src/proguard/optimize/info/AccessMethodMarker.java b/src/proguard/optimize/info/AccessMethodMarker.java new file mode 100644 index 0000000..6965cec --- /dev/null +++ b/src/proguard/optimize/info/AccessMethodMarker.java @@ -0,0 +1,187 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +/** + * This InstructionVisitor marks the types of class accesses and class member + * accesses of the methods whose instructions it visits. + * + * @author Eric Lafortune + */ +public class AccessMethodMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + ClassVisitor, + MemberVisitor +{ + private Method invokingMethod; + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + invokingMethod = method; + + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + // Check the referenced class or class member, if any. + stringConstant.referencedClassAccept(this); + stringConstant.referencedMemberAccept(this); + } + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + // Check the referenced class. + clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); + + // Check the referenced class member itself. + refConstant.referencedClassAccept(this); + refConstant.referencedMemberAccept(this); + } + + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + // Check the referenced class. + classConstant.referencedClassAccept(this); + } + + + // Implementations for ClassVisitor. + + public void visitAnyClass(Clazz clazz) + { + int accessFlags = clazz.getAccessFlags(); + + if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) + { + setAccessesPackageCode(invokingMethod); + } + } + + + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz clazz, Member member) + { + int accessFlags = member.getAccessFlags(); + + if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) + { + setAccessesPrivateCode(invokingMethod); + } + else if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) + { + setAccessesProtectedCode(invokingMethod); + } + else if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0) + { + setAccessesPackageCode(invokingMethod); + } + } + + + // Small utility methods. + + private static void setAccessesPrivateCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setAccessesPrivateCode(); + } + } + + + /** + * Returns whether the given method accesses private class members. + */ + public static boolean accessesPrivateCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || info.accessesPrivateCode(); + } + + + private static void setAccessesPackageCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setAccessesPackageCode(); + } + } + + + /** + * Returns whether the given method accesses package visible classes or class + * members. + */ + public static boolean accessesPackageCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || info.accessesPackageCode(); + } + + + private static void setAccessesProtectedCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setAccessesProtectedCode(); + } + } + + + /** + * Returns whether the given method accesses protected class members. + */ + public static boolean accessesProtectedCode(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || info.accessesProtectedCode(); + } +} diff --git a/src/proguard/optimize/info/BackwardBranchMarker.java b/src/proguard/optimize/info/BackwardBranchMarker.java new file mode 100644 index 0000000..9e09b0f --- /dev/null +++ b/src/proguard/optimize/info/BackwardBranchMarker.java @@ -0,0 +1,90 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; + +/** + * This InstructionVisitor marks all methods that branch backward in any of the + * instructions that it visits. + * + * @author Eric Lafortune + */ +public class BackwardBranchMarker +extends SimplifiedVisitor +implements InstructionVisitor +{ + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) + { + markBackwardBranch(method, branchInstruction.branchOffset); + } + + + public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) + { + markBackwardBranch(method, switchInstruction.defaultOffset); + + for (int index = 0; index < switchInstruction.jumpOffsets.length; index++) + { + markBackwardBranch(method, switchInstruction.jumpOffsets[index]); + } + } + + + // Small utility methods. + + /** + * Marks the given method if the given branch offset is negative. + */ + private void markBackwardBranch(Method method, int branchOffset) + { + if (branchOffset < 0) + { + setBranchesBackward(method); + } + } + + + private static void setBranchesBackward(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setBranchesBackward(); + } + } + + + public static boolean branchesBackward(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || info.branchesBackward(); + } +} diff --git a/src/proguard/optimize/info/CatchExceptionMarker.java b/src/proguard/optimize/info/CatchExceptionMarker.java new file mode 100644 index 0000000..3f2a06f --- /dev/null +++ b/src/proguard/optimize/info/CatchExceptionMarker.java @@ -0,0 +1,69 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.util.SimplifiedVisitor; + +/** + * This AttributeVisitor marks all methods that catch exceptions. + * + * @author Eric Lafortune + */ +public class CatchExceptionMarker +extends SimplifiedVisitor +implements AttributeVisitor +{ + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + if (codeAttribute.u2exceptionTableLength > 0) + { + markCatchException(method); + } + } + + + // Small utility methods. + + private static void markCatchException(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setCatchesExceptions(); + } + } + + + public static boolean catchesExceptions(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || + info.catchesExceptions(); + } +} diff --git a/src/proguard/optimize/info/CaughtClassFilter.java b/src/proguard/optimize/info/CaughtClassFilter.java new file mode 100644 index 0000000..5e17763 --- /dev/null +++ b/src/proguard/optimize/info/CaughtClassFilter.java @@ -0,0 +1,63 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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 caught as exceptions. + * + * @see CaughtClassMarker + * @author Eric Lafortune + */ +public class CaughtClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + public CaughtClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (CaughtClassMarker.isCaught(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (CaughtClassMarker.isCaught(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/CaughtClassMarker.java b/src/proguard/optimize/info/CaughtClassMarker.java new file mode 100644 index 0000000..0cc350e --- /dev/null +++ b/src/proguard/optimize/info/CaughtClassMarker.java @@ -0,0 +1,63 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.ClassVisitor; + +/** + * This InstructionVisitor marks all classes that are used in an 'instanceof' + * test by any of the instructions that it visits. + * + * @author Eric Lafortune + */ +public class CaughtClassMarker +implements ClassVisitor +{ + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + public void visitProgramClass(ProgramClass programClass) + { + setCaught(programClass); + } + + + // Small utility methods. + + private static void setCaught(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setCaught(); + } + } + + + public static boolean isCaught(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.isCaught(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/ClassOptimizationInfo.java b/src/proguard/optimize/info/ClassOptimizationInfo.java new file mode 100644 index 0000000..99b6e7b --- /dev/null +++ b/src/proguard/optimize/info/ClassOptimizationInfo.java @@ -0,0 +1,151 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.Clazz; + +/** + * This class stores some optimization information that can be attached to + * a class. + * + * @author Eric Lafortune + */ +public class ClassOptimizationInfo +{ + private boolean isInstantiated = false; + private boolean isInstanceofed = false; + private boolean isDotClassed = false; + private boolean isCaught = false; + private boolean containsPackageVisibleMembers = false; + private boolean invokesPackageVisibleMembers = false; + private Clazz targetClass; + + + public void setInstantiated() + { + isInstantiated = true; + } + + + public boolean isInstantiated() + { + return isInstantiated; + } + + + public void setInstanceofed() + { + isInstanceofed = true; + } + + + public boolean isInstanceofed() + { + return isInstanceofed; + } + + + public void setDotClassed() + { + isDotClassed = true; + } + + + public boolean isDotClassed() + { + return isDotClassed; + } + + + public void setCaught() + { + isCaught = true; + } + + + public boolean isCaught() + { + return isCaught; + } + + + public void setContainsPackageVisibleMembers() + { + containsPackageVisibleMembers = true; + } + + + public boolean containsPackageVisibleMembers() + { + return containsPackageVisibleMembers; + } + + + public void setInvokesPackageVisibleMembers() + { + invokesPackageVisibleMembers = true; + } + + + public boolean invokesPackageVisibleMembers() + { + return invokesPackageVisibleMembers; + } + + + public void setTargetClass(Clazz targetClass) + { + this.targetClass = targetClass; + } + + + public Clazz getTargetClass() + { + return targetClass; + } + + + public void merge(ClassOptimizationInfo other) + { + this.isInstantiated |= other.isInstantiated; + this.isInstanceofed |= other.isInstanceofed; + this.isDotClassed |= other.isDotClassed; + this.isCaught |= other.isCaught; + this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers; + this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers; + } + + + public static void setClassOptimizationInfo(Clazz clazz) + { + clazz.setVisitorInfo(new ClassOptimizationInfo()); + } + + + public static ClassOptimizationInfo getClassOptimizationInfo(Clazz clazz) + { + Object visitorInfo = clazz.getVisitorInfo(); + + return visitorInfo instanceof ClassOptimizationInfo ? + (ClassOptimizationInfo)visitorInfo : + null; + } +} diff --git a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java new file mode 100644 index 0000000..9cb167c --- /dev/null +++ b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java @@ -0,0 +1,47 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.ClassVisitor; +import proguard.optimize.KeepMarker; + +/** + * This ClassVisitor attaches a ClassOptimizationInfo instance to every class + * that is not being kept that it visits. + * + * @author Eric Lafortune + */ +public class ClassOptimizationInfoSetter +extends SimplifiedVisitor +implements ClassVisitor +{ + // Implementations for MemberVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (!KeepMarker.isKept(programClass)) + { + ClassOptimizationInfo.setClassOptimizationInfo(programClass); + } + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/DotClassFilter.java b/src/proguard/optimize/info/DotClassFilter.java new file mode 100644 index 0000000..8cbe7f0 --- /dev/null +++ b/src/proguard/optimize/info/DotClassFilter.java @@ -0,0 +1,63 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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 used in a .class construct. + * + * @see DotClassMarker + * @author Eric Lafortune + */ +public class DotClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + public DotClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (DotClassMarker.isDotClassed(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (DotClassMarker.isDotClassed(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/DotClassMarker.java b/src/proguard/optimize/info/DotClassMarker.java new file mode 100644 index 0000000..b5f12a7 --- /dev/null +++ b/src/proguard/optimize/info/DotClassMarker.java @@ -0,0 +1,96 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This InstructionVisitor marks all classes that are used in a .class + * construct by any of the instructions that it visits. + * + * @author Eric Lafortune + */ +public class DotClassMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + ClassVisitor +{ + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + if (constantInstruction.opcode == InstructionConstants.OP_LDC || + constantInstruction.opcode == InstructionConstants.OP_LDC_W) + { + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + classConstant.referencedClassAccept(this); + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + public void visitProgramClass(ProgramClass programClass) + { + setDotClassed(programClass); + } + + + // Small utility methods. + + private static void setDotClassed(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setDotClassed(); + } + } + + + public static boolean isDotClassed(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.isDotClassed(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/ExceptionInstructionChecker.java b/src/proguard/optimize/info/ExceptionInstructionChecker.java new file mode 100644 index 0000000..2792d90 --- /dev/null +++ b/src/proguard/optimize/info/ExceptionInstructionChecker.java @@ -0,0 +1,187 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.RefConstant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This class can tell whether an instruction might throw exceptions. + * + * @author Eric Lafortune + */ +public class ExceptionInstructionChecker +extends SimplifiedVisitor +implements InstructionVisitor +// ConstantVisitor, +// MemberVisitor +{ + // A return value for the visitor methods. + private boolean mayThrowExceptions; + + + /** + * Returns whether the given instruction may throw exceptions. + */ + public boolean mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) + { + mayThrowExceptions = false; + + instruction.accept(clazz, method, codeAttribute, offset, this); + + return mayThrowExceptions; + } + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) + { + 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) + { + // These instructions may throw exceptions. + mayThrowExceptions = true; + } + + } + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + 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) + { + // 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) +// { +// // Check if the invoking the method may throw an exception. +// clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); +// } + } + + +// // Implementations for ConstantVisitor. +// +// public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) +// { +// Member referencedMember = refConstant.referencedMember; +// +// // Do we have a reference to the method? +// if (referencedMember == null) +// { +// // We'll have to assume invoking the unknown method may throw an +// // an exception. +// mayThrowExceptions = true; +// } +// else +// { +// // First check the referenced method itself. +// refConstant.referencedMemberAccept(this); +// +// // If the result isn't conclusive, check down the hierarchy. +// if (!mayThrowExceptions) +// { +// Clazz referencedClass = refConstant.referencedClass; +// Method referencedMethod = (Method)referencedMember; +// +// // Check all other implementations of the method in the class +// // hierarchy. +// referencedClass.methodImplementationsAccept(referencedMethod, +// false, +// false, +// true, +// true, +// this); +// } +// } +// } +// +// +// // Implementations for MemberVisitor. +// +// public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) +// { +// mayThrowExceptions = mayThrowExceptions || +// ExceptionMethodMarker.mayThrowExceptions(programMethod); +// } +// +// +// public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) +// { +// mayThrowExceptions = mayThrowExceptions || +// !NoExceptionMethodMarker.doesntThrowExceptions(libraryMethod); +// } +} diff --git a/src/proguard/optimize/info/FieldOptimizationInfo.java b/src/proguard/optimize/info/FieldOptimizationInfo.java new file mode 100644 index 0000000..7a2d068 --- /dev/null +++ b/src/proguard/optimize/info/FieldOptimizationInfo.java @@ -0,0 +1,162 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.MethodLinker; +import proguard.evaluation.value.*; + +/** + * This class stores some optimization information that can be attached to + * a field. + * + * @author Eric Lafortune + */ +public class FieldOptimizationInfo +{ + private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory(); + + private boolean isWritten; + private boolean isRead; + private boolean canBeMadePrivate = true; + private ReferenceValue referencedClass; + private Value value; + + + public FieldOptimizationInfo(Clazz clazz, Field field) + { + isWritten = + isRead = (field.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0; + value = initialValue(field.getDescriptor(clazz)); + } + + + public void setWritten() + { + isWritten = true; + } + + + public boolean isWritten() + { + return isWritten; + } + + + public void setRead() + { + isRead = true; + } + + + public boolean isRead() + { + return isRead; + } + + + public void setCanNotBeMadePrivate() + { + canBeMadePrivate = false; + } + + + public boolean canBeMadePrivate() + { + return canBeMadePrivate; + } + + + public void generalizeReferencedClass(ReferenceValue referencedClass) + { + this.referencedClass = this.referencedClass != null ? + this.referencedClass.generalize(referencedClass) : + referencedClass; + } + + + public ReferenceValue getReferencedClass() + { + return referencedClass; + } + + + public void generalizeValue(Value value) + { + this.value = this.value != null ? + this.value.generalize(value) : + value; + } + + + public Value getValue() + { + return value; + } + + + // Small utility methods. + + private Value initialValue(String type) + { + switch (type.charAt(0)) + { + case ClassConstants.INTERNAL_TYPE_BOOLEAN: + case ClassConstants.INTERNAL_TYPE_BYTE: + case ClassConstants.INTERNAL_TYPE_CHAR: + case ClassConstants.INTERNAL_TYPE_SHORT: + case ClassConstants.INTERNAL_TYPE_INT: + return VALUE_FACTORY.createIntegerValue(0); + + case ClassConstants.INTERNAL_TYPE_LONG: + return VALUE_FACTORY.createLongValue(0L); + + case ClassConstants.INTERNAL_TYPE_FLOAT: + return VALUE_FACTORY.createFloatValue(0.0f); + + case ClassConstants.INTERNAL_TYPE_DOUBLE: + return VALUE_FACTORY.createDoubleValue(0.0); + + case ClassConstants.INTERNAL_TYPE_CLASS_START: + case ClassConstants.INTERNAL_TYPE_ARRAY: + return VALUE_FACTORY.createReferenceValueNull(); + + default: + throw new IllegalArgumentException("Invalid type ["+type+"]"); + } + } + + + public static void setFieldOptimizationInfo(Clazz clazz, Field field) + { + MethodLinker.lastMember(field).setVisitorInfo(new FieldOptimizationInfo(clazz, field)); + } + + + public static FieldOptimizationInfo getFieldOptimizationInfo(Field field) + { + Object visitorInfo = MethodLinker.lastMember(field).getVisitorInfo(); + + return visitorInfo instanceof FieldOptimizationInfo ? + (FieldOptimizationInfo)visitorInfo : + null; + } +} diff --git a/src/proguard/optimize/info/InstanceofClassFilter.java b/src/proguard/optimize/info/InstanceofClassFilter.java new file mode 100644 index 0000000..35e1d77 --- /dev/null +++ b/src/proguard/optimize/info/InstanceofClassFilter.java @@ -0,0 +1,63 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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 used in an 'instanceof' test. + * + * @see InstanceofClassMarker + * @author Eric Lafortune + */ +public class InstanceofClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + public InstanceofClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (InstanceofClassMarker.isInstanceofed(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (InstanceofClassMarker.isInstanceofed(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/InstanceofClassMarker.java b/src/proguard/optimize/info/InstanceofClassMarker.java new file mode 100644 index 0000000..c60e1f8 --- /dev/null +++ b/src/proguard/optimize/info/InstanceofClassMarker.java @@ -0,0 +1,93 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.ClassConstant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +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. + * + * @author Eric Lafortune + */ +public class InstanceofClassMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + ClassVisitor +{ + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + if (constantInstruction.opcode == InstructionConstants.OP_INSTANCEOF) + { + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + } + + + // Implementations for ConstantVisitor. + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + classConstant.referencedClassAccept(this); + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + public void visitProgramClass(ProgramClass programClass) + { + setInstanceofed(programClass); + } + + + // Small utility methods. + + private static void setInstanceofed(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setInstanceofed(); + } + } + + + public static boolean isInstanceofed(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.isInstanceofed(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/InstantiationClassFilter.java b/src/proguard/optimize/info/InstantiationClassFilter.java new file mode 100644 index 0000000..a24e617 --- /dev/null +++ b/src/proguard/optimize/info/InstantiationClassFilter.java @@ -0,0 +1,62 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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 InstantiationClassFilter +implements ClassVisitor +{ + private final ClassVisitor classVisitor; + + + public InstantiationClassFilter(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + if (InstantiationClassMarker.isInstantiated(programClass)) + { + classVisitor.visitProgramClass(programClass); + } + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + if (InstantiationClassMarker.isInstantiated(libraryClass)) + { + classVisitor.visitLibraryClass(libraryClass); + } + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/InstantiationClassMarker.java b/src/proguard/optimize/info/InstantiationClassMarker.java new file mode 100644 index 0000000..124c23b --- /dev/null +++ b/src/proguard/optimize/info/InstantiationClassMarker.java @@ -0,0 +1,93 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.ClassConstant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This InstructionVisitor marks all classes that are instantiated by any of + * the instructions that it visits. + * + * @author Eric Lafortune + */ +public class InstantiationClassMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + ClassVisitor +{ + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + if (constantInstruction.opcode == InstructionConstants.OP_NEW) + { + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + } + + + // Implementations for ConstantVisitor. + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + classConstant.referencedClassAccept(this); + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + public void visitProgramClass(ProgramClass programClass) + { + setInstantiated(programClass); + } + + + // Small utility methods. + + private static void setInstantiated(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setInstantiated(); + } + } + + + public static boolean isInstantiated(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.isInstantiated(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java new file mode 100644 index 0000000..a170a8e --- /dev/null +++ b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java @@ -0,0 +1,59 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.MemberVisitor; +import proguard.optimize.KeepMarker; + +/** + * This MemberVisitor attaches a FieldOptimizationInfo instance to every field + * and a MethodOptimizationInfo instance to every method that is not being kept + * that it visits. + * + * @author Eric Lafortune + */ +public class MemberOptimizationInfoSetter +extends SimplifiedVisitor +implements MemberVisitor +{ + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + if (!KeepMarker.isKept(programMethod)) + { + MethodOptimizationInfo.setMethodOptimizationInfo(programClass, + programMethod); + } + } + + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + if (!KeepMarker.isKept(programField)) + { + FieldOptimizationInfo.setFieldOptimizationInfo(programClass, + programField); + } + } +} diff --git a/src/proguard/optimize/info/MethodInvocationMarker.java b/src/proguard/optimize/info/MethodInvocationMarker.java new file mode 100644 index 0000000..2528c94 --- /dev/null +++ b/src/proguard/optimize/info/MethodInvocationMarker.java @@ -0,0 +1,107 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This InstructionVisitor counts the number of times methods are invoked from + * the instructions that are visited. + * + * @author Eric Lafortune + */ +public class MethodInvocationMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + MemberVisitor +{ + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + // Mark the referenced method, if any. + stringConstant.referencedMemberAccept(this); + } + + + public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) + { + // Mark the referenced method. + refConstant.referencedMemberAccept(this); + } + + + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz Clazz, Member member) {} + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + incrementInvocationCount(programMethod); + } + + + // Small utility methods. + + private static void incrementInvocationCount(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.incrementInvocationCount(); + } + } + + + /** + * Returns the number of times the given method was invoked by the + * instructions that were visited. + */ + public static int getInvocationCount(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info != null ? info.getInvocationCount() : + Integer.MAX_VALUE; + } +} diff --git a/src/proguard/optimize/info/MethodOptimizationInfo.java b/src/proguard/optimize/info/MethodOptimizationInfo.java new file mode 100644 index 0000000..d3b1bde --- /dev/null +++ b/src/proguard/optimize/info/MethodOptimizationInfo.java @@ -0,0 +1,302 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.*; +import proguard.evaluation.value.Value; + +/** + * This class stores some optimization information that can be attached to + * a method. + * + * @author Eric Lafortune + */ +public class MethodOptimizationInfo +{ + private boolean hasNoSideEffects = false; + private boolean hasSideEffects = false; + private boolean canBeMadePrivate = true; + private boolean catchesExceptions = false; + private boolean branchesBackward = false; + private boolean invokesSuperMethods = false; + private boolean accessesPrivateCode = false; + private boolean accessesPackageCode = false; + private boolean accessesProtectedCode = false; + private int invocationCount = 0; + private int parameterSize = 0; + private long usedParameters = 0L; + private Value[] parameters; + private Value returnValue; + + + /** + * Creates a new MethodOptimizationInfo for the given method. + */ + public MethodOptimizationInfo(Clazz clazz, Method method) + { + // Set up an array of the right size for storing information about the + // passed parameters. + int parameterCount = + ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz)); + + if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0) + { + parameterCount++; + } + + if (parameterCount > 0) + { + parameters = new Value[parameterCount]; + } + } + + + public void setNoSideEffects() + { + hasNoSideEffects = true; + } + + + public boolean hasNoSideEffects() + { + return hasNoSideEffects; + } + + + public void setSideEffects() + { + hasSideEffects = true; + } + + + public boolean hasSideEffects() + { + return hasSideEffects; + } + + + public void setCanNotBeMadePrivate() + { + canBeMadePrivate = false; + } + + + public boolean canBeMadePrivate() + { + return canBeMadePrivate; + } + + + public void setCatchesExceptions() + { + catchesExceptions = true; + } + + + public boolean catchesExceptions() + { + return catchesExceptions; + } + + + public void setBranchesBackward() + { + branchesBackward = true; + } + + + public boolean branchesBackward() + { + return branchesBackward; + } + + + public void setInvokesSuperMethods() + { + invokesSuperMethods = true; + } + + + public boolean invokesSuperMethods() + { + return invokesSuperMethods; + } + + + public void setAccessesPrivateCode() + { + accessesPrivateCode = true; + } + + + public boolean accessesPrivateCode() + { + return accessesPrivateCode; + } + + + public void setAccessesPackageCode() + { + accessesPackageCode = true; + } + + + public boolean accessesPackageCode() + { + return accessesPackageCode; + } + + + public void setAccessesProtectedCode() + { + accessesProtectedCode = true; + } + + + public boolean accessesProtectedCode() + { + return accessesProtectedCode; + } + + + public void incrementInvocationCount() + { + invocationCount++; + } + + + public int getInvocationCount() + { + return invocationCount; + } + + + public void setParameterSize(int parameterSize) + { + this.parameterSize = parameterSize; + } + + + public int getParameterSize() + { + return parameterSize; + } + + + public void setParameterUsed(int parameterIndex) + { + usedParameters |= 1 << parameterIndex; + } + + + public void setUsedParameters(long usedParameters) + { + this.usedParameters = usedParameters; + } + + + public boolean isParameterUsed(int parameterIndex) + { + return parameterIndex >= 64 || (usedParameters & (1 << parameterIndex)) != 0; + } + + + public long getUsedParameters() + { + return usedParameters; + } + + + public void generalizeParameter(int parameterIndex, Value parameter) + { + parameters[parameterIndex] = parameters[parameterIndex] != null ? + parameters[parameterIndex].generalize(parameter) : + parameter; + } + + + public Value getParameter(int parameterIndex) + { + return parameters != null ? + parameters[parameterIndex] : + null; + } + + + public void generalizeReturnValue(Value returnValue) + { + this.returnValue = this.returnValue != null ? + this.returnValue.generalize(returnValue) : + returnValue; + } + + + public Value getReturnValue() + { + return returnValue; + } + + + public void merge(MethodOptimizationInfo other) + { + if (other != null) + { + this.hasNoSideEffects &= other.hasNoSideEffects; + this.hasSideEffects |= other.hasSideEffects; + //this.canBeMadePrivate &= other.canBeMadePrivate; + this.catchesExceptions |= other.catchesExceptions; + this.branchesBackward |= other.branchesBackward; + this.invokesSuperMethods |= other.invokesSuperMethods; + this.accessesPrivateCode |= other.accessesPrivateCode; + this.accessesPackageCode |= other.accessesPackageCode; + this.accessesProtectedCode |= other.accessesProtectedCode; + } + else + { + this.hasNoSideEffects = false; + this.hasSideEffects = true; + //this.canBeMadePrivate = false; + this.catchesExceptions = true; + this.branchesBackward = true; + this.invokesSuperMethods = true; + this.accessesPrivateCode = true; + this.accessesPackageCode = true; + this.accessesProtectedCode = true; + } + } + + + public static void setMethodOptimizationInfo(Clazz clazz, Method method) + { + MethodLinker.lastMember(method).setVisitorInfo(new MethodOptimizationInfo(clazz, method)); + } + + + public static MethodOptimizationInfo getMethodOptimizationInfo(Method method) + { + Object visitorInfo = MethodLinker.lastMember(method).getVisitorInfo(); + + return visitorInfo instanceof MethodOptimizationInfo ? + (MethodOptimizationInfo)visitorInfo : + null; + } +} diff --git a/src/proguard/optimize/info/NoSideEffectMethodMarker.java b/src/proguard/optimize/info/NoSideEffectMethodMarker.java new file mode 100644 index 0000000..5c78408 --- /dev/null +++ b/src/proguard/optimize/info/NoSideEffectMethodMarker.java @@ -0,0 +1,91 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.*; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This MemberVisitor marks all methods that it visits as not having any side + * effects. It will make the SideEffectMethodMarker consider them as such + * without further analysis. + * + * @see SideEffectMethodMarker + * @author Eric Lafortune + */ +public class NoSideEffectMethodMarker +extends SimplifiedVisitor +implements MemberVisitor +{ + // A visitor info flag to indicate the visitor accepter is being kept, + // but that it doesn't have any side effects. + private static final Object KEPT_BUT_NO_SIDE_EFFECTS = new Object(); + + + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz Clazz, Member member) + { + // Ignore any attempts to mark fields. + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + markNoSideEffects(programMethod); + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + markNoSideEffects(libraryMethod); + } + + + // Small utility methods. + + private static void markNoSideEffects(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setNoSideEffects(); + } + else + { + MethodLinker.lastMember(method).setVisitorInfo(KEPT_BUT_NO_SIDE_EFFECTS); + } + } + + + public static boolean hasNoSideEffects(Method method) + { + if (MethodLinker.lastVisitorAccepter(method).getVisitorInfo() == KEPT_BUT_NO_SIDE_EFFECTS) + { + return true; + } + + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info != null && + info.hasNoSideEffects(); + } +} diff --git a/src/proguard/optimize/info/NonPrivateMemberMarker.java b/src/proguard/optimize/info/NonPrivateMemberMarker.java new file mode 100644 index 0000000..d451643 --- /dev/null +++ b/src/proguard/optimize/info/NonPrivateMemberMarker.java @@ -0,0 +1,177 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +/** + * This ClassVisitor marks all class members that can not be made private in the + * classes that it visits, and in the classes to which they refer. + * + * @author Eric Lafortune + */ +public class NonPrivateMemberMarker +extends SimplifiedVisitor +implements ClassVisitor, + ConstantVisitor, + MemberVisitor +{ + private final MethodImplementationFilter filteredMethodMarker = new MethodImplementationFilter(this); + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Mark all referenced class members in different classes. + programClass.constantPoolEntriesAccept(this); + + // Explicitly mark the method. + programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, + ClassConstants.INTERNAL_METHOD_TYPE_CLINIT, + this); + + // Explicitly mark the parameterless method. + programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT, + ClassConstants.INTERNAL_METHOD_TYPE_INIT, + this); + + // Mark all methods that may have implementations. + programClass.methodsAccept(filteredMethodMarker); + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + // Go over all methods. + libraryClass.methodsAccept(this); + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + 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); + } + } + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + Clazz referencedClass = refConstant.referencedClass; + + // Is it refering 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 && + !referencedClass.equals(clazz) || + !refConstant.getClassName(clazz).equals(clazz.getName())) + { + // The referenced class member can never be made private. + refConstant.referencedMemberAccept(this); + } + } + + + // Implementations for MemberVisitor. + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + markCanNotBeMadePrivate(programField); + } + + + public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) + { + markCanNotBeMadePrivate(libraryField); + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + markCanNotBeMadePrivate(programMethod); + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + markCanNotBeMadePrivate(libraryMethod); + } + + + // Small utility methods. + + private static void markCanNotBeMadePrivate(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + if (info != null) + { + info.setCanNotBeMadePrivate(); + } + } + + + /** + * Returns whether the given field can be made private. + */ + public static boolean canBeMadePrivate(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + return info != null && + info.canBeMadePrivate(); + } + + + private static void markCanNotBeMadePrivate(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setCanNotBeMadePrivate(); + } + } + + + /** + * Returns whether the given method can be made private. + */ + public static boolean canBeMadePrivate(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info != null && + info.canBeMadePrivate(); + } +} diff --git a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java new file mode 100644 index 0000000..d40bc6b --- /dev/null +++ b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java @@ -0,0 +1,67 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.MemberVisitor; + +/** + * This MemberVisitor marks all classes that contain visited package visible + * members. + * + * @author Eric Lafortune + */ +public class PackageVisibleMemberContainingClassMarker +extends SimplifiedVisitor +implements MemberVisitor +{ + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz clazz, Member member) + { + if ((member.getAccessFlags() & + (ClassConstants.INTERNAL_ACC_PRIVATE | + ClassConstants.INTERNAL_ACC_PUBLIC)) == 0) + { + setPackageVisibleMembers(clazz); + } + } + + + // Small utility methods. + + private static void setPackageVisibleMembers(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setContainsPackageVisibleMembers(); + } + } + + + public static boolean containsPackageVisibleMembers(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.containsPackageVisibleMembers(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java new file mode 100644 index 0000000..9ec8ec6 --- /dev/null +++ b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java @@ -0,0 +1,81 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.constant.visitor.ConstantVisitor; +import proguard.classfile.constant.*; +import proguard.classfile.util.SimplifiedVisitor; + +/** + * This ConstantVisitor marks all classes that invoke package visible members + * in other classes. + * + * @author Eric Lafortune + */ +public class PackageVisibleMemberInvokingClassMarker +extends SimplifiedVisitor +implements ConstantVisitor +{ + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + Clazz referencedClass = refConstant.referencedClass; + if (referencedClass != null && + (referencedClass.getAccessFlags() & + ClassConstants.INTERNAL_ACC_PUBLIC) == 0) + { + setInvokesPackageVisibleMembers(clazz); + } + + Member referencedMember = refConstant.referencedMember; + if (referencedMember != null && + (referencedMember.getAccessFlags() & + (ClassConstants.INTERNAL_ACC_PUBLIC | + ClassConstants.INTERNAL_ACC_PRIVATE)) == 0) + { + setInvokesPackageVisibleMembers(clazz); + } + } + + + // Small utility methods. + + private static void setInvokesPackageVisibleMembers(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + if (info != null) + { + info.setInvokesPackageVisibleMembers(); + } + } + + + public static boolean invokesPackageVisibleMembers(Clazz clazz) + { + ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz); + return info == null || info.invokesPackageVisibleMembers(); + } +} \ No newline at end of file diff --git a/src/proguard/optimize/info/ParameterUsageMarker.java b/src/proguard/optimize/info/ParameterUsageMarker.java new file mode 100644 index 0000000..15ce88a --- /dev/null +++ b/src/proguard/optimize/info/ParameterUsageMarker.java @@ -0,0 +1,285 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.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.optimize.evaluation.PartialEvaluator; +import proguard.evaluation.value.*; + +/** + * This MemberVisitor counts the parameters and marks the used parameters + * of the methods that it visits. It also marks the 'this' parameters of + * methods that have hierarchies. + * + * @author Eric Lafortune + */ +public class ParameterUsageMarker +extends SimplifiedVisitor +implements MemberVisitor, + AttributeVisitor, + InstructionVisitor +{ + private static final boolean DEBUG = false; + + + private final boolean markThisParameter; + private final boolean markAllParameters; + private final PartialEvaluator partialEvaluator = new PartialEvaluator(); + + + /** + * Creates a new ParameterUsageMarker. + */ + public ParameterUsageMarker() + { + this(false, false); + } + + + /** + * Creates a new ParameterUsageMarker that optionally marks all parameters. + * @param markThisParameter specifies whether all 'this' parameters should + * be marked as being used. + * @param markAllParameters specifies whether all other parameters should + * be marked as being used. + */ + public ParameterUsageMarker(boolean markThisParameter, + boolean markAllParameters) + { + this.markThisParameter = markThisParameter; + this.markAllParameters = markAllParameters; + } + + + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + int parameterSize = + ClassUtil.internalMethodParameterSize(programMethod.getDescriptor(programClass), + programMethod.getAccessFlags()); + + if (parameterSize > 0) + { + int accessFlags = programMethod.getAccessFlags(); + + // Must we mark the 'this' parameter? + if (markThisParameter && + (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0) + { + // Mark the 'this' parameter. + markParameterUsed(programMethod, 0); + } + + // Must we mark all other parameters? + if (markAllParameters) + { + // Mark all parameters, without the 'this' parameter. + markUsedParameters(programMethod, + (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? + -1L : -2L); + } + + // Is it a native method? + if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0) + { + // Mark all parameters. + markUsedParameters(programMethod, -1L); + } + + // Is it an abstract method? + else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) + { + // Mark the 'this' parameter. + markParameterUsed(programMethod, 0); + } + + // Is it a non-native, concrete method? + else + { + // Is the method not static, but synchronized, or can it have + // other implementations, or is it a class instance initializer? + if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0 && + ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0 || + programClass.mayHaveImplementations(programMethod) || + programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) + { + // Mark the 'this' parameter. + markParameterUsed(programMethod, 0); + } + + // Mark the parameters that are used by the code. + programMethod.attributesAccept(programClass, this); + } + + if (DEBUG) + { + System.out.print("ParameterUsageMarker: ["+programClass.getName() +"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]: "); + for (int index = 0; index < parameterSize; index++) + { + System.out.print(isParameterUsed(programMethod, index) ? '+' : '-'); + } + System.out.println(); + } + + } + + // Set the parameter size. + setParameterSize(programMethod, parameterSize); + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + // Can the method have other implementations? + if (libraryClass.mayHaveImplementations(libraryMethod)) + { + // All implementations must keep all parameters of this method, + // including the 'this' parameter. + markUsedParameters(libraryMethod, -1L); + } + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + // Evaluate the code. + partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); + + // Mark the parameters that are used by the code. + codeAttribute.instructionsAccept(clazz, method, this); + } + + + // 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 (partialEvaluator.isTraced(offset) && + variableInstruction.isLoad()) + { + int parameterIndex = variableInstruction.variableIndex; + if (parameterIndex < codeAttribute.u2maxLocals) + { + Value producer = + partialEvaluator.getVariablesBefore(offset).getProducerValue(parameterIndex); + if (producer != null && + producer.instructionOffsetValue().contains(PartialEvaluator.AT_METHOD_ENTRY)) + { + // Mark the variable. + markParameterUsed(method, parameterIndex); + + // Account for Category 2 instructions, which take up two entries. + if (variableInstruction.isCategory2()) + { + markParameterUsed(method, parameterIndex + 1); + } + } + } + } + } + + + // Small utility methods. + + /** + * Sets the total size of the parameters. + */ + private static void setParameterSize(Method method, int parameterSize) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setParameterSize(parameterSize); + } + } + + + /** + * Returns the total size of the parameters. + */ + public static int getParameterSize(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info != null ? info.getParameterSize() : 0; + } + + + /** + * Marks the given parameter as being used. + */ + public static void markParameterUsed(Method method, int variableIndex) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setParameterUsed(variableIndex); + } + } + + + /** + * Marks the given parameters as being used. + */ + public static void markUsedParameters(Method method, long usedParameters) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setUsedParameters(info.getUsedParameters() | usedParameters); + } + } + + + /** + * Returns whether the given parameter is being used. + */ + public static boolean isParameterUsed(Method method, int variableIndex) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || + info.isParameterUsed(variableIndex); + } + + + /** + * Returns which parameters are being used. + */ + public static long getUsedParameters(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info != null ? info.getUsedParameters() : -1L; + } +} diff --git a/src/proguard/optimize/info/ReadWriteFieldMarker.java b/src/proguard/optimize/info/ReadWriteFieldMarker.java new file mode 100644 index 0000000..57d8561 --- /dev/null +++ b/src/proguard/optimize/info/ReadWriteFieldMarker.java @@ -0,0 +1,163 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This InstructionVisitor marks all fields that are write-only. + * + * @author Eric Lafortune + */ +public class ReadWriteFieldMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + MemberVisitor +{ + // Parameters for the visitor methods. + private boolean reading = true; + private boolean writing = true; + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + byte opcode = constantInstruction.opcode; + + // Check for instructions that involve fields. + switch (opcode) + { + case InstructionConstants.OP_LDC: + case InstructionConstants.OP_LDC_W: + // Mark the field, if any, as being read from and written to. + reading = true; + writing = true; + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + break; + + case InstructionConstants.OP_GETSTATIC: + case InstructionConstants.OP_GETFIELD: + // Mark the field as being read from. + reading = true; + writing = false; + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + break; + + case InstructionConstants.OP_PUTSTATIC: + case InstructionConstants.OP_PUTFIELD: + // Mark the field as being written to. + reading = false; + writing = true; + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + break; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + // Mark the referenced field, if any. + stringConstant.referencedMemberAccept(this); + } + + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) + { + // Mark the referenced field. + fieldrefConstant.referencedMemberAccept(this); + } + + + // Implementations for MemberVisitor. + + public void visitAnyMember(Clazz Clazz, Member member) {} + + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + // Mark the field if it is being read from. + if (reading) + { + markAsRead(programField); + } + + // Mark the field if it is being written to. + if (writing) + { + markAsWritten(programField); + } + } + + + // Small utility methods. + + private static void markAsRead(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + if (info != null) + { + info.setRead(); + } + } + + + public static boolean isRead(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + return info == null || + info.isRead(); + } + + + private static void markAsWritten(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + if (info != null) + { + info.setWritten(); + } + } + + + public static boolean isWritten(Field field) + { + FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field); + return info == null || + info.isWritten(); + } +} diff --git a/src/proguard/optimize/info/SideEffectInstructionChecker.java b/src/proguard/optimize/info/SideEffectInstructionChecker.java new file mode 100644 index 0000000..8be9dc1 --- /dev/null +++ b/src/proguard/optimize/info/SideEffectInstructionChecker.java @@ -0,0 +1,224 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +/** + * This class can tell whether an instruction has any side effects. Return + * instructions can be included or not. + * + * @see ReadWriteFieldMarker + * @see NoSideEffectMethodMarker + * @see SideEffectMethodMarker + * @author Eric Lafortune + */ +public class SideEffectInstructionChecker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor, + MemberVisitor +{ + private final boolean includeReturnInstructions; + + // A return value for the visitor methods. + private boolean hasSideEffects; + + + public SideEffectInstructionChecker(boolean includeReturnInstructions) + { + this.includeReturnInstructions = includeReturnInstructions; + } + + + public boolean hasSideEffects(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) + { + hasSideEffects = false; + + instruction.accept(clazz, method, codeAttribute, offset, this); + + return hasSideEffects; + } + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) + { + byte opcode = simpleInstruction.opcode; + + // Check for instructions that might cause side effects. + if (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_ATHROW || + opcode == InstructionConstants.OP_MONITORENTER || + opcode == InstructionConstants.OP_MONITOREXIT || + (includeReturnInstructions && + (opcode == InstructionConstants.OP_IRETURN || + opcode == InstructionConstants.OP_LRETURN || + opcode == InstructionConstants.OP_FRETURN || + opcode == InstructionConstants.OP_DRETURN || + opcode == InstructionConstants.OP_ARETURN || + opcode == InstructionConstants.OP_RETURN))) + { + // These instructions always cause a side effect. + hasSideEffects = true; + } + + } + + + public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) + { + byte opcode = variableInstruction.opcode; + + // Check for instructions that might cause side effects. + if (includeReturnInstructions && + opcode == InstructionConstants.OP_RET) + { + hasSideEffects = true; + } + } + + + 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) + { + // Check if the field is write-only or volatile, or if the invoked + // method is causing any side effects. + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + } + } + + + public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) + { + byte opcode = branchInstruction.opcode; + + // Check for instructions that might cause side effects. + if (includeReturnInstructions && + (opcode == InstructionConstants.OP_JSR || + opcode == InstructionConstants.OP_JSR_W)) + { + hasSideEffects = true; + } + } + + + // Implementations for ConstantVisitor. + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) + { + // We'll have to assume accessing an unknown field has side effects. + hasSideEffects = true; + + // Check the referenced field. + fieldrefConstant.referencedMemberAccept(this); + } + + + public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) + { + Member referencedMember = refConstant.referencedMember; + + // 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)); + } + } + } + } + + + // Implementations for MemberVisitor. + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + hasSideEffects = ReadWriteFieldMarker.isRead(programField); + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + hasSideEffects = hasSideEffects || + SideEffectMethodMarker.hasSideEffects(programMethod); + } + + + public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) + { + hasSideEffects = true; + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + hasSideEffects = hasSideEffects || + !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod); + } +} diff --git a/src/proguard/optimize/info/SideEffectMethodMarker.java b/src/proguard/optimize/info/SideEffectMethodMarker.java new file mode 100644 index 0000000..25fda72 --- /dev/null +++ b/src/proguard/optimize/info/SideEffectMethodMarker.java @@ -0,0 +1,175 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +/** + * This ClassPoolVisitor marks all methods that have side effects. + * + * @see ReadWriteFieldMarker + * @see NoSideEffectMethodMarker + * @author Eric Lafortune + */ +public class SideEffectMethodMarker +extends SimplifiedVisitor +implements ClassPoolVisitor, + ClassVisitor, + MemberVisitor, + AttributeVisitor +{ + // A reusable object for checking whether instructions have side effects. + private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false); + + // Parameters and values for visitor methods. + private int newSideEffectCount; + private boolean hasSideEffects; + + + // Implementations for ClassPoolVisitor. + + public void visitClassPool(ClassPool classPool) + { + // Go over all classes and their methods, marking if they have side + // effects, until no new cases can be found. + do + { + newSideEffectCount = 0; + + // Go over all classes and their methods once. + classPool.classesAccept(this); + } + while (newSideEffectCount > 0); + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Go over all methods. + programClass.methodsAccept(this); + } + + + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + if (!hasSideEffects(programMethod) && + !NoSideEffectMethodMarker.hasNoSideEffects(programMethod)) + { + // Initialize the return value. + hasSideEffects = + (programMethod.getAccessFlags() & + (ClassConstants.INTERNAL_ACC_NATIVE | + ClassConstants.INTERNAL_ACC_SYNCHRONIZED)) != 0; + + // Look further if the method hasn't been marked yet. + if (!hasSideEffects) + { + // Investigate the actual code. + programMethod.attributesAccept(programClass, this); + } + + // Mark the method depending on the return value. + if (hasSideEffects) + { + markSideEffects(programMethod); + + newSideEffectCount++; + } + } + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + // Remember whether the code has any side effects. + hasSideEffects = hasSideEffects(clazz, method, codeAttribute); + } + + + // Small utility methods. + + /** + * Returns whether the given code has any side effects. + */ + private boolean hasSideEffects(Clazz clazz, + Method method, + CodeAttribute codeAttribute) + { + byte[] code = codeAttribute.code; + int length = codeAttribute.u4codeLength; + + // Go over all instructions. + int offset = 0; + do + { + // Get the current instruction. + Instruction instruction = InstructionFactory.create(code, offset); + + // Check if it may be throwing exceptions. + if (sideEffectInstructionChecker.hasSideEffects(clazz, + method, + codeAttribute, + offset, + instruction)) + { + return true; + } + + // Go to the next instruction. + offset += instruction.length(offset); + } + while (offset < length); + + return false; + } + + + private static void markSideEffects(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setSideEffects(); + } + } + + + public static boolean hasSideEffects(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || + info.hasSideEffects(); + } +} diff --git a/src/proguard/optimize/info/SuperInvocationMarker.java b/src/proguard/optimize/info/SuperInvocationMarker.java new file mode 100644 index 0000000..6f3d3bd --- /dev/null +++ b/src/proguard/optimize/info/SuperInvocationMarker.java @@ -0,0 +1,93 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.CodeAttribute; +import proguard.classfile.constant.RefConstant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; + +/** + * This InstructionVisitor marks all methods that invoke super methods (other + * than initializers) from the instructions that it visits. + * + * @author Eric Lafortune + */ +public class SuperInvocationMarker +extends SimplifiedVisitor +implements InstructionVisitor, + ConstantVisitor +{ + private boolean invokesSuperMethods; + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL) + { + invokesSuperMethods = false; + + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + + if (invokesSuperMethods) + { + setInvokesSuperMethods(method); + } + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) + { + invokesSuperMethods = + !clazz.equals(refConstant.referencedClass) && + !refConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); + } + + + // Small utility methods. + + private static void setInvokesSuperMethods(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + if (info != null) + { + info.setInvokesSuperMethods(); + } + } + + + public static boolean invokesSuperMethods(Method method) + { + MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method); + return info == null || info.invokesSuperMethods(); + } +} diff --git a/src/proguard/optimize/info/VariableUsageMarker.java b/src/proguard/optimize/info/VariableUsageMarker.java new file mode 100644 index 0000000..660c4ba --- /dev/null +++ b/src/proguard/optimize/info/VariableUsageMarker.java @@ -0,0 +1,95 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; + +/** + * This AttributeVisitor marks the local variables that are used in the code + * attributes that it visits. + * + * @author Eric Lafortune + */ +public class VariableUsageMarker +extends SimplifiedVisitor +implements AttributeVisitor, + InstructionVisitor +{ + private boolean[] variableUsed = new boolean[ClassConstants.TYPICAL_VARIABLES_SIZE]; + + + /** + * Returns whether the given variable has been marked as being used. + */ + public boolean isVariableUsed(int variableIndex) + { + return variableUsed[variableIndex]; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + int maxLocals = codeAttribute.u2maxLocals; + + // Try to reuse the previous array. + if (variableUsed.length < maxLocals) + { + variableUsed = new boolean[maxLocals]; + } + else + { + for (int index = 0; index < maxLocals; index++) + { + variableUsed[index] = false; + } + } + + codeAttribute.instructionsAccept(clazz, method, this); + } + + + // 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) + { + // Mark the variable. + variableUsed[variableInstruction.variableIndex] = true; + + // Account for Category 2 instructions, which take up two entries. + if (variableInstruction.isCategory2()) + { + variableUsed[variableInstruction.variableIndex + 1] = true; + } + } +} diff --git a/src/proguard/optimize/info/package.html b/src/proguard/optimize/info/package.html new file mode 100644 index 0000000..d16486e --- /dev/null +++ b/src/proguard/optimize/info/package.html @@ -0,0 +1,4 @@ + +This package contains classes to collect additional information about classes +and class members, which can then be used for optimization. + -- cgit v1.2.3