summaryrefslogtreecommitdiffstats
path: root/src/proguard/optimize
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/optimize')
-rw-r--r--src/proguard/optimize/BootstrapMethodArgumentShrinker.java13
-rw-r--r--src/proguard/optimize/ChangedCodePrinter.java57
-rw-r--r--src/proguard/optimize/ConstantMemberFilter.java2
-rw-r--r--src/proguard/optimize/ConstantParameterFilter.java5
-rw-r--r--src/proguard/optimize/DuplicateInitializerFixer.java34
-rw-r--r--src/proguard/optimize/DuplicateInitializerInvocationFixer.java12
-rw-r--r--src/proguard/optimize/KeepMarker.java2
-rw-r--r--src/proguard/optimize/KeptClassFilter.java2
-rw-r--r--src/proguard/optimize/KeptMemberFilter.java2
-rw-r--r--src/proguard/optimize/MemberDescriptorSpecializer.java4
-rw-r--r--src/proguard/optimize/MethodDescriptorShrinker.java139
-rw-r--r--src/proguard/optimize/MethodStaticizer.java6
-rw-r--r--src/proguard/optimize/OptimizationInfoMemberFilter.java2
-rw-r--r--src/proguard/optimize/Optimizer.java168
-rw-r--r--src/proguard/optimize/ParameterShrinker.java8
-rw-r--r--src/proguard/optimize/TailRecursionSimplifier.java37
-rw-r--r--src/proguard/optimize/WriteOnlyFieldFilter.java2
-rw-r--r--src/proguard/optimize/evaluation/EvaluationShrinker.java280
-rw-r--r--src/proguard/optimize/evaluation/EvaluationSimplifier.java404
-rw-r--r--src/proguard/optimize/evaluation/LivenessAnalyzer.java2
-rw-r--r--src/proguard/optimize/evaluation/LoadingInvocationUnit.java45
-rw-r--r--src/proguard/optimize/evaluation/PartialEvaluator.java43
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java94
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumClassChecker.java74
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java164
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java583
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumUseChecker.java760
-rw-r--r--src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java820
-rw-r--r--src/proguard/optimize/evaluation/StoringInvocationUnit.java6
-rw-r--r--src/proguard/optimize/evaluation/TracedBranchUnit.java2
-rw-r--r--src/proguard/optimize/evaluation/VariableOptimizer.java8
-rw-r--r--src/proguard/optimize/info/AccessMethodMarker.java13
-rw-r--r--src/proguard/optimize/info/BackwardBranchMarker.java2
-rw-r--r--src/proguard/optimize/info/CatchExceptionMarker.java2
-rw-r--r--src/proguard/optimize/info/CaughtClassFilter.java2
-rw-r--r--src/proguard/optimize/info/CaughtClassMarker.java3
-rw-r--r--src/proguard/optimize/info/ClassOptimizationInfo.java16
-rw-r--r--src/proguard/optimize/info/ClassOptimizationInfoSetter.java4
-rw-r--r--src/proguard/optimize/info/DotClassFilter.java2
-rw-r--r--src/proguard/optimize/info/DotClassMarker.java2
-rw-r--r--src/proguard/optimize/info/DynamicInvocationMarker.java79
-rw-r--r--src/proguard/optimize/info/ExceptionInstructionChecker.java101
-rw-r--r--src/proguard/optimize/info/FieldOptimizationInfo.java82
-rw-r--r--src/proguard/optimize/info/InstanceofClassFilter.java2
-rw-r--r--src/proguard/optimize/info/InstanceofClassMarker.java2
-rw-r--r--src/proguard/optimize/info/InstantiationClassFilter.java2
-rw-r--r--src/proguard/optimize/info/InstantiationClassMarker.java2
-rw-r--r--src/proguard/optimize/info/MemberOptimizationInfoSetter.java2
-rw-r--r--src/proguard/optimize/info/MethodInvocationMarker.java2
-rw-r--r--src/proguard/optimize/info/MethodOptimizationInfo.java25
-rw-r--r--src/proguard/optimize/info/NoSideEffectMethodMarker.java2
-rw-r--r--src/proguard/optimize/info/NonPrivateMemberMarker.java10
-rw-r--r--src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java8
-rw-r--r--src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java10
-rw-r--r--src/proguard/optimize/info/ParameterUsageMarker.java16
-rw-r--r--src/proguard/optimize/info/ReadWriteFieldMarker.java2
-rw-r--r--src/proguard/optimize/info/SideEffectInstructionChecker.java108
-rw-r--r--src/proguard/optimize/info/SideEffectMethodFilter.java2
-rw-r--r--src/proguard/optimize/info/SideEffectMethodMarker.java8
-rw-r--r--src/proguard/optimize/info/SimpleEnumFilter.java63
-rw-r--r--src/proguard/optimize/info/SimpleEnumMarker.java75
-rw-r--r--src/proguard/optimize/info/StaticInitializerContainingClassFilter.java2
-rw-r--r--src/proguard/optimize/info/StaticInitializerContainingClassMarker.java8
-rw-r--r--src/proguard/optimize/info/SuperInvocationMarker.java4
-rw-r--r--src/proguard/optimize/info/VariableUsageMarker.java2
-rw-r--r--src/proguard/optimize/peephole/BranchTargetFinder.java85
-rw-r--r--src/proguard/optimize/peephole/ClassFinalizer.java14
-rw-r--r--src/proguard/optimize/peephole/ClassMerger.java171
-rw-r--r--src/proguard/optimize/peephole/GotoCommonCodeReplacer.java2
-rw-r--r--src/proguard/optimize/peephole/GotoGotoReplacer.java2
-rw-r--r--src/proguard/optimize/peephole/GotoReturnReplacer.java2
-rw-r--r--src/proguard/optimize/peephole/HorizontalClassMerger.java4
-rw-r--r--src/proguard/optimize/peephole/InstructionSequenceConstants.java76
-rw-r--r--src/proguard/optimize/peephole/InstructionSequenceReplacer.java5
-rw-r--r--src/proguard/optimize/peephole/InstructionSequencesReplacer.java2
-rw-r--r--src/proguard/optimize/peephole/MemberPrivatizer.java8
-rw-r--r--src/proguard/optimize/peephole/MethodFinalizer.java20
-rw-r--r--src/proguard/optimize/peephole/MethodInliner.java69
-rw-r--r--src/proguard/optimize/peephole/NopRemover.java2
-rw-r--r--src/proguard/optimize/peephole/PeepholeOptimizer.java2
-rw-r--r--src/proguard/optimize/peephole/ReachableCodeMarker.java2
-rw-r--r--src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java2
-rw-r--r--src/proguard/optimize/peephole/TargetClassChanger.java92
-rw-r--r--src/proguard/optimize/peephole/UnreachableCodeRemover.java2
-rw-r--r--src/proguard/optimize/peephole/UnreachableExceptionRemover.java11
-rw-r--r--src/proguard/optimize/peephole/VariableShrinker.java4
-rw-r--r--src/proguard/optimize/peephole/VerticalClassMerger.java4
87 files changed, 4328 insertions, 698 deletions
diff --git a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
index 26f1349..b4ac4cc 100644
--- a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
+++ b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,13 +21,11 @@
package proguard.optimize;
import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.attribute.BootstrapMethodInfo;
+import proguard.classfile.attribute.visitor.BootstrapMethodInfoVisitor;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.editor.ConstantPoolEditor;
-import proguard.classfile.util.*;
+import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
import proguard.optimize.info.*;
import proguard.optimize.peephole.VariableShrinker;
@@ -96,6 +94,9 @@ implements BootstrapMethodInfoVisitor,
// Implementations for MemberVisitor.
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
+
+
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
usedParameters = ParameterUsageMarker.getUsedParameters(programMethod);
diff --git a/src/proguard/optimize/ChangedCodePrinter.java b/src/proguard/optimize/ChangedCodePrinter.java
index 668d43d..261e164 100644
--- a/src/proguard/optimize/ChangedCodePrinter.java
+++ b/src/proguard/optimize/ChangedCodePrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -47,7 +47,6 @@ implements AttributeVisitor
// Implementations for AttributeVisitor.
-
public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
{
attributeVisitor.visitUnknownAttribute(clazz, unknownAttribute);
@@ -144,6 +143,12 @@ implements AttributeVisitor
}
+ public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute exceptionsAttribute)
+ {
+ attributeVisitor.visitMethodParametersAttribute(clazz, method, exceptionsAttribute);
+ }
+
+
public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
{
attributeVisitor.visitExceptionsAttribute(clazz, method, exceptionsAttribute);
@@ -228,6 +233,54 @@ implements AttributeVisitor
}
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, runtimeVisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, field, runtimeVisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, method, runtimeVisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, method, codeAttribute, runtimeVisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, runtimeInvisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, field, runtimeInvisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, method, runtimeInvisibleTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, method, codeAttribute, runtimeInvisibleTypeAnnotationsAttribute);
+ }
+
+
public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
{
attributeVisitor.visitAnnotationDefaultAttribute(clazz, method, annotationDefaultAttribute);
diff --git a/src/proguard/optimize/ConstantMemberFilter.java b/src/proguard/optimize/ConstantMemberFilter.java
index 1f30a30..6bd8619 100644
--- a/src/proguard/optimize/ConstantMemberFilter.java
+++ b/src/proguard/optimize/ConstantMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/ConstantParameterFilter.java b/src/proguard/optimize/ConstantParameterFilter.java
index 1500fd0..8a5058e 100644
--- a/src/proguard/optimize/ConstantParameterFilter.java
+++ b/src/proguard/optimize/ConstantParameterFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -25,7 +25,6 @@ import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
import proguard.evaluation.value.Value;
import proguard.optimize.evaluation.StoringInvocationUnit;
-import proguard.optimize.info.ParameterUsageMarker;
/**
* This <code>MemberVisitor</code> delegates its visits to program methods
@@ -60,7 +59,7 @@ implements MemberVisitor
// All parameters of non-static methods are shifted by one in the local
// variable frame.
int firstParameterIndex =
- (programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ?
0 : 1;
int parameterCount =
diff --git a/src/proguard/optimize/DuplicateInitializerFixer.java b/src/proguard/optimize/DuplicateInitializerFixer.java
index 95bc2f1..f5d5787 100644
--- a/src/proguard/optimize/DuplicateInitializerFixer.java
+++ b/src/proguard/optimize/DuplicateInitializerFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,9 +21,9 @@
package proguard.optimize;
import proguard.classfile.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.editor.ConstantPoolEditor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
@@ -41,11 +41,11 @@ implements MemberVisitor,
private static final char[] TYPES = new char[]
{
- ClassConstants.INTERNAL_TYPE_BYTE,
- ClassConstants.INTERNAL_TYPE_CHAR,
- ClassConstants.INTERNAL_TYPE_SHORT,
- ClassConstants.INTERNAL_TYPE_INT,
- ClassConstants.INTERNAL_TYPE_BOOLEAN
+ ClassConstants.TYPE_BYTE,
+ ClassConstants.TYPE_CHAR,
+ ClassConstants.TYPE_SHORT,
+ ClassConstants.TYPE_INT,
+ ClassConstants.TYPE_BOOLEAN
};
@@ -78,7 +78,7 @@ implements MemberVisitor,
{
// Is it a class instance initializer?
String name = programMethod.getName(programClass);
- if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ if (name.equals(ClassConstants.METHOD_NAME_INIT))
{
// Is there already another initializer with the same descriptor?
String descriptor = programMethod.getDescriptor(programClass);
@@ -92,7 +92,7 @@ implements MemberVisitor,
programMethod = (ProgramMethod)similarMethod;
}
- int index = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ int index = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
// Try to find a new, unique descriptor.
int typeCounter = 0;
@@ -105,7 +105,7 @@ implements MemberVisitor,
for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++)
{
- newDescriptorBuffer.append(ClassConstants.INTERNAL_TYPE_ARRAY);
+ newDescriptorBuffer.append(ClassConstants.TYPE_ARRAY);
}
newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]);
@@ -171,9 +171,9 @@ implements MemberVisitor,
public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
{
String descriptor = method.getDescriptor(clazz);
- int descriptorIndex = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
- String signature = clazz.getString(signatureAttribute.u2signatureIndex);
- int signatureIndex = signature.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ int descriptorIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
+ String signature = signatureAttribute.getSignature(clazz);
+ int signatureIndex = signature.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
String newSignature = signature.substring(0, signatureIndex) +
descriptor.charAt(descriptorIndex - 1) +
@@ -188,13 +188,13 @@ implements MemberVisitor,
public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
{
// Update the number of parameters.
- int oldParametersCount = parameterAnnotationsAttribute.u2parametersCount++;
+ int oldParametersCount = parameterAnnotationsAttribute.u1parametersCount++;
if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null ||
- parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u2parametersCount)
+ parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u1parametersCount)
{
- int[] annotationsCounts = new int[parameterAnnotationsAttribute.u2parametersCount];
- Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u2parametersCount][];
+ int[] annotationsCounts = new int[parameterAnnotationsAttribute.u1parametersCount];
+ Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u1parametersCount][];
System.arraycopy(parameterAnnotationsAttribute.u2parameterAnnotationsCount,
0,
diff --git a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java b/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
index 5edaba0..22bfc52 100644
--- a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
+++ b/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -131,11 +131,15 @@ implements AttributeVisitor,
// Implementations for ConstantVisitor.
- public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
{
// Check the referenced constructor descriptor.
- descriptor = methodrefConstant.getType(clazz);
- methodrefConstant.referencedMemberAccept(this);
+ if (refConstant.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT))
+ {
+ descriptor = refConstant.getType(clazz);
+
+ refConstant.referencedMemberAccept(this);
+ }
}
diff --git a/src/proguard/optimize/KeepMarker.java b/src/proguard/optimize/KeepMarker.java
index b0eab7b..c98ca6e 100644
--- a/src/proguard/optimize/KeepMarker.java
+++ b/src/proguard/optimize/KeepMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/KeptClassFilter.java b/src/proguard/optimize/KeptClassFilter.java
index 60a9d3e..c4e436f 100644
--- a/src/proguard/optimize/KeptClassFilter.java
+++ b/src/proguard/optimize/KeptClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/KeptMemberFilter.java b/src/proguard/optimize/KeptMemberFilter.java
index 1bdadb4..279c019 100644
--- a/src/proguard/optimize/KeptMemberFilter.java
+++ b/src/proguard/optimize/KeptMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/MemberDescriptorSpecializer.java b/src/proguard/optimize/MemberDescriptorSpecializer.java
index 4dce62e..4656092 100644
--- a/src/proguard/optimize/MemberDescriptorSpecializer.java
+++ b/src/proguard/optimize/MemberDescriptorSpecializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -99,7 +99,7 @@ implements MemberVisitor
// All parameters of non-static methods are shifted by one in the local
// variable frame.
int firstParameterIndex =
- (programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ?
0 : 1;
int parameterCount =
diff --git a/src/proguard/optimize/MethodDescriptorShrinker.java b/src/proguard/optimize/MethodDescriptorShrinker.java
index d8d4425..f5f52b0 100644
--- a/src/proguard/optimize/MethodDescriptorShrinker.java
+++ b/src/proguard/optimize/MethodDescriptorShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,13 +23,15 @@ package proguard.optimize;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.editor.ConstantPoolEditor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
import proguard.optimize.info.*;
import proguard.optimize.peephole.VariableShrinker;
+import java.util.Arrays;
+
/**
* This MemberVisitor removes unused parameters in the descriptors of the
* methods that it visits.
@@ -74,32 +76,26 @@ implements MemberVisitor,
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
+ if (DEBUG)
+ {
+ System.out.println("MethodDescriptorShrinker: ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]");
+ }
+
// Update the descriptor if it has any unused parameters.
String descriptor = programMethod.getDescriptor(programClass);
String newDescriptor = shrinkDescriptor(programMethod, descriptor);
- if (!descriptor.equals(newDescriptor))
+ if (!newDescriptor.equals(descriptor))
{
- // Shrink the signature and parameter annotations.
- programMethod.attributesAccept(programClass, this);
-
String name = programMethod.getName(programClass);
String newName = name;
// Append a code, if the method isn't a class instance initializer.
- if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ if (!name.equals(ClassConstants.METHOD_NAME_INIT))
{
newName += ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
}
- if (DEBUG)
- {
- System.out.println("MethodDescriptorShrinker:");
- System.out.println(" ["+programClass.getName()+"."+
- name+descriptor+"] -> ["+
- newName+newDescriptor+"]");
- }
-
ConstantPoolEditor constantPoolEditor =
new ConstantPoolEditor(programClass);
@@ -120,6 +116,14 @@ implements MemberVisitor,
programMethod.u2descriptorIndex =
constantPoolEditor.addUtf8Constant(newDescriptor);
+ if (DEBUG)
+ {
+ System.out.println(" -> ["+newName+newDescriptor+"]");
+ }
+
+ // Shrink the signature and parameter annotations.
+ programMethod.attributesAccept(programClass, this);
+
// Visit the method, if required.
if (extraMemberVisitor != null)
{
@@ -136,19 +140,32 @@ implements MemberVisitor,
public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
{
+ if (DEBUG)
+ {
+ System.out.println(" ["+signatureAttribute.getSignature(clazz)+"]");
+ }
+
// Compute the new signature.
- String signature = clazz.getString(signatureAttribute.u2signatureIndex);
+ String signature = signatureAttribute.getSignature(clazz);
String newSignature = shrinkDescriptor(method, signature);
- // Update the signature.
- signatureAttribute.u2signatureIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
+ if (!newSignature.equals(signature))
+ {
+ // Update the signature.
+ signatureAttribute.u2signatureIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
- // Update the referenced classes.
- signatureAttribute.referencedClasses =
- shrinkReferencedClasses(method,
- signature,
- signatureAttribute.referencedClasses);
+ // Update the referenced classes.
+ signatureAttribute.referencedClasses =
+ shrinkReferencedClasses(method,
+ signature,
+ signatureAttribute.referencedClasses);
+
+ if (DEBUG)
+ {
+ System.out.println(" -> ["+newSignature+"]");
+ }
+ }
}
@@ -160,7 +177,7 @@ implements MemberVisitor,
// All parameters of non-static methods are shifted by one in the local
// variable frame.
int parameterIndex =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ?
0 : 1;
int annotationIndex = 0;
@@ -186,7 +203,7 @@ implements MemberVisitor,
}
// Update the number of parameters.
- parameterAnnotationsAttribute.u2parametersCount = newAnnotationIndex;
+ parameterAnnotationsAttribute.u1parametersCount = newAnnotationIndex;
// Clear the unused entries.
while (newAnnotationIndex < annotationIndex)
@@ -207,18 +224,20 @@ implements MemberVisitor,
// All parameters of non-static methods are shifted by one in the local
// variable frame.
int parameterIndex =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ?
0 : 1;
- // Go over the parameters.
InternalTypeEnumeration internalTypeEnumeration =
new InternalTypeEnumeration(descriptor);
- StringBuffer newDescriptorBuffer = new StringBuffer();
+ StringBuffer newDescriptorBuffer =
+ new StringBuffer(descriptor.length());
+ // Copy the formal type parameters.
newDescriptorBuffer.append(internalTypeEnumeration.formalTypeParameters());
- newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN);
+ newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_OPEN);
+ // Go over the parameters.
while (internalTypeEnumeration.hasMoreTypes())
{
String type = internalTypeEnumeration.nextType();
@@ -234,7 +253,8 @@ implements MemberVisitor,
parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
}
- newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ // Copy the return type.
+ newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_CLOSE);
newDescriptorBuffer.append(internalTypeEnumeration.returnType());
return newDescriptorBuffer.toString();
@@ -253,30 +273,32 @@ implements MemberVisitor,
// All parameters of non-static methods are shifted by one in the local
// variable frame.
int parameterIndex =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ?
0 : 1;
- int referencedClassIndex = 0;
- int newReferencedClassIndex = 0;
-
- // Go over the parameters.
InternalTypeEnumeration internalTypeEnumeration =
new InternalTypeEnumeration(descriptor);
- // Also look at the formal type parameters.
- String type = internalTypeEnumeration.formalTypeParameters();
- int count = new DescriptorClassEnumeration(type).classCount();
- for (int counter = 0; counter < count; counter++)
+ int referencedClassIndex = 0;
+ int newReferencedClassIndex = 0;
+
+ // Copy the formal type parameters.
{
- referencedClasses[newReferencedClassIndex++] =
- referencedClasses[referencedClassIndex++];
+ String type = internalTypeEnumeration.formalTypeParameters();
+ int count = new DescriptorClassEnumeration(type).classCount();
+ for (int counter = 0; counter < count; counter++)
+ {
+ referencedClasses[newReferencedClassIndex++] =
+ referencedClasses[referencedClassIndex++];
+ }
}
+ // Go over the parameters.
while (internalTypeEnumeration.hasMoreTypes())
{
// Consider the classes referenced by this parameter type.
- type = internalTypeEnumeration.nextType();
- count = new DescriptorClassEnumeration(type).classCount();
+ String type = internalTypeEnumeration.nextType();
+ int count = new DescriptorClassEnumeration(type).classCount();
if (ParameterUsageMarker.isParameterUsed(method, parameterIndex))
{
@@ -296,19 +318,30 @@ implements MemberVisitor,
parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
}
- // Also look at the return value.
- type = internalTypeEnumeration.returnType();
- count = new DescriptorClassEnumeration(type).classCount();
- for (int counter = 0; counter < count; counter++)
+ // Copy the return type.
{
- referencedClasses[newReferencedClassIndex++] =
- referencedClasses[referencedClassIndex++];
+ String type = internalTypeEnumeration.returnType();
+ int count = new DescriptorClassEnumeration(type).classCount();
+ for (int counter = 0; counter < count; counter++)
+ {
+ referencedClasses[newReferencedClassIndex++] =
+ referencedClasses[referencedClassIndex++];
+ }
}
- // Clear the unused entries.
- while (newReferencedClassIndex < referencedClassIndex)
+ // Shrink the array to the proper size.
+ if (newReferencedClassIndex == 0)
{
- referencedClasses[newReferencedClassIndex++] = null;
+ referencedClasses = null;
+ }
+ else if (newReferencedClassIndex < referencedClassIndex)
+ {
+ Clazz[] newReferencedClasses = new Clazz[newReferencedClassIndex];
+ System.arraycopy(referencedClasses, 0,
+ newReferencedClasses, 0,
+ newReferencedClassIndex);
+
+ referencedClasses = newReferencedClasses;
}
}
diff --git a/src/proguard/optimize/MethodStaticizer.java b/src/proguard/optimize/MethodStaticizer.java
index c8bdd11..c672bfa 100644
--- a/src/proguard/optimize/MethodStaticizer.java
+++ b/src/proguard/optimize/MethodStaticizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -74,8 +74,8 @@ implements MemberVisitor,
{
// Make the method static.
programMethod.u2accessFlags =
- (programMethod.getAccessFlags() & ~ClassConstants.INTERNAL_ACC_FINAL) |
- ClassConstants.INTERNAL_ACC_STATIC;
+ (programMethod.getAccessFlags() & ~ClassConstants.ACC_FINAL) |
+ ClassConstants.ACC_STATIC;
// Visit the method, if required.
if (extraStaticMemberVisitor != null)
diff --git a/src/proguard/optimize/OptimizationInfoMemberFilter.java b/src/proguard/optimize/OptimizationInfoMemberFilter.java
index 2c5454c..bbfac20 100644
--- a/src/proguard/optimize/OptimizationInfoMemberFilter.java
+++ b/src/proguard/optimize/OptimizationInfoMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/Optimizer.java b/src/proguard/optimize/Optimizer.java
index 8042825..20f4083 100644
--- a/src/proguard/optimize/Optimizer.java
+++ b/src/proguard/optimize/Optimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,13 +23,12 @@ package proguard.optimize;
import proguard.*;
import proguard.classfile.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.Constant;
import proguard.classfile.constant.visitor.*;
import proguard.classfile.editor.*;
import proguard.classfile.instruction.visitor.*;
import proguard.classfile.util.MethodLinker;
import proguard.classfile.visitor.*;
-import proguard.evaluation.*;
+import proguard.evaluation.InvocationUnit;
import proguard.evaluation.value.*;
import proguard.optimize.evaluation.*;
import proguard.optimize.info.*;
@@ -47,6 +46,7 @@ import java.util.*;
public class Optimizer
{
private static final String CLASS_MARKING_FINAL = "class/marking/final";
+ private static final String CLASS_UNBOXING_ENUM = "class/unboxing/enum";
private static final String CLASS_MERGING_VERTICAL = "class/merging/vertical";
private static final String CLASS_MERGING_HORIZONTAL = "class/merging/horizontal";
private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly";
@@ -141,6 +141,7 @@ public class Optimizer
new ConstantMatcher(true);
boolean classMarkingFinal = filter.matches(CLASS_MARKING_FINAL);
+ boolean classUnboxingEnum = filter.matches(CLASS_UNBOXING_ENUM);
boolean classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL);
boolean classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL);
boolean fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY);
@@ -171,6 +172,7 @@ public class Optimizer
// Create counters to count the numbers of optimizations.
ClassCounter classMarkingFinalCounter = new ClassCounter();
+ ClassCounter classUnboxingEnumCounter = new ClassCounter();
ClassCounter classMergingVerticalCounter = new ClassCounter();
ClassCounter classMergingHorizontalCounter = new ClassCounter();
MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter();
@@ -251,11 +253,13 @@ public class Optimizer
libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker));
// We also keep all classes that are involved in .class constructs.
+ // We're not looking at enum classes though, so they can be simplified.
programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_ENUM,
new AllMethodVisitor(
new AllAttributeVisitor(
new AllInstructionVisitor(
- new DotClassClassVisitor(keepMarker)))));
+ new DotClassClassVisitor(keepMarker))))));
// We also keep all classes that are accessed dynamically.
programClassPool.classesAccept(
@@ -271,7 +275,7 @@ public class Optimizer
// We also keep all bootstrap method signatures.
programClassPool.classesAccept(
- new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_7,
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
new AllAttributeVisitor(
new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
new AllBootstrapMethodInfoVisitor(
@@ -279,6 +283,32 @@ public class Optimizer
new MethodrefTraveler(
new ReferencedMemberVisitor(keepMarker))))))));
+ // We also keep all bootstrap method arguments that point to methods.
+ // These arguments are typically the method handles for
+ // java.lang.invoke.LambdaMetafactory#metafactory, which provides the
+ // implementations for closures.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllAttributeVisitor(
+ new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
+ new AllBootstrapMethodInfoVisitor(
+ new BootstrapMethodArgumentVisitor(
+ new MethodrefTraveler(
+ new ReferencedMemberVisitor(keepMarker))))))));
+
+ // We also keep all classes (and their methods) returned by dynamic
+ // method invocations. They may return dynamic implementations of
+ // interfaces that otherwise appear unused.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllConstantVisitor(
+ new DynamicReturnedClassVisitor(
+ new MultiClassVisitor(new ClassVisitor[]
+ {
+ keepMarker,
+ new AllMemberVisitor(keepMarker)
+ })))));
+
// Attach some optimization info to all classes and class members, so
// it can be filled out later.
programClassPool.classesAccept(new ClassOptimizationInfoSetter());
@@ -311,8 +341,9 @@ public class Optimizer
{
// Make methods final, whereever possible.
programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
new AllMethodVisitor(
- new MethodFinalizer(methodMarkingFinalCounter)));
+ new MethodFinalizer(methodMarkingFinalCounter))));
}
if (fieldRemovalWriteonly)
@@ -337,6 +368,55 @@ public class Optimizer
new ReadWriteFieldMarker()));
}
+ if (classUnboxingEnum)
+ {
+ ClassCounter counter = new ClassCounter();
+
+ // Mark all final enums that qualify as simple enums.
+ programClassPool.classesAccept(
+ new ClassAccessFilter(ClassConstants.ACC_FINAL |
+ ClassConstants.ACC_ENUM, 0,
+ new SimpleEnumClassChecker()));
+
+ // Count the preliminary number of simple enums.
+ programClassPool.classesAccept(
+ new SimpleEnumFilter(counter));
+
+ // Only continue checking simple enums if there are any candidates.
+ if (counter.getCount() > 0)
+ {
+ // Unmark all simple enums that are explicitly used as objects.
+ programClassPool.classesAccept(
+ new SimpleEnumUseChecker());
+
+ // Count the definitive number of simple enums.
+ programClassPool.classesAccept(
+ new SimpleEnumFilter(classUnboxingEnumCounter));
+
+ // Only start handling simple enums if there are any.
+ if (classUnboxingEnumCounter.getCount() > 0)
+ {
+ // Simplify the use of the enum classes in code.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new SimpleEnumUseSimplifier())));
+
+ // Simplify the static initializers of simple enum classes.
+ programClassPool.classesAccept(
+ new SimpleEnumFilter(
+ new SimpleEnumClassSimplifier()));
+
+ // Simplify the use of the enum classes in descriptors.
+ programClassPool.classesAccept(
+ new SimpleEnumDescriptorSimplifier());
+
+ // Update references to class members with simple enum classes.
+ programClassPool.classesAccept(new MemberReferenceFixer());
+ }
+ }
+ }
+
// Mark all used parameters, including the 'this' parameters.
programClassPool.classesAccept(
new AllMethodVisitor(
@@ -354,25 +434,36 @@ public class Optimizer
// programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter()));
// Perform partial evaluation for filling out fields, method parameters,
- // and method return values.
- ValueFactory valueFactory = new IdentifiedValueFactory();
-
+ // and method return values, so they can be propagated.
if (fieldPropagationValue ||
methodPropagationParameter ||
methodPropagationReturnvalue)
{
- // Fill out fields, method parameters, and return values, so they
- // can be propagated.
+ // We'll create values to be stored with fields, method parameters,
+ // and return values.
+ ValueFactory valueFactory = new ParticularValueFactory();
+ ValueFactory detailedValueFactory = new DetailedValueFactory();
+
InvocationUnit storingInvocationUnit =
new StoringInvocationUnit(valueFactory,
fieldPropagationValue,
methodPropagationParameter,
methodPropagationReturnvalue);
+ // Evaluate synthetic classes in more detail, notably to propagate
+ // the arrays of the classes generated for enum switch statements.
+ programClassPool.classesAccept(
+ new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0,
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new PartialEvaluator(detailedValueFactory, storingInvocationUnit, false)))));
+
+ // Evaluate non-synthetic classes.
programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_SYNTHETIC,
new AllMethodVisitor(
new AllAttributeVisitor(
- new PartialEvaluator(valueFactory, storingInvocationUnit, false))));
+ new PartialEvaluator(valueFactory, storingInvocationUnit, false)))));
if (fieldPropagationValue)
{
@@ -397,8 +488,38 @@ public class Optimizer
new AllMethodVisitor(
new ConstantMemberFilter(methodPropagationReturnvalueCounter)));
}
+
+ if (classUnboxingEnumCounter.getCount() > 0)
+ {
+ // Propagate the simple enum constant counts.
+ programClassPool.classesAccept(
+ new SimpleEnumFilter(
+ new SimpleEnumArrayPropagator()));
+ }
+
+ if (codeSimplificationAdvanced)
+ {
+ // Fill out constants into the arrays of synthetic classes,
+ // notably the arrays of the classes generated for enum switch
+ // statements.
+ InvocationUnit loadingInvocationUnit =
+ new LoadingInvocationUnit(valueFactory,
+ fieldPropagationValue,
+ methodPropagationParameter,
+ methodPropagationReturnvalue);
+
+ programClassPool.classesAccept(
+ new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0,
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new PartialEvaluator(valueFactory, loadingInvocationUnit, false)))));
+ }
}
+ // Perform partial evaluation again, now loading any previously stored
+ // values for fields, method parameters, and method return values.
+ ValueFactory valueFactory = new IdentifiedValueFactory();
+
InvocationUnit loadingInvocationUnit =
new LoadingInvocationUnit(valueFactory,
fieldPropagationValue,
@@ -446,7 +567,7 @@ public class Optimizer
programClassPool.classesAccept(
new AllMethodVisitor(
new OptimizationInfoMemberFilter(
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC,
+ new MemberAccessFilter(0, ClassConstants.ACC_STATIC,
new MethodStaticizer(methodMarkingStaticCounter)))));
}
@@ -548,6 +669,7 @@ public class Optimizer
new DotClassMarker(),
new MethodInvocationMarker(),
new SuperInvocationMarker(),
+ new DynamicInvocationMarker(),
new BackwardBranchMarker(),
new AccessMethodMarker(),
})),
@@ -561,7 +683,8 @@ public class Optimizer
if (classMergingVertical)
{
- // Merge classes into their superclasses or interfaces.
+ // Merge subclasses up into their superclasses or
+ // merge interfaces down into their implementing classes.
programClassPool.classesAccept(
new VerticalClassMerger(configuration.allowAccessModification,
configuration.mergeInterfacesAggressively,
@@ -593,8 +716,7 @@ public class Optimizer
// Fix the access flags of referenced merged classes and their
// class members.
programClassPool.classesAccept(
- new AllConstantVisitor(
- new AccessFixer()));
+ new AccessFixer());
}
// Fix the access flags of the inner classes information.
@@ -667,9 +789,9 @@ public class Optimizer
{
// Make all non-private fields private, whereever possible.
programClassPool.classesAccept(
- new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE,
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
new AllFieldVisitor(
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
new MemberPrivatizer(fieldMarkingPrivateCounter)))));
}
@@ -677,9 +799,9 @@ public class Optimizer
{
// Make all non-private methods private, whereever possible.
programClassPool.classesAccept(
- new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE,
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
new AllMethodVisitor(
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
new MemberPrivatizer(methodMarkingPrivateCounter)))));
}
@@ -691,8 +813,7 @@ public class Optimizer
// Fix the access flags of referenced classes and class members,
// for MethodInliner.
programClassPool.classesAccept(
- new AllConstantVisitor(
- new AccessFixer()));
+ new AccessFixer());
}
if (methodRemovalParameterCounter .getCount() > 0 ||
@@ -842,6 +963,7 @@ public class Optimizer
new ConstantPoolShrinker());
int classMarkingFinalCount = classMarkingFinalCounter .getCount();
+ int classUnboxingEnumCount = classUnboxingEnumCounter .getCount();
int classMergingVerticalCount = classMergingVerticalCounter .getCount();
int classMergingHorizontalCount = classMergingHorizontalCounter .getCount();
int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount();
@@ -882,6 +1004,7 @@ public class Optimizer
if (configuration.verbose)
{
System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal));
+ System.out.println(" Number of unboxed enum classes: " + classUnboxingEnumCount + disabled(classUnboxingEnum));
System.out.println(" Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical));
System.out.println(" Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal));
System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly));
@@ -911,6 +1034,7 @@ public class Optimizer
}
return classMarkingFinalCount > 0 ||
+ classUnboxingEnumCount > 0 ||
classMergingVerticalCount > 0 ||
classMergingHorizontalCount > 0 ||
fieldRemovalWriteonlyCount > 0 ||
diff --git a/src/proguard/optimize/ParameterShrinker.java b/src/proguard/optimize/ParameterShrinker.java
index 33d37d1..eb2592e 100644
--- a/src/proguard/optimize/ParameterShrinker.java
+++ b/src/proguard/optimize/ParameterShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,7 +29,7 @@ import proguard.classfile.visitor.MemberVisitor;
import proguard.optimize.info.ParameterUsageMarker;
/**
- * This MemberVisitor removes unused parameters from the code of the methods
+ * This AttributeVisitor removes unused parameters from the code of the methods
* that it visits.
*
* @see ParameterUsageMarker
@@ -41,7 +41,11 @@ public class ParameterShrinker
extends SimplifiedVisitor
implements AttributeVisitor
{
+ //*
private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("ps") != null;
+ //*/
private final MemberVisitor extraVariableMemberVisitor;
diff --git a/src/proguard/optimize/TailRecursionSimplifier.java b/src/proguard/optimize/TailRecursionSimplifier.java
index f820566..dd38d6b 100644
--- a/src/proguard/optimize/TailRecursionSimplifier.java
+++ b/src/proguard/optimize/TailRecursionSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,7 @@ package proguard.optimize;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.MethodrefConstant;
+import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.editor.CodeAttributeComposer;
import proguard.classfile.instruction.*;
@@ -91,15 +91,14 @@ implements AttributeVisitor,
int accessFlags = method.getAccessFlags();
if (// Only check the method if it is private, static, or final.
- (accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE |
- ClassConstants.INTERNAL_ACC_STATIC |
- ClassConstants.INTERNAL_ACC_FINAL)) != 0 &&
+ (accessFlags & (ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC |
+ ClassConstants.ACC_FINAL)) != 0 &&
// Only check the method if it is not synchronized, etc.
- (accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED |
- ClassConstants.INTERNAL_ACC_NATIVE |
- ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0)
+ (accessFlags & (ClassConstants.ACC_SYNCHRONIZED |
+ ClassConstants.ACC_NATIVE |
+ ClassConstants.ACC_ABSTRACT)) == 0)
{
// codeAttributeComposer.DEBUG = DEBUG =
// clazz.getName().equals("abc/Def") &&
@@ -254,7 +253,7 @@ implements AttributeVisitor,
// Implementations for ConstantVisitor.
- public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant methodrefConstant)
{
recursive = targetMethod.equals(methodrefConstant.referencedMember);
}
@@ -280,7 +279,7 @@ implements AttributeVisitor,
String descriptor = method.getDescriptor(clazz);
boolean isStatic =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0;
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0;
// Count the number of parameters, taking into account their categories.
int parameterSize = ClassUtil.internalMethodParameterSize(descriptor);
@@ -314,23 +313,23 @@ implements AttributeVisitor,
byte opcode;
switch (parameterType.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:
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE:
+ case ClassConstants.TYPE_CHAR:
+ case ClassConstants.TYPE_SHORT:
+ case ClassConstants.TYPE_INT:
opcode = InstructionConstants.OP_ISTORE;
break;
- case ClassConstants.INTERNAL_TYPE_LONG:
+ case ClassConstants.TYPE_LONG:
opcode = InstructionConstants.OP_LSTORE;
break;
- case ClassConstants.INTERNAL_TYPE_FLOAT:
+ case ClassConstants.TYPE_FLOAT:
opcode = InstructionConstants.OP_FSTORE;
break;
- case ClassConstants.INTERNAL_TYPE_DOUBLE:
+ case ClassConstants.TYPE_DOUBLE:
opcode = InstructionConstants.OP_DSTORE;
break;
diff --git a/src/proguard/optimize/WriteOnlyFieldFilter.java b/src/proguard/optimize/WriteOnlyFieldFilter.java
index 762bd91..7aad651 100644
--- a/src/proguard/optimize/WriteOnlyFieldFilter.java
+++ b/src/proguard/optimize/WriteOnlyFieldFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java
index 2e86532..daccec1 100644
--- a/src/proguard/optimize/evaluation/EvaluationShrinker.java
+++ b/src/proguard/optimize/evaluation/EvaluationShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -30,7 +30,7 @@ import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
-import proguard.evaluation.*;
+import proguard.evaluation.TracedStack;
import proguard.evaluation.value.*;
import proguard.optimize.info.*;
@@ -50,8 +50,8 @@ implements AttributeVisitor
private static final boolean DEBUG_RESULTS = false;
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG_RESULTS = true;
- private static boolean DEBUG = true;
+ private static boolean DEBUG = System.getProperty("es") != null;
+ private static boolean DEBUG_RESULTS = DEBUG;
//*/
private static final int UNSUPPORTED = -1;
@@ -177,11 +177,7 @@ implements AttributeVisitor
if (DEBUG_RESULTS)
{
System.out.println();
- System.out.println("Class "+ClassUtil.externalClassName(clazz.getName()));
- System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(),
- 0,
- method.getName(clazz),
- method.getDescriptor(clazz)));
+ System.out.println("EvaluationShrinker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
}
// Initialize the necessary array.
@@ -542,7 +538,7 @@ implements AttributeVisitor
int parameterSize = ParameterUsageMarker.getParameterSize(programMethod);
// Make the method invocation static, if possible.
- if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0 &&
+ if ((programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 &&
!ParameterUsageMarker.isParameterUsed(programMethod, 0))
{
replaceByStaticInvocation(programClass,
@@ -705,7 +701,7 @@ implements AttributeVisitor
{
// Mark any variable initializations for this variable load that
// are required according to the JVM.
- markVariableInitializers(offset, variableInstruction.variableIndex);
+ markVariableInitializersBefore(offset, variableInstruction.variableIndex);
}
}
}
@@ -729,6 +725,8 @@ implements AttributeVisitor
if (isInstructionNecessary(offset))
{
// Check all stack entries that are popped.
+ // Unusual case: an exception handler with an exception that is
+ // no longer consumed directly by a method.
// Typical case: a freshly marked variable initialization that
// requires some value on the stack.
int popCount = instruction.stackPopCount(clazz);
@@ -739,17 +737,36 @@ implements AttributeVisitor
int stackSize = tracedStack.size();
+ int requiredPopCount = 0;
int requiredPushCount = 0;
for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
{
- if (!isStackSimplifiedBefore(offset, stackIndex))
+ boolean stackSimplifiedBefore =
+ isStackSimplifiedBefore(offset, stackIndex);
+ boolean stackEntryPresentBefore =
+ isStackEntryPresentBefore(offset, stackIndex);
+
+ if (stackSimplifiedBefore)
{
// Is this stack entry pushed by any producer
- // (because it is required by other consumers)?
+ // (maybe an exception in an exception handler)?
if (isStackEntryPresentBefore(offset, stackIndex))
{
// Mark all produced stack entries.
markStackEntryProducers(offset, stackIndex);
+
+ // Remember to pop it.
+ requiredPopCount++;
+ }
+ }
+ else
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (stackEntryPresentBefore)
+ {
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex);
}
else
{
@@ -759,6 +776,14 @@ implements AttributeVisitor
}
}
+ // Pop some unnecessary stack entries.
+ if (requiredPopCount > 0)
+ {
+ if (DEBUG) System.out.println(" Inserting before marked consumer "+instruction.toString(offset));
+
+ insertPopInstructions(offset, false, true, popCount);
+ }
+
// Push some necessary stack entries.
if (requiredPushCount > 0)
{
@@ -769,7 +794,7 @@ implements AttributeVisitor
throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]");
}
- insertPushInstructions(offset, false, tracedStack.getTop(0).computationalType());
+ insertPushInstructions(offset, false, true, tracedStack.getTop(0).computationalType());
}
}
@@ -826,7 +851,7 @@ implements AttributeVisitor
{
if (DEBUG) System.out.println(" Inserting after marked producer "+instruction.toString(offset));
- insertPopInstructions(offset, false, requiredPopCount);
+ insertPopInstructions(offset, false, false, requiredPopCount);
}
}
}
@@ -863,7 +888,7 @@ implements AttributeVisitor
{
if (DEBUG) System.out.println(" Replacing unmarked consumer "+instruction.toString(offset));
- insertPopInstructions(offset, true, expectedPopCount);
+ insertPopInstructions(offset, true, false, expectedPopCount);
}
}
@@ -893,7 +918,7 @@ implements AttributeVisitor
{
if (DEBUG) System.out.println(" Replacing unmarked producer "+instruction.toString(offset));
- insertPushInstructions(offset, true, tracedStack.getTop(0).computationalType());
+ insertPushInstructions(offset, true, false, tracedStack.getTop(0).computationalType());
}
}
}
@@ -1434,35 +1459,65 @@ implements AttributeVisitor
/**
- * Marks the initializing instructions of the variable consumer at the given
- * offset.
- * @param consumerOffset the offset of the variable consumer.
- * @param variableIndex the index of the variable that is loaded.
+ * Ensures that the given variable is initialized before the specified
+ * consumer of that variable, in the JVM's view.
+ * @param consumerOffset the instruction offset before which the variable
+ * needs to be initialized.
+ * @param variableIndex the index of the variable.
*/
- private void markVariableInitializers(int consumerOffset,
- int variableIndex)
+ private void markVariableInitializersBefore(int consumerOffset,
+ int variableIndex)
{
+ // Make sure the variable is initialized after all producers.
+ // Use the simple evaluator, to get the JVM's view of what is
+ // initialized.
InstructionOffsetValue producerOffsets =
simplePartialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
- if (producerOffsets != null)
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
{
- int offsetCount = producerOffsets.instructionOffsetCount();
- for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ // Avoid infinite loops by only looking at producers before
+ // the consumer.
+ int producerOffset =
+ producerOffsets.instructionOffset(offsetIndex);
+ if (producerOffset < consumerOffset)
{
- // Make sure the variable and the instruction are marked
- // at the producing offset.
- int offset = producerOffsets.instructionOffset(offsetIndex);
+ markVariableInitializersAfter(producerOffset, variableIndex);
+ }
+ }
+ }
- if (!isInstructionNecessary(offset) &&
- isVariableInitialization(offset, variableIndex))
- {
- if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at ");
- markInstruction(offset);
+ /**
+ * Ensures that the given variable is initialized after the specified
+ * producer of that variable, in the JVM's view.
+ * @param producerOffset the instruction offset after which the variable
+ * needs to be initialized.
+ * @param variableIndex the index of the variable.
+ */
+ private void markVariableInitializersAfter(int producerOffset,
+ int variableIndex)
+ {
+ // No problem if the producer has already been marked.
+ if (!isInstructionNecessary(producerOffset))
+ {
+ // Is the unmarked producer a variable initialization?
+ if (isVariableInitialization(producerOffset, variableIndex))
+ {
+ // Mark the producer.
+ if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at ");
- if (DEBUG) System.out.println();
- }
+ markInstruction(producerOffset);
+
+ if (DEBUG) System.out.println();
+ }
+ else
+ {
+ // Don't mark the producer, but recursively look at the
+ // preceding producers of the same variable. Their values
+ // will fall through, replacing this producer.
+ markVariableInitializersBefore(producerOffset, variableIndex);
}
}
}
@@ -1645,6 +1700,7 @@ implements AttributeVisitor
*/
private void insertPushInstructions(int offset,
boolean replace,
+ boolean before,
int computationalType)
{
// Mark this instruction.
@@ -1657,21 +1713,7 @@ implements AttributeVisitor
if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset));
// Replace or insert the push instruction.
- if (replace)
- {
- // Replace the push instruction.
- codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
- }
- else
- {
- // Insert the push instruction.
- codeAttributeEditor.insertBeforeInstruction(offset, replacementInstruction);
-
- if (extraAddedInstructionVisitor != null)
- {
- replacementInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
+ insertInstruction(offset, replace, before, replacementInstruction);
}
@@ -1700,7 +1742,10 @@ implements AttributeVisitor
* Pops the given number of stack entries at or after the given offset.
* The instructions are marked as necessary.
*/
- private void insertPopInstructions(int offset, boolean replace, int popCount)
+ private void insertPopInstructions(int offset,
+ boolean replace,
+ boolean before,
+ int popCount)
{
// Mark this instruction.
markInstruction(offset);
@@ -1713,19 +1758,7 @@ implements AttributeVisitor
Instruction popInstruction =
new SimpleInstruction(InstructionConstants.OP_POP);
- if (replace)
- {
- codeAttributeEditor.replaceInstruction(offset, popInstruction);
- }
- else
- {
- codeAttributeEditor.insertAfterInstruction(offset, popInstruction);
-
- if (extraAddedInstructionVisitor != null)
- {
- popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
+ insertInstruction(offset, replace, before, popInstruction);
break;
}
case 2:
@@ -1734,19 +1767,7 @@ implements AttributeVisitor
Instruction popInstruction =
new SimpleInstruction(InstructionConstants.OP_POP2);
- if (replace)
- {
- codeAttributeEditor.replaceInstruction(offset, popInstruction);
- }
- else
- {
- codeAttributeEditor.insertAfterInstruction(offset, popInstruction);
-
- if (extraAddedInstructionVisitor != null)
- {
- popInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
+ insertInstruction(offset, replace, before, popInstruction);
break;
}
default:
@@ -1771,31 +1792,86 @@ implements AttributeVisitor
popInstructions[popCount / 2] = popInstruction;
}
- if (replace)
- {
- codeAttributeEditor.replaceInstruction(offset, popInstructions);
+ insertInstructions(offset,
+ replace,
+ before,
+ popInstruction,
+ popInstructions);
+ break;
+ }
+ }
+ }
- for (int index = 1; index < popInstructions.length; index++)
- {
- if (extraAddedInstructionVisitor != null)
- {
- popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
- }
- else
+
+ /**
+ * Inserts or replaces the given instruction at the given offset.
+ */
+ private void insertInstruction(int offset,
+ boolean replace,
+ boolean before,
+ Instruction instruction)
+ {
+ if (replace)
+ {
+ codeAttributeEditor.replaceInstruction(offset, instruction);
+ }
+ else
+ {
+ if (before)
+ {
+ codeAttributeEditor.insertBeforeInstruction(offset, instruction);
+ }
+ else
+ {
+ codeAttributeEditor.insertAfterInstruction(offset, instruction);
+ }
+
+ if (extraAddedInstructionVisitor != null)
+ {
+ instruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
+ }
+ }
+ }
+
+
+ /**
+ * Inserts or replaces the given instruction at the given offset.
+ */
+ private void insertInstructions(int offset,
+ boolean replace,
+ boolean before,
+ Instruction instruction,
+ Instruction[] instructions)
+ {
+ if (replace)
+ {
+ codeAttributeEditor.replaceInstruction(offset, instructions);
+
+ if (extraAddedInstructionVisitor != null)
+ {
+ for (int index = 1; index < instructions.length; index++)
{
- codeAttributeEditor.insertAfterInstruction(offset, popInstructions);
+ instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
+ }
+ }
+ }
+ else
+ {
+ if (before)
+ {
+ codeAttributeEditor.insertBeforeInstruction(offset, instructions);
+ }
+ else
+ {
+ codeAttributeEditor.insertAfterInstruction(offset, instructions);
+ }
- for (int index = 0; index < popInstructions.length; index++)
- {
- if (extraAddedInstructionVisitor != null)
- {
- popInstructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
- }
- }
+ for (int index = 0; index < instructions.length; index++)
+ {
+ if (extraAddedInstructionVisitor != null)
+ {
+ instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
}
- break;
}
}
}
@@ -1998,14 +2074,14 @@ implements AttributeVisitor
int variableIndex)
{
// Wasn't the variable set yet?
- Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex);
+ Value valueBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex);
if (valueBefore == null)
{
return true;
}
// Is the computational type different now?
- Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex);
+ Value valueAfter = simplePartialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex);
if (valueAfter.computationalType() != valueBefore.computationalType())
{
return true;
@@ -2020,7 +2096,7 @@ implements AttributeVisitor
}
// Was the producer an argument (which may be removed)?
- Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex);
+ Value producersBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex);
return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 &&
producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY;
}
diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/src/proguard/optimize/evaluation/EvaluationSimplifier.java
index e6e73d9..8187342 100644
--- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java
+++ b/src/proguard/optimize/evaluation/EvaluationSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,10 +27,12 @@ import proguard.classfile.editor.*;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
-import proguard.evaluation.*;
+import proguard.classfile.visitor.ClassPrinter;
+import proguard.evaluation.TracedVariables;
import proguard.evaluation.value.*;
-import proguard.optimize.info.*;
+import proguard.optimize.info.SideEffectInstructionChecker;
+
+import java.util.Arrays;
/**
* This AttributeVisitor simplifies the code attributes that it visits, based
@@ -49,7 +51,7 @@ implements AttributeVisitor,
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = true;
+ private static boolean DEBUG = System.getProperty("es") != null;
//*/
private final InstructionVisitor extraInstructionVisitor;
@@ -125,11 +127,7 @@ implements AttributeVisitor,
if (DEBUG)
{
System.out.println();
- System.out.println("Class "+ClassUtil.externalClassName(clazz.getName()));
- System.out.println("Method "+ClassUtil.externalFullMethodDescription(clazz.getName(),
- 0,
- method.getName(clazz),
- method.getDescriptor(clazz)));
+ System.out.println("EvaluationSimplifier ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
}
// Evaluate the method.
@@ -185,6 +183,7 @@ implements AttributeVisitor,
case InstructionConstants.OP_I2B:
case InstructionConstants.OP_I2C:
case InstructionConstants.OP_I2S:
+ case InstructionConstants.OP_ARRAYLENGTH:
replaceIntegerPushInstruction(clazz, offset, simpleInstruction);
break;
@@ -354,15 +353,50 @@ implements AttributeVisitor,
}
- public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
+ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
{
// First try to simplify it to a simple branch.
- replaceBranchInstruction(clazz, offset, switchInstruction);
+ replaceBranchInstruction(clazz, offset, tableSwitchInstruction);
- // Otherwise make sure all branch targets are valid.
+ // Otherwise try to simplify simple enum switches.
if (!codeAttributeEditor.isModified(offset))
{
- replaceSwitchInstruction(clazz, offset, switchInstruction);
+ replaceSimpleEnumSwitchInstruction(clazz,
+ codeAttribute,
+ offset,
+ tableSwitchInstruction);
+
+ // Otherwise make sure all branch targets are valid.
+ if (!codeAttributeEditor.isModified(offset))
+ {
+ cleanUpSwitchInstruction(clazz, offset, tableSwitchInstruction);
+
+ trimSwitchInstruction(clazz, offset, tableSwitchInstruction);
+ }
+ }
+ }
+
+
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ // First try to simplify it to a simple branch.
+ replaceBranchInstruction(clazz, offset, lookUpSwitchInstruction);
+
+ // Otherwise try to simplify simple enum switches.
+ if (!codeAttributeEditor.isModified(offset))
+ {
+ replaceSimpleEnumSwitchInstruction(clazz,
+ codeAttribute,
+ offset,
+ lookUpSwitchInstruction);
+
+ // Otherwise make sure all branch targets are valid.
+ if (!codeAttributeEditor.isModified(offset))
+ {
+ cleanUpSwitchInstruction(clazz, offset, lookUpSwitchInstruction);
+
+ trimSwitchInstruction(clazz, offset, lookUpSwitchInstruction);
+ }
}
}
@@ -824,9 +858,185 @@ implements AttributeVisitor,
/**
+ * Replaces the given table switch instruction, if it is based on the value
+ * of a fixed array. This is typical for switches on simple enums.
+ */
+ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
+ CodeAttribute codeAttribute,
+ int offset,
+ TableSwitchInstruction tableSwitchInstruction)
+ {
+ // Check if the switch instruction is consuming a single value loaded
+ // from a fully specified array.
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getStackBefore(offset).getTopProducerValue(0).instructionOffsetValue();
+
+ if (producerOffsets.instructionOffsetCount() == 1)
+ {
+ int producerOffset = producerOffsets.instructionOffset(0);
+
+ if (codeAttribute.code[producerOffset] == InstructionConstants.OP_IALOAD &&
+ !codeAttributeEditor.isModified(producerOffset))
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(producerOffset).getTop(1).referenceValue();
+
+ if (referenceValue.isParticular())
+ {
+ // Simplify the entire construct.
+ replaceSimpleEnumSwitchInstruction(clazz,
+ codeAttribute,
+ producerOffset,
+ offset,
+ tableSwitchInstruction,
+ referenceValue);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given table switch instruction that is based on a value of
+ * the given fixed array.
+ */
+ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
+ CodeAttribute codeAttribute,
+ int loadOffset,
+ int switchOffset,
+ TableSwitchInstruction tableSwitchInstruction,
+ ReferenceValue mappingValue)
+ {
+ ValueFactory valueFactory = new ParticularValueFactory();
+
+ // Transform the jump offsets.
+ int[] jumpOffsets = tableSwitchInstruction.jumpOffsets;
+ int[] newJumpOffsets = new int[mappingValue.arrayLength(valueFactory).value()];
+
+ for (int index = 0; index < newJumpOffsets.length; index++)
+ {
+ int switchCase =
+ mappingValue.integerArrayLoad(valueFactory.createIntegerValue(
+ index),
+ valueFactory).value();
+
+ newJumpOffsets[index] =
+ switchCase >= tableSwitchInstruction.lowCase &&
+ switchCase <= tableSwitchInstruction.highCase ?
+ jumpOffsets[switchCase - tableSwitchInstruction.lowCase] :
+ tableSwitchInstruction.defaultOffset;
+ }
+
+ // Update the instruction.
+ tableSwitchInstruction.lowCase = 0;
+ tableSwitchInstruction.highCase = newJumpOffsets.length - 1;
+ tableSwitchInstruction.jumpOffsets = newJumpOffsets;
+
+ // Replace the original one with the new version.
+ replaceSimpleEnumSwitchInstruction(clazz,
+ loadOffset,
+ switchOffset,
+ tableSwitchInstruction);
+
+ cleanUpSwitchInstruction(clazz, switchOffset, tableSwitchInstruction);
+
+ trimSwitchInstruction(clazz, switchOffset, tableSwitchInstruction);
+ }
+
+
+ /**
+ * Replaces the given look up switch instruction, if it is based on the
+ * value of a fixed array. This is typical for switches on simple enums.
+ */
+ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
+ CodeAttribute codeAttribute,
+ int offset,
+ LookUpSwitchInstruction lookupSwitchInstruction)
+ {
+ // Check if the switch instruction is consuming a single value loaded
+ // from a fully specified array.
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getStackBefore(offset).getTopProducerValue(0).instructionOffsetValue();
+
+ if (producerOffsets.instructionOffsetCount() == 1)
+ {
+ int producerOffset = producerOffsets.instructionOffset(0);
+
+ if (codeAttribute.code[producerOffset] == InstructionConstants.OP_IALOAD &&
+ !codeAttributeEditor.isModified(producerOffset))
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(producerOffset).getTop(1).referenceValue();
+
+ if (referenceValue.isParticular())
+ {
+ // Simplify the entire construct.
+ replaceSimpleEnumSwitchInstruction(clazz,
+ codeAttribute,
+ producerOffset,
+ offset,
+ lookupSwitchInstruction,
+ referenceValue);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given look up switch instruction that is based on a value of
+ * the given fixed array. This is typical for switches on simple enums.
+ */
+ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
+ CodeAttribute codeAttribute,
+ int loadOffset,
+ int switchOffset,
+ LookUpSwitchInstruction lookupSwitchInstruction,
+ ReferenceValue mappingValue)
+ {
+ ValueFactory valueFactory = new ParticularValueFactory();
+
+ // Transform the jump offsets.
+ int[] cases = lookupSwitchInstruction.cases;
+ int[] jumpOffsets = lookupSwitchInstruction.jumpOffsets;
+ int[] newJumpOffsets = new int[mappingValue.arrayLength(valueFactory).value()];
+
+ for (int index = 0; index < newJumpOffsets.length; index++)
+ {
+ int switchCase =
+ mappingValue.integerArrayLoad(valueFactory.createIntegerValue(index),
+ valueFactory).value();
+
+ int caseIndex = Arrays.binarySearch(cases, switchCase);
+
+ newJumpOffsets[index] = caseIndex >= 0 ?
+ jumpOffsets[caseIndex] :
+ lookupSwitchInstruction.defaultOffset;
+ }
+
+ // Replace the original lookup switch with a table switch.
+ TableSwitchInstruction replacementSwitchInstruction =
+ new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH,
+ lookupSwitchInstruction.defaultOffset,
+ 0,
+ newJumpOffsets.length - 1,
+ newJumpOffsets);
+
+ replaceSimpleEnumSwitchInstruction(clazz,
+ loadOffset,
+ switchOffset,
+ replacementSwitchInstruction);
+
+ cleanUpSwitchInstruction(clazz, switchOffset, replacementSwitchInstruction);
+
+ trimSwitchInstruction(clazz, switchOffset, replacementSwitchInstruction);
+ }
+
+
+ /**
* Makes sure all branch targets of the given switch instruction are valid.
*/
- private void replaceSwitchInstruction(Clazz clazz,
+ private void cleanUpSwitchInstruction(Clazz clazz,
int offset,
SwitchInstruction switchInstruction)
{
@@ -872,6 +1082,129 @@ implements AttributeVisitor,
/**
+ * Trims redundant offsets from the given switch instruction.
+ */
+ private void trimSwitchInstruction(Clazz clazz,
+ int offset,
+ TableSwitchInstruction tableSwitchInstruction)
+ {
+ // Get an offset that can serve as a valid default offset.
+ int defaultOffset = tableSwitchInstruction.defaultOffset;
+ int[] jumpOffsets = tableSwitchInstruction.jumpOffsets;
+ int length = jumpOffsets.length;
+
+ // Find the lowest index with a non-default jump offset.
+ int lowIndex = 0;
+ while (lowIndex < length &&
+ jumpOffsets[lowIndex] == defaultOffset)
+ {
+ lowIndex++;
+ }
+
+ // Find the highest index with a non-default jump offset.
+ int highIndex = length - 1;
+ while (highIndex >= 0 &&
+ jumpOffsets[highIndex] == defaultOffset)
+ {
+ highIndex--;
+ }
+
+ // Can we use a shorter array?
+ int newLength = highIndex - lowIndex + 1;
+ if (newLength < length)
+ {
+ if (newLength <= 0)
+ {
+ // Replace the switch instruction by a simple branch instruction.
+ Instruction replacementInstruction =
+ new BranchInstruction(InstructionConstants.OP_GOTO,
+ defaultOffset);
+
+ replaceInstruction(clazz, offset, tableSwitchInstruction,
+ replacementInstruction);
+ }
+ else
+ {
+ // Trim the array.
+ int[] newJumpOffsets = new int[newLength];
+
+ System.arraycopy(jumpOffsets, lowIndex, newJumpOffsets, 0, newLength);
+
+ tableSwitchInstruction.jumpOffsets = newJumpOffsets;
+ tableSwitchInstruction.lowCase += lowIndex;
+ tableSwitchInstruction.highCase -= length - newLength - lowIndex;
+
+ replaceInstruction(clazz, offset, tableSwitchInstruction,
+ tableSwitchInstruction);
+ }
+ }
+ }
+
+
+ /**
+ * Trims redundant offsets from the given switch instruction.
+ */
+ private void trimSwitchInstruction(Clazz clazz,
+ int offset,
+ LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ // Get an offset that can serve as a valid default offset.
+ int defaultOffset = lookUpSwitchInstruction.defaultOffset;
+ int[] jumpOffsets = lookUpSwitchInstruction.jumpOffsets;
+ int length = jumpOffsets.length;
+ int newLength = length;
+
+ // Count the default jump offsets.
+ for (int index = 0; index < length; index++)
+ {
+ if (jumpOffsets[index] == defaultOffset)
+ {
+ newLength--;
+ }
+ }
+
+ // Can we use shorter arrays?
+ if (newLength < length)
+ {
+ if (newLength <= 0)
+ {
+ // Replace the switch instruction by a simple branch instruction.
+ Instruction replacementInstruction =
+ new BranchInstruction(InstructionConstants.OP_GOTO,
+ defaultOffset);
+
+ replaceInstruction(clazz, offset, lookUpSwitchInstruction,
+ replacementInstruction);
+ }
+ else
+ {
+ // Remove redundant entries from the arrays.
+ int[] cases = lookUpSwitchInstruction.cases;
+ int[] newJumpOffsets = new int[newLength];
+ int[] newCases = new int[newLength];
+
+ int newIndex = 0;
+
+ for (int index = 0; index < length; index++)
+ {
+ if (jumpOffsets[index] != defaultOffset)
+ {
+ newJumpOffsets[newIndex] = jumpOffsets[index];
+ newCases[newIndex++] = cases[index];
+ }
+ }
+
+ lookUpSwitchInstruction.jumpOffsets = newJumpOffsets;
+ lookUpSwitchInstruction.cases = newCases;
+
+ replaceInstruction(clazz, offset, lookUpSwitchInstruction,
+ lookUpSwitchInstruction);
+ }
+ }
+ }
+
+
+ /**
* Replaces the given instruction by an infinite loop.
*/
private void replaceByInfiniteLoop(Clazz clazz,
@@ -891,7 +1224,11 @@ implements AttributeVisitor,
{
// Note: we're not passing the right arguments for now, knowing that
// they aren't used anyway.
- instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
+ instruction.accept(clazz,
+ null,
+ null,
+ offset,
+ extraInstructionVisitor);
}
}
@@ -985,4 +1322,39 @@ implements AttributeVisitor,
}
}
}
+
+
+ /**
+ * Replaces the simple enum switch instructions at a given offsets by a
+ * given replacement instruction.
+ */
+ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
+ int loadOffset,
+ int switchOffset,
+ SwitchInstruction replacementSwitchInstruction)
+ {
+ if (DEBUG) System.out.println(" Replacing switch instruction at ["+switchOffset+"] -> ["+loadOffset+"] swap + pop, "+replacementSwitchInstruction.toString(switchOffset)+")");
+
+ // Remove the array load instruction.
+ codeAttributeEditor.replaceInstruction(loadOffset, new Instruction[]
+ {
+ new SimpleInstruction(InstructionConstants.OP_SWAP),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ });
+
+ // Replace the switch instruction.
+ codeAttributeEditor.replaceInstruction(switchOffset, replacementSwitchInstruction);
+
+ // Visit the instruction, if required.
+ if (extraInstructionVisitor != null)
+ {
+ // Note: we're not passing the right arguments for now, knowing that
+ // they aren't used anyway.
+ replacementSwitchInstruction.accept(clazz,
+ null,
+ null,
+ switchOffset,
+ extraInstructionVisitor);
+ }
+ }
}
diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/src/proguard/optimize/evaluation/LivenessAnalyzer.java
index 5ce8ccb..87bd4e5 100644
--- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java
+++ b/src/proguard/optimize/evaluation/LivenessAnalyzer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
index d6baa67..80b4b84 100644
--- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
+++ b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -26,7 +26,7 @@ import proguard.evaluation.BasicInvocationUnit;
import proguard.evaluation.value.*;
/**
- * This InvocationUbit loads parameter values and return values that were
+ * This InvocationUnit loads parameter values and return values that were
* previously stored with the methods that are invoked.
*
* @see StoringInvocationUnit
@@ -45,7 +45,7 @@ extends BasicInvocationUnit
*/
public LoadingInvocationUnit(ValueFactory valueFactory)
{
- this(valueFactory, false, false, false);
+ this(valueFactory, true, true, true);
}
@@ -80,8 +80,7 @@ extends BasicInvocationUnit
{
// Retrieve the stored field class value.
ReferenceValue value = StoringInvocationUnit.getFieldClassValue((Field)referencedMember);
- if (value != null &&
- value.isParticular())
+ if (value != null)
{
return value;
}
@@ -104,8 +103,7 @@ extends BasicInvocationUnit
{
// Retrieve the stored field value.
Value value = StoringInvocationUnit.getFieldValue((Field)referencedMember);
- if (value != null &&
- value.isParticular())
+ if (value != null)
{
return value;
}
@@ -126,8 +124,7 @@ extends BasicInvocationUnit
{
// Retrieve the stored method parameter value.
Value value = StoringInvocationUnit.getMethodParameterValue(method, parameterIndex);
- if (value != null &&
- value.isParticular())
+ if (value != null)
{
return value;
}
@@ -153,8 +150,7 @@ extends BasicInvocationUnit
{
// Retrieve the stored method return value.
Value value = StoringInvocationUnit.getMethodReturnValue((Method)referencedMember);
- if (value != null &&
- value.isParticular())
+ if (value != null)
{
return value;
}
@@ -165,31 +161,4 @@ extends BasicInvocationUnit
refConstant,
type);
}
-
-
-// // Small utility methods.
-//
-// private Value refresh(Value value)
-// {
-// if (value.isParticular())
-// {
-// return value;
-// }
-//
-// switch (value.computationalType())
-// {
-// case Value.TYPE_INTEGER: return valueFactory.createIntegerValue();
-// case Value.TYPE_LONG: return valueFactory.createLongValue();
-// case Value.TYPE_FLOAT: return valueFactory.createFloatValue();
-// case Value.TYPE_DOUBLE: return valueFactory.createDoubleValue();
-// default:
-// {
-// ReferenceValue referenceValue = value.referenceValue();
-//
-// return valueFactory.createReferenceValue(referenceValue.getType(),
-// referenceValue.getReferencedClass(),
-// referenceValue.isNull() != Value.NEVER);
-// }
-// }
-// }
}
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java
index 6a5bedf..0301f12 100644
--- a/src/proguard/optimize/evaluation/PartialEvaluator.java
+++ b/src/proguard/optimize/evaluation/PartialEvaluator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -96,9 +96,10 @@ implements AttributeVisitor,
* during evaluation.
* @param invocationUnit the invocation unit that will handle all
* communication with other fields and methods.
- * @param evaluateAllCode a flag that specifies whether all branch targets
- * and exception handlers should be evaluated,
- * even if they are unreachable.
+ * @param evaluateAllCode a flag that specifies whether all casts, branch
+ * targets, and exception handlers should be
+ * evaluated, even if they are unnecessary or
+ * unreachable.
*/
public PartialEvaluator(ValueFactory valueFactory,
InvocationUnit invocationUnit,
@@ -132,17 +133,22 @@ implements AttributeVisitor,
/**
* Creates a new PartialEvaluator.
- * @param valueFactory the value factory that will create all
- * values during evaluation.
- * @param invocationUnit the invocation unit that will handle all
- * communication with other fields and methods.
- * @param evaluateAllCode a flag that specifies whether all branch
- * targets and exception handlers should be
- * evaluated, even if they are unreachable.
- * @param branchUnit the branch unit that will handle all
- * branches.
- * @param branchTargetFinder the utility class that will find all
- * branches.
+ * @param valueFactory the value factory that will create
+ * all values during evaluation.
+ * @param invocationUnit the invocation unit that will handle
+ * all communication with other fields
+ * and methods.
+ * @param evaluateAllCode a flag that specifies whether all
+ * casts, branch targets, and exception
+ * handlers should be evaluated, even
+ * if they are unnecessary or
+ * unreachable.
+ * @param branchUnit the branch unit that will handle all
+ * branches.
+ * @param branchTargetFinder the utility class that will find all
+ * branches.
+ * @param callingInstructionBlockStack the stack of instruction blocks to
+ * be evaluated
*/
private PartialEvaluator(ValueFactory valueFactory,
InvocationUnit invocationUnit,
@@ -293,7 +299,7 @@ implements AttributeVisitor,
if (isTraced(offset))
{
int initializationOffset = branchTargetFinder.initializationOffset(offset);
- if (initializationOffset != NONE)
+ if (initializationOffset >= 0)
{
System.out.println(" is to be initialized at ["+initializationOffset+"]");
}
@@ -639,7 +645,8 @@ implements AttributeVisitor,
stack,
valueFactory,
branchUnit,
- invocationUnit);
+ invocationUnit,
+ evaluateAllCode);
int instructionOffset = startOffset;
@@ -1055,7 +1062,7 @@ implements AttributeVisitor,
//stack.push(valueFactory.createReference((ClassConstant)((ProgramClass)clazz).getConstant(exceptionInfo.u2catchType), false));
String catchClassName = catchType != 0 ?
clazz.getClassName(catchType) :
- ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE;
+ ClassConstants.NAME_JAVA_LANG_THROWABLE;
Clazz catchClass = catchType != 0 ?
((ClassConstant)((ProgramClass)clazz).getConstant(catchType)).referencedClass :
diff --git a/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java b/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
new file mode 100644
index 0000000..d6aaf7d
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
@@ -0,0 +1,94 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.*;
+
+/**
+ * This ClassVisitor propagates the value of the $VALUES field to the values()
+ * method in the simple enum classes that it visits.
+ *
+ * @see SimpleEnumMarker
+ * @author Eric Lafortune
+ */
+public class SimpleEnumArrayPropagator
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor
+{
+ private final ValueFactory valueFactory = new ParticularValueFactory();
+
+ private Value array;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Update the return value of the "int[] values()" method.
+ programClass.methodsAccept(new MemberDescriptorFilter("()[I", this));
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Find the array length of the "int[] $VALUES" field.
+ programClass.fieldsAccept(new MemberDescriptorFilter("[I", this));
+
+ if (array != null)
+ {
+ // Set the array value with the found array length. We can't use
+ // the original array, because its elements might get overwritten.
+ Value propagatedArray =
+ valueFactory.createArrayReferenceValue("I",
+ null,
+ array.referenceValue().arrayLength(
+ valueFactory));
+
+ setMethodReturnValue(programMethod, propagatedArray);
+
+ array = null;
+ }
+ }
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ array = StoringInvocationUnit.getFieldValue(programField);
+ }
+
+
+ // Small utility methods.
+
+ private static void setMethodReturnValue(Method method, Value value)
+ {
+ MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
+ if (info != null)
+ {
+ info.setReturnValue(value);
+ }
+ }
+}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java b/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
new file mode 100644
index 0000000..1bd5008
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
@@ -0,0 +1,74 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.info.SimpleEnumMarker;
+
+/**
+ * This ClassVisitor marks all program classes that it visits as simple enums,
+ * if their methods qualify.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleEnumClassChecker
+implements ClassVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+
+ private final SimpleEnumMarker simpleEnumMarker = new SimpleEnumMarker(true);
+ private final MemberVisitor virtualMethodChecker = new MemberAccessFilter(0,
+ ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC,
+ new MemberToClassVisitor(
+ new SimpleEnumMarker(false)));
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Does the class have the simple enum constructor?
+ if (programClass.findMethod(ClassConstants.METHOD_NAME_INIT,
+ ClassConstants.METHOD_TYPE_INIT_ENUM) != null)
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumClassChecker: ["+programClass.getName()+"] is a candidate simple enum, without extra fields");
+ }
+
+ // Mark it.
+ simpleEnumMarker.visitProgramClass(programClass);
+
+ // However, unmark it again if it has any non-private, non-static
+ // methods.
+ programClass.methodsAccept(virtualMethodChecker);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
new file mode 100644
index 0000000..33f775f
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
@@ -0,0 +1,164 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.optimize.info.SimpleEnumMarker;
+import proguard.optimize.peephole.*;
+
+/**
+ * This ClassVisitor simplifies the classes that it visits to simple enums.
+ *
+ * @see SimpleEnumMarker
+ * @see MemberReferenceFixer
+ * @author Eric Lafortune
+ */
+public class SimpleEnumClassSimplifier
+extends SimplifiedVisitor
+implements ClassVisitor,
+ AttributeVisitor,
+ InstructionVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+
+ private static final int ENUM_CLASS_NAME = InstructionSequenceReplacer.A;
+ private static final int ENUM_TYPE_NAME = InstructionSequenceReplacer.B;
+ private static final int ENUM_CONSTANT_NAME = InstructionSequenceReplacer.X;
+ private static final int ENUM_CONSTANT_ORDINAL = InstructionSequenceReplacer.Y;
+ private static final int ENUM_CONSTANT_FIELD_NAME = InstructionSequenceReplacer.Z;
+
+ private static final int STRING_ENUM_CONSTANT_NAME = 0;
+
+ private static final int METHOD_ENUM_INIT = 1;
+ private static final int FIELD_ENUM_CONSTANT = 2;
+
+ private static final int CLASS_ENUM = 3;
+
+ private static final int NAME_AND_TYPE_ENUM_INIT = 4;
+ private static final int NAME_AND_TYPE_ENUM_CONSTANT = 5;
+
+ private static final int UTF8_INIT = 6;
+ private static final int UTF8_STRING_I = 7;
+
+
+ private static final Constant[] CONSTANTS = new Constant[]
+ {
+ new StringConstant(ENUM_CONSTANT_NAME, null, null),
+
+ new MethodrefConstant(CLASS_ENUM, NAME_AND_TYPE_ENUM_INIT, null, null),
+ new FieldrefConstant( CLASS_ENUM, NAME_AND_TYPE_ENUM_CONSTANT, null, null),
+
+ new ClassConstant(ENUM_CLASS_NAME, null),
+
+ new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_I),
+ new NameAndTypeConstant(ENUM_CONSTANT_FIELD_NAME, ENUM_TYPE_NAME),
+
+ new Utf8Constant(ClassConstants.METHOD_NAME_INIT),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_INIT_ENUM),
+ };
+
+ private static final Instruction[] INSTRUCTIONS = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_ENUM),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_ENUM_CONSTANT_NAME),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, ENUM_CONSTANT_ORDINAL),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_ENUM_INIT),
+ };
+
+ private static final Instruction[] REPLACEMENT_INSTRUCTIONS = new Instruction[]
+ {
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, ENUM_CONSTANT_ORDINAL),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ new SimpleInstruction(InstructionConstants.OP_IADD),
+ };
+
+
+ private final CodeAttributeEditor codeAttributeEditor =
+ new CodeAttributeEditor(true, true);
+
+ private final InstructionSequenceReplacer instructionSequenceReplacer =
+ new InstructionSequenceReplacer(CONSTANTS,
+ INSTRUCTIONS,
+ REPLACEMENT_INSTRUCTIONS,
+ null,
+ codeAttributeEditor);
+
+ private final MemberVisitor initializerSimplifier = new AllAttributeVisitor(this);
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumClassSimplifier: ["+programClass.getName()+"]");
+ }
+
+ // Unmark the class as an enum.
+ programClass.u2accessFlags &= ~ClassConstants.ACC_ENUM;
+
+ // Remove the valueOf method, if present.
+ Method valueOfMethod =
+ programClass.findMethod(ClassConstants.METHOD_NAME_VALUEOF, null);
+ if (valueOfMethod != null)
+ {
+ new ClassEditor(programClass).removeMethod(valueOfMethod);
+ }
+
+ // Simplify the static initializer.
+ programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
+ ClassConstants.METHOD_TYPE_CLINIT,
+ initializerSimplifier);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Set up the code attribute editor.
+ codeAttributeEditor.reset(codeAttribute.u4codeLength);
+
+ // Find the peephole changes.
+ codeAttribute.instructionsAccept(clazz, method, instructionSequenceReplacer);
+
+ // Apply the peephole changes.
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
new file mode 100644
index 0000000..f1323ea
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
@@ -0,0 +1,583 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.info.*;
+
+/**
+ * This ClassVisitor simplifies the descriptors that contain simple enums in
+ * the program classes that it visits.
+ *
+ * @see SimpleEnumMarker
+ * @see MemberReferenceFixer
+ * @author Eric Lafortune
+ */
+public class SimpleEnumDescriptorSimplifier
+extends SimplifiedVisitor
+implements ClassVisitor,
+ ConstantVisitor,
+ MemberVisitor,
+ AttributeVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumDescriptorSimplifier: "+programClass.getName());
+ }
+
+ // Simplify the class members.
+ programClass.fieldsAccept(this);
+ programClass.methodsAccept(this);
+
+ // Simplify the attributes.
+ //programClass.attributesAccept(this);
+
+ // Simplify the simple enum array constants.
+ programClass.constantPoolEntriesAccept(this);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ // Does the constant refer to a simple enum type?
+ Clazz referencedClass = stringConstant.referencedClass;
+ if (isSimpleEnum(referencedClass))
+ {
+ // Is it an array type?
+ String name = stringConstant.getString(clazz);
+ if (ClassUtil.isInternalArrayType(name))
+ {
+ // Update the type.
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor((ProgramClass)clazz);
+
+ String newName = simplifyDescriptor(name, referencedClass);
+
+ stringConstant.u2stringIndex =
+ constantPoolEditor.addUtf8Constant(newName);
+
+ // Clear the referenced class.
+ stringConstant.referencedClass = null;
+ }
+ }
+ }
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // Update the descriptor if it has any simple enum classes.
+ String descriptor = invokeDynamicConstant.getType(clazz);
+ String newDescriptor = simplifyDescriptor(descriptor, invokeDynamicConstant.referencedClasses);
+
+ if (!descriptor.equals(newDescriptor))
+ {
+ // Update the descriptor.
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor((ProgramClass)clazz);
+
+ invokeDynamicConstant.u2nameAndTypeIndex =
+ constantPoolEditor.addNameAndTypeConstant(invokeDynamicConstant.getName(clazz),
+ newDescriptor);
+
+ // Update the referenced classes.
+ invokeDynamicConstant.referencedClasses =
+ simplifyReferencedClasses(descriptor, invokeDynamicConstant.referencedClasses);
+ }
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Does the constant refer to a simple enum type?
+ Clazz referencedClass = classConstant.referencedClass;
+ if (isSimpleEnum(referencedClass))
+ {
+ // Is it an array type?
+ String name = classConstant.getName(clazz);
+ if (ClassUtil.isInternalArrayType(name))
+ {
+ // Update the type.
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor((ProgramClass)clazz);
+
+ String newName = simplifyDescriptor(name, referencedClass);
+
+ classConstant.u2nameIndex =
+ constantPoolEditor.addUtf8Constant(newName);
+
+ // Clear the referenced class.
+ classConstant.referencedClass = null;
+ }
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ // Update the descriptor if it has a simple enum class.
+ String descriptor = programField.getDescriptor(programClass);
+ String newDescriptor = simplifyDescriptor(descriptor, programField.referencedClass);
+
+ if (!descriptor.equals(newDescriptor))
+ {
+ String name = programField.getName(programClass);
+ String newName = name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
+
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumDescriptorSimplifier: ["+programClass.getName()+"."+name+" "+descriptor + "] -> ["+newName+" "+newDescriptor+"]");
+ }
+
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor(programClass);
+
+ // Update the name.
+ programField.u2nameIndex =
+ constantPoolEditor.addUtf8Constant(newName);
+
+ // Update the descriptor itself.
+ programField.u2descriptorIndex =
+ constantPoolEditor.addUtf8Constant(newDescriptor);
+
+ // Clear the referenced class.
+ programField.referencedClass = null;
+
+ // Clear the field value.
+ FieldOptimizationInfo fieldOptimizationInfo =
+ FieldOptimizationInfo.getFieldOptimizationInfo(programField);
+ if (fieldOptimizationInfo != null)
+ {
+ fieldOptimizationInfo.resetValue(programClass, programField);
+ }
+
+ // Simplify the signature.
+ programField.attributesAccept(programClass, this);
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+// // Skip the valueOf method.
+// if (programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_VALUEOF))
+// {
+// return;
+// }
+
+ // Simplify the code, the signature, and the parameter annotations,
+ // before simplifying the descriptor.
+ programMethod.attributesAccept(programClass, this);
+
+ // Update the descriptor if it has any simple enum classes.
+ String descriptor = programMethod.getDescriptor(programClass);
+ String newDescriptor = simplifyDescriptor(descriptor, programMethod.referencedClasses);
+
+ if (!descriptor.equals(newDescriptor))
+ {
+ String name = programMethod.getName(programClass);
+ String newName = name;
+
+ // Append a code, if the method isn't a class instance initializer.
+ if (!name.equals(ClassConstants.METHOD_NAME_INIT))
+ {
+ newName += ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode()));
+ }
+
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumDescriptorSimplifier: ["+programClass.getName()+"."+name+descriptor+"] -> ["+newName+newDescriptor+"]");
+ }
+
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor(programClass);
+
+ // Update the name, if necessary.
+ if (!newName.equals(name))
+ {
+ programMethod.u2nameIndex =
+ constantPoolEditor.addUtf8Constant(newName);
+ }
+
+ // Update the descriptor itself.
+ programMethod.u2descriptorIndex =
+ constantPoolEditor.addUtf8Constant(newDescriptor);
+
+ // Update the referenced classes.
+ programMethod.referencedClasses =
+ simplifyReferencedClasses(descriptor, programMethod.referencedClasses);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Simplify the local variable descriptors.
+ codeAttribute.attributesAccept(clazz, method, this);
+ }
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ // Change the references of the local variables.
+ localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ // Change the references of the local variables.
+ localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute)
+ {
+ // We're only looking at the base type for now.
+ if (signatureAttribute.referencedClasses != null &&
+ signatureAttribute.referencedClasses.length > 0)
+ {
+ // Update the signature if it has any simple enum classes.
+ String signature = signatureAttribute.getSignature(clazz);
+ String newSignature = simplifyDescriptor(signature,
+ signatureAttribute.referencedClasses[0]);
+
+ if (!signature.equals(newSignature))
+ {
+ // Update the signature.
+ signatureAttribute.u2signatureIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
+
+ // Clear the referenced class.
+ signatureAttribute.referencedClasses[0] = null;
+ }
+ }
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
+ {
+ // Compute the new signature.
+ String signature = signatureAttribute.getSignature(clazz);
+ String newSignature = simplifyDescriptor(signature,
+ signatureAttribute.referencedClasses);
+
+ if (!signature.equals(newSignature))
+ {
+ // Update the signature.
+ signatureAttribute.u2signatureIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
+ {
+ // Update the descriptor if it has a simple enum class.
+ String descriptor = localVariableInfo.getDescriptor(clazz);
+ String newDescriptor = simplifyDescriptor(descriptor, localVariableInfo.referencedClass);
+
+ if (!descriptor.equals(newDescriptor))
+ {
+ // Update the descriptor.
+ localVariableInfo.u2descriptorIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newDescriptor);
+
+ // Clear the referenced class.
+ localVariableInfo.referencedClass = null;
+ }
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ // We're only looking at the base type for now.
+ if (localVariableTypeInfo.referencedClasses != null &&
+ localVariableTypeInfo.referencedClasses.length > 0)
+ {
+ // Update the signature if it has any simple enum classes.
+ String signature = localVariableTypeInfo.getSignature(clazz);
+ String newSignature = simplifyDescriptor(signature,
+ localVariableTypeInfo.referencedClasses[0]);
+
+ if (!signature.equals(newSignature))
+ {
+ // Update the signature.
+ localVariableTypeInfo.u2signatureIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
+
+ // Clear the referenced class.
+ localVariableTypeInfo.referencedClasses[0] = null;
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the descriptor with simplified enum type.
+ */
+ private String simplifyDescriptor(String descriptor,
+ Clazz referencedClass)
+ {
+ return isSimpleEnum(referencedClass) ?
+ descriptor.substring(0, ClassUtil.internalArrayTypeDimensionCount(descriptor)) + ClassConstants.TYPE_INT :
+ descriptor;
+ }
+
+
+ /**
+ * Returns the descriptor with simplified enum types.
+ */
+ private String simplifyDescriptor(String descriptor,
+ Clazz[] referencedClasses)
+ {
+ if (referencedClasses != null)
+ {
+ InternalTypeEnumeration internalTypeEnumeration =
+ new InternalTypeEnumeration(descriptor);
+
+ int referencedClassIndex = 0;
+
+ StringBuffer newDescriptorBuffer =
+ new StringBuffer(descriptor.length());
+
+ // Go over the formal type parameters.
+ {
+ // Consider the classes referenced by this formal type
+ // parameter.
+ String type = internalTypeEnumeration.formalTypeParameters();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Replace simple enum types.
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ if (isSimpleEnum(referencedClass))
+ {
+ // Let's replace the simple enum type by
+ // java.lang.Integer.
+ type =
+ type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
+ ClassConstants.NAME_JAVA_LANG_INTEGER;
+ }
+ }
+
+ newDescriptorBuffer.append(type);
+ }
+
+ newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_OPEN);
+
+ // Go over the parameters.
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ // Consider the classes referenced by this parameter type.
+ String type = internalTypeEnumeration.nextType();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Replace simple enum types.
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ if (isSimpleEnum(referencedClass))
+ {
+ type =
+ type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
+ ClassConstants.TYPE_INT;
+ }
+ }
+
+ newDescriptorBuffer.append(type);
+ }
+
+ newDescriptorBuffer.append(ClassConstants.METHOD_ARGUMENTS_CLOSE);
+
+ // Go over the return value.
+ {
+ String type = internalTypeEnumeration.returnType();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Replace simple enum types.
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ if (isSimpleEnum(referencedClass))
+ {
+ type =
+ type.substring(0, ClassUtil.internalArrayTypeDimensionCount(type)) +
+ ClassConstants.TYPE_INT;
+ }
+ }
+
+ newDescriptorBuffer.append(type);
+ }
+
+ descriptor = newDescriptorBuffer.toString();
+ }
+
+ return descriptor;
+ }
+
+
+ /**
+ * Returns the simplified and shrunk array of referenced classes for the
+ * given descriptor.
+ */
+ private Clazz[] simplifyReferencedClasses(String descriptor,
+ Clazz[] referencedClasses)
+ {
+ if (referencedClasses != null)
+ {
+ InternalTypeEnumeration internalTypeEnumeration =
+ new InternalTypeEnumeration(descriptor);
+
+ int referencedClassIndex = 0;
+ int newReferencedClassIndex = 0;
+
+ // Go over the formal type parameters.
+ {
+ String type = internalTypeEnumeration.formalTypeParameters();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Clear all non-simple enum classes
+ // (now java.lang.Integer).
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ referencedClasses[newReferencedClassIndex++] =
+ isSimpleEnum(referencedClass) ? null : referencedClass;
+ }
+ }
+
+ // Go over the parameters.
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ // Consider the classes referenced by this parameter type.
+ String type = internalTypeEnumeration.nextType();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Copy all non-simple enum classes.
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ if (!isSimpleEnum(referencedClass))
+ {
+ referencedClasses[newReferencedClassIndex++] =
+ referencedClass;
+ }
+ }
+ }
+
+ // Go over the return type.
+ {
+ String type = internalTypeEnumeration.returnType();
+ int count = new DescriptorClassEnumeration(type).classCount();
+
+ // Copy all non-simple enum classes.
+ for (int counter = 0; counter < count; counter++)
+ {
+ Clazz referencedClass =
+ referencedClasses[referencedClassIndex++];
+
+ if (!isSimpleEnum(referencedClass))
+ {
+ referencedClasses[newReferencedClassIndex++] =
+ referencedClass;
+ }
+ }
+ }
+
+ // Shrink the array to the proper size.
+ if (newReferencedClassIndex == 0)
+ {
+ referencedClasses = null;
+ }
+ else if (newReferencedClassIndex < referencedClassIndex)
+ {
+ Clazz[] newReferencedClasses = new Clazz[newReferencedClassIndex];
+ System.arraycopy(referencedClasses, 0,
+ newReferencedClasses, 0,
+ newReferencedClassIndex);
+
+ referencedClasses = newReferencedClasses;
+ }
+ }
+
+ return referencedClasses;
+ }
+
+
+ /**
+ * Returns whether the given class is not null and a simple enum class.
+ */
+ private boolean isSimpleEnum(Clazz clazz)
+ {
+ return clazz != null &&
+ SimpleEnumMarker.isSimpleEnum(clazz);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java b/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
new file mode 100644
index 0000000..b748c68
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
@@ -0,0 +1,760 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+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.*;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.SimpleEnumMarker;
+
+/**
+ * This ClassVisitor marks enums that can't be simplified due to the way they
+ * are used in the classes that it visits.
+ *
+ * @see SimpleEnumMarker
+ * @author Eric Lafortune
+ */
+public class SimpleEnumUseChecker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor,
+ ParameterVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+ private final PartialEvaluator partialEvaluator;
+ private final MemberVisitor methodCodeChecker = new AllAttributeVisitor(this);
+ private final ConstantVisitor invokedMethodChecker = new ReferencedMemberVisitor(this);
+ private final ConstantVisitor parameterChecker = new ReferencedMemberVisitor(new AllParameterVisitor(this));
+ private final ClassVisitor complexEnumMarker = new SimpleEnumMarker(false);
+ private final ReferencedClassVisitor referencedComplexEnumMarker = new ReferencedClassVisitor(complexEnumMarker);
+
+
+ // Fields acting as parameters and return values for the visitor methods.
+ private int invocationOffset;
+
+
+ /**
+ * Creates a new SimpleEnumUseSimplifier.
+ */
+ public SimpleEnumUseChecker()
+ {
+ this(new PartialEvaluator());
+ }
+
+
+ /**
+ * Creates a new SimpleEnumUseChecker.
+ * @param partialEvaluator the partial evaluator that will execute the code
+ * and provide information about the results.
+ */
+ public SimpleEnumUseChecker(PartialEvaluator partialEvaluator)
+ {
+ this.partialEvaluator = partialEvaluator;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if ((programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) != 0)
+ {
+ // Unmark the simple enum classes in annotations.
+ programClass.methodsAccept(referencedComplexEnumMarker);
+ }
+ else
+ {
+ // Unmark the simple enum classes that are used in a complex way.
+ programClass.methodsAccept(methodCodeChecker);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Evaluate the method.
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ // Check all traced instructions.
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (partialEvaluator.isTraced(offset))
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, this);
+
+ // Check generalized stacks and variables at branch targets.
+ if (partialEvaluator.isBranchOrExceptionTarget(offset))
+ {
+ checkMixedStackEntriesBefore(offset);
+
+ checkMixedVariablesBefore(offset);
+ }
+ }
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_AASTORE:
+ {
+ // Check if the instruction is storing a simple enum in a
+ // more general array.
+ if (!isPoppingSimpleEnumType(offset, 2))
+ {
+ if (DEBUG)
+ {
+ if (isPoppingSimpleEnumType(offset))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] stores enum ["+
+ partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] in more general array ["+
+ partialEvaluator.getStackBefore(offset).getTop(2).referenceValue().getType()+"]");
+ }
+ }
+
+ markPoppedComplexEnumType(offset);
+ }
+ break;
+ }
+ case InstructionConstants.OP_ARETURN:
+ {
+ // Check if the instruction is returning a simple enum as a
+ // more general type.
+ if (!isReturningSimpleEnumType(clazz, method))
+ {
+ if (DEBUG)
+ {
+ if (isPoppingSimpleEnumType(offset))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] returns enum [" +
+ partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as more general type");
+ }
+ }
+
+ markPoppedComplexEnumType(offset);
+ }
+ break;
+ }
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ {
+ // Make sure the popped type is not a simple enum type.
+ if (DEBUG)
+ {
+ if (isPoppingSimpleEnumType(offset))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] uses enum ["+
+ partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as monitor");
+ }
+ }
+
+ markPoppedComplexEnumType(offset);
+
+ break;
+ }
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_PUTFIELD:
+ {
+ // Check if the instruction is generalizing a simple enum to a
+ // different type.
+ invocationOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ parameterChecker);
+ break;
+ }
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ {
+ // Check if the instruction is calling a simple enum.
+ String invokedMethodName =
+ clazz.getRefName(constantInstruction.constantIndex);
+ String invokedMethodType =
+ clazz.getRefType(constantInstruction.constantIndex);
+ int stackEntryIndex =
+ ClassUtil.internalMethodParameterSize(invokedMethodType);
+ if (isPoppingSimpleEnumType(offset, stackEntryIndex) &&
+ !isSupportedMethod(invokedMethodName,
+ invokedMethodType))
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] calls ["+partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue().getType()+"."+invokedMethodName+"]");
+ }
+
+ markPoppedComplexEnumType(offset, stackEntryIndex);
+ }
+
+ // Check if any of the parameters is generalizing a simple
+ // enum to a different type.
+ invocationOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ parameterChecker);
+ break;
+ }
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ {
+ // Check if it is calling a method that we can't simplify.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ invokedMethodChecker);
+
+ // Check if any of the parameters is generalizing a simple
+ // enum to a different type.
+ invocationOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ parameterChecker);
+ break;
+ }
+ case InstructionConstants.OP_CHECKCAST:
+ case InstructionConstants.OP_INSTANCEOF:
+ {
+ // Check if the instruction is popping a different type.
+ if (!isPoppingExpectedType(offset,
+ clazz,
+ constantInstruction.constantIndex))
+ {
+ if (DEBUG)
+ {
+ if (isPoppingSimpleEnumType(offset))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] is casting or checking ["+
+ partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as ["+
+ clazz.getClassName(constantInstruction.constantIndex)+"]");
+ }
+ }
+
+ // Make sure the popped type is not a simple enum type.
+ markPoppedComplexEnumType(offset);
+
+ // Make sure the checked type is not a simple enum type.
+ // We're somewhat arbitrarily skipping casts in static
+ // methods of simple enum classes, because they do occur
+ // in values() and valueOf(String), without obstructing
+ // simplification.
+ if (!isSimpleEnum(clazz) ||
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 ||
+ constantInstruction.opcode != InstructionConstants.OP_CHECKCAST)
+ {
+ if (DEBUG)
+ {
+ if (isSimpleEnum(((ClassConstant)((ProgramClass)clazz).getConstant(constantInstruction.constantIndex)).referencedClass))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] is casting or checking ["+
+ partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] as ["+
+ clazz.getClassName(constantInstruction.constantIndex)+"]");
+ }
+ }
+
+ markConstantComplexEnumType(clazz, constantInstruction.constantIndex);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ switch (branchInstruction.opcode)
+ {
+ case InstructionConstants.OP_IFACMPEQ:
+ case InstructionConstants.OP_IFACMPNE:
+ {
+ // Check if the instruction is comparing different types.
+ if (!isPoppingIdenticalTypes(offset, 0, 1))
+ {
+ if (DEBUG)
+ {
+ if (isPoppingSimpleEnumType(offset, 0))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] compares ["+partialEvaluator.getStackBefore(offset).getTop(0).referenceValue().getType()+"] to plain type");
+ }
+
+ if (isPoppingSimpleEnumType(offset, 1))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] compares ["+partialEvaluator.getStackBefore(offset).getTop(1).referenceValue().getType()+"] to plain type");
+ }
+ }
+
+ // Make sure the first popped type is not a simple enum type.
+ markPoppedComplexEnumType(offset, 0);
+
+ // Make sure the second popped type is not a simple enum type.
+ markPoppedComplexEnumType(offset, 1);
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
+ {
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (isSimpleEnum(programClass) &&
+ isUnsupportedMethod(programMethod.getName(programClass),
+ programMethod.getDescriptor(programClass)))
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumUseChecker: invocation of ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]");
+ }
+
+ complexEnumMarker.visitProgramClass(programClass);
+ }
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ // Check if the parameter is passing a simple enum as a more general
+ // type.
+ int stackEntryIndex = parameterSize - parameterOffset - 1;
+ if (ClassUtil.isInternalClassType(parameterType) &&
+ !isPoppingExpectedType(invocationOffset, stackEntryIndex,
+ ClassUtil.isInternalArrayType(parameterType) ?
+ parameterType :
+ ClassUtil.internalClassNameFromClassType(parameterType)))
+ {
+ if (DEBUG)
+ {
+ ReferenceValue poppedValue =
+ partialEvaluator.getStackBefore(invocationOffset).getTop(stackEntryIndex).referenceValue();
+ if (isSimpleEnumType(poppedValue))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+poppedValue.getType()+"] "+
+ (member instanceof Field ?
+ ("is stored as more general type ["+parameterType+"] in field ["+clazz.getName()+"."+member.getName(clazz)+"]") :
+ ("is passed as more general argument #"+parameterIndex+" ["+parameterType+"] to ["+clazz.getName()+"."+member.getName(clazz)+"]")));
+ }
+ }
+
+ // Make sure the popped type is not a simple enum type.
+ markPoppedComplexEnumType(invocationOffset, stackEntryIndex);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the specified enum method is supported for simple enums.
+ */
+ private boolean isSupportedMethod(String name, String type)
+ {
+ return
+ name.equals(ClassConstants.METHOD_NAME_ORDINAL) &&
+ type.equals(ClassConstants.METHOD_TYPE_ORDINAL) ||
+
+ name.equals(ClassConstants.METHOD_NAME_CLONE) &&
+ type.equals(ClassConstants.METHOD_TYPE_CLONE);
+ }
+
+
+ /**
+ * Returns whether the specified enum method is unsupported for simple enums.
+ */
+ private boolean isUnsupportedMethod(String name, String type)
+ {
+ return
+ name.equals(ClassConstants.METHOD_NAME_VALUEOF);
+ }
+
+
+ /**
+ * Unmarks simple enum classes that are mixed with incompatible reference
+ * types in the stack before the given instruction offset.
+ */
+ private void checkMixedStackEntriesBefore(int offset)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
+
+ // Check all stack entries.
+ int stackSize = stackBefore.size();
+
+ for (int stackEntryIndex = 0; stackEntryIndex < stackSize; stackEntryIndex++)
+ {
+ // Check reference entries.
+ Value stackEntry = stackBefore.getBottom(stackEntryIndex);
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ // Check reference entries with multiple producers.
+ InstructionOffsetValue producerOffsets =
+ stackBefore.getBottomActualProducerValue(stackEntryIndex).instructionOffsetValue();
+
+ int producerCount = producerOffsets.instructionOffsetCount();
+ if (producerCount > 1)
+ {
+ // Is the consumed stack entry not a simple enum?
+ ReferenceValue consumedStackEntry =
+ stackEntry.referenceValue();
+
+ if (!isSimpleEnumType(consumedStackEntry))
+ {
+ // Check all producers.
+ for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
+ {
+ int producerOffset =
+ producerOffsets.instructionOffset(producerIndex);
+
+ if (producerOffset >= 0)
+ {
+ if (DEBUG)
+ {
+ ReferenceValue producedValue =
+ partialEvaluator.getStackAfter(producerOffset).getTop(0).referenceValue();
+ if (isSimpleEnumType(producedValue))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+producedValue.getType()+"] mixed with general type on stack");
+ }
+ }
+
+ // Make sure the produced stack entry isn't a
+ // simple enum either.
+ markPushedComplexEnumType(producerOffset);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Unmarks simple enum classes that are mixed with incompatible reference
+ * types in the variables before the given instruction offset.
+ */
+ private void checkMixedVariablesBefore(int offset)
+ {
+ TracedVariables variablesBefore =
+ partialEvaluator.getVariablesBefore(offset);
+
+ // Check all variables.
+ int variablesSize = variablesBefore.size();
+
+ for (int variableIndex = 0; variableIndex < variablesSize; variableIndex++)
+ {
+ // Check reference variables.
+ Value variable = variablesBefore.getValue(variableIndex);
+ if (variable != null &&
+ variable.computationalType() == Value.TYPE_REFERENCE)
+ {
+ // Check reference variables with multiple producers.
+ InstructionOffsetValue producerOffsets =
+ variablesBefore.getProducerValue(variableIndex).instructionOffsetValue();
+
+ int producerCount = producerOffsets.instructionOffsetCount();
+ if (producerCount > 1)
+ {
+ // Is the consumed variable not a simple enum?
+ ReferenceValue consumedVariable =
+ variable.referenceValue();
+
+ if (!isSimpleEnumType(consumedVariable))
+ {
+ // Check all producers.
+ for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
+ {
+ int producerOffset =
+ producerOffsets.instructionOffset(producerIndex);
+
+ if (producerOffset >= 0)
+ {
+ if (DEBUG)
+ {
+ ReferenceValue producedValue =
+ partialEvaluator.getVariablesAfter(producerOffset).getValue(variableIndex).referenceValue();
+ if (isSimpleEnumType(producedValue))
+ {
+ System.out.println("SimpleEnumUseChecker: ["+producedValue.getType()+"] mixed with general type in variables");
+ }
+ }
+
+ // Make sure the stored variable entry isn't a
+ // simple enum either.
+ markStoredComplexEnumType(producerOffset, variableIndex);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping two
+ * identical reference types.
+ */
+ private boolean isPoppingIdenticalTypes(int offset,
+ int stackEntryIndex1,
+ int stackEntryIndex2)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
+
+ String type1 =
+ stackBefore.getTop(stackEntryIndex1).referenceValue().getType();
+ String type2 =
+ stackBefore.getTop(stackEntryIndex2).referenceValue().getType();
+
+ return type1 == null ? type2 == null : type1.equals(type2);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping exactly
+ * the reference type of the specified class constant.
+ */
+ private boolean isPoppingExpectedType(int offset,
+ Clazz clazz,
+ int constantIndex)
+ {
+ return isPoppingExpectedType(offset, 0, clazz, constantIndex);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping exactly
+ * the reference type of the specified class constant.
+ */
+ private boolean isPoppingExpectedType(int offset,
+ int stackEntryIndex,
+ Clazz clazz,
+ int constantIndex)
+ {
+ return isPoppingExpectedType(offset,
+ stackEntryIndex,
+ clazz.getClassName(constantIndex));
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping exactly
+ * the given reference type.
+ */
+ private boolean isPoppingExpectedType(int offset,
+ int stackEntryIndex,
+ String expectedType)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
+
+ String poppedType =
+ stackBefore.getTop(stackEntryIndex).referenceValue().getType();
+
+ return expectedType.equals(poppedType);
+ }
+
+
+ /**
+ * Returns whether the given method is returning a simple enum type.
+ * This includes simple enum arrays.
+ */
+ private boolean isReturningSimpleEnumType(Clazz clazz, Method method)
+ {
+ String descriptor = method.getDescriptor(clazz);
+ String returnType = ClassUtil.internalMethodReturnType(descriptor);
+
+ if (ClassUtil.isInternalClassType(returnType))
+ {
+ Clazz[] referencedClasses =
+ ((ProgramMethod)method).referencedClasses;
+
+ if (referencedClasses != null)
+ {
+ int returnedClassIndex =
+ new DescriptorClassEnumeration(descriptor).classCount() - 1;
+
+ Clazz returnedClass = referencedClasses[returnedClassIndex];
+
+ return isSimpleEnum(returnedClass);
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a type
+ * with a simple enum class. This includes simple enum arrays.
+ */
+ private boolean isPoppingSimpleEnumType(int offset)
+ {
+ return isPoppingSimpleEnumType(offset, 0);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a type
+ * with a simple enum class. This includes simple enum arrays.
+ */
+ private boolean isPoppingSimpleEnumType(int offset, int stackEntryIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
+
+ return isSimpleEnumType(referenceValue);
+ }
+
+
+ /**
+ * Returns whether the given value is a simple enum type. This includes
+ * simple enum arrays.
+ */
+ private boolean isSimpleEnumType(ReferenceValue referenceValue)
+ {
+ return isSimpleEnum(referenceValue.getReferencedClass());
+ }
+
+
+ /**
+ * Returns whether the given class is not null and a simple enum class.
+ */
+ private boolean isSimpleEnum(Clazz clazz)
+ {
+ return clazz != null &&
+ SimpleEnumMarker.isSimpleEnum(clazz);
+ }
+
+
+ /**
+ * Marks the enum class of the popped type as complex.
+ */
+ private void markConstantComplexEnumType(Clazz clazz, int constantIndex)
+ {
+ clazz.constantPoolEntryAccept(constantIndex,
+ referencedComplexEnumMarker);
+ }
+
+
+ /**
+ * Marks the enum class of the popped type as complex.
+ */
+ private void markPoppedComplexEnumType(int offset)
+ {
+ markPoppedComplexEnumType(offset, 0);
+ }
+
+
+ /**
+ * Marks the enum class of the specified popped type as complex.
+ */
+ private void markPoppedComplexEnumType(int offset, int stackEntryIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
+
+ markComplexEnumType(referenceValue);
+ }
+
+
+ /**
+ * Marks the enum class of the specified pushed type as complex.
+ */
+ private void markPushedComplexEnumType(int offset)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackAfter(offset).getTop(0).referenceValue();
+
+ markComplexEnumType(referenceValue);
+ }
+
+
+ /**
+ * Marks the enum class of the specified stored type as complex.
+ */
+ private void markStoredComplexEnumType(int offset, int variableIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getVariablesAfter(offset).getValue(variableIndex).referenceValue();
+
+ markComplexEnumType(referenceValue);
+ }
+
+
+ /**
+ * Marks the enum class of the specified value as complex.
+ */
+ private void markComplexEnumType(ReferenceValue referenceValue)
+ {
+ Clazz clazz = referenceValue.getReferencedClass();
+ if (clazz != null)
+ {
+ clazz.accept(complexEnumMarker);
+ }
+ }
+}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java b/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
new file mode 100644
index 0000000..b5a2396
--- /dev/null
+++ b/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
@@ -0,0 +1,820 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.SimpleEnumMarker;
+
+/**
+ * This AttributeVisitor simplifies the use of enums in the code attributes that
+ * it visits.
+ *
+ * @see SimpleEnumMarker
+ * @see MemberReferenceFixer
+ * @author Eric Lafortune
+ */
+public class SimpleEnumUseSimplifier
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor,
+ ParameterVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+ private final InstructionVisitor extraInstructionVisitor;
+
+ private final PartialEvaluator partialEvaluator;
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, true);
+ private final ConstantVisitor nullParameterFixer = new ReferencedMemberVisitor(new AllParameterVisitor(this));
+
+ // Fields acting as parameters and return values for the visitor methods.
+ private Clazz invocationClazz;
+ private Method invocationMethod;
+ private CodeAttribute invocationCodeAttribute;
+ private int invocationOffset;
+ private boolean isSimpleEnum;
+
+
+ /**
+ * Creates a new SimpleEnumUseSimplifier.
+ */
+ public SimpleEnumUseSimplifier()
+ {
+ this(new PartialEvaluator(), null);
+ }
+
+
+ /**
+ * Creates a new SimpleEnumDescriptorSimplifier.
+ * @param partialEvaluator the partial evaluator that will
+ * execute the code and provide
+ * information about the results.
+ * @param extraInstructionVisitor an optional extra visitor for all
+ * simplified instructions.
+ */
+ public SimpleEnumUseSimplifier(PartialEvaluator partialEvaluator,
+ InstructionVisitor extraInstructionVisitor)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.extraInstructionVisitor = extraInstructionVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumUseSimplifier: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ }
+
+ // Skip the non-static methods of simple enum classes.
+ if (SimpleEnumMarker.isSimpleEnum(clazz) &&
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0)
+ {
+ return;
+ }
+
+ // Evaluate the method.
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ // Reset the code changes.
+ codeAttributeEditor.reset(codeLength);
+
+ // Replace any instructions that can be simplified.
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (partialEvaluator.isTraced(offset))
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, this);
+ }
+ }
+
+ // Apply all accumulated changes to the code.
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_AALOAD:
+ {
+ if (isPushingSimpleEnum(offset))
+ {
+ // Load a simple enum integer from an integer array.
+ replaceInstruction(clazz,
+ offset,
+ simpleInstruction,
+ new SimpleInstruction(
+ InstructionConstants.OP_IALOAD));
+ }
+ break;
+ }
+ case InstructionConstants.OP_AASTORE:
+ {
+ if (isPoppingSimpleEnumArray(offset, 2))
+ {
+ // Store a simple enum integer in an integer array.
+ replaceInstruction(clazz,
+ offset,
+ simpleInstruction,
+ new SimpleInstruction(InstructionConstants.OP_IASTORE));
+
+ // Replace any producers of null constants.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
+ }
+ break;
+ }
+ case InstructionConstants.OP_ARETURN:
+ {
+ if (isReturningSimpleEnum(clazz, method))
+ {
+ // Return a simple enum integer instead of an enum.
+ replaceInstruction(clazz,
+ offset,
+ simpleInstruction,
+ new SimpleInstruction(InstructionConstants.OP_IRETURN));
+
+ // Replace any producers of null constants.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ int variableIndex = variableInstruction.variableIndex;
+
+ switch (variableInstruction.opcode)
+ {
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+ {
+ if (isPushingSimpleEnum(offset))
+ {
+ // Load a simple enum integer instead of an enum.
+ replaceInstruction(clazz,
+ offset,
+ variableInstruction,
+ new VariableInstruction(InstructionConstants.OP_ILOAD,
+ variableIndex));
+
+ // Replace any producers of null constants.
+ replaceNullVariableProducers(clazz,
+ method,
+ codeAttribute,
+ offset,
+ variableIndex);
+ }
+ break;
+ }
+ case InstructionConstants.OP_ASTORE:
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3:
+ {
+ if (!partialEvaluator.isSubroutineStart(offset) &&
+ isPoppingSimpleEnum(offset))
+ {
+ // Store a simple enum integer instead of an enum.
+ replaceInstruction(clazz,
+ offset,
+ variableInstruction,
+ new VariableInstruction(InstructionConstants.OP_ISTORE,
+ variableIndex));
+
+ // Replace any producers of null constants.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_PUTFIELD:
+ {
+ // Replace any producers of null constants.
+ invocationClazz = clazz;
+ invocationMethod = method;
+ invocationCodeAttribute = codeAttribute;
+ invocationOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ nullParameterFixer);
+ break;
+ }
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ {
+ // Check if the instruction is calling a simple enum.
+ String invokedMethodName =
+ clazz.getRefName(constantInstruction.constantIndex);
+ String invokedMethodType =
+ clazz.getRefType(constantInstruction.constantIndex);
+ int stackEntryIndex =
+ ClassUtil.internalMethodParameterSize(invokedMethodType);
+ if (isPoppingSimpleEnum(offset, stackEntryIndex))
+ {
+ replaceSupportedMethod(clazz,
+ offset,
+ constantInstruction,
+ invokedMethodName,
+ invokedMethodType);
+ }
+
+ // Fall through to check the parameters.
+ }
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ {
+ // Replace any producers of null constants.
+ invocationClazz = clazz;
+ invocationMethod = method;
+ invocationCodeAttribute = codeAttribute;
+ invocationOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ nullParameterFixer);
+ break;
+ }
+ case InstructionConstants.OP_ANEWARRAY:
+ {
+ int constantIndex = constantInstruction.constantIndex;
+
+ if (isReferencingSimpleEnum(clazz, constantIndex) &&
+ !ClassUtil.isInternalArrayType(clazz.getClassName(constantIndex)))
+ {
+ // Create an integer array instead of an enum array.
+ replaceInstruction(clazz,
+ offset,
+ constantInstruction,
+ new SimpleInstruction(InstructionConstants.OP_NEWARRAY,
+ InstructionConstants.ARRAY_T_INT));
+ }
+ break;
+ }
+ case InstructionConstants.OP_CHECKCAST:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Enum classes can only be simple if the checkcast
+ // succeeds, so we can delete it.
+ deleteInstruction(clazz,
+ offset,
+ constantInstruction);
+
+ // Replace any producers of null constants.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
+ }
+ break;
+ }
+ case InstructionConstants.OP_INSTANCEOF:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Enum classes can only be simple if the instanceof
+ // succeeds, so we can push a constant result.
+ replaceInstruction(clazz,
+ offset,
+ constantInstruction,
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1));
+
+ // Replace any producers of null constants.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, offset);
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ switch (branchInstruction.opcode)
+ {
+ case InstructionConstants.OP_IFACMPEQ:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Compare simple enum integers instead of enums.
+ replaceInstruction(clazz,
+ offset,
+ branchInstruction,
+ new BranchInstruction(InstructionConstants.OP_IFICMPEQ,
+ branchInstruction.branchOffset));
+ }
+ break;
+ }
+ case InstructionConstants.OP_IFACMPNE:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Compare simple enum integers instead of enums.
+ replaceInstruction(clazz,
+ offset,
+ branchInstruction,
+ new BranchInstruction(InstructionConstants.OP_IFICMPNE,
+ branchInstruction.branchOffset));
+ }
+ break;
+ }
+ case InstructionConstants.OP_IFNULL:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Compare with 0 instead of null.
+ replaceInstruction(clazz,
+ offset,
+ branchInstruction,
+ new BranchInstruction(
+ InstructionConstants.OP_IFEQ,
+ branchInstruction.branchOffset));
+ }
+ break;
+ }
+ case InstructionConstants.OP_IFNONNULL:
+ {
+ if (isPoppingSimpleEnum(offset))
+ {
+ // Compare with 0 instead of null.
+ replaceInstruction(clazz,
+ offset,
+ branchInstruction,
+ new BranchInstruction(InstructionConstants.OP_IFNE,
+ branchInstruction.branchOffset));
+ }
+ break;
+ }
+ }
+ }
+
+
+ public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
+ {
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ // Does the constant refer to a simple enum type?
+ isSimpleEnum = isSimpleEnum(stringConstant.referencedClass);
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Does the constant refer to a simple enum type?
+ isSimpleEnum = isSimpleEnum(classConstant.referencedClass);
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ // Check if the parameter is passing a simple enum as a more general
+ // type.
+ if (!ClassUtil.isInternalPrimitiveType(parameterType.charAt(0)) &&
+ isSimpleEnum(referencedClass))
+ {
+ // Replace any producers of null constants for this parameter.
+ int stackEntryIndex = parameterSize - parameterOffset - 1;
+
+ replaceNullStackEntryProducers(invocationClazz,
+ invocationMethod,
+ invocationCodeAttribute,
+ invocationOffset,
+ stackEntryIndex);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the constant at the given offset is referencing a
+ * simple enum class.
+ */
+ private boolean isReferencingSimpleEnum(Clazz clazz, int constantIndex)
+ {
+ isSimpleEnum = false;
+
+ clazz.constantPoolEntryAccept(constantIndex, this);
+
+ return isSimpleEnum;
+ }
+
+
+ /**
+ * Returns whether the given method is returning a simple enum class.
+ */
+ private boolean isReturningSimpleEnum(Clazz clazz, Method method)
+ {
+ String descriptor = method.getDescriptor(clazz);
+ String returnType = ClassUtil.internalMethodReturnType(descriptor);
+
+ if (ClassUtil.isInternalClassType(returnType) &&
+ !ClassUtil.isInternalArrayType(returnType))
+ {
+ Clazz[] referencedClasses =
+ ((ProgramMethod)method).referencedClasses;
+
+ if (referencedClasses != null)
+ {
+ int returnedClassIndex =
+ new DescriptorClassEnumeration(descriptor).classCount() - 1;
+
+ Clazz returnedClass = referencedClasses[returnedClassIndex];
+
+ return isSimpleEnum(returnedClass);
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is pushing a simple
+ * enum class.
+ */
+ private boolean isPushingSimpleEnum(int offset)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackAfter(offset).getTop(0).referenceValue();
+
+ Clazz referencedClass = referenceValue.getReferencedClass();
+
+ return isSimpleEnum(referencedClass) &&
+ !ClassUtil.isInternalArrayType(referenceValue.getType());
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a simple
+ * enum class.
+ */
+ private boolean isPoppingSimpleEnum(int offset)
+ {
+ return isPoppingSimpleEnum(offset, 0);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a simple
+ * enum class.
+ */
+ private boolean isPoppingSimpleEnum(int offset, int stackEntryIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
+
+ return isSimpleEnum(referenceValue.getReferencedClass()) &&
+ !ClassUtil.isInternalArrayType(referenceValue.getType());
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a simple
+ * enum type. This includes simple enum arrays.
+ */
+ private boolean isPoppingSimpleEnumType(int offset, int stackEntryIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
+
+ return isSimpleEnum(referenceValue.getReferencedClass());
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is popping a
+ * one-dimensional simple enum array.
+ */
+ private boolean isPoppingSimpleEnumArray(int offset, int stackEntryIndex)
+ {
+ ReferenceValue referenceValue =
+ partialEvaluator.getStackBefore(offset).getTop(stackEntryIndex).referenceValue();
+
+ return isSimpleEnum(referenceValue.getReferencedClass()) &&
+ ClassUtil.internalArrayTypeDimensionCount(referenceValue.getType()) == 1;
+ }
+
+
+ /**
+ * Returns whether the given class is not null and a simple enum class.
+ */
+ private boolean isSimpleEnum(Clazz clazz)
+ {
+ return clazz != null &&
+ SimpleEnumMarker.isSimpleEnum(clazz);
+ }
+
+
+ /**
+ * Returns whether the specified enum method is supported for simple enums.
+ */
+ private void replaceSupportedMethod(Clazz clazz,
+ int offset,
+ Instruction instruction,
+ String name,
+ String type)
+ {
+ if (name.equals(ClassConstants.METHOD_NAME_ORDINAL) &&
+ type.equals(ClassConstants.METHOD_TYPE_ORDINAL))
+ {
+ Instruction[] replacementInstructions = new Instruction[]
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ new SimpleInstruction(InstructionConstants.OP_ISUB),
+ };
+
+ replaceInstructions(clazz,
+ offset,
+ instruction,
+ replacementInstructions);
+ }
+ }
+
+
+ /**
+ * Replaces the instruction at the given offset by the given instructions.
+ */
+ private void replaceInstructions(Clazz clazz,
+ int offset,
+ Instruction instruction,
+ Instruction[] replacementInstructions)
+ {
+ if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstructions.length+" instructions");
+
+ codeAttributeEditor.replaceInstruction(offset, replacementInstructions);
+
+ // Visit the instruction, if required.
+ if (extraInstructionVisitor != null)
+ {
+ // Note: we're not passing the right arguments for now, knowing that
+ // they aren't used anyway.
+ instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
+ }
+ }
+
+
+ /**
+ * Replaces the instruction at the given offset by the given instruction,
+ * popping any now unused stack entries.
+ */
+ private void replaceInstruction(Clazz clazz,
+ int offset,
+ Instruction instruction,
+ Instruction replacementInstruction)
+ {
+ // Pop unneeded stack entries if necessary.
+ int popCount =
+ instruction.stackPopCount(clazz) -
+ replacementInstruction.stackPopCount(clazz);
+
+ insertPopInstructions(offset, popCount);
+
+ if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(offset)+" -> "+replacementInstruction.toString()+(popCount == 0 ? "" : " ("+popCount+" pops)"));
+
+ codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
+
+ // Visit the instruction, if required.
+ if (extraInstructionVisitor != null)
+ {
+ // Note: we're not passing the right arguments for now, knowing that
+ // they aren't used anyway.
+ instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
+ }
+ }
+
+
+ /**
+ * Deletes the instruction at the given offset, popping any now unused
+ * stack entries.
+ */
+ private void deleteInstruction(Clazz clazz,
+ int offset,
+ Instruction instruction)
+ {
+ // Pop unneeded stack entries if necessary.
+ //int popCount = instruction.stackPopCount(clazz);
+ //
+ //insertPopInstructions(offset, popCount);
+ //
+ //if (DEBUG) System.out.println(" Deleting instruction "+instruction.toString(offset)+(popCount == 0 ? "" : " ("+popCount+" pops)"));
+
+ if (DEBUG) System.out.println(" Deleting instruction "+instruction.toString(offset));
+
+ codeAttributeEditor.deleteInstruction(offset);
+
+ // Visit the instruction, if required.
+ if (extraInstructionVisitor != null)
+ {
+ // Note: we're not passing the right arguments for now, knowing that
+ // they aren't used anyway.
+ instruction.accept(clazz, null, null, offset, extraInstructionVisitor);
+ }
+ }
+
+
+ /**
+ * Pops the given number of stack entries before the instruction at the
+ * given offset.
+ */
+ private void insertPopInstructions(int offset, int popCount)
+ {
+ switch (popCount)
+ {
+ case 0:
+ {
+ break;
+ }
+ case 1:
+ {
+ // Insert a single pop instruction.
+ Instruction popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP);
+
+ codeAttributeEditor.insertBeforeInstruction(offset,
+ popInstruction);
+ break;
+ }
+ case 2:
+ {
+ // Insert a single pop2 instruction.
+ Instruction popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP2);
+
+ codeAttributeEditor.insertBeforeInstruction(offset,
+ popInstruction);
+ break;
+ }
+ default:
+ {
+ // Insert the specified number of pop instructions.
+ Instruction[] popInstructions =
+ new Instruction[popCount / 2 + popCount % 2];
+
+ Instruction popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP2);
+
+ for (int index = 0; index < popCount / 2; index++)
+ {
+ popInstructions[index] = popInstruction;
+ }
+
+ if (popCount % 2 == 1)
+ {
+ popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP);
+
+ popInstructions[popCount / 2] = popInstruction;
+ }
+
+ codeAttributeEditor.insertBeforeInstruction(offset,
+ popInstructions);
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Replaces aconst_null producers of the consumer of the top stack entry
+ * at the given offset by iconst_0.
+ */
+ private void replaceNullStackEntryProducers(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int consumerOffset)
+ {
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, consumerOffset, 0);
+ }
+
+
+ /**
+ * Replaces aconst_null producers of the specified stack entry by
+ * iconst_0.
+ */
+ private void replaceNullStackEntryProducers(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int consumerOffset,
+ int stackEntryIndex)
+ {
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getStackBefore(consumerOffset).getTopActualProducerValue(stackEntryIndex).instructionOffsetValue();
+
+ for (int index = 0; index < producerOffsets.instructionOffsetCount(); index++)
+ {
+ int producerOffset = producerOffsets.instructionOffset(index);
+
+ // TODO: A method might be pushing the null constant.
+ if (producerOffset >= 0 &&
+ codeAttribute.code[producerOffset] == InstructionConstants.OP_ACONST_NULL)
+ {
+ // Replace pushing null by pushing 0.
+ replaceInstruction(clazz,
+ producerOffset,
+ new SimpleInstruction(InstructionConstants.OP_ACONST_NULL),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0));
+ }
+ }
+ }
+
+
+ /**
+ * Replaces aconst_null/astore producers of the specified reference variable by
+ * iconst_0/istore.
+ */
+ private void replaceNullVariableProducers(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int consumerOffset,
+ int variableIndex)
+ {
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
+
+ for (int index = 0; index < producerOffsets.instructionOffsetCount(); index++)
+ {
+ int producerOffset = producerOffsets.instructionOffset(index);
+
+ if (producerOffset >= 0 &&
+ partialEvaluator.getVariablesAfter(producerOffset).getValue(variableIndex).referenceValue().isNull() == Value.ALWAYS)
+ {
+ // Replace loading null by loading 0.
+ replaceInstruction(clazz,
+ producerOffset,
+ new VariableInstruction(InstructionConstants.OP_ASTORE, variableIndex),
+ new VariableInstruction(InstructionConstants.OP_ISTORE, variableIndex));
+
+ // Replace pushing null by pushing 0.
+ replaceNullStackEntryProducers(clazz, method, codeAttribute, producerOffset);
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/evaluation/StoringInvocationUnit.java b/src/proguard/optimize/evaluation/StoringInvocationUnit.java
index 846f685..271b654 100644
--- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java
+++ b/src/proguard/optimize/evaluation/StoringInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,7 +27,7 @@ import proguard.evaluation.value.*;
import proguard.optimize.info.*;
/**
- * This InvocationUbit stores parameter values and return values with the
+ * This InvocationUnit stores parameter values and return values with the
* methods that are invoked.
*
* @see LoadingInvocationUnit
@@ -126,7 +126,7 @@ extends BasicInvocationUnit
generalizeMethodReturnValue(method, value);
}
}
-
+
// Small utility methods.
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java
index e6acf6f..9e55275 100644
--- a/src/proguard/optimize/evaluation/TracedBranchUnit.java
+++ b/src/proguard/optimize/evaluation/TracedBranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java
index 73efddc..bef1445 100644
--- a/src/proguard/optimize/evaluation/VariableOptimizer.java
+++ b/src/proguard/optimize/evaluation/VariableOptimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,11 +21,11 @@
package proguard.optimize.evaluation;
import proguard.classfile.*;
+import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.editor.*;
-import proguard.classfile.visitor.MemberVisitor;
-import proguard.classfile.attribute.*;
import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberVisitor;
/**
* This AttributeVisitor optimizes variable allocation based on their the liveness,
@@ -110,7 +110,7 @@ implements AttributeVisitor,
codeAttribute.attributesAccept(clazz, method, this);
int startIndex =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ||
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ||
reuseThis ? 0 : 1;
int parameterSize =
diff --git a/src/proguard/optimize/info/AccessMethodMarker.java b/src/proguard/optimize/info/AccessMethodMarker.java
index e4c8d7c..4c3c17b 100644
--- a/src/proguard/optimize/info/AccessMethodMarker.java
+++ b/src/proguard/optimize/info/AccessMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,8 +21,7 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.attribute.CodeAttribute;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
@@ -110,7 +109,7 @@ implements InstructionVisitor,
{
int accessFlags = clazz.getAccessFlags();
- if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
+ if ((accessFlags & ClassConstants.ACC_PUBLIC) == 0)
{
setAccessesPackageCode(invokingMethod);
}
@@ -123,15 +122,15 @@ implements InstructionVisitor,
{
int accessFlags = member.getAccessFlags();
- if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0)
+ if ((accessFlags & ClassConstants.ACC_PRIVATE) != 0)
{
setAccessesPrivateCode(invokingMethod);
}
- else if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0)
+ else if ((accessFlags & ClassConstants.ACC_PROTECTED) != 0)
{
setAccessesProtectedCode(invokingMethod);
}
- else if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
+ else if ((accessFlags & ClassConstants.ACC_PUBLIC) == 0)
{
setAccessesPackageCode(invokingMethod);
}
diff --git a/src/proguard/optimize/info/BackwardBranchMarker.java b/src/proguard/optimize/info/BackwardBranchMarker.java
index 07bfefb..089b66e 100644
--- a/src/proguard/optimize/info/BackwardBranchMarker.java
+++ b/src/proguard/optimize/info/BackwardBranchMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CatchExceptionMarker.java b/src/proguard/optimize/info/CatchExceptionMarker.java
index 8f87a08..2894d2a 100644
--- a/src/proguard/optimize/info/CatchExceptionMarker.java
+++ b/src/proguard/optimize/info/CatchExceptionMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CaughtClassFilter.java b/src/proguard/optimize/info/CaughtClassFilter.java
index 762e7de..0c32151 100644
--- a/src/proguard/optimize/info/CaughtClassFilter.java
+++ b/src/proguard/optimize/info/CaughtClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CaughtClassMarker.java b/src/proguard/optimize/info/CaughtClassMarker.java
index 1752f0c..31ee1a8 100644
--- a/src/proguard/optimize/info/CaughtClassMarker.java
+++ b/src/proguard/optimize/info/CaughtClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,7 +21,6 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
/**
diff --git a/src/proguard/optimize/info/ClassOptimizationInfo.java b/src/proguard/optimize/info/ClassOptimizationInfo.java
index dbe041e..5ac56f9 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfo.java
+++ b/src/proguard/optimize/info/ClassOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -34,6 +34,7 @@ public class ClassOptimizationInfo
private boolean isInstanceofed = false;
private boolean isDotClassed = false;
private boolean isCaught = false;
+ private boolean isSimpleEnum = false;
private boolean containsStaticInitializer = false;
private boolean containsPackageVisibleMembers = false;
private boolean invokesPackageVisibleMembers = false;
@@ -88,6 +89,18 @@ public class ClassOptimizationInfo
}
+ public void setSimpleEnum(boolean simple)
+ {
+ isSimpleEnum = simple;
+ }
+
+
+ public boolean isSimpleEnum()
+ {
+ return isSimpleEnum;
+ }
+
+
public void setContainsStaticInitializer()
{
containsStaticInitializer = true;
@@ -157,7 +170,6 @@ public class 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
index f3d78e2..b9211e7 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
+++ b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
*/
package proguard.optimize.info;
-import proguard.classfile.*;
+import proguard.classfile.ProgramClass;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
import proguard.optimize.KeepMarker;
diff --git a/src/proguard/optimize/info/DotClassFilter.java b/src/proguard/optimize/info/DotClassFilter.java
index c3fd878..8ab4f98 100644
--- a/src/proguard/optimize/info/DotClassFilter.java
+++ b/src/proguard/optimize/info/DotClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/DotClassMarker.java b/src/proguard/optimize/info/DotClassMarker.java
index ef5cfd1..d9519ac 100644
--- a/src/proguard/optimize/info/DotClassMarker.java
+++ b/src/proguard/optimize/info/DotClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/DynamicInvocationMarker.java b/src/proguard/optimize/info/DynamicInvocationMarker.java
new file mode 100644
index 0000000..daee6b4
--- /dev/null
+++ b/src/proguard/optimize/info/DynamicInvocationMarker.java
@@ -0,0 +1,79 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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 whether the methods whose instructions it
+ * visits contain the invokedynamic instruction.
+ *
+ * @author Eric Lafortune
+ */
+public class DynamicInvocationMarker
+extends SimplifiedVisitor
+implements InstructionVisitor,
+ ConstantVisitor,
+ ClassVisitor,
+ 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)
+ {
+ if (constantInstruction.opcode == InstructionConstants.OP_INVOKEDYNAMIC)
+ {
+ setInvokesDynamically(method);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private static void setInvokesDynamically(Method method)
+ {
+ MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
+ if (info != null)
+ {
+ info.setInvokesDynamically();
+ }
+ }
+
+
+ /**
+ * Returns whether the given method calls the invokedynamic instruction.
+ */
+ public static boolean invokesDynamically(Method method)
+ {
+ MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
+ return info == null || info.invokesDynamically();
+ }
+}
diff --git a/src/proguard/optimize/info/ExceptionInstructionChecker.java b/src/proguard/optimize/info/ExceptionInstructionChecker.java
index 4bfa96f..a32a1d3 100644
--- a/src/proguard/optimize/info/ExceptionInstructionChecker.java
+++ b/src/proguard/optimize/info/ExceptionInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,12 +22,9 @@ 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.
@@ -45,15 +42,90 @@ implements InstructionVisitor
/**
- * Returns whether the given instruction may throw exceptions.
+ * Returns whether the specified method may throw exceptions.
*/
- public boolean mayThrowExceptions(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ public boolean mayThrowExceptions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute)
{
- mayThrowExceptions = false;
+ return mayThrowExceptions(clazz,
+ method,
+ codeAttribute,
+ 0,
+ codeAttribute.u4codeLength);
+ }
+
+
+ /**
+ * Returns whether the specified block of code may throw exceptions.
+ */
+ public boolean mayThrowExceptions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int startOffset,
+ int endOffset)
+ {
+ byte[] code = codeAttribute.code;
+
+ // Go over all instructions.
+ int offset = startOffset;
+ while (offset < endOffset)
+ {
+ // Get the current instruction.
+ Instruction instruction = InstructionFactory.create(code, offset);
- instruction.accept(clazz, method, codeAttribute, offset, this);
+ // Check if it may be throwing exceptions.
+ if (mayThrowExceptions(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction))
+ {
+ return true;
+ }
- return mayThrowExceptions;
+ // Go to the next instruction.
+ offset += instruction.length(offset);
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the specified instruction may throw exceptions.
+ */
+ public boolean mayThrowExceptions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset)
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code, offset);
+
+ return mayThrowExceptions(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction);
+ }
+
+
+ /**
+ * Returns whether the given instruction may throw exceptions.
+ */
+ public boolean mayThrowExceptions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ Instruction instruction)
+ {
+ return instruction.mayThrowExceptions();
+
+// mayThrowExceptions = false;
+//
+// instruction.accept(clazz, method, codeAttribute, offset, this);
+//
+// return mayThrowExceptions;
}
@@ -64,15 +136,13 @@ implements InstructionVisitor
public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
{
- byte opcode = simpleInstruction.opcode;
-
// Check for instructions that may throw exceptions.
// Note that monitorexit can not sensibly throw exceptions, except the
// broken and deprecated asynchronous ThreadDeath. Removing the
// artificial infinite looping exception blocks that recent compilers
// add does not strictly follow the JVM specs, but it does have the
// additional benefit of avoiding a bug in the JVM in JDK 1.1.
- switch (opcode)
+ switch (simpleInstruction.opcode)
{
case InstructionConstants.OP_IDIV:
case InstructionConstants.OP_LDIV:
@@ -101,16 +171,13 @@ implements InstructionVisitor
// 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.
- switch (opcode)
+ switch (constantInstruction.opcode)
{
case InstructionConstants.OP_GETSTATIC:
case InstructionConstants.OP_PUTSTATIC:
@@ -128,7 +195,6 @@ implements InstructionVisitor
case InstructionConstants.OP_MULTIANEWARRAY:
// These instructions may throw exceptions.
mayThrowExceptions = true;
- }
// case InstructionConstants.OP_INVOKEVIRTUAL:
// case InstructionConstants.OP_INVOKESPECIAL:
@@ -136,6 +202,7 @@ implements InstructionVisitor
// case InstructionConstants.OP_INVOKEINTERFACE:
// // Check if the invoking the method may throw an exception.
// clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
}
diff --git a/src/proguard/optimize/info/FieldOptimizationInfo.java b/src/proguard/optimize/info/FieldOptimizationInfo.java
index 0fa9167..730eead 100644
--- a/src/proguard/optimize/info/FieldOptimizationInfo.java
+++ b/src/proguard/optimize/info/FieldOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,11 +21,11 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.attribute.visitor.*;
import proguard.classfile.attribute.*;
-import proguard.classfile.util.*;
-import proguard.evaluation.value.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
import proguard.evaluation.ConstantValueFactory;
+import proguard.evaluation.value.*;
/**
* This class stores some optimization information that can be attached to
@@ -37,8 +37,9 @@ public class FieldOptimizationInfo
extends SimplifiedVisitor
implements AttributeVisitor
{
- private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory();
- private static final ConstantValueFactory CONSTANT_VALUE_FACTORY = new ConstantValueFactory(VALUE_FACTORY);
+ private static final ParticularValueFactory VALUE_FACTORY = new ParticularValueFactory();
+ private static final ConstantValueFactory CONSTANT_VALUE_FACTORY = new ConstantValueFactory(VALUE_FACTORY);
+ private static final InitialValueFactory INITIAL_VALUE_FACTORY = new InitialValueFactory(VALUE_FACTORY);
private boolean isWritten;
private boolean isRead;
@@ -52,20 +53,9 @@ implements AttributeVisitor
int accessFlags = field.getAccessFlags();
isWritten =
- isRead = (accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0;
+ isRead = (accessFlags & ClassConstants.ACC_VOLATILE) != 0;
- if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
- {
- // See if we can initialize the static field with a constant value.
- field.accept(clazz, new AllAttributeVisitor(this));
- }
-
- if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
- value == null)
- {
- // Otherwise initialize the non-final field with the default value.
- value = initialValue(field.getDescriptor(clazz));
- }
+ resetValue(clazz, field);
}
@@ -129,6 +119,30 @@ implements AttributeVisitor
}
+ public void resetValue(Clazz clazz, Field field)
+ {
+ int accessFlags = field.getAccessFlags();
+
+ value = null;
+
+ // See if we can initialize a static field with a constant value.
+ if ((accessFlags & ClassConstants.ACC_STATIC) != 0)
+ {
+ field.accept(clazz, new AllAttributeVisitor(this));
+ }
+
+ // Otherwise initialize a non-final field with the default value.
+ // Conservatively, even a final field needs to be initialized with the
+ // default value, because it may be accessed before it is set.
+ if (value == null &&
+ (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY ||
+ (accessFlags & ClassConstants.ACC_FINAL) == 0))
+ {
+ value = INITIAL_VALUE_FACTORY.createValue(field.getDescriptor(clazz));
+ }
+ }
+
+
public void generalizeValue(Value value)
{
this.value = this.value != null ?
@@ -157,36 +171,6 @@ implements AttributeVisitor
// 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)
{
field.setVisitorInfo(new FieldOptimizationInfo(clazz, field));
diff --git a/src/proguard/optimize/info/InstanceofClassFilter.java b/src/proguard/optimize/info/InstanceofClassFilter.java
index 7cd85bc..ab345fb 100644
--- a/src/proguard/optimize/info/InstanceofClassFilter.java
+++ b/src/proguard/optimize/info/InstanceofClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstanceofClassMarker.java b/src/proguard/optimize/info/InstanceofClassMarker.java
index 96d5baf..3556dd8 100644
--- a/src/proguard/optimize/info/InstanceofClassMarker.java
+++ b/src/proguard/optimize/info/InstanceofClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstantiationClassFilter.java b/src/proguard/optimize/info/InstantiationClassFilter.java
index a659f06..7822205 100644
--- a/src/proguard/optimize/info/InstantiationClassFilter.java
+++ b/src/proguard/optimize/info/InstantiationClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstantiationClassMarker.java b/src/proguard/optimize/info/InstantiationClassMarker.java
index b4afffd..3f90991 100644
--- a/src/proguard/optimize/info/InstantiationClassMarker.java
+++ b/src/proguard/optimize/info/InstantiationClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
index 3c27c93..ad64cf9 100644
--- a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
+++ b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/MethodInvocationMarker.java b/src/proguard/optimize/info/MethodInvocationMarker.java
index afb2336..c9a9131 100644
--- a/src/proguard/optimize/info/MethodInvocationMarker.java
+++ b/src/proguard/optimize/info/MethodInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/MethodOptimizationInfo.java b/src/proguard/optimize/info/MethodOptimizationInfo.java
index fe754e5..9bfdb50 100644
--- a/src/proguard/optimize/info/MethodOptimizationInfo.java
+++ b/src/proguard/optimize/info/MethodOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -38,6 +38,7 @@ public class MethodOptimizationInfo
private boolean catchesExceptions = false;
private boolean branchesBackward = false;
private boolean invokesSuperMethods = false;
+ private boolean invokesDynamically = false;
private boolean accessesPrivateCode = false;
private boolean accessesPackageCode = false;
private boolean accessesProtectedCode = false;
@@ -58,7 +59,7 @@ public class MethodOptimizationInfo
int parameterCount =
ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz));
- if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0)
+ if ((method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0)
{
parameterCount++;
}
@@ -142,6 +143,18 @@ public class MethodOptimizationInfo
}
+ public void setInvokesDynamically()
+ {
+ invokesDynamically = true;
+ }
+
+
+ public boolean invokesDynamically()
+ {
+ return invokesDynamically;
+ }
+
+
public void setAccessesPrivateCode()
{
accessesPrivateCode = true;
@@ -256,6 +269,13 @@ public class MethodOptimizationInfo
}
+ // For setting enum return values.
+ public void setReturnValue(Value returnValue)
+ {
+ this.returnValue = returnValue;
+ }
+
+
public void merge(MethodOptimizationInfo other)
{
if (other != null)
@@ -266,6 +286,7 @@ public class MethodOptimizationInfo
this.catchesExceptions |= other.catchesExceptions;
this.branchesBackward |= other.branchesBackward;
this.invokesSuperMethods |= other.invokesSuperMethods;
+ this.invokesDynamically |= other.invokesDynamically;
this.accessesPrivateCode |= other.accessesPrivateCode;
this.accessesPackageCode |= other.accessesPackageCode;
this.accessesProtectedCode |= other.accessesProtectedCode;
diff --git a/src/proguard/optimize/info/NoSideEffectMethodMarker.java b/src/proguard/optimize/info/NoSideEffectMethodMarker.java
index bf5ce45..34549b3 100644
--- a/src/proguard/optimize/info/NoSideEffectMethodMarker.java
+++ b/src/proguard/optimize/info/NoSideEffectMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/NonPrivateMemberMarker.java b/src/proguard/optimize/info/NonPrivateMemberMarker.java
index 06f8500..152e114 100644
--- a/src/proguard/optimize/info/NonPrivateMemberMarker.java
+++ b/src/proguard/optimize/info/NonPrivateMemberMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -49,13 +49,13 @@ implements ClassVisitor,
programClass.constantPoolEntriesAccept(this);
// Explicitly mark the <clinit> method.
- programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
- ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+ programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
+ ClassConstants.METHOD_TYPE_CLINIT,
this);
// Explicitly mark the parameterless <init> method.
- programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
- ClassConstants.INTERNAL_METHOD_TYPE_INIT,
+ programClass.methodAccept(ClassConstants.METHOD_NAME_INIT,
+ ClassConstants.METHOD_TYPE_INIT,
this);
// Mark all methods that may have implementations.
diff --git a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
index 02e1a18..7f1dfdb 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
+++ b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -39,7 +39,7 @@ implements ClassVisitor,
public void visitAnyClass(Clazz clazz)
{
// Check the class itself.
- if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
+ if ((clazz.getAccessFlags() & ClassConstants.ACC_PUBLIC) == 0)
{
setPackageVisibleMembers(clazz);
}
@@ -57,8 +57,8 @@ implements ClassVisitor,
public void visitAnyMember(Clazz clazz, Member member)
{
if ((member.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_PRIVATE |
- ClassConstants.INTERNAL_ACC_PUBLIC)) == 0)
+ (ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_PUBLIC)) == 0)
{
setPackageVisibleMembers(clazz);
}
diff --git a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
index 3148e3d..6a8e329 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
+++ b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,8 +21,8 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
@@ -89,7 +89,7 @@ implements ConstantVisitor,
public void visitAnyClass(Clazz clazz)
{
if ((clazz.getAccessFlags() &
- ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
+ ClassConstants.ACC_PUBLIC) == 0)
{
setInvokesPackageVisibleMembers(referencingClass);
}
@@ -101,8 +101,8 @@ implements ConstantVisitor,
public void visitAnyMember(Clazz clazz, Member member)
{
if ((member.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_PUBLIC |
- ClassConstants.INTERNAL_ACC_PRIVATE)) == 0)
+ (ClassConstants.ACC_PUBLIC |
+ ClassConstants.ACC_PRIVATE)) == 0)
{
setInvokesPackageVisibleMembers(referencingClass);
}
diff --git a/src/proguard/optimize/info/ParameterUsageMarker.java b/src/proguard/optimize/info/ParameterUsageMarker.java
index a2a264d..0061148 100644
--- a/src/proguard/optimize/info/ParameterUsageMarker.java
+++ b/src/proguard/optimize/info/ParameterUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -89,7 +89,7 @@ implements MemberVisitor,
// Must we mark the 'this' parameter?
if (markThisParameter &&
- (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0)
+ (accessFlags & ClassConstants.ACC_STATIC) == 0)
{
// Mark the 'this' parameter.
markParameterUsed(programMethod, 0);
@@ -100,19 +100,19 @@ implements MemberVisitor,
{
// Mark all parameters, without the 'this' parameter.
markUsedParameters(programMethod,
- (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+ (accessFlags & ClassConstants.ACC_STATIC) != 0 ?
-1L : -2L);
}
// Is it a native method?
- if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0)
+ if ((accessFlags & ClassConstants.ACC_NATIVE) != 0)
{
// Mark all parameters.
markUsedParameters(programMethod, -1L);
}
// Is it an abstract method?
- else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0)
+ else if ((accessFlags & ClassConstants.ACC_ABSTRACT) != 0)
{
// Mark the 'this' parameter.
markParameterUsed(programMethod, 0);
@@ -123,10 +123,10 @@ implements MemberVisitor,
{
// 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 ||
+ if ((accessFlags & ClassConstants.ACC_STATIC) == 0 &&
+ ((accessFlags & ClassConstants.ACC_SYNCHRONIZED) != 0 ||
programClass.mayHaveImplementations(programMethod) ||
- programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)))
+ programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT)))
{
// Mark the 'this' parameter.
markParameterUsed(programMethod, 0);
diff --git a/src/proguard/optimize/info/ReadWriteFieldMarker.java b/src/proguard/optimize/info/ReadWriteFieldMarker.java
index 6bd4b2f..ea98d3e 100644
--- a/src/proguard/optimize/info/ReadWriteFieldMarker.java
+++ b/src/proguard/optimize/info/ReadWriteFieldMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/SideEffectInstructionChecker.java b/src/proguard/optimize/info/SideEffectInstructionChecker.java
index 91f1f02..49a1281 100644
--- a/src/proguard/optimize/info/SideEffectInstructionChecker.java
+++ b/src/proguard/optimize/info/SideEffectInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -33,7 +33,8 @@ import java.util.*;
/**
* This class can tell whether an instruction has any side effects outside of
- * its method. Return instructions can be included or not.
+ * its method. Return instructions and local field accesses can be included or
+ * not.
*
* @see ReadWriteFieldMarker
* @see StaticInitializerContainingClassMarker
@@ -47,17 +48,25 @@ implements InstructionVisitor,
ConstantVisitor,
MemberVisitor
{
- private static final boolean OPTIMIZE_CONSERVATIVELY = System.getProperty("optimize.conservatively") != null;
+ static final boolean OPTIMIZE_CONSERVATIVELY = System.getProperty("optimize.conservatively") != null;
private final boolean includeReturnInstructions;
private final boolean includeLocalFieldAccess;
// A return value for the visitor methods.
+ private boolean writingField;
private Clazz referencingClass;
private boolean hasSideEffects;
+ /**
+ * Creates a new SideEffectInstructionChecker
+ * @param includeReturnInstructions specifies whether return instructions
+ * count as side effects.
+ * @param includeLocalFieldAccess specifies whether reading or writing
+ * local fields counts as side effects.
+ */
public SideEffectInstructionChecker(boolean includeReturnInstructions,
boolean includeLocalFieldAccess)
{
@@ -96,6 +105,10 @@ implements InstructionVisitor,
// Check for instructions that might cause side effects.
switch (opcode)
{
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_IREM:
+ case InstructionConstants.OP_LREM:
case InstructionConstants.OP_IALOAD:
case InstructionConstants.OP_LALOAD:
case InstructionConstants.OP_FALOAD:
@@ -104,8 +117,13 @@ implements InstructionVisitor,
case InstructionConstants.OP_BALOAD:
case InstructionConstants.OP_CALOAD:
case InstructionConstants.OP_SALOAD:
+ case InstructionConstants.OP_NEWARRAY:
+ case InstructionConstants.OP_ARRAYLENGTH:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_MULTIANEWARRAY:
// These instructions strictly taken may cause a side effect
- // (NullPointerException, ArrayIndexOutOfBoundsException).
+ // (ArithmeticException, NullPointerException,
+ // ArrayIndexOutOfBoundsException, NegativeArraySizeException).
hasSideEffects = OPTIMIZE_CONSERVATIVELY;
break;
@@ -160,16 +178,53 @@ implements InstructionVisitor,
switch (opcode)
{
case InstructionConstants.OP_GETSTATIC:
+ // Check if accessing the field might cause any side effects.
+ writingField = false;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
case InstructionConstants.OP_PUTSTATIC:
- case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
- // Check if the field is write-only or volatile, or if the
- // invoked method is causing any side effects.
+ // Check if accessing the field might cause any side effects.
+ writingField = true;
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
break;
case InstructionConstants.OP_GETFIELD:
+ if (OPTIMIZE_CONSERVATIVELY)
+ {
+ // These instructions strictly taken may cause a side effect
+ // (NullPointerException).
+ hasSideEffects = true;
+ }
+ else
+ {
+ // Check if the field is write-only or volatile.
+ writingField = false;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
+ break;
+
case InstructionConstants.OP_PUTFIELD:
+ if (OPTIMIZE_CONSERVATIVELY)
+ {
+ // These instructions strictly taken may cause a side effect
+ // (NullPointerException).
+ hasSideEffects = true;
+ }
+ else
+ {
+ // Check if the field is write-only or volatile.
+ writingField = true;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
+ break;
+
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ // Check if the invoked method is causing any side effects.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
case InstructionConstants.OP_INVOKEVIRTUAL:
case InstructionConstants.OP_INVOKEINTERFACE:
case InstructionConstants.OP_INVOKEDYNAMIC:
@@ -181,15 +236,16 @@ implements InstructionVisitor,
}
else
{
- // Check if the field is write-only or volatile, or if the
- // invoked method is causing any side effects.
+ // Check if the invoked method is causing any side effects.
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
}
break;
+ case InstructionConstants.OP_ANEWARRAY:
case InstructionConstants.OP_CHECKCAST:
+ case InstructionConstants.OP_MULTIANEWARRAY:
// This instructions strictly taken may cause a side effect
- // (ClassCastException).
+ // (ClassCastException, NegativeArraySizeException).
hasSideEffects = OPTIMIZE_CONSERVATIVELY;
break;
}
@@ -252,11 +308,9 @@ implements InstructionVisitor,
{
hasSideEffects =
(includeLocalFieldAccess || !programClass.equals(referencingClass)) &&
- ((ReadWriteFieldMarker.isRead(programField) &&
- ReadWriteFieldMarker.isWritten(programField)) ||
- ((programField.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) ||
- (!programClass.equals(referencingClass) &&
- !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))));
+ ((writingField && ReadWriteFieldMarker.isRead(programField)) ||
+ (programField.getAccessFlags() & ClassConstants.ACC_VOLATILE) != 0 ||
+ mayHaveSideEffects(referencingClass, programClass));
}
@@ -267,8 +321,7 @@ implements InstructionVisitor,
hasSideEffects =
!NoSideEffectMethodMarker.hasNoSideEffects(programMethod) &&
(SideEffectMethodMarker.hasSideEffects(programMethod) ||
- (!programClass.equals(referencingClass) &&
- !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))));
+ mayHaveSideEffects(referencingClass, programClass));
}
@@ -285,6 +338,21 @@ implements InstructionVisitor,
}
+ // Small utility methods.
+
+ /**
+ * Returns whether a field reference or method invocation from the
+ * referencing class to the referenced class might have any side
+ * effects.
+ */
+ private boolean mayHaveSideEffects(Clazz referencingClass, Clazz referencedClass)
+ {
+ return
+ !referencedClass.equals(referencingClass) &&
+ !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(referencedClass));
+ }
+
+
/**
* Returns the set of superclasses and interfaces that are initialized.
*/
@@ -296,8 +364,8 @@ implements InstructionVisitor,
// static initializers.
clazz.hierarchyAccept(true, true, true, false,
new StaticInitializerContainingClassFilter(
- new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
- ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+ new NamedMethodVisitor(ClassConstants.METHOD_NAME_CLINIT,
+ ClassConstants.METHOD_TYPE_CLINIT,
new SideEffectMethodFilter(
new MemberToClassVisitor(
new ClassCollector(set))))));
diff --git a/src/proguard/optimize/info/SideEffectMethodFilter.java b/src/proguard/optimize/info/SideEffectMethodFilter.java
index 52e072a..3821870 100644
--- a/src/proguard/optimize/info/SideEffectMethodFilter.java
+++ b/src/proguard/optimize/info/SideEffectMethodFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/SideEffectMethodMarker.java b/src/proguard/optimize/info/SideEffectMethodMarker.java
index f7953c0..79584e1 100644
--- a/src/proguard/optimize/info/SideEffectMethodMarker.java
+++ b/src/proguard/optimize/info/SideEffectMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -86,8 +86,8 @@ implements ClassPoolVisitor,
// Initialize the return value.
hasSideEffects =
(programMethod.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_NATIVE |
- ClassConstants.INTERNAL_ACC_SYNCHRONIZED)) != 0;
+ (ClassConstants.ACC_NATIVE |
+ ClassConstants.ACC_SYNCHRONIZED)) != 0;
// Look further if the method hasn't been marked yet.
if (!hasSideEffects)
@@ -132,7 +132,7 @@ implements ClassPoolVisitor,
int length = codeAttribute.u4codeLength;
SideEffectInstructionChecker checker =
- method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ?
+ method.getName(clazz).equals(ClassConstants.METHOD_NAME_CLINIT) ?
initializerSideEffectInstructionChecker :
sideEffectInstructionChecker;
diff --git a/src/proguard/optimize/info/SimpleEnumFilter.java b/src/proguard/optimize/info/SimpleEnumFilter.java
new file mode 100644
index 0000000..8db58f4
--- /dev/null
+++ b/src/proguard/optimize/info/SimpleEnumFilter.java
@@ -0,0 +1,63 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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 simple enums.
+ *
+ * @see SimpleEnumMarker
+ * @author Eric Lafortune
+ */
+public class SimpleEnumFilter
+implements ClassVisitor
+{
+ private final ClassVisitor classVisitor;
+
+
+ public SimpleEnumFilter(ClassVisitor classVisitor)
+ {
+ this.classVisitor = classVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (SimpleEnumMarker.isSimpleEnum(programClass))
+ {
+ classVisitor.visitProgramClass(programClass);
+ }
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ if (SimpleEnumMarker.isSimpleEnum(libraryClass))
+ {
+ classVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/proguard/optimize/info/SimpleEnumMarker.java b/src/proguard/optimize/info/SimpleEnumMarker.java
new file mode 100644
index 0000000..dfb1ccb
--- /dev/null
+++ b/src/proguard/optimize/info/SimpleEnumMarker.java
@@ -0,0 +1,75 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2014 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 marks all program classes that it visits with a given
+ * flag for simple enums.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleEnumMarker
+implements ClassVisitor
+{
+ private final boolean simple;
+
+
+ /**
+ * Creates a new SimpleEnumMarker that marks visited classes with the
+ * given flag.
+ */
+ public SimpleEnumMarker(boolean simple)
+ {
+ this.simple = simple;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ setSimpleEnum(programClass);
+ }
+
+
+ // Small utility methods.
+
+ private void setSimpleEnum(Clazz clazz)
+ {
+ ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
+ if (info != null)
+ {
+ info.setSimpleEnum(simple);
+ }
+ }
+
+
+ public static boolean isSimpleEnum(Clazz clazz)
+ {
+ ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
+ return info != null && info.isSimpleEnum();
+ }
+} \ No newline at end of file
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
index 36aa392..ccb3d31 100644
--- a/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
+++ b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
index 3a7e642..12e0079 100644
--- a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
+++ b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,7 +22,7 @@ package proguard.optimize.info;
import proguard.classfile.*;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.*;
+import proguard.classfile.visitor.ClassVisitor;
/**
* This ClassVisitor marks all classes that contain static initializers.
@@ -37,8 +37,8 @@ implements ClassVisitor
public void visitAnyClass(Clazz clazz)
{
- if (clazz.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
- ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) != null)
+ if (clazz.findMethod(ClassConstants.METHOD_NAME_CLINIT,
+ ClassConstants.METHOD_TYPE_CLINIT) != null)
{
setStaticInitializer(clazz);
}
diff --git a/src/proguard/optimize/info/SuperInvocationMarker.java b/src/proguard/optimize/info/SuperInvocationMarker.java
index 37b118a..990a9ea 100644
--- a/src/proguard/optimize/info/SuperInvocationMarker.java
+++ b/src/proguard/optimize/info/SuperInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -69,7 +69,7 @@ implements InstructionVisitor,
{
invokesSuperMethods =
!clazz.equals(refConstant.referencedClass) &&
- !refConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+ !refConstant.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT);
}
diff --git a/src/proguard/optimize/info/VariableUsageMarker.java b/src/proguard/optimize/info/VariableUsageMarker.java
index b189ca9..1d3c04a 100644
--- a/src/proguard/optimize/info/VariableUsageMarker.java
+++ b/src/proguard/optimize/info/VariableUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java
index 79499f1..507c1f8 100644
--- a/src/proguard/optimize/peephole/BranchTargetFinder.java
+++ b/src/proguard/optimize/peephole/BranchTargetFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -50,9 +50,14 @@ implements AttributeVisitor,
private static boolean DEBUG = System.getProperty("btf") != null;
//*/
- public static final int NONE = -2;
- public static final int AT_METHOD_ENTRY = -1;
+ public static final int NONE = -1;
+ // We'll explicitly mark instructions that are not part of a subroutine,
+ // with NO_SUBROUTINE. Subroutines may just branch back into normal code
+ // (e.g. due to a break instruction in Java code), and we want to avoid
+ // marking such normal code as subroutine. The first mark wins, so we're
+ // assuming that such code is marked as normal code before it is marked
+ // as subroutine.
public static final int UNKNOWN = -1;
public static final int NO_SUBROUTINE = -2;
@@ -355,24 +360,17 @@ implements AttributeVisitor,
currentSubroutineStart = NO_SUBROUTINE;
recentCreationOffsetIndex = 0;
- // Initialize the stack of 'new' instruction offsets if this method
- // is an instance initializer.
- if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
- {
- recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY;
- }
-
// Mark branch targets by going over all instructions.
codeAttribute.instructionsAccept(clazz, method, this);
+
+ // Mark branch targets in the exception table.
+ codeAttribute.exceptionsAccept(clazz, method, this);
}
while (repeat);
// The end of the code is a branch target sentinel.
instructionMarks[codeLength] = BRANCH_TARGET;
- // Mark branch targets in the exception table.
- codeAttribute.exceptionsAccept(clazz, method, this);
-
if (containsSubroutines)
{
// Set the subroutine returning flag and the subroutine end at each
@@ -487,33 +485,39 @@ implements AttributeVisitor,
// Check if this is an instruction of a subroutine.
checkSubroutine(offset);
- // Check if the instruction is a 'new' instruction.
- if (constantInstruction.opcode == InstructionConstants.OP_NEW)
+ byte opcode = constantInstruction.opcode;
+ if (opcode == InstructionConstants.OP_NEW)
{
// Push the 'new' instruction offset on the stack.
recentCreationOffsets[recentCreationOffsetIndex++] = offset;
}
- else
+ else if (opcode == InstructionConstants.OP_INVOKESPECIAL)
{
- // Check if the instruction is an initializer invocation.
+ // Is it calling an instance initializer?
isInitializer = false;
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
if (isInitializer)
{
- // Pop the 'new' instruction offset from the stack.
- int recentCreationOffset = recentCreationOffsets[--recentCreationOffsetIndex];
+ // Do we have any 'new' instruction offsets on the stack?
+ if (recentCreationOffsetIndex > 0)
+ {
+ // Pop the 'new' instruction offset from the stack.
+ int recentCreationOffset = recentCreationOffsets[--recentCreationOffsetIndex];
- // Fill it out in the creation offsets.
- creationOffsets[offset] = recentCreationOffset;
+ // Link the creation offset and the initialization offset.
+ // TODO: There could be multiple initialization offsets.
+ creationOffsets[offset] = recentCreationOffset;
- // Fill out the initialization offsets.
- if (recentCreationOffset == AT_METHOD_ENTRY)
- {
- superInitializationOffset = offset;
+ initializationOffsets[recentCreationOffset] = offset;
}
else
{
- initializationOffsets[recentCreationOffset] = offset;
+ // Remember the super initialization offset.
+ // TODO: There could be multiple initialization offsets.
+ // For instance, in the constructor of the generated class
+ // groovy.inspect.swingui.GeneratedBytecodeAwareGroovyClassLoader
+ // in groovy-all-2.2.1.jar.
+ superInitializationOffset = offset;
}
}
}
@@ -613,7 +617,8 @@ implements AttributeVisitor,
public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
{
- isInitializer = methodrefConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+ // Remember whether the method is an initializer.
+ isInitializer = methodrefConstant.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT);
}
@@ -621,10 +626,24 @@ implements AttributeVisitor,
public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
{
+ int startPC = exceptionInfo.u2startPC;
+ int endPC = exceptionInfo.u2endPC;
+ int handlerPC = exceptionInfo.u2handlerPC;
+
// Mark the exception offsets.
- instructionMarks[exceptionInfo.u2startPC] |= EXCEPTION_START;
- instructionMarks[exceptionInfo.u2endPC] |= EXCEPTION_END;
- instructionMarks[exceptionInfo.u2handlerPC] |= EXCEPTION_HANDLER;
+ instructionMarks[startPC] |= EXCEPTION_START;
+ instructionMarks[endPC] |= EXCEPTION_END;
+ instructionMarks[handlerPC] |= EXCEPTION_HANDLER;
+
+ // Mark the handler as part of a subroutine if necessary.
+ if (subroutineStarts[handlerPC] == UNKNOWN &&
+ subroutineStarts[startPC] != UNKNOWN)
+ {
+ subroutineStarts[handlerPC] = subroutineStarts[startPC];
+
+ // We'll have to go over all instructions again.
+ repeat = true;
+ }
}
@@ -737,12 +756,6 @@ implements AttributeVisitor,
{
// Mark the subroutine start.
subroutineStarts[offset] = currentSubroutineStart;
-
- if (currentSubroutineStart >= 0)
- {
- // Mark the subroutine end at the subroutine start.
- subroutineEnds[currentSubroutineStart] = offset;
- }
}
}
}
diff --git a/src/proguard/optimize/peephole/ClassFinalizer.java b/src/proguard/optimize/peephole/ClassFinalizer.java
index 378f972..1529c2c 100644
--- a/src/proguard/optimize/peephole/ClassFinalizer.java
+++ b/src/proguard/optimize/peephole/ClassFinalizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,8 +21,8 @@
package proguard.optimize.peephole;
import proguard.classfile.*;
-import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.ClassVisitor;
import proguard.optimize.KeepMarker;
/**
@@ -66,13 +66,13 @@ implements ClassVisitor
// and it is not being kept,
// and it doesn't have any subclasses,
// then make it final.
- if ((programClass.u2accessFlags & (ClassConstants.INTERNAL_ACC_FINAL |
- ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
+ if ((programClass.u2accessFlags & (ClassConstants.ACC_FINAL |
+ ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_ABSTRACT)) == 0 &&
!KeepMarker.isKept(programClass) &&
programClass.subClasses == null)
{
- programClass.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL;
+ programClass.u2accessFlags |= ClassConstants.ACC_FINAL;
// Visit the class, if required.
if (extraClassVisitor != null)
diff --git a/src/proguard/optimize/peephole/ClassMerger.java b/src/proguard/optimize/peephole/ClassMerger.java
index aa40c75..9bcc993 100644
--- a/src/proguard/optimize/peephole/ClassMerger.java
+++ b/src/proguard/optimize/peephole/ClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -49,9 +49,11 @@ implements ClassVisitor,
ConstantVisitor
{
//*
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = false;
+ private static final boolean DETAILS = false;
/*/
- private static boolean DEBUG = System.getProperty("cm") != null;
+ private static boolean DEBUG = System.getProperty("cm") != null;
+ private static boolean DETAILS = System.getProperty("cmd") != null;
//*/
@@ -152,7 +154,9 @@ implements ClassVisitor,
// Don't merge annotation classes, with all their introspection and
// infinite recursion.
- (programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 &&
+ (programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) == 0 &&
+
+ (!DETAILS || print(programClass, "Package visibility?")) &&
// Only merge classes if we can change the access permissions, or
// if they are in the same package, or
@@ -161,77 +165,117 @@ implements ClassVisitor,
(allowAccessModification ||
((programClass.getAccessFlags() &
targetClass.getAccessFlags() &
- ClassConstants.INTERNAL_ACC_PUBLIC) != 0 &&
+ ClassConstants.ACC_PUBLIC) != 0 &&
!PackageVisibleMemberContainingClassMarker.containsPackageVisibleMembers(programClass) &&
!PackageVisibleMemberInvokingClassMarker.invokesPackageVisibleMembers(programClass)) ||
ClassUtil.internalPackageName(programClass.getName()).equals(
ClassUtil.internalPackageName(targetClass.getName()))) &&
+ (!DETAILS || print(programClass, "Interface/abstract/single?")) &&
+
// Only merge two classes or two interfaces or two abstract classes,
- // or a class into an interface with a single implementation.
+ // or a single implementation into its interface.
((programClass.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) ==
+ (ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_ABSTRACT)) ==
(targetClass.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) ||
+ (ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_ABSTRACT)) ||
(isOnlySubClass(programClass, targetClass) &&
+ programClass.getSuperClass() != null &&
(programClass.getSuperClass().equals(targetClass) ||
programClass.getSuperClass().equals(targetClass.getSuperClass())))) &&
+ (!DETAILS || print(programClass, "Indirect implementation?")) &&
+
// One class must not implement the other class indirectly.
!indirectlyImplementedInterfaces(programClass).contains(targetClass) &&
!targetClass.extendsOrImplements(programClass) &&
+ (!DETAILS || print(programClass, "Interfaces same subinterfaces?")) &&
+
+ // Interfaces must have exactly the same subinterfaces, not
+ // counting themselves, to avoid any loops in the interface
+ // hierarchy.
+ ((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 ||
+ (targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 ||
+ subInterfaces(programClass, targetClass).equals(subInterfaces(targetClass, programClass))) &&
+
+ (!DETAILS || print(programClass, "Same initialized superclasses?")) &&
+
// The two classes must have the same superclasses and interfaces
// with static initializers.
initializedSuperClasses(programClass).equals(initializedSuperClasses(targetClass)) &&
+ (!DETAILS || print(programClass, "Same instanceofed superclasses?")) &&
+
// The two classes must have the same superclasses and interfaces
// that are tested with 'instanceof'.
instanceofedSuperClasses(programClass).equals(instanceofedSuperClasses(targetClass)) &&
+ (!DETAILS || print(programClass, "Same caught superclasses?")) &&
+
// The two classes must have the same superclasses that are caught
// as exceptions.
caughtSuperClasses(programClass).equals(caughtSuperClasses(targetClass)) &&
+ (!DETAILS || print(programClass, "Not .classed?")) &&
+
// The two classes must not both be part of a .class construct.
!(DotClassMarker.isDotClassed(programClass) &&
DotClassMarker.isDotClassed(targetClass)) &&
+ (!DETAILS || print(programClass, "No clashing fields?")) &&
+
// The classes must not have clashing fields.
!haveAnyIdenticalFields(programClass, targetClass) &&
+ (!DETAILS || print(programClass, "No unwanted fields?")) &&
+
// The two classes must not introduce any unwanted fields.
!introducesUnwantedFields(programClass, targetClass) &&
!introducesUnwantedFields(targetClass, programClass) &&
+ (!DETAILS || print(programClass, "No shadowed fields?")) &&
+
// The two classes must not shadow each others fields.
!shadowsAnyFields(programClass, targetClass) &&
!shadowsAnyFields(targetClass, programClass) &&
+ (!DETAILS || print(programClass, "No clashing methods?")) &&
+
// The classes must not have clashing methods.
!haveAnyIdenticalMethods(programClass, targetClass) &&
+ (!DETAILS || print(programClass, "No abstract methods?")) &&
+
// The classes must not introduce abstract methods, unless
// explicitly allowed.
(mergeInterfacesAggressively ||
(!introducesUnwantedAbstractMethods(programClass, targetClass) &&
!introducesUnwantedAbstractMethods(targetClass, programClass))) &&
+ (!DETAILS || print(programClass, "No overridden methods?")) &&
+
// The classes must not override each others concrete methods.
!overridesAnyMethods(programClass, targetClass) &&
!overridesAnyMethods(targetClass, programClass) &&
+ (!DETAILS || print(programClass, "No shadowed methods?")) &&
+
// The classes must not shadow each others non-private methods.
!shadowsAnyMethods(programClass, targetClass) &&
!shadowsAnyMethods(targetClass, programClass))
{
+ // We're not actually merging the classes, but only copying the
+ // contents from the source class to the target class. We'll
+ // then let all other classes point to it. The shrinking step
+ // will finally remove the source class.
if (DEBUG)
{
System.out.println("ClassMerger ["+programClass.getName()+"] -> ["+targetClass.getName()+"]");
- System.out.println(" Source interface? ["+((programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]");
- System.out.println(" Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]");
+ System.out.println(" Source interface? ["+((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE)!=0)+"]");
+ System.out.println(" Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE)!=0)+"]");
System.out.println(" Source subclasses ["+programClass.subClasses+"]");
System.out.println(" Target subclasses ["+targetClass.subClasses+"]");
System.out.println(" Source superclass ["+programClass.getSuperClass().getName()+"]");
@@ -249,17 +293,21 @@ implements ClassVisitor,
targetClass.u2accessFlags =
((targetAccessFlags &
sourceAccessFlags) &
- (ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) |
+ (ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_ABSTRACT)) |
((targetAccessFlags |
sourceAccessFlags) &
- (ClassConstants.INTERNAL_ACC_PUBLIC |
- ClassConstants.INTERNAL_ACC_SUPER |
- ClassConstants.INTERNAL_ACC_ANNOTATTION |
- ClassConstants.INTERNAL_ACC_ENUM));
-
- // Copy over the superclass, unless it's the target class itself.
- //if (!targetClass.getName().equals(programClass.getSuperName()))
+ (ClassConstants.ACC_PUBLIC |
+ ClassConstants.ACC_SUPER |
+ ClassConstants.ACC_ANNOTATTION |
+ ClassConstants.ACC_ENUM));
+
+ // Copy over the superclass, if it's a non-interface class being
+ // merged into an interface class.
+ // However, we're currently never merging in a way that changes the
+ // superclass.
+ //if ((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 &&
+ // (targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) != 0)
//{
// targetClass.u2superClass =
// new ConstantAdder(targetClass).addConstant(programClass, programClass.u2superClass);
@@ -267,6 +315,9 @@ implements ClassVisitor,
// Copy over the interfaces that aren't present yet and that
// wouldn't cause loops in the class hierarchy.
+ // Note that the code shouldn't be iterating over the original
+ // list at this point. This is why we only add subclasses in
+ // a separate step.
programClass.interfaceConstantsAccept(
new ExceptClassConstantFilter(targetClass.getName(),
new ImplementedClassConstantFilter(targetClass,
@@ -282,10 +333,11 @@ implements ClassVisitor,
// Copy over the other attributes.
programClass.attributesAccept(
- new AttributeNameFilter(new NotMatcher(new OrMatcher(new OrMatcher(
- new FixedStringMatcher(ClassConstants.ATTR_SourceFile),
- new FixedStringMatcher(ClassConstants.ATTR_InnerClasses)),
- new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))),
+ new AttributeNameFilter(new NotMatcher(
+ new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_BootstrapMethods),
+ new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_SourceFile),
+ new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_InnerClasses),
+ new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))))),
new AttributeAdder(targetClass, true)));
// Update the optimization information of the target class.
@@ -314,6 +366,14 @@ implements ClassVisitor,
}
+ private boolean print(ProgramClass programClass, String message)
+ {
+ System.out.println("Merge ["+targetClass.getName()+"] <- ["+programClass.getName()+"] "+message);
+
+ return true;
+ }
+
+
// Small utility methods.
/**
@@ -352,6 +412,23 @@ implements ClassVisitor,
/**
+ * Returns the set of interface subclasses, not including the given class.
+ */
+ private Set subInterfaces(Clazz clazz, Clazz exceptClass)
+ {
+ Set set = new HashSet();
+
+ // Visit all subclasses, collecting the interface classes.
+ clazz.hierarchyAccept(false, false, false, true,
+ new ClassAccessFilter(ClassConstants.ACC_INTERFACE, 0,
+ new ExceptClassesFilter(new Clazz[] { exceptClass },
+ new ClassCollector(set))));
+
+ return set;
+ }
+
+
+ /**
* Returns the set of superclasses and interfaces that are initialized.
*/
private Set initializedSuperClasses(Clazz clazz)
@@ -392,7 +469,7 @@ implements ClassVisitor,
private Set caughtSuperClasses(Clazz clazz)
{
// Don't bother if this isn't an exception at all.
- if (!clazz.extends_(ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE))
+ if (!clazz.extends_(ClassConstants.NAME_JAVA_LANG_THROWABLE))
{
return Collections.EMPTY_SET;
}
@@ -410,8 +487,8 @@ implements ClassVisitor,
/**
- * Returns whether the two given classes have class members with the same
- * name and descriptor.
+ * Returns whether the two given classes have fields with the same
+ * names and descriptors.
*/
private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass)
{
@@ -445,7 +522,7 @@ implements ClassVisitor,
MemberCounter counter = new MemberCounter();
// Count all non-static fields in the the source class.
- programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC,
+ programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.ACC_STATIC,
counter));
return counter.getCount() > 0;
@@ -465,7 +542,7 @@ implements ClassVisitor,
clazz.hierarchyAccept(true, false, false, true,
new AllFieldVisitor(
new SimilarMemberVisitor(targetClass, true, true, true, false,
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
counter))));
return counter.getCount() > 0;
@@ -482,9 +559,9 @@ implements ClassVisitor,
// Visit all non-abstract methods, counting the ones that are also
// present in the target class.
- clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT,
+ clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT,
new SimilarMemberVisitor(targetClass, true, false, false, false,
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT,
+ new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT,
counter))));
return counter.getCount() > 0;
@@ -501,8 +578,8 @@ implements ClassVisitor,
// It's ok if the target class is already abstract and it has at most
// the class as a subclass.
if ((targetClass.getAccessFlags() &
- (ClassConstants.INTERNAL_ACC_ABSTRACT |
- ClassConstants.INTERNAL_ACC_INTERFACE)) != 0 &&
+ (ClassConstants.ACC_ABSTRACT |
+ ClassConstants.ACC_INTERFACE)) != 0 &&
(targetClass.subClasses == null ||
isOnlySubClass(clazz, targetClass)))
{
@@ -514,12 +591,12 @@ implements ClassVisitor,
// Collect all abstract methods, and similar abstract methods in the
// class hierarchy of the target class.
- clazz.methodsAccept(new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0,
+ clazz.methodsAccept(new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
new MultiMemberVisitor(new MemberVisitor[]
{
counter,
new SimilarMemberVisitor(targetClass, true, true, true, false,
- new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0,
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
new MemberCollector(targetSet)))
})));
@@ -537,11 +614,11 @@ implements ClassVisitor,
// Visit all non-private non-static methods, counting the ones that are
// being overridden in the class hierarchy of the target class.
- clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT,
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)),
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)),
+ clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT,
+ new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_CLINIT)),
+ new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)),
new SimilarMemberVisitor(targetClass, true, true, false, false,
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT,
counter))))));
return counter.getCount() > 0;
@@ -560,20 +637,20 @@ implements ClassVisitor,
// non-private methods in the class hierarchy of the target class.
clazz.hierarchyAccept(true, false, false, true,
new AllMethodVisitor(
- new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0,
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)),
+ new MemberAccessFilter(ClassConstants.ACC_PRIVATE, 0,
+ new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)),
new SimilarMemberVisitor(targetClass, true, true, true, false,
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
counter))))));
// Visit all static methods, counting the ones that are shadowing
// non-private methods in the class hierarchy of the target class.
clazz.hierarchyAccept(true, false, false, true,
new AllMethodVisitor(
- new MemberAccessFilter(ClassConstants.INTERNAL_ACC_STATIC, 0,
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)),
+ new MemberAccessFilter(ClassConstants.ACC_STATIC, 0,
+ new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_CLINIT)),
new SimilarMemberVisitor(targetClass, true, true, true, false,
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
counter))))));
return counter.getCount() > 0;
@@ -638,4 +715,4 @@ implements ClassVisitor,
// Linked methods share their optimization info.
}
}
-} \ No newline at end of file
+}
diff --git a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
index 3bfd98c..a1f422f 100644
--- a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
+++ b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/GotoGotoReplacer.java b/src/proguard/optimize/peephole/GotoGotoReplacer.java
index 4a490a1..bf7292b 100644
--- a/src/proguard/optimize/peephole/GotoGotoReplacer.java
+++ b/src/proguard/optimize/peephole/GotoGotoReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/GotoReturnReplacer.java b/src/proguard/optimize/peephole/GotoReturnReplacer.java
index b6deec8..aa8ed9f 100644
--- a/src/proguard/optimize/peephole/GotoReturnReplacer.java
+++ b/src/proguard/optimize/peephole/GotoReturnReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/HorizontalClassMerger.java b/src/proguard/optimize/peephole/HorizontalClassMerger.java
index 31d3d33..ef76f9b 100644
--- a/src/proguard/optimize/peephole/HorizontalClassMerger.java
+++ b/src/proguard/optimize/peephole/HorizontalClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
*/
package proguard.optimize.peephole;
-import proguard.classfile.*;
+import proguard.classfile.ProgramClass;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
diff --git a/src/proguard/optimize/peephole/InstructionSequenceConstants.java b/src/proguard/optimize/peephole/InstructionSequenceConstants.java
index 4ab9056..df96dda 100644
--- a/src/proguard/optimize/peephole/InstructionSequenceConstants.java
+++ b/src/proguard/optimize/peephole/InstructionSequenceConstants.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -345,43 +345,43 @@ public class InstructionSequenceConstants
new Utf8Constant("J"),
new Utf8Constant("F"),
new Utf8Constant("D"),
- new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING),
- new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_EQUALS),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_EQUALS),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_LENGTH),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LENGTH),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_VALUEOF),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_CHAR),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_INT),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_LONG),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_FLOAT),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_OBJECT),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_INIT),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INIT),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_VOID),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_TOSTRING),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_TOSTRING),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_APPEND),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER),
- new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.NAME_JAVA_LANG_STRING),
+ new Utf8Constant(ClassConstants.NAME_JAVA_LANG_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.NAME_JAVA_LANG_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_NAME_EQUALS),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_EQUALS),
+ new Utf8Constant(ClassConstants.METHOD_NAME_LENGTH),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_LENGTH),
+ new Utf8Constant(ClassConstants.METHOD_NAME_VALUEOF),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_BOOLEAN),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_CHAR),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_INT),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_LONG),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_FLOAT),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_DOUBLE),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_VALUEOF_OBJECT),
+ new Utf8Constant(ClassConstants.METHOD_NAME_INIT),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_INIT),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_STRING_VOID),
+ new Utf8Constant(ClassConstants.METHOD_NAME_TOSTRING),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_TOSTRING),
+ new Utf8Constant(ClassConstants.METHOD_NAME_APPEND),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_BOOLEAN_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_CHAR_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_INT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_LONG_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_FLOAT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_DOUBLE_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_STRING_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_OBJECT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_BOOLEAN_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_CHAR_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_INT_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_LONG_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_FLOAT_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_DOUBLE_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_STRING_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.METHOD_TYPE_OBJECT_STRING_BUILDER),
};
public static final Instruction[][][] VARIABLE = new Instruction[][][]
diff --git a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
index 7ec1a95..6a1d872 100644
--- a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
+++ b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -153,7 +153,8 @@ implements InstructionVisitor,
{
// Reset the instruction sequence matcher if the instruction is a branch
// target or if it has already been modified.
- if (branchTargetFinder.isTarget(offset) ||
+ if ((branchTargetFinder != null &&
+ branchTargetFinder.isTarget(offset)) ||
codeAttributeEditor.isModified(offset))
{
instructionSequenceMatcher.reset();
diff --git a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
index 22fb6cd..9aca05a 100644
--- a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
+++ b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/MemberPrivatizer.java b/src/proguard/optimize/peephole/MemberPrivatizer.java
index f57281c..420d80a 100644
--- a/src/proguard/optimize/peephole/MemberPrivatizer.java
+++ b/src/proguard/optimize/peephole/MemberPrivatizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -72,7 +72,7 @@ implements MemberVisitor
// Make the field private.
programField.u2accessFlags =
AccessUtil.replaceAccessFlags(programField.u2accessFlags,
- ClassConstants.INTERNAL_ACC_PRIVATE);
+ ClassConstants.ACC_PRIVATE);
// Visit the field, if required.
if (extraMemberVisitor != null)
@@ -88,10 +88,10 @@ implements MemberVisitor
// Is the method unmarked?
if (NonPrivateMemberMarker.canBeMadePrivate(programMethod))
{
- // Make the method private.
+ // Make the method private and no longer final.
programMethod.u2accessFlags =
AccessUtil.replaceAccessFlags(programMethod.u2accessFlags,
- ClassConstants.INTERNAL_ACC_PRIVATE);
+ ClassConstants.ACC_PRIVATE);
// Visit the method, if required.
if (extraMemberVisitor != null)
diff --git a/src/proguard/optimize/peephole/MethodFinalizer.java b/src/proguard/optimize/peephole/MethodFinalizer.java
index 89174ac..2ce3029 100644
--- a/src/proguard/optimize/peephole/MethodFinalizer.java
+++ b/src/proguard/optimize/peephole/MethodFinalizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,7 +22,7 @@ package proguard.optimize.peephole;
import proguard.classfile.*;
import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.visitor.MemberVisitor;
import proguard.optimize.KeepMarker;
/**
@@ -61,7 +61,7 @@ implements MemberVisitor
// Implementations for MemberVisitor.
-
+
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
String name = programMethod.getName(programClass);
@@ -71,17 +71,17 @@ implements MemberVisitor
// and its class is final,
// or it is not being kept and it is not overridden,
// then make it final.
- if ((programMethod.u2accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE |
- ClassConstants.INTERNAL_ACC_STATIC |
- ClassConstants.INTERNAL_ACC_FINAL |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
- !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
- ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0 ||
+ if ((programMethod.u2accessFlags & (ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC |
+ ClassConstants.ACC_FINAL |
+ ClassConstants.ACC_ABSTRACT)) == 0 &&
+ !name.equals(ClassConstants.METHOD_NAME_INIT) &&
+ ((programClass.u2accessFlags & ClassConstants.ACC_FINAL) != 0 ||
(!KeepMarker.isKept(programMethod) &&
(programClass.subClasses == null ||
!memberFinder.isOverriden(programClass, programMethod)))))
{
- programMethod.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL;
+ programMethod.u2accessFlags |= ClassConstants.ACC_FINAL;
// Visit the method, if required.
if (extraMemberVisitor != null)
diff --git a/src/proguard/optimize/peephole/MethodInliner.java b/src/proguard/optimize/peephole/MethodInliner.java
index 947cd43..5068965 100644
--- a/src/proguard/optimize/peephole/MethodInliner.java
+++ b/src/proguard/optimize/peephole/MethodInliner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -30,7 +30,7 @@ import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
-import proguard.optimize.*;
+import proguard.optimize.KeepMarker;
import proguard.optimize.info.*;
import java.util.*;
@@ -155,6 +155,8 @@ implements AttributeVisitor,
System.err.println(" Inlined method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
}
System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
+
+ ex.printStackTrace();
System.err.println("Not inlining this method");
if (DEBUG)
@@ -185,7 +187,7 @@ implements AttributeVisitor,
exceptionInfoAdder = new ExceptionInfoAdder(targetClass, codeAttributeComposer);
estimatedResultingCodeLength = codeAttribute.u4codeLength;
inliningMethods.clear();
- uninitializedObjectCount = method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? 1 : 0;
+ uninitializedObjectCount = method.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT) ? 1 : 0;
inlinedAny = false;
codeAttributeComposer.reset();
stackSizeComputer.visitCodeAttribute(clazz, method, codeAttribute);
@@ -252,7 +254,7 @@ implements AttributeVisitor,
String descriptor = method.getDescriptor(clazz);
boolean isStatic =
- (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0;
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) != 0;
// Count the number of parameters, taking into account their categories.
int parameterCount = ClassUtil.internalMethodParameterCount(descriptor);
@@ -287,23 +289,23 @@ implements AttributeVisitor,
byte opcode;
switch (parameterType.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:
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE:
+ case ClassConstants.TYPE_CHAR:
+ case ClassConstants.TYPE_SHORT:
+ case ClassConstants.TYPE_INT:
opcode = InstructionConstants.OP_ISTORE;
break;
- case ClassConstants.INTERNAL_TYPE_LONG:
+ case ClassConstants.TYPE_LONG:
opcode = InstructionConstants.OP_LSTORE;
break;
- case ClassConstants.INTERNAL_TYPE_FLOAT:
+ case ClassConstants.TYPE_FLOAT:
opcode = InstructionConstants.OP_FSTORE;
break;
- case ClassConstants.INTERNAL_TYPE_DOUBLE:
+ case ClassConstants.TYPE_DOUBLE:
opcode = InstructionConstants.OP_DSTORE;
break;
@@ -471,12 +473,9 @@ implements AttributeVisitor,
// Implementations for ConstantVisitor.
- public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) {}
-
-
- public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
{
- methodrefConstant.referencedMemberAccept(this);
+ refConstant.referencedMemberAccept(this);
}
@@ -493,22 +492,23 @@ implements AttributeVisitor,
!KeepMarker.isKept(programMethod) &&
// Only inline the method if it is private, static, or final.
- (accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE |
- ClassConstants.INTERNAL_ACC_STATIC |
- ClassConstants.INTERNAL_ACC_FINAL)) != 0 &&
+ // This currently precludes default interface methods, because
+ // they can't be final.
+ (accessFlags & (ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC |
+ ClassConstants.ACC_FINAL)) != 0 &&
// Only inline the method if it is not synchronized, etc.
- (accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED |
- ClassConstants.INTERNAL_ACC_NATIVE |
- ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
+ (accessFlags & (ClassConstants.ACC_SYNCHRONIZED |
+ ClassConstants.ACC_NATIVE |
+ ClassConstants.ACC_ABSTRACT)) == 0 &&
// Don't inline an <init> method, except in an <init> method in the
// same class.
-// (!programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ||
+// (!programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT) ||
// (programClass.equals(targetClass) &&
-// targetMethod.getName(targetClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) &&
- !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
+// targetMethod.getName(targetClass).equals(ClassConstants.METHOD_NAME_INIT))) &&
+ !programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT) &&
// Don't inline a method into itself.
(!programMethod.equals(targetMethod) ||
@@ -522,9 +522,10 @@ implements AttributeVisitor,
// introducing incompatible constructs.
targetClass.u4version >= programClass.u4version &&
- // Only inline the method if it doesn't invoke a super method, or if
- // it is in the same class.
- (!SuperInvocationMarker.invokesSuperMethods(programMethod) ||
+ // Only inline the method if it doesn't invoke a super method or a
+ // dynamic method, or if it is in the same class.
+ (!SuperInvocationMarker.invokesSuperMethods(programMethod) &&
+ !DynamicInvocationMarker.invokesDynamically(programMethod) ||
programClass.equals(targetClass)) &&
// Only inline the method if it doesn't branch backward while there
@@ -554,9 +555,11 @@ implements AttributeVisitor,
// Only inline the method if it comes from the a class with at most
// a subset of the initialized superclasses.
- (programClass.equals(targetClass) ||
+ ((accessFlags & ClassConstants.ACC_STATIC) == 0 ||
+ programClass.equals(targetClass) ||
initializedSuperClasses(targetClass).containsAll(initializedSuperClasses(programClass))))
- { boolean oldInlining = inlining;
+ {
+ boolean oldInlining = inlining;
inlining = true;
inliningMethods.push(programMethod);
@@ -574,7 +577,7 @@ implements AttributeVisitor,
inlining = oldInlining;
inliningMethods.pop();
}
- else if (programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ else if (programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT))
{
uninitializedObjectCount--;
}
diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/peephole/NopRemover.java
index 9396c40..b869045 100644
--- a/src/proguard/optimize/peephole/NopRemover.java
+++ b/src/proguard/optimize/peephole/NopRemover.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/PeepholeOptimizer.java b/src/proguard/optimize/peephole/PeepholeOptimizer.java
index 2a602ee..35c4426 100644
--- a/src/proguard/optimize/peephole/PeepholeOptimizer.java
+++ b/src/proguard/optimize/peephole/PeepholeOptimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/ReachableCodeMarker.java b/src/proguard/optimize/peephole/ReachableCodeMarker.java
index b6fcf18..2b8fb10 100644
--- a/src/proguard/optimize/peephole/ReachableCodeMarker.java
+++ b/src/proguard/optimize/peephole/ReachableCodeMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java
index a67c6ff..5d3ccd3 100644
--- a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java
+++ b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/TargetClassChanger.java b/src/proguard/optimize/peephole/TargetClassChanger.java
index f997e03..a65cad5 100644
--- a/src/proguard/optimize/peephole/TargetClassChanger.java
+++ b/src/proguard/optimize/peephole/TargetClassChanger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,14 +21,14 @@
package proguard.optimize.peephole;
import proguard.classfile.*;
-import proguard.classfile.editor.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.visitor.*;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.util.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
/**
@@ -58,6 +58,9 @@ implements ClassVisitor,
public void visitProgramClass(ProgramClass programClass)
{
+ // We're only making changes locally in the class.
+ // Not all other classes may have been retargeted yet.
+
// Change the references of the constant pool.
programClass.constantPoolEntriesAccept(this);
@@ -68,10 +71,41 @@ implements ClassVisitor,
// Change the references of the attributes.
programClass.attributesAccept(this);
- // Is the class itself being retargeted?
+ // Remove duplicate interfaces and interface classes that have ended
+ // up pointing to the class itself.
+ boolean[] delete = null;
+ for (int index = 0; index < programClass.u2interfacesCount; index++)
+ {
+ Clazz interfaceClass = programClass.getInterface(index);
+ if (interfaceClass != null &&
+ (programClass.equals(interfaceClass) ||
+ containsInterfaceClass(programClass,
+ index,
+ interfaceClass)))
+ {
+ // Lazily create the array.
+ if (delete == null)
+ {
+ delete = new boolean[programClass.u2interfacesCount];
+ }
+
+ delete[index] = true;
+ }
+ }
+
+ if (delete != null)
+ {
+ new InterfaceDeleter(delete).visitProgramClass(programClass);
+ }
+
+ // Is the class being retargeted?
Clazz targetClass = ClassMerger.getTargetClass(programClass);
if (targetClass != null)
{
+ // We're not changing anything special in the superclass and
+ // interface hierarchy of the retargeted class. The shrinking
+ // step will remove the class for us.
+
// Restore the class name. We have to add a new class entry
// to avoid an existing entry with the same name being reused. The
// names have to be fixed later, based on their referenced classes.
@@ -80,29 +114,14 @@ implements ClassVisitor,
programClass.getName(),
programClass);
- // This class will loose all its interfaces.
- programClass.u2interfacesCount = 0;
-
- // This class will loose all its subclasses.
+ // This class will no longer have any subclasses, because their
+ // subclasses and interfaces will be retargeted.
programClass.subClasses = null;
}
else
{
- // Remove interface classes that are pointing to this class.
- int newInterfacesCount = 0;
- for (int index = 0; index < programClass.u2interfacesCount; index++)
- {
- Clazz interfaceClass = programClass.getInterface(index);
- if (!programClass.equals(interfaceClass))
- {
- programClass.u2interfaces[newInterfacesCount++] =
- programClass.u2interfaces[index];
- }
- }
- programClass.u2interfacesCount = newInterfacesCount;
-
- // Update the subclasses of the superclass and interfaces of the
- // target class.
+ // This class has become the subclass of its possibly new
+ // superclass and of any new interfaces.
ConstantVisitor subclassAdder =
new ReferencedClassVisitor(
new SubclassFilter(programClass,
@@ -279,8 +298,7 @@ implements ClassVisitor,
}
-
- // Implementations for LocalVariableInfoVisitor.
+ // Implementations for LocalVariableInfoVisitor.
public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
{
@@ -289,6 +307,7 @@ implements ClassVisitor,
updateReferencedClass(localVariableInfo.referencedClass);
}
+
// Implementations for LocalVariableTypeInfoVisitor.
public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
@@ -297,6 +316,7 @@ implements ClassVisitor,
updateReferencedClasses(localVariableTypeInfo.referencedClasses);
}
+
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
@@ -379,7 +399,27 @@ implements ClassVisitor,
// Small utility methods.
- /**
+ /**
+ * Returns whether the given class contains the given interface
+ * class in its first given number of interfaces.
+ */
+ private boolean containsInterfaceClass(Clazz clazz,
+ int interfaceCount,
+ Clazz interfaceClass)
+ {
+ for (int index = 0; index < interfaceCount; index++)
+ {
+ if (interfaceClass.equals(clazz.getInterface(index)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
* Updates the retargeted classes in the given array of classes.
*/
private void updateReferencedClasses(Clazz[] referencedClasses)
diff --git a/src/proguard/optimize/peephole/UnreachableCodeRemover.java b/src/proguard/optimize/peephole/UnreachableCodeRemover.java
index 570b3ca..f4e3603 100644
--- a/src/proguard/optimize/peephole/UnreachableCodeRemover.java
+++ b/src/proguard/optimize/peephole/UnreachableCodeRemover.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java
index 8e77716..150c4c5 100644
--- a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java
+++ b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -41,9 +41,6 @@ implements AttributeVisitor,
private final ExceptionInfoVisitor extraExceptionInfoVisitor;
- private final ExceptionInstructionChecker exceptionInstructionChecker = new ExceptionInstructionChecker();
-
-
/**
* Creates a new UnreachableExceptionRemover.
*/
@@ -123,11 +120,7 @@ implements AttributeVisitor,
Instruction instruction = InstructionFactory.create(code, offset);
// Check if it may be throwing exceptions.
- if (exceptionInstructionChecker.mayThrowExceptions(clazz,
- method,
- codeAttribute,
- offset,
- instruction))
+ if (instruction.mayThrowExceptions())
{
return true;
}
diff --git a/src/proguard/optimize/peephole/VariableShrinker.java b/src/proguard/optimize/peephole/VariableShrinker.java
index 6c05944..6387f1e 100644
--- a/src/proguard/optimize/peephole/VariableShrinker.java
+++ b/src/proguard/optimize/peephole/VariableShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 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
@@ -78,7 +78,7 @@ implements AttributeVisitor
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
- if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) == 0)
+ if ((method.getAccessFlags() & ClassConstants.ACC_ABSTRACT) == 0)
{
// Compute the parameter size.
int parameterSize =
diff --git a/src/proguard/optimize/peephole/VerticalClassMerger.java b/src/proguard/optimize/peephole/VerticalClassMerger.java
index 825de94..560e989 100644
--- a/src/proguard/optimize/peephole/VerticalClassMerger.java
+++ b/src/proguard/optimize/peephole/VerticalClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,7 +21,6 @@
package proguard.optimize.peephole;
import proguard.classfile.ProgramClass;
-import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
@@ -80,6 +79,7 @@ implements ClassVisitor
public void visitProgramClass(ProgramClass programClass)
{
+ // Try inlining all immediate subclasses into this class.
programClass.subclassesAccept(new ClassMerger(programClass,
allowAccessModification,
mergeInterfacesAggressively,