{@link
@@ -48,6 +51,23 @@ public ProgramField()
}
+ /**
+ * Creates an initialized ProgramField without attributes.
+ */
+ public ProgramField(int u2accessFlags,
+ int u2nameIndex,
+ int u2descriptorIndex,
+ Clazz referencedClass)
+ {
+ this(u2accessFlags,
+ u2nameIndex,
+ u2descriptorIndex,
+ 0,
+ EMPTY_ATTRIBUTES,
+ referencedClass);
+ }
+
+
/**
* Creates an initialized ProgramField.
*/
diff --git a/src/proguard/classfile/ProgramMember.java b/core/src/proguard/classfile/ProgramMember.java
similarity index 98%
rename from src/proguard/classfile/ProgramMember.java
rename to core/src/proguard/classfile/ProgramMember.java
index 8736bf8..1a0d9f8 100644
--- a/src/proguard/classfile/ProgramMember.java
+++ b/core/src/proguard/classfile/ProgramMember.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/ProgramMethod.java b/core/src/proguard/classfile/ProgramMethod.java
similarity index 84%
rename from src/proguard/classfile/ProgramMethod.java
rename to core/src/proguard/classfile/ProgramMethod.java
index b13f2ef..8a9a529 100644
--- a/src/proguard/classfile/ProgramMethod.java
+++ b/core/src/proguard/classfile/ProgramMethod.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,9 @@
*/
public class ProgramMethod extends ProgramMember implements Method
{
+ private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0];
+
+
/**
* An extra field containing all the classes referenced in the
* descriptor string. This field is filled out by the {@link
@@ -50,6 +53,23 @@ public ProgramMethod()
}
+ /**
+ * Creates an initialized ProgramMethod without attributes.
+ */
+ public ProgramMethod(int u2accessFlags,
+ int u2nameIndex,
+ int u2descriptorIndex,
+ Clazz[] referencedClasses)
+ {
+ this(u2accessFlags,
+ u2nameIndex,
+ u2descriptorIndex,
+ 0,
+ EMPTY_ATTRIBUTES,
+ referencedClasses);
+ }
+
+
/**
* Creates an initialized ProgramMethod.
*/
diff --git a/src/proguard/classfile/VisitorAccepter.java b/core/src/proguard/classfile/VisitorAccepter.java
similarity index 96%
rename from src/proguard/classfile/VisitorAccepter.java
rename to core/src/proguard/classfile/VisitorAccepter.java
index d06766a..f4f1efb 100644
--- a/src/proguard/classfile/VisitorAccepter.java
+++ b/core/src/proguard/classfile/VisitorAccepter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/Attribute.java b/core/src/proguard/classfile/attribute/Attribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/Attribute.java
rename to core/src/proguard/classfile/attribute/Attribute.java
index 4a475a0..fe0ee5d 100644
--- a/src/proguard/classfile/attribute/Attribute.java
+++ b/core/src/proguard/classfile/attribute/Attribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/BootstrapMethodInfo.java b/core/src/proguard/classfile/attribute/BootstrapMethodInfo.java
old mode 100755
new mode 100644
similarity index 97%
rename from src/proguard/classfile/attribute/BootstrapMethodInfo.java
rename to core/src/proguard/classfile/attribute/BootstrapMethodInfo.java
index 6290257..0e1803d
--- a/src/proguard/classfile/attribute/BootstrapMethodInfo.java
+++ b/core/src/proguard/classfile/attribute/BootstrapMethodInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/BootstrapMethodsAttribute.java b/core/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
old mode 100755
new mode 100644
similarity index 98%
rename from src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
rename to core/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
index 08970e1..4e62455
--- a/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
+++ b/core/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/CodeAttribute.java b/core/src/proguard/classfile/attribute/CodeAttribute.java
similarity index 84%
rename from src/proguard/classfile/attribute/CodeAttribute.java
rename to core/src/proguard/classfile/attribute/CodeAttribute.java
index 0afd5dc..970d0b7 100644
--- a/src/proguard/classfile/attribute/CodeAttribute.java
+++ b/core/src/proguard/classfile/attribute/CodeAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -32,6 +32,11 @@
*/
public class CodeAttribute extends Attribute
{
+ private static final byte[] EMPTY_CODE = new byte[0];
+ private static final ExceptionInfo[] EMPTY_EXCEPTION_TABLE = new ExceptionInfo[0];
+ private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0];
+
+
public int u2maxStack;
public int u2maxLocals;
public int u4codeLength;
@@ -50,6 +55,41 @@ public CodeAttribute()
}
+ /**
+ * Creates a partially initialized CodeAttribute without code, exceptions,
+ * or attributes.
+ */
+ public CodeAttribute(int u2attributeNameIndex)
+ {
+ this(u2attributeNameIndex,
+ 0,
+ 0,
+ 0,
+ EMPTY_CODE);
+ }
+
+
+ /**
+ * Creates an initialized CodeAttribute without exceptions or attributes.
+ */
+ public CodeAttribute(int u2attributeNameIndex,
+ int u2maxStack,
+ int u2maxLocals,
+ int u4codeLength,
+ byte[] code)
+ {
+ this(u2attributeNameIndex,
+ u2maxStack,
+ u2maxLocals,
+ u4codeLength,
+ code,
+ 0,
+ EMPTY_EXCEPTION_TABLE,
+ 0,
+ EMPTY_ATTRIBUTES);
+ }
+
+
/**
* Creates an initialized CodeAttribute.
*/
diff --git a/src/proguard/classfile/attribute/ConstantValueAttribute.java b/core/src/proguard/classfile/attribute/ConstantValueAttribute.java
similarity index 96%
rename from src/proguard/classfile/attribute/ConstantValueAttribute.java
rename to core/src/proguard/classfile/attribute/ConstantValueAttribute.java
index c4d9d80..66fa84a 100644
--- a/src/proguard/classfile/attribute/ConstantValueAttribute.java
+++ b/core/src/proguard/classfile/attribute/ConstantValueAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/DeprecatedAttribute.java b/core/src/proguard/classfile/attribute/DeprecatedAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/DeprecatedAttribute.java
rename to core/src/proguard/classfile/attribute/DeprecatedAttribute.java
index ad3ac4b..326a7e5 100644
--- a/src/proguard/classfile/attribute/DeprecatedAttribute.java
+++ b/core/src/proguard/classfile/attribute/DeprecatedAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/EnclosingMethodAttribute.java b/core/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/EnclosingMethodAttribute.java
rename to core/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
index a01fc5a..75c0e76 100644
--- a/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
+++ b/core/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/ExceptionInfo.java b/core/src/proguard/classfile/attribute/ExceptionInfo.java
similarity index 94%
rename from src/proguard/classfile/attribute/ExceptionInfo.java
rename to core/src/proguard/classfile/attribute/ExceptionInfo.java
index 5c35e6f..d0550b7 100644
--- a/src/proguard/classfile/attribute/ExceptionInfo.java
+++ b/core/src/proguard/classfile/attribute/ExceptionInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -45,12 +45,11 @@ public class ExceptionInfo implements VisitorAccepter
*/
public ExceptionInfo()
{
- this(0, 0, 0, 0);
}
/**
- * Creates an ExceptionInfo with the given properties.
+ * Creates an initialized ExceptionInfo.
*/
public ExceptionInfo(int u2startPC,
int u2endPC,
diff --git a/src/proguard/classfile/attribute/ExceptionsAttribute.java b/core/src/proguard/classfile/attribute/ExceptionsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/ExceptionsAttribute.java
rename to core/src/proguard/classfile/attribute/ExceptionsAttribute.java
index a47fc57..e2487ee 100644
--- a/src/proguard/classfile/attribute/ExceptionsAttribute.java
+++ b/core/src/proguard/classfile/attribute/ExceptionsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/ExtendedLineNumberInfo.java b/core/src/proguard/classfile/attribute/ExtendedLineNumberInfo.java
similarity index 96%
rename from src/proguard/classfile/attribute/ExtendedLineNumberInfo.java
rename to core/src/proguard/classfile/attribute/ExtendedLineNumberInfo.java
index 8f910bd..ff902ec 100644
--- a/src/proguard/classfile/attribute/ExtendedLineNumberInfo.java
+++ b/core/src/proguard/classfile/attribute/ExtendedLineNumberInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/InnerClassesAttribute.java b/core/src/proguard/classfile/attribute/InnerClassesAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/InnerClassesAttribute.java
rename to core/src/proguard/classfile/attribute/InnerClassesAttribute.java
index bb81ece..eb493de 100644
--- a/src/proguard/classfile/attribute/InnerClassesAttribute.java
+++ b/core/src/proguard/classfile/attribute/InnerClassesAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/InnerClassesInfo.java b/core/src/proguard/classfile/attribute/InnerClassesInfo.java
similarity index 85%
rename from src/proguard/classfile/attribute/InnerClassesInfo.java
rename to core/src/proguard/classfile/attribute/InnerClassesInfo.java
index 21938ea..10a8f32 100644
--- a/src/proguard/classfile/attribute/InnerClassesInfo.java
+++ b/core/src/proguard/classfile/attribute/InnerClassesInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,31 +41,6 @@ public class InnerClassesInfo implements VisitorAccepter
public Object visitorInfo;
- /**
- * Returns the inner class index.
- */
- protected int getInnerClassIndex()
- {
- return u2innerClassIndex;
- }
-
- /**
- * Returns the name index.
- */
- protected int getInnerNameIndex()
- {
- return u2innerNameIndex;
- }
-
- /**
- * Sets the name index.
- */
- protected void setInnerNameIndex(int index)
- {
- u2innerNameIndex = index;
- }
-
-
/**
* Applies the given constant pool visitor to the class constant of the
* inner class, if any.
diff --git a/src/proguard/classfile/attribute/LineNumberInfo.java b/core/src/proguard/classfile/attribute/LineNumberInfo.java
similarity index 96%
rename from src/proguard/classfile/attribute/LineNumberInfo.java
rename to core/src/proguard/classfile/attribute/LineNumberInfo.java
index ab0ee32..0d6786b 100644
--- a/src/proguard/classfile/attribute/LineNumberInfo.java
+++ b/core/src/proguard/classfile/attribute/LineNumberInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/LineNumberTableAttribute.java b/core/src/proguard/classfile/attribute/LineNumberTableAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/LineNumberTableAttribute.java
rename to core/src/proguard/classfile/attribute/LineNumberTableAttribute.java
index bc9dd4d..99b538f 100644
--- a/src/proguard/classfile/attribute/LineNumberTableAttribute.java
+++ b/core/src/proguard/classfile/attribute/LineNumberTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/LocalVariableInfo.java b/core/src/proguard/classfile/attribute/LocalVariableInfo.java
similarity index 98%
rename from src/proguard/classfile/attribute/LocalVariableInfo.java
rename to core/src/proguard/classfile/attribute/LocalVariableInfo.java
index 3cdc66e..274b3fe 100644
--- a/src/proguard/classfile/attribute/LocalVariableInfo.java
+++ b/core/src/proguard/classfile/attribute/LocalVariableInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/LocalVariableTableAttribute.java b/core/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/LocalVariableTableAttribute.java
rename to core/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
index 67fe031..0338208 100644
--- a/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
+++ b/core/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/LocalVariableTypeInfo.java b/core/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
similarity index 98%
rename from src/proguard/classfile/attribute/LocalVariableTypeInfo.java
rename to core/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
index 918d099..e060494 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
+++ b/core/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/LocalVariableTypeTableAttribute.java b/core/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
rename to core/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
index 1c64434..db9f488 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
+++ b/core/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/MethodParametersAttribute.java b/core/src/proguard/classfile/attribute/MethodParametersAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/MethodParametersAttribute.java
rename to core/src/proguard/classfile/attribute/MethodParametersAttribute.java
index 30086ae..079d3bd 100644
--- a/src/proguard/classfile/attribute/MethodParametersAttribute.java
+++ b/core/src/proguard/classfile/attribute/MethodParametersAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/ParameterInfo.java b/core/src/proguard/classfile/attribute/ParameterInfo.java
similarity index 81%
rename from src/proguard/classfile/attribute/ParameterInfo.java
rename to core/src/proguard/classfile/attribute/ParameterInfo.java
index e0a8f32..4f1200d 100644
--- a/src/proguard/classfile/attribute/ParameterInfo.java
+++ b/core/src/proguard/classfile/attribute/ParameterInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
package proguard.classfile.attribute;
import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
/**
* Representation of a parameter, as defined in a method parameters
@@ -67,6 +68,19 @@ public String getName(Clazz clazz)
}
+ /**
+ * Applies the given constant pool visitor to the Utf8 constant that
+ * represents the name of the parameter, if any.
+ */
+ public void nameConstantAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2nameIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2nameIndex, constantVisitor);
+ }
+ }
+
+
// Implementations for VisitorAccepter.
public Object getVisitorInfo()
diff --git a/src/proguard/classfile/attribute/SignatureAttribute.java b/core/src/proguard/classfile/attribute/SignatureAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/SignatureAttribute.java
rename to core/src/proguard/classfile/attribute/SignatureAttribute.java
index 943056f..20ec26b 100644
--- a/src/proguard/classfile/attribute/SignatureAttribute.java
+++ b/core/src/proguard/classfile/attribute/SignatureAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/SourceDirAttribute.java b/core/src/proguard/classfile/attribute/SourceDirAttribute.java
similarity index 96%
rename from src/proguard/classfile/attribute/SourceDirAttribute.java
rename to core/src/proguard/classfile/attribute/SourceDirAttribute.java
index 10328cf..cc46f59 100644
--- a/src/proguard/classfile/attribute/SourceDirAttribute.java
+++ b/core/src/proguard/classfile/attribute/SourceDirAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/SourceFileAttribute.java b/core/src/proguard/classfile/attribute/SourceFileAttribute.java
similarity index 96%
rename from src/proguard/classfile/attribute/SourceFileAttribute.java
rename to core/src/proguard/classfile/attribute/SourceFileAttribute.java
index 86535b4..a3c5cd0 100644
--- a/src/proguard/classfile/attribute/SourceFileAttribute.java
+++ b/core/src/proguard/classfile/attribute/SourceFileAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/SyntheticAttribute.java b/core/src/proguard/classfile/attribute/SyntheticAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/SyntheticAttribute.java
rename to core/src/proguard/classfile/attribute/SyntheticAttribute.java
index b3120db..fbfb80c 100644
--- a/src/proguard/classfile/attribute/SyntheticAttribute.java
+++ b/core/src/proguard/classfile/attribute/SyntheticAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/UnknownAttribute.java b/core/src/proguard/classfile/attribute/UnknownAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/UnknownAttribute.java
rename to core/src/proguard/classfile/attribute/UnknownAttribute.java
index 6654bf6..41dfccc 100644
--- a/src/proguard/classfile/attribute/UnknownAttribute.java
+++ b/core/src/proguard/classfile/attribute/UnknownAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/Annotation.java b/core/src/proguard/classfile/attribute/annotation/Annotation.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/Annotation.java
rename to core/src/proguard/classfile/attribute/annotation/Annotation.java
index 1b02799..19ed8b1 100644
--- a/src/proguard/classfile/attribute/annotation/Annotation.java
+++ b/core/src/proguard/classfile/attribute/annotation/Annotation.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/AnnotationDefaultAttribute.java b/core/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
index 85fc792..8895419 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/AnnotationElementValue.java b/core/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
index b957f82..25d5217 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/AnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
index 167710e..6aba0ae 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/ArrayElementValue.java b/core/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/ArrayElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
index 06c8417..589f12a 100644
--- a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/ClassElementValue.java b/core/src/proguard/classfile/attribute/annotation/ClassElementValue.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/ClassElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/ClassElementValue.java
index 945d280..1a60974 100644
--- a/src/proguard/classfile/attribute/annotation/ClassElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/ClassElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/ConstantElementValue.java b/core/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/ConstantElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
index 0e7a4b6..86b3c47 100644
--- a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/ElementValue.java b/core/src/proguard/classfile/attribute/annotation/ElementValue.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/ElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/ElementValue.java
index 8d18c1f..c252c0f 100644
--- a/src/proguard/classfile/attribute/annotation/ElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/ElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/EnumConstantElementValue.java b/core/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
rename to core/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
index 8a82cd7..fe1d5dc 100644
--- a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
+++ b/core/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/ParameterAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
index 666762f..177c7f2 100644
--- a/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
index 6e2a416..5a0160f 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
index b9772bd..ce920b6 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java
index 6addf96..d265ced 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeInvisibleTypeAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
index 7b5ff00..ceeca39 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
index a1a2e1a..b2d3330 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java
index 2652a1f..66c049e 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/RuntimeVisibleTypeAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/TypeAnnotation.java b/core/src/proguard/classfile/attribute/annotation/TypeAnnotation.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/TypeAnnotation.java
rename to core/src/proguard/classfile/attribute/annotation/TypeAnnotation.java
index 1246dfa..4586190 100644
--- a/src/proguard/classfile/attribute/annotation/TypeAnnotation.java
+++ b/core/src/proguard/classfile/attribute/annotation/TypeAnnotation.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/TypeAnnotationsAttribute.java b/core/src/proguard/classfile/attribute/annotation/TypeAnnotationsAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/TypeAnnotationsAttribute.java
rename to core/src/proguard/classfile/attribute/annotation/TypeAnnotationsAttribute.java
index 644d045..6423ab9 100644
--- a/src/proguard/classfile/attribute/annotation/TypeAnnotationsAttribute.java
+++ b/core/src/proguard/classfile/attribute/annotation/TypeAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/TypePathInfo.java b/core/src/proguard/classfile/attribute/annotation/TypePathInfo.java
similarity index 96%
rename from src/proguard/classfile/attribute/annotation/TypePathInfo.java
rename to core/src/proguard/classfile/attribute/annotation/TypePathInfo.java
index 1aa91f2..f566962 100644
--- a/src/proguard/classfile/attribute/annotation/TypePathInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/TypePathInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/package.html b/core/src/proguard/classfile/attribute/annotation/package.html
similarity index 100%
rename from src/proguard/classfile/attribute/annotation/package.html
rename to core/src/proguard/classfile/attribute/annotation/package.html
diff --git a/src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java
similarity index 93%
rename from src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java
index 81c709d..44bd4e4 100644
--- a/src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/CatchTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -55,8 +55,8 @@ public CatchTargetInfo(byte u1targetType)
/**
* Creates an initialized CatchTargetInfo.
*/
- protected CatchTargetInfo(byte u1targetType,
- int u2exceptionTableIndex)
+ public CatchTargetInfo(byte u1targetType,
+ int u2exceptionTableIndex)
{
super(u1targetType);
diff --git a/src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java
index 6b6a9c9..940b97b 100644
--- a/src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/EmptyTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/FormalParameterTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/FormalParameterTargetInfo.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/target/FormalParameterTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/FormalParameterTargetInfo.java
index 07906f5..0a621e2 100644
--- a/src/proguard/classfile/attribute/annotation/target/FormalParameterTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/FormalParameterTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/LocalVariableTargetElement.java b/core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetElement.java
similarity index 96%
rename from src/proguard/classfile/attribute/annotation/target/LocalVariableTargetElement.java
rename to core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetElement.java
index 85e3a68..89d48fd 100644
--- a/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetElement.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetElement.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/LocalVariableTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetInfo.java
similarity index 91%
rename from src/proguard/classfile/attribute/annotation/target/LocalVariableTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetInfo.java
index 7e532fc..5c4520e 100644
--- a/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/LocalVariableTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -56,9 +56,9 @@ public LocalVariableTargetInfo(byte u1targetType)
/**
* Creates an initialized LocalVariableTargetInfo.
*/
- protected LocalVariableTargetInfo(byte u1targetType,
- int u2tableLength,
- LocalVariableTargetElement[] table)
+ public LocalVariableTargetInfo(byte u1targetType,
+ int u2tableLength,
+ LocalVariableTargetElement[] table)
{
super(u1targetType);
diff --git a/src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java
similarity index 93%
rename from src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java
index 6eb7e98..026978c 100644
--- a/src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/OffsetTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -55,8 +55,8 @@ public OffsetTargetInfo(byte u1targetType)
/**
* Creates an initialized OffsetTargetInfo.
*/
- protected OffsetTargetInfo(byte u1targetType,
- int u2offset)
+ public OffsetTargetInfo(byte u1targetType,
+ int u2offset)
{
super(u1targetType);
diff --git a/src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java
similarity index 95%
rename from src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java
index 6bb82f0..e3e9fc4 100644
--- a/src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/SuperTypeTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,9 @@
*/
public class SuperTypeTargetInfo extends TargetInfo
{
+ public final int EXTENDS_INDEX = 65535;
+
+
public int u2superTypeIndex;
diff --git a/src/proguard/classfile/attribute/annotation/target/TargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/TargetInfo.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/target/TargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/TargetInfo.java
index 138942f..fa0e34f 100644
--- a/src/proguard/classfile/attribute/annotation/target/TargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/TargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/ThrowsTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/ThrowsTargetInfo.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/target/ThrowsTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/ThrowsTargetInfo.java
index c42a45b..725d3d9 100644
--- a/src/proguard/classfile/attribute/annotation/target/ThrowsTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/ThrowsTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java
similarity index 91%
rename from src/proguard/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java
index deb6eaa..bf4df77 100644
--- a/src/proguard/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/TypeArgumentTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -56,9 +56,9 @@ public TypeArgumentTargetInfo(byte u1targetType)
/**
* Creates an initialized TypeArgumentTargetInfo.
*/
- protected TypeArgumentTargetInfo(byte u1targetType,
- int u2offset,
- int u1typeArgumentIndex)
+ public TypeArgumentTargetInfo(byte u1targetType,
+ int u2offset,
+ int u1typeArgumentIndex)
{
super(u1targetType);
diff --git a/src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java
index 6c628ad..36e6361 100644
--- a/src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/TypeParameterBoundTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/TypeParameterTargetInfo.java b/core/src/proguard/classfile/attribute/annotation/target/TypeParameterTargetInfo.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/target/TypeParameterTargetInfo.java
rename to core/src/proguard/classfile/attribute/annotation/target/TypeParameterTargetInfo.java
index 06f2b57..c08a67a 100644
--- a/src/proguard/classfile/attribute/annotation/target/TypeParameterTargetInfo.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/TypeParameterTargetInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java b/core/src/proguard/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java
index 659a0ff..43b0507 100644
--- a/src/proguard/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/visitor/LocalVariableTargetElementVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java b/core/src/proguard/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java
index fef99f1..29e5606 100644
--- a/src/proguard/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/target/visitor/TargetInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
similarity index 99%
rename from src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
index cead20c..cd52e02 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/AllElementValueVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
similarity index 99%
rename from src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
index 3e9bf0f..1847856 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedClassVisitor.java
similarity index 91%
rename from src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedClassVisitor.java
index 646b5ab..5703b71 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@
*
* @author Eric Lafortune
*/
-public class AnnotatedClassVisitor
+public class AnnotationToAnnotatedClassVisitor
extends SimplifiedVisitor
implements AnnotationVisitor
{
@@ -42,7 +42,7 @@ public class AnnotatedClassVisitor
private Clazz lastVisitedClass;
- public AnnotatedClassVisitor(ClassVisitor classVisitor)
+ public AnnotationToAnnotatedClassVisitor(ClassVisitor classVisitor)
{
this.classVisitor = classVisitor;
}
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedMemberVisitor.java
similarity index 91%
rename from src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedMemberVisitor.java
index c21dcd6..1a30c79 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationToAnnotatedMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@
*
* @author Eric Lafortune
*/
-public class AnnotationToMemberVisitor
+public class AnnotationToAnnotatedMemberVisitor
extends SimplifiedVisitor
implements AnnotationVisitor
{
@@ -42,7 +42,7 @@ public class AnnotationToMemberVisitor
private Member lastVisitedMember;
- public AnnotationToMemberVisitor(MemberVisitor memberVisitor)
+ public AnnotationToAnnotatedMemberVisitor(MemberVisitor memberVisitor)
{
this.memberVisitor = memberVisitor;
}
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
similarity index 62%
rename from src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
index 0d5a6e6..d5247f8 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +25,8 @@
import proguard.classfile.attribute.annotation.Annotation;
import proguard.util.*;
+import java.util.List;
+
/**
* This AnnotationVisitor delegates its visits to another given
* AnnotationVisitor, but only when the visited annotation has
@@ -40,16 +42,49 @@ public class AnnotationTypeFilter
/**
- * Creates a new ClassNameFilter.
- * @param regularExpression the regular expression against which annotation
- * type names will be matched.
- * @param annotationVisitor the annotationVisitor to which
- * visits will be delegated.
+ * Creates a new AnnotationTypeFilter.
+ * @param regularExpression the regular expression against which
+ * annotation type names will be matched.
+ * @param annotationVisitor the annotation visitor to which visits
+ * will be delegated.
+ */
+ public AnnotationTypeFilter(String regularExpression,
+ AnnotationVisitor annotationVisitor)
+ {
+ this(regularExpression, null, annotationVisitor);
+ }
+
+
+ /**
+ * Creates a new AnnotationTypeFilter.
+ * @param regularExpression the regular expression against which
+ * annotation type names will be matched.
+ * @param variableStringMatchers an optional mutable list of
+ * VariableStringMatcher instances that match
+ * the wildcards.
+ * @param annotationVisitor the annotation visitor to which visits
+ * will be delegated.
*/
public AnnotationTypeFilter(String regularExpression,
+ List variableStringMatchers,
+ AnnotationVisitor annotationVisitor)
+ {
+ this(new ListParser(new ClassNameParser()).parse(regularExpression),
+ annotationVisitor);
+ }
+
+
+ /**
+ * Creates a new AnnotationTypeFilter.
+ * @param regularExpressionMatcher the string matcher against which
+ * class names will be matched.
+ * @param annotationVisitor the annotation visitor to which visits
+ * will be delegated.
+ */
+ public AnnotationTypeFilter(StringMatcher regularExpressionMatcher,
AnnotationVisitor annotationVisitor)
{
- this.regularExpressionMatcher = new ListParser(new ClassNameParser()).parse(regularExpression);
+ this.regularExpressionMatcher = regularExpressionMatcher;
this.annotationVisitor = annotationVisitor;
}
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
index b9c93e9..e1c3a8f 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/ElementValueVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
similarity index 98%
rename from src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
index 076c042..7864b21 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java
index 3a2f4fd..c7c63fa 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/TypeAnnotationVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java b/core/src/proguard/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java
rename to core/src/proguard/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java
index 34bfa08..62c04ef 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/annotation/visitor/TypePathInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/annotation/visitor/package.html b/core/src/proguard/classfile/attribute/annotation/visitor/package.html
similarity index 100%
rename from src/proguard/classfile/attribute/annotation/visitor/package.html
rename to core/src/proguard/classfile/attribute/annotation/visitor/package.html
diff --git a/core/src/proguard/classfile/attribute/module/ExportsInfo.java b/core/src/proguard/classfile/attribute/module/ExportsInfo.java
new file mode 100644
index 0000000..6599c27
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/ExportsInfo.java
@@ -0,0 +1,106 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * Representation of a Exports entry in a Module attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ExportsInfo implements VisitorAccepter
+{
+ public int u2exportsIndex;
+ public int u2exportsFlags;
+ public int u2exportsToCount;
+ public int[] u2exportsToIndex;
+
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates an uninitialized ExportsInfo.
+ */
+ public ExportsInfo()
+ {
+ }
+
+
+ /**
+ * Creates an initialized ExportsInfo.
+ */
+ public ExportsInfo(int u2exportsIndex,
+ int u2exportsFlags,
+ int u2exportsToCount,
+ int[] u2exportsToIndex)
+ {
+ this.u2exportsIndex = u2exportsIndex;
+ this.u2exportsFlags = u2exportsFlags;
+ this.u2exportsToCount = u2exportsToCount;
+ this.u2exportsToIndex = u2exportsToIndex;
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the package constant of the
+ * package, if any.
+ */
+ public void packageAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2exportsIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2exportsIndex, constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all exportsToIndex.
+ */
+ public void exportsToIndexAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ // Loop over all exportsToIndex.
+ for (int index = 0; index < u2exportsToCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2exportsToIndex[index], constantVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/ModuleAttribute.java b/core/src/proguard/classfile/attribute/module/ModuleAttribute.java
new file mode 100644
index 0000000..84a9efb
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/ModuleAttribute.java
@@ -0,0 +1,195 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.attribute.module.visitor.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * This Attribute represents a module attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ModuleAttribute extends Attribute
+{
+ public int u2moduleNameIndex;
+ public int u2moduleFlags;
+ public int u2moduleVersionIndex;
+ public int u2requiresCount;
+ public RequiresInfo[] requires;
+ public int u2exportsCount;
+ public ExportsInfo[] exports;
+ public int u2opensCount;
+ public OpensInfo[] opens;
+ public int u2usesCount;
+ public int[] u2uses;
+ public int u2providesCount;
+ public ProvidesInfo[] provides;
+
+
+ /**
+ * Creates an uninitialized ModuleAttribute.
+ */
+ public ModuleAttribute()
+ {
+ }
+
+
+ /**
+ * Creates an initialized ModuleAttribute.
+ */
+ public ModuleAttribute(int u2attributeNameIndex,
+ int u2moduleNameIndex,
+ int u2moduleFlags,
+ int u2moduleVersionIndex,
+ int u2requiresCount,
+ RequiresInfo[] requires,
+ int u2exportsCount,
+ ExportsInfo[] exports,
+ int u2opensCount,
+ OpensInfo[] opens,
+ int u2usesCount,
+ int[] u2uses,
+ int u2ProvidesCount,
+ ProvidesInfo[] provides)
+ {
+ super(u2attributeNameIndex);
+
+ this.u2moduleNameIndex = u2moduleNameIndex;
+ this.u2moduleFlags = u2moduleFlags;
+ this.u2moduleVersionIndex = u2moduleVersionIndex;
+ this.u2requiresCount = u2requiresCount;
+ this.requires = requires;
+ this.u2exportsCount = u2exportsCount;
+ this.exports = exports;
+ this.u2opensCount = u2opensCount;
+ this.opens = opens;
+ this.u2usesCount = u2usesCount;
+ this.u2uses = u2uses;
+ this.u2providesCount = u2ProvidesCount;
+ this.provides = provides;
+ }
+
+
+ // Implementations for Attribute.
+
+ public void accept(Clazz clazz, AttributeVisitor attributeVisitor)
+ {
+ attributeVisitor.visitModuleAttribute(clazz, this);
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the Utf8 constant of the name,
+ * if any.
+ */
+ public void nameAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2moduleNameIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2moduleNameIndex, constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the Utf8 constant of the
+ * version, if any.
+ */
+ public void versionAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2moduleVersionIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2moduleVersionIndex, constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given visitor to all requires.
+ */
+ public void requiresAccept(Clazz clazz, RequiresInfoVisitor requiresInfoVisitor)
+ {
+ for (int index = 0; index < u2requiresCount; index++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of RequiresInfo.
+ requiresInfoVisitor.visitRequiresInfo(clazz, requires[index]);
+ }
+ }
+
+
+ /**
+ * Applies the given visitor to all exports.
+ */
+ public void exportsAccept(Clazz clazz, ExportsInfoVisitor exportsInfoVisitor)
+ {
+ for (int index = 0; index < u2exportsCount; index++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of ExportsInfo.
+ exportsInfoVisitor.visitExportsInfo(clazz, exports[index]);
+ }
+ }
+
+
+ /**
+ * Applies the given visitor to all exports.
+ */
+ public void opensAccept(Clazz clazz, OpensInfoVisitor opensInfoVisitor)
+ {
+ for (int index = 0; index < u2opensCount; index++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of OpensInfo.
+ opensInfoVisitor.visitOpensInfo(clazz, opens[index]);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all uses.
+ */
+ public void usesAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ for (int index = 0; index < u2usesCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2uses[index], constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given visitor to all provides.
+ */
+ public void providesAccept(Clazz clazz, ProvidesInfoVisitor providesInfoVisitor)
+ {
+ for (int index = 0; index < u2providesCount; index++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of ProvidesInfo.
+ providesInfoVisitor.visitProvidesInfo(clazz, provides[index]);
+ }
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/ModuleMainClassAttribute.java b/core/src/proguard/classfile/attribute/module/ModuleMainClassAttribute.java
new file mode 100644
index 0000000..c929c39
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/ModuleMainClassAttribute.java
@@ -0,0 +1,76 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This Attribute represents a main class attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ModuleMainClassAttribute extends Attribute
+{
+ public int u2mainClass;
+
+
+ /**
+ * Creates an uninitialized ModuleMainClassAttribute.
+ */
+ public ModuleMainClassAttribute()
+ {
+ }
+
+
+ /**
+ * Creates an initialized ModuleMainClassAttribute.
+ */
+ public ModuleMainClassAttribute(int u2attributeNameIndex, int u2mainClass)
+ {
+ super(u2attributeNameIndex);
+ this.u2mainClass = u2mainClass;
+ }
+
+
+ // Implementations for Attribute.
+
+ public void accept(Clazz clazz, AttributeVisitor attributeVisitor)
+ {
+ attributeVisitor.visitModuleMainClassAttribute(clazz, this);
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the class constant of the
+ * main class, if any.
+ */
+ public void mainClassAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2mainClass != 0)
+ {
+ clazz.constantPoolEntryAccept(u2mainClass, constantVisitor);
+ }
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/ModulePackagesAttribute.java b/core/src/proguard/classfile/attribute/module/ModulePackagesAttribute.java
new file mode 100644
index 0000000..6a01f36
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/ModulePackagesAttribute.java
@@ -0,0 +1,79 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * This Attribute represents a module packages attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ModulePackagesAttribute extends Attribute
+{
+ public int u2packagesCount;
+ public int[] u2packages;
+
+
+ /**
+ * Creates an uninitialized ModulePackagesAttribute.
+ */
+ public ModulePackagesAttribute()
+ {
+ }
+
+
+ /**
+ * Creates an initialized ModulePackagesAttribute.
+ */
+ public ModulePackagesAttribute(int u2attributeNameIndex,
+ int u2packagesCount,
+ int[] u2packages)
+ {
+ super(u2attributeNameIndex);
+ this.u2packagesCount = u2packagesCount;
+ this.u2packages = u2packages;
+ }
+
+
+ // Implementations for Attribute.
+
+ public void accept(Clazz clazz, AttributeVisitor attributeVisitor)
+ {
+ attributeVisitor.visitModulePackagesAttribute(clazz, this);
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all packages.
+ */
+ public void packagesAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ // Loop over all packages.
+ for (int index = 0; index < u2packagesCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2packages[index], constantVisitor);
+ }
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/OpensInfo.java b/core/src/proguard/classfile/attribute/module/OpensInfo.java
new file mode 100644
index 0000000..70eb402
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/OpensInfo.java
@@ -0,0 +1,106 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * Representation of a Opens entry in a Module attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class OpensInfo implements VisitorAccepter
+{
+ public int u2opensIndex;
+ public int u2opensFlags;
+ public int u2opensToCount;
+ public int[] u2opensToIndex;
+
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates an uninitialized OpensInfo.
+ */
+ public OpensInfo()
+ {
+ }
+
+
+ /**
+ * Creates an initialized OpensInfo.
+ */
+ public OpensInfo(int u2opensIndex,
+ int u2opensFlags,
+ int u2opensToCount,
+ int[] u2opensToIndex)
+ {
+ this.u2opensIndex = u2opensIndex;
+ this.u2opensFlags = u2opensFlags;
+ this.u2opensToCount = u2opensToCount;
+ this.u2opensToIndex = u2opensToIndex;
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the package constant of the
+ * package, if any.
+ */
+ public void packageAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2opensIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2opensIndex, constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all targets.
+ */
+ public void targetsAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ // Loop over all targets.
+ for (int index = 0; index < u2opensToCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2opensToIndex[index], constantVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/ProvidesInfo.java b/core/src/proguard/classfile/attribute/module/ProvidesInfo.java
new file mode 100644
index 0000000..c1a0427
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/ProvidesInfo.java
@@ -0,0 +1,103 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * Representation of a Provides entry in a Module attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ProvidesInfo implements VisitorAccepter
+{
+ public int u2providesIndex;
+ public int u2providesWithCount;
+ public int[] u2providesWithIndex;
+
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates an uninitialized ProvidesInfo.
+ */
+ public ProvidesInfo()
+ {
+ }
+
+
+ /**
+ * Creates an initialized ProvidesInfo.
+ */
+ public ProvidesInfo(int u2providesIndex,
+ int u2providesWithCount,
+ int[] u2providesWithIndex)
+ {
+ this.u2providesIndex = u2providesIndex;
+ this.u2providesWithCount = u2providesWithCount;
+ this.u2providesWithIndex = u2providesWithIndex;
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the class constant of the
+ * provides, if any.
+ */
+ public void providesAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2providesIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2providesIndex, constantVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all with entries.
+ */
+ public void withAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ // Loop over all u2providesWithIndex entries.
+ for (int index = 0; index < u2providesWithCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2providesWithIndex[index], constantVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/RequiresInfo.java b/core/src/proguard/classfile/attribute/module/RequiresInfo.java
new file mode 100644
index 0000000..b3b86ca
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/RequiresInfo.java
@@ -0,0 +1,102 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * Representation of a Requires entry in a Module attribute.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class RequiresInfo implements VisitorAccepter
+{
+ public int u2requiresIndex;
+ public int u2requiresFlags;
+ public int u2requiresVersionIndex;
+
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates an uninitialized RequiresInfo.
+ */
+ public RequiresInfo()
+ {
+ }
+
+
+ /**
+ * Creates an uninitialized RequiresInfo.
+ */
+ public RequiresInfo(int u2requiresIndex,
+ int u2requiresFlags,
+ int u2requiresVersionIndex)
+ {
+ this.u2requiresIndex = u2requiresIndex;
+ this.u2requiresFlags = u2requiresFlags;
+ this.u2requiresVersionIndex = u2requiresVersionIndex;
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the module constant of the
+ * module, if any.
+ */
+ public void moduleAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2requiresIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2requiresIndex, constantVisitor);
+ }
+ }
+
+ /**
+ * Applies the given constant pool visitor to the Utf8 constant of the
+ * version, if any.
+ */
+ public void versionAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ if (u2requiresVersionIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(u2requiresVersionIndex, constantVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/package.html b/core/src/proguard/classfile/attribute/module/package.html
new file mode 100644
index 0000000..1e5d11b
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/package.html
@@ -0,0 +1,4 @@
+
+This package contains classes to represent the module attributes inside class
+files.
+
diff --git a/core/src/proguard/classfile/attribute/module/visitor/AllExportsInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/AllExportsInfoVisitor.java
new file mode 100644
index 0000000..5eef7d9
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/AllExportsInfoVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.module.ModuleAttribute;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given ExportsInfoVisitor visit all
+ * ExportsInfo objects of the ModuleAttribute objects it visits.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class AllExportsInfoVisitor
+extends SimplifiedVisitor
+ implements AttributeVisitor
+{
+ private final ExportsInfoVisitor exportsInfoVisitor;
+
+
+ public AllExportsInfoVisitor(ExportsInfoVisitor exportsInfoVisitor)
+ {
+ this.exportsInfoVisitor = exportsInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.exportsAccept(clazz, exportsInfoVisitor);
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/AllOpensInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/AllOpensInfoVisitor.java
new file mode 100644
index 0000000..65fe4f2
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/AllOpensInfoVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.attribute.module.ModuleAttribute;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given OpensInfoVisitor visit all
+ * OpensInfo objects of the ModuleAttribute objects it visits.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class AllOpensInfoVisitor
+extends SimplifiedVisitor
+ implements AttributeVisitor
+{
+ private final OpensInfoVisitor opensInfoVisitor;
+
+
+ public AllOpensInfoVisitor(OpensInfoVisitor opensInfoVisitor)
+ {
+ this.opensInfoVisitor = opensInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.opensAccept(clazz, opensInfoVisitor);
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/AllProvidesInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/AllProvidesInfoVisitor.java
new file mode 100644
index 0000000..fd7834c
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/AllProvidesInfoVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.module.ModuleAttribute;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given ProvidesInfoVisitor visit all
+ * ProvidesInfo objects of the ModuleAttribute objects it visits.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class AllProvidesInfoVisitor
+extends SimplifiedVisitor
+ implements AttributeVisitor
+{
+ private final ProvidesInfoVisitor providesInfoVisitor;
+
+
+ public AllProvidesInfoVisitor(ProvidesInfoVisitor providesInfoVisitor)
+ {
+ this.providesInfoVisitor = providesInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.providesAccept(clazz, providesInfoVisitor);
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/AllRequiresInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/AllRequiresInfoVisitor.java
new file mode 100644
index 0000000..1dbe261
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/AllRequiresInfoVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.module.ModuleAttribute;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given RequiresInfoVisitor visit all
+ * RequiresInfo objects of the ModuleAttribute objects it visits.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class AllRequiresInfoVisitor
+extends SimplifiedVisitor
+ implements AttributeVisitor
+{
+ private final RequiresInfoVisitor requiresInfoVisitor;
+
+
+ public AllRequiresInfoVisitor(RequiresInfoVisitor requiresInfoVisitor)
+ {
+ this.requiresInfoVisitor = requiresInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.requiresAccept(clazz, requiresInfoVisitor);
+ }
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/ExportsInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/ExportsInfoVisitor.java
new file mode 100644
index 0000000..a57a6d4
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/ExportsInfoVisitor.java
@@ -0,0 +1,37 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.module.ExportsInfo;
+
+/**
+ * This interface specifies the methods for a visitor of
+ * ExportsInfo objects. Note that there is only a single
+ * implementation of ExportsInfo, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Joachim Vandersmissen
+ */
+public interface ExportsInfoVisitor
+{
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo);
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/OpensInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/OpensInfoVisitor.java
new file mode 100644
index 0000000..551ee5b
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/OpensInfoVisitor.java
@@ -0,0 +1,37 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.module.*;
+
+/**
+ * This interface specifies the methods for a visitor of
+ * OpensInfo objects. Note that there is only a single
+ * implementation of OpensInfo, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Joachim Vandersmissen
+ */
+public interface OpensInfoVisitor
+{
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo);
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/ProvidesInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/ProvidesInfoVisitor.java
new file mode 100644
index 0000000..50e3e64
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/ProvidesInfoVisitor.java
@@ -0,0 +1,37 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.module.ProvidesInfo;
+
+/**
+ * This interface specifies the methods for a visitor of
+ * ProvidesInfo objects. Note that there is only a single
+ * implementation of ProvidesInfo, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Joachim Vandersmissen
+ */
+public interface ProvidesInfoVisitor
+{
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo);
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/RequiresInfoVisitor.java b/core/src/proguard/classfile/attribute/module/visitor/RequiresInfoVisitor.java
new file mode 100644
index 0000000..4bad50c
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/RequiresInfoVisitor.java
@@ -0,0 +1,37 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.module.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.module.RequiresInfo;
+
+/**
+ * This interface specifies the methods for a visitor of
+ * RequiresInfo objects. Note that there is only a single
+ * implementation of RequiresInfo, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Joachim Vandersmissen
+ */
+public interface RequiresInfoVisitor
+{
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo);
+}
diff --git a/core/src/proguard/classfile/attribute/module/visitor/package.html b/core/src/proguard/classfile/attribute/module/visitor/package.html
new file mode 100644
index 0000000..01537ff
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/module/visitor/package.html
@@ -0,0 +1,3 @@
+
+This package contains visitors for module attributes and their components.
+
diff --git a/src/proguard/classfile/attribute/package.html b/core/src/proguard/classfile/attribute/package.html
similarity index 100%
rename from src/proguard/classfile/attribute/package.html
rename to core/src/proguard/classfile/attribute/package.html
diff --git a/src/proguard/classfile/attribute/preverification/DoubleType.java b/core/src/proguard/classfile/attribute/preverification/DoubleType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/DoubleType.java
rename to core/src/proguard/classfile/attribute/preverification/DoubleType.java
index ff124d7..d76086c 100644
--- a/src/proguard/classfile/attribute/preverification/DoubleType.java
+++ b/core/src/proguard/classfile/attribute/preverification/DoubleType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/FloatType.java b/core/src/proguard/classfile/attribute/preverification/FloatType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/FloatType.java
rename to core/src/proguard/classfile/attribute/preverification/FloatType.java
index 3a8e831..8cb66a8 100644
--- a/src/proguard/classfile/attribute/preverification/FloatType.java
+++ b/core/src/proguard/classfile/attribute/preverification/FloatType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/FullFrame.java b/core/src/proguard/classfile/attribute/preverification/FullFrame.java
similarity index 99%
rename from src/proguard/classfile/attribute/preverification/FullFrame.java
rename to core/src/proguard/classfile/attribute/preverification/FullFrame.java
index 8c405d2..fe3c64f 100644
--- a/src/proguard/classfile/attribute/preverification/FullFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/FullFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/IntegerType.java b/core/src/proguard/classfile/attribute/preverification/IntegerType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/IntegerType.java
rename to core/src/proguard/classfile/attribute/preverification/IntegerType.java
index 5228b61..ebdfb4c 100644
--- a/src/proguard/classfile/attribute/preverification/IntegerType.java
+++ b/core/src/proguard/classfile/attribute/preverification/IntegerType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/LessZeroFrame.java b/core/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/LessZeroFrame.java
rename to core/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
index 4308506..055fcce 100644
--- a/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/LongType.java b/core/src/proguard/classfile/attribute/preverification/LongType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/LongType.java
rename to core/src/proguard/classfile/attribute/preverification/LongType.java
index 82b8af9..5cd4ae0 100644
--- a/src/proguard/classfile/attribute/preverification/LongType.java
+++ b/core/src/proguard/classfile/attribute/preverification/LongType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/MoreZeroFrame.java b/core/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
rename to core/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
index a885804..fef29c7 100644
--- a/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/NullType.java b/core/src/proguard/classfile/attribute/preverification/NullType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/NullType.java
rename to core/src/proguard/classfile/attribute/preverification/NullType.java
index 96003f0..658ca62 100644
--- a/src/proguard/classfile/attribute/preverification/NullType.java
+++ b/core/src/proguard/classfile/attribute/preverification/NullType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/ObjectType.java b/core/src/proguard/classfile/attribute/preverification/ObjectType.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/ObjectType.java
rename to core/src/proguard/classfile/attribute/preverification/ObjectType.java
index 5a4f1b7..8d6f384 100644
--- a/src/proguard/classfile/attribute/preverification/ObjectType.java
+++ b/core/src/proguard/classfile/attribute/preverification/ObjectType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/SameOneFrame.java b/core/src/proguard/classfile/attribute/preverification/SameOneFrame.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/SameOneFrame.java
rename to core/src/proguard/classfile/attribute/preverification/SameOneFrame.java
index 8a16762..d9f0b17 100644
--- a/src/proguard/classfile/attribute/preverification/SameOneFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/SameOneFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/SameZeroFrame.java b/core/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/SameZeroFrame.java
rename to core/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
index 90200ba..82df6ac 100644
--- a/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/StackMapAttribute.java b/core/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/StackMapAttribute.java
rename to core/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
index 5ff0a08..3757c7c 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
+++ b/core/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -64,8 +64,6 @@ public StackMapAttribute(int stackMapFramesCount,
}
-
-
// Implementations for Attribute.
public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor)
diff --git a/src/proguard/classfile/attribute/preverification/StackMapFrame.java b/core/src/proguard/classfile/attribute/preverification/StackMapFrame.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/StackMapFrame.java
rename to core/src/proguard/classfile/attribute/preverification/StackMapFrame.java
index 474650c..62168fa 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapFrame.java
+++ b/core/src/proguard/classfile/attribute/preverification/StackMapFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/StackMapTableAttribute.java b/core/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
rename to core/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
index b122221..4daf61e 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
+++ b/core/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/TopType.java b/core/src/proguard/classfile/attribute/preverification/TopType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/TopType.java
rename to core/src/proguard/classfile/attribute/preverification/TopType.java
index 065c9eb..8258f27 100644
--- a/src/proguard/classfile/attribute/preverification/TopType.java
+++ b/core/src/proguard/classfile/attribute/preverification/TopType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/UninitializedThisType.java b/core/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/UninitializedThisType.java
rename to core/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
index 21d210b..c19e439 100644
--- a/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
+++ b/core/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/UninitializedType.java b/core/src/proguard/classfile/attribute/preverification/UninitializedType.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/UninitializedType.java
rename to core/src/proguard/classfile/attribute/preverification/UninitializedType.java
index ad44e05..4cba448 100644
--- a/src/proguard/classfile/attribute/preverification/UninitializedType.java
+++ b/core/src/proguard/classfile/attribute/preverification/UninitializedType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/VerificationType.java b/core/src/proguard/classfile/attribute/preverification/VerificationType.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/VerificationType.java
rename to core/src/proguard/classfile/attribute/preverification/VerificationType.java
index 29ff241..fcf977e 100644
--- a/src/proguard/classfile/attribute/preverification/VerificationType.java
+++ b/core/src/proguard/classfile/attribute/preverification/VerificationType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/VerificationTypeFactory.java b/core/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
similarity index 98%
rename from src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
rename to core/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
index 3fca3d3..4e142d4 100644
--- a/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
+++ b/core/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java b/core/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
rename to core/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
index 910bd39..cd98800 100644
--- a/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
+++ b/core/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java b/core/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
similarity index 99%
rename from src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
rename to core/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
index 3f087d5..dab527f 100644
--- a/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
+++ b/core/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/AllAttributeVisitor.java b/core/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
similarity index 98%
rename from src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
index 62c53fb..4e8b627 100644
--- a/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
index 11e892f..e97510d 100644
--- a/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/AllExceptionInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
index 1e4a6d6..6bfff5f 100644
--- a/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
index 2c2d560..c31195f 100644
--- a/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/AllLineNumberInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/AllLineNumberInfoVisitor.java
similarity index 97%
rename from src/proguard/classfile/attribute/visitor/AllLineNumberInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AllLineNumberInfoVisitor.java
index a3a37ba..df12881 100644
--- a/src/proguard/classfile/attribute/visitor/AllLineNumberInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AllLineNumberInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/attribute/visitor/AttributeCounter.java b/core/src/proguard/classfile/attribute/visitor/AttributeCounter.java
new file mode 100644
index 0000000..febdccd
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/visitor/AttributeCounter.java
@@ -0,0 +1,59 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.Counter;
+
+/**
+ * This AttributeVisitor counts the number of attributes that have been visited.
+ *
+ * @author Thomas Neidhart
+ */
+public class AttributeCounter
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ Counter
+{
+ private int count;
+
+
+ // Implementations for Counter.
+
+ /**
+ * Returns the number of class members that has been visited so far.
+ */
+ public int getCount()
+ {
+ return count;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute)
+ {
+ count++;
+ }
+
+}
diff --git a/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java b/core/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
similarity index 95%
rename from src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
rename to core/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
index 340e4f2..81f61f9 100644
--- a/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
+++ b/core/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
import proguard.util.*;
@@ -143,6 +144,33 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ if (accepted(clazz, moduleAttribute))
+ {
+ attributeVisitor.visitModuleAttribute(clazz, moduleAttribute);
+ }
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ if (accepted(clazz, moduleMainClassAttribute))
+ {
+ attributeVisitor.visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+ }
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ if (accepted(clazz, modulePackagesAttribute))
+ {
+ attributeVisitor.visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+ }
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
if (accepted(clazz, deprecatedAttribute))
diff --git a/core/src/proguard/classfile/attribute/visitor/AttributeToClassVisitor.java b/core/src/proguard/classfile/attribute/visitor/AttributeToClassVisitor.java
new file mode 100644
index 0000000..6f1087f
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/visitor/AttributeToClassVisitor.java
@@ -0,0 +1,55 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This AttributeVisitor delegates to a given ClassVisitor.
+ *
+ * @author Eric Lafortune
+ */
+public class AttributeToClassVisitor
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final ClassVisitor classVisitor;
+
+
+ /**
+ * Creates a new AttributeToClassVisitor.
+ */
+ public AttributeToClassVisitor(ClassVisitor classVisitor)
+ {
+ this.classVisitor = classVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute)
+ {
+ clazz.accept(classVisitor);
+ }
+}
diff --git a/src/proguard/classfile/attribute/visitor/AttributeVisitor.java b/core/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
similarity index 89%
rename from src/proguard/classfile/attribute/visitor/AttributeVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
index 668d13a..e2c1c38 100644
--- a/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
/**
@@ -35,15 +36,15 @@ public interface AttributeVisitor
{
// Attributes that are attached to classes.
- public void visitUnknownAttribute( Clazz clazz, UnknownAttribute unknownAttribute);
- public void visitBootstrapMethodsAttribute( Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute);
- public void visitSourceFileAttribute( Clazz clazz, SourceFileAttribute sourceFileAttribute);
- public void visitSourceDirAttribute( Clazz clazz, SourceDirAttribute sourceDirAttribute);
- public void visitInnerClassesAttribute( Clazz clazz, InnerClassesAttribute innerClassesAttribute);
- public void visitEnclosingMethodAttribute( Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute);
-
- // Attributes that are attached to classes, fields, and methods.
-
+ public void visitUnknownAttribute( Clazz clazz, UnknownAttribute unknownAttribute);
+ public void visitBootstrapMethodsAttribute( Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute);
+ public void visitSourceFileAttribute( Clazz clazz, SourceFileAttribute sourceFileAttribute);
+ public void visitSourceDirAttribute( Clazz clazz, SourceDirAttribute sourceDirAttribute);
+ public void visitInnerClassesAttribute( Clazz clazz, InnerClassesAttribute innerClassesAttribute);
+ public void visitEnclosingMethodAttribute( Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute);
+ public void visitModuleAttribute( Clazz clazz, ModuleAttribute moduleAttribute);
+ public void visitModuleMainClassAttribute( Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute);
+ public void visitModulePackagesAttribute( Clazz clazz, ModulePackagesAttribute modulePackagesAttribute);
public void visitDeprecatedAttribute( Clazz clazz, DeprecatedAttribute deprecatedAttribute);
public void visitDeprecatedAttribute( Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute);
public void visitDeprecatedAttribute( Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute);
@@ -98,4 +99,4 @@ public interface AttributeVisitor
public void visitRuntimeInvisibleTypeAnnotationsAttribute( Clazz clazz, Method method, CodeAttribute codeAttribute, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute);
public void visitAnnotationDefaultAttribute( Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute);
-}
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
old mode 100755
new mode 100644
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
index f796837..d7a63a5
--- a/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 @@
import proguard.classfile.Clazz;
import proguard.classfile.attribute.BootstrapMethodInfo;
-
/**
* This interface specifies the methods for a visitor of
* BootstrapMethodInfo objects. Note that there is only a single
diff --git a/core/src/proguard/classfile/attribute/visitor/DebugAttributeVisitor.java b/core/src/proguard/classfile/attribute/visitor/DebugAttributeVisitor.java
new file mode 100644
index 0000000..d6e198a
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/visitor/DebugAttributeVisitor.java
@@ -0,0 +1,591 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.preverification.*;
+import proguard.classfile.visitor.SimpleClassPrinter;
+
+/**
+ * This AttributeVisitor delegates to a given AttributeVisitor, timing the
+ * invocations and printing out warnings when the timings exceed a given
+ * threshold.
+ *
+ * @author Eric Lafortune
+ */
+public class DebugAttributeVisitor
+implements AttributeVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ public static boolean DEBUG = System.getProperty("dav") != null;
+ //*/
+
+
+ private final String message;
+ private final long maximumTime;
+ private final AttributeVisitor attributeVisitor;
+
+
+ /**
+ * Creates a new DebugAttributeVisitor.
+ * @param attributeVisitor the AttributeVisitor to which visits will be
+ * delegated.
+ */
+ public DebugAttributeVisitor(AttributeVisitor attributeVisitor)
+ {
+ this(attributeVisitor.getClass().getName(),
+ attributeVisitor);
+ }
+
+
+ /**
+ * Creates a new DebugAttributeVisitor.
+ * @param message the message to be printed when the maximum
+ * invocation time is exceeded.
+ * @param attributeVisitor the AttributeVisitor to which visits will be
+ * delegated.
+ */
+ public DebugAttributeVisitor(String message,
+ AttributeVisitor attributeVisitor)
+ {
+ this(message,
+ 10000L,
+ attributeVisitor);
+ }
+
+
+ /**
+ * Creates a new DebugAttributeVisitor.
+ * @param message the message to be printed when the maximum
+ * invocation time is exceeded.
+ * @param maximumTime the maximum invocation time.
+ * @param attributeVisitor the AttributeVisitor to which visits will be
+ * delegated.
+ */
+ public DebugAttributeVisitor(String message,
+ long maximumTime,
+ AttributeVisitor attributeVisitor)
+ {
+ String debugTime = System.getProperty("debug.time");
+
+ this.message = message;
+ this.maximumTime = debugTime != null ? Long.valueOf(debugTime) : maximumTime;
+ this.attributeVisitor = attributeVisitor;
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitUnknownAttribute(clazz, unknownAttribute);
+
+ checkTime(clazz, unknownAttribute, startTime);
+ }
+
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute);
+
+ checkTime(clazz, bootstrapMethodsAttribute, startTime);
+ }
+
+ public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSourceFileAttribute(clazz, sourceFileAttribute);
+
+ checkTime(clazz, sourceFileAttribute, startTime);
+ }
+
+ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSourceDirAttribute(clazz, sourceDirAttribute);
+
+ checkTime(clazz, sourceDirAttribute, startTime);
+ }
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitInnerClassesAttribute(clazz, innerClassesAttribute);
+
+ checkTime(clazz, innerClassesAttribute, startTime);
+ }
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitEnclosingMethodAttribute(clazz, enclosingMethodAttribute);
+
+ checkTime(clazz, enclosingMethodAttribute, startTime);
+ }
+
+
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitModuleAttribute(clazz, moduleAttribute);
+
+ checkTime(clazz, moduleAttribute, startTime);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+
+ checkTime(clazz, moduleMainClassAttribute, startTime);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+
+ checkTime(clazz, modulePackagesAttribute, startTime);
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitDeprecatedAttribute(clazz, deprecatedAttribute);
+
+ checkTime(clazz, deprecatedAttribute, startTime);
+ }
+
+ public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitDeprecatedAttribute(clazz, field, deprecatedAttribute);
+
+ checkTime(clazz, field, deprecatedAttribute, startTime);
+ }
+
+ public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitDeprecatedAttribute(clazz, method, deprecatedAttribute);
+
+ checkTime(clazz, method, deprecatedAttribute, startTime);
+ }
+
+ public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSyntheticAttribute(clazz, syntheticAttribute);
+
+ checkTime(clazz, syntheticAttribute, startTime);
+ }
+
+ public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSyntheticAttribute(clazz, field, syntheticAttribute);
+
+ checkTime(clazz, field, syntheticAttribute, startTime);
+ }
+
+ public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSyntheticAttribute(clazz, method, syntheticAttribute);
+
+ checkTime(clazz, method, syntheticAttribute, startTime);
+ }
+
+ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSignatureAttribute(clazz, signatureAttribute);
+
+ checkTime(clazz, signatureAttribute, startTime);
+ }
+
+ public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSignatureAttribute(clazz, field, signatureAttribute);
+
+ checkTime(clazz, field, signatureAttribute, startTime);
+ }
+
+ public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitSignatureAttribute(clazz, method, signatureAttribute);
+
+ checkTime(clazz, method, signatureAttribute, startTime);
+ }
+
+ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitConstantValueAttribute(clazz, field, constantValueAttribute);
+
+ checkTime(clazz, field, constantValueAttribute, startTime);
+ }
+
+ public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitMethodParametersAttribute(clazz, method, methodParametersAttribute);
+
+ checkTime(clazz, method, methodParametersAttribute, startTime);
+ }
+
+ public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitExceptionsAttribute(clazz, method, exceptionsAttribute);
+
+ checkTime(clazz, method, exceptionsAttribute, startTime);
+ }
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitCodeAttribute(clazz, method, codeAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitStackMapAttribute(clazz, method, codeAttribute, stackMapAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitStackMapTableAttribute(clazz, method, codeAttribute, stackMapTableAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitLineNumberTableAttribute(clazz, method, codeAttribute, lineNumberTableAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute);
+
+ checkTime(clazz, method, codeAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute);
+
+ checkTime(clazz, runtimeVisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, field, runtimeVisibleAnnotationsAttribute);
+
+ checkTime(clazz, field, runtimeVisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleAnnotationsAttribute(clazz, method, runtimeVisibleAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeVisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute);
+
+ checkTime(clazz, runtimeInvisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, field, runtimeInvisibleAnnotationsAttribute);
+
+ checkTime(clazz, field, runtimeInvisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleAnnotationsAttribute(clazz, method, runtimeInvisibleAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeInvisibleAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleParameterAnnotationsAttribute(clazz, method, runtimeVisibleParameterAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeVisibleParameterAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleParameterAnnotationsAttribute(clazz, method, runtimeInvisibleParameterAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeInvisibleParameterAnnotationsAttribute, startTime);
+ }
+
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, runtimeVisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, runtimeVisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, field, runtimeVisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, field, runtimeVisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, method, runtimeVisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeVisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeVisibleTypeAnnotationsAttribute(clazz, method, codeAttribute, runtimeVisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeVisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, runtimeInvisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, runtimeInvisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, field, runtimeInvisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, field, runtimeInvisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, method, runtimeInvisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeInvisibleTypeAnnotationsAttribute, startTime);
+ }
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitRuntimeInvisibleTypeAnnotationsAttribute(clazz, method, codeAttribute, runtimeInvisibleTypeAnnotationsAttribute);
+
+ checkTime(clazz, method, runtimeInvisibleTypeAnnotationsAttribute, startTime);
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ long startTime = startTime();
+
+ attributeVisitor.visitAnnotationDefaultAttribute(clazz, method, annotationDefaultAttribute);
+
+ checkTime(clazz, method, annotationDefaultAttribute, startTime);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the current time.
+ */
+ private long startTime()
+ {
+ return DEBUG ? System.currentTimeMillis() : 0L;
+ }
+
+
+ /**
+ * Checks the time after having visited the given attribute, and prints
+ * out a message if necessary.
+ */
+ private void checkTime(Clazz clazz,
+ Attribute attribute,
+ long startTime)
+ {
+ if (DEBUG)
+ {
+ long endTime = startTime();
+
+ long deltaTime = endTime - startTime;
+
+ if (deltaTime > maximumTime)
+ {
+ System.err.println("=== " + message + " took "+((double)deltaTime/1000.)+" seconds ===");
+ //attribute.accept(clazz, new ClassPrinter());
+ System.err.println();
+ }
+ }
+ }
+
+
+ /**
+ * Checks the time after having visited the given attribute, and prints
+ * out a message if necessary.
+ */
+ private void checkTime(Clazz clazz,
+ Field field,
+ Attribute attribute,
+ long startTime)
+ {
+ if (DEBUG)
+ {
+ long endTime = startTime();
+
+ long deltaTime = endTime - startTime;
+
+ if (deltaTime > maximumTime)
+ {
+ System.err.println("=== " + message + " took "+((double)deltaTime/1000.)+" seconds ===");
+ field.accept(clazz, new SimpleClassPrinter(true));
+ System.err.println();
+ }
+ }
+ }
+
+
+ /**
+ * Checks the time after having visited the given attribute, and prints
+ * out a message if necessary.
+ */
+ private void checkTime(Clazz clazz,
+ Method method,
+ Attribute attribute,
+ long startTime)
+ {
+ if (DEBUG)
+ {
+ long endTime = startTime();
+
+ long deltaTime = endTime - startTime;
+
+ if (deltaTime > maximumTime)
+ {
+ System.err.println("=== " + message + " took "+((double)deltaTime/1000.)+" seconds ===");
+ method.accept(clazz, new SimpleClassPrinter(true));
+ System.err.println();
+ }
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
index e15ab7c..80bbb7c 100644
--- a/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/InnerClassesInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
index d4e4984..49dfc75 100644
--- a/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/attribute/visitor/InstructionToAttributeVisitor.java b/core/src/proguard/classfile/attribute/visitor/InstructionToAttributeVisitor.java
new file mode 100644
index 0000000..c2b80c7
--- /dev/null
+++ b/core/src/proguard/classfile/attribute/visitor/InstructionToAttributeVisitor.java
@@ -0,0 +1,58 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.attribute.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This InstructionVisitor delegates to a given AttributeVisitor.
+ *
+ * @author Johan Leys
+ */
+public class InstructionToAttributeVisitor
+extends SimplifiedVisitor
+implements InstructionVisitor
+{
+ private final AttributeVisitor attributeVisitor;
+
+
+ /**
+ * Creates a new InstructionToAttributeVisitor.
+ */
+ public InstructionToAttributeVisitor(AttributeVisitor attributeVisitor)
+ {
+ this.attributeVisitor = attributeVisitor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ codeAttribute.accept(clazz, method, attributeVisitor);
+ }
+}
+
diff --git a/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
index c58d113..323cf19 100644
--- a/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/LineNumberRangeFinder.java b/core/src/proguard/classfile/attribute/visitor/LineNumberRangeFinder.java
similarity index 97%
rename from src/proguard/classfile/attribute/visitor/LineNumberRangeFinder.java
rename to core/src/proguard/classfile/attribute/visitor/LineNumberRangeFinder.java
index 4cbbff0..e7ebc24 100644
--- a/src/proguard/classfile/attribute/visitor/LineNumberRangeFinder.java
+++ b/core/src/proguard/classfile/attribute/visitor/LineNumberRangeFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/LocalVariableInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
index 523c192..96c4d81 100644
--- a/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
index 870d340..07b2518 100644
--- a/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/MultiAttributeVisitor.java b/core/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
similarity index 80%
rename from src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
index 92698ef..58bef79 100644
--- a/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,9 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
+import proguard.util.ArrayUtil;
/**
* This AttributeVisitor delegates all visits to each AttributeVisitor
@@ -34,42 +36,28 @@
public class MultiAttributeVisitor implements AttributeVisitor
{
private AttributeVisitor[] attributeVisitors;
+ private int attributeVisitorCount;
public MultiAttributeVisitor()
{
+ this.attributeVisitors = new AttributeVisitor[16];
}
- public MultiAttributeVisitor(AttributeVisitor[] attributeVisitors)
+ public MultiAttributeVisitor(AttributeVisitor... attributeVisitors)
{
- this.attributeVisitors = attributeVisitors;
+ this.attributeVisitors = attributeVisitors;
+ this.attributeVisitorCount = attributeVisitors.length;
}
public void addAttributeVisitor(AttributeVisitor attributeVisitor)
{
- incrementArraySize();
-
- attributeVisitors[attributeVisitors.length - 1] = attributeVisitor;
- }
-
-
- private void incrementArraySize()
- {
- if (attributeVisitors == null)
- {
- attributeVisitors = new AttributeVisitor[1];
- }
- else
- {
- AttributeVisitor[] newAttributeVisitors =
- new AttributeVisitor[attributeVisitors.length + 1];
- System.arraycopy(attributeVisitors, 0,
- newAttributeVisitors, 0,
- attributeVisitors.length);
- attributeVisitors = newAttributeVisitors;
- }
+ attributeVisitors =
+ ArrayUtil.add(attributeVisitors,
+ attributeVisitorCount++,
+ attributeVisitor);
}
@@ -78,7 +66,7 @@ private void incrementArraySize()
public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitUnknownAttribute(clazz, unknownAttribute);
}
@@ -87,7 +75,7 @@ public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute
public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute);
}
@@ -96,7 +84,7 @@ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribut
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSourceFileAttribute(clazz, sourceFileAttribute);
}
@@ -105,7 +93,7 @@ public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFile
public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSourceDirAttribute(clazz, sourceDirAttribute);
}
@@ -114,7 +102,7 @@ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAtt
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitInnerClassesAttribute(clazz, innerClassesAttribute);
}
@@ -123,16 +111,43 @@ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerC
public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitEnclosingMethodAttribute(clazz, enclosingMethodAttribute);
}
}
- public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
{
for (int index = 0; index < attributeVisitors.length; index++)
+ {
+ attributeVisitors[index].visitModuleAttribute(clazz, moduleAttribute);
+ }
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ for (int index = 0; index < attributeVisitors.length; index++)
+ {
+ attributeVisitors[index].visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+ }
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ for (int index = 0; index < attributeVisitors.length; index++)
+ {
+ attributeVisitors[index].visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+ }
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
+ {
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitDeprecatedAttribute(clazz, deprecatedAttribute);
}
@@ -141,7 +156,7 @@ public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecated
public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSyntheticAttribute(clazz, syntheticAttribute);
}
@@ -150,7 +165,7 @@ public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAtt
public void visitSignatureAttribute(Clazz clazz, SignatureAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSignatureAttribute(clazz, syntheticAttribute);
}
@@ -159,7 +174,7 @@ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute syntheticAtt
public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitDeprecatedAttribute(clazz, field, deprecatedAttribute);
}
@@ -168,7 +183,7 @@ public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribu
public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSyntheticAttribute(clazz, field, syntheticAttribute);
}
@@ -177,7 +192,7 @@ public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute
public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSignatureAttribute(clazz, field, syntheticAttribute);
}
@@ -186,7 +201,7 @@ public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute
public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitDeprecatedAttribute(clazz, method, deprecatedAttribute);
}
@@ -195,7 +210,7 @@ public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttri
public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSyntheticAttribute(clazz, method, syntheticAttribute);
}
@@ -204,7 +219,7 @@ public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribu
public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute syntheticAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitSignatureAttribute(clazz, method, syntheticAttribute);
}
@@ -213,7 +228,7 @@ public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribu
public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitConstantValueAttribute(clazz, field, constantValueAttribute);
}
@@ -231,7 +246,7 @@ public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodPar
public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitExceptionsAttribute(clazz, method, exceptionsAttribute);
}
@@ -240,7 +255,7 @@ public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttri
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitCodeAttribute(clazz, method, codeAttribute);
}
@@ -249,7 +264,7 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitStackMapAttribute(clazz, method, codeAttribute, stackMapAttribute);
}
@@ -258,7 +273,7 @@ public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute cod
public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitStackMapTableAttribute(clazz, method, codeAttribute, stackMapTableAttribute);
}
@@ -267,7 +282,7 @@ public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribut
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitLineNumberTableAttribute(clazz, method, codeAttribute, lineNumberTableAttribute);
}
@@ -276,7 +291,7 @@ public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttrib
public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute);
}
@@ -285,7 +300,7 @@ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAtt
public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute);
}
@@ -294,7 +309,7 @@ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, Cod
public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, runtimeVisibleAnnotationsAttribute);
}
@@ -303,7 +318,7 @@ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleA
public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, runtimeInvisibleAnnotationsAttribute);
}
@@ -312,7 +327,7 @@ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisi
public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, field, runtimeVisibleAnnotationsAttribute);
}
@@ -321,7 +336,7 @@ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, Ru
public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, field, runtimeInvisibleAnnotationsAttribute);
}
@@ -330,7 +345,7 @@ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field,
public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeVisibleAnnotationsAttribute(clazz, method, runtimeVisibleAnnotationsAttribute);
}
@@ -339,7 +354,7 @@ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method,
public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeInvisibleAnnotationsAttribute(clazz, method, runtimeInvisibleAnnotationsAttribute);
}
@@ -348,7 +363,7 @@ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method
public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeVisibleParameterAnnotationsAttribute(clazz, method, runtimeVisibleParameterAnnotationsAttribute);
}
@@ -357,7 +372,7 @@ public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method
public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitRuntimeInvisibleParameterAnnotationsAttribute(clazz, method, runtimeInvisibleParameterAnnotationsAttribute);
}
@@ -438,7 +453,7 @@ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, Method me
public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
{
- for (int index = 0; index < attributeVisitors.length; index++)
+ for (int index = 0; index < attributeVisitorCount; index++)
{
attributeVisitors[index].visitAnnotationDefaultAttribute(clazz, method, annotationDefaultAttribute);
}
diff --git a/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java b/core/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
similarity index 93%
rename from src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
rename to core/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
index 52bbae1..d04f3ca 100644
--- a/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
+++ b/core/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
/**
@@ -93,6 +94,34 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ if (moduleAttribute.u2requiresCount > 0 ||
+ moduleAttribute.u2exportsCount > 0 ||
+ moduleAttribute.u2opensCount > 0 ||
+ moduleAttribute.u2usesCount > 0 ||
+ moduleAttribute.u2providesCount > 0)
+ {
+ attributeVisitor.visitModuleAttribute(clazz, moduleAttribute);
+ }
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ attributeVisitor.visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ if (modulePackagesAttribute.u2packagesCount > 0)
+ {
+ attributeVisitor.visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+ }
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
attributeVisitor.visitDeprecatedAttribute(clazz, deprecatedAttribute);
diff --git a/src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java b/core/src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java
similarity index 96%
rename from src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java
rename to core/src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java
index 59a7430..f55d19a 100644
--- a/src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java
+++ b/core/src/proguard/classfile/attribute/visitor/ParameterInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/attribute/visitor/RequiredAttributeFilter.java b/core/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
similarity index 94%
rename from src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
rename to core/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
index 32f29bf..0b2c8fc 100644
--- a/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
+++ b/core/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
import proguard.obfuscate.AttributeShrinker;
@@ -127,6 +128,33 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ if (optionalAttributeVisitor != null)
+ {
+ optionalAttributeVisitor.visitModuleAttribute(clazz, moduleAttribute);
+ }
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ if (optionalAttributeVisitor != null)
+ {
+ optionalAttributeVisitor.visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+ }
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ if (optionalAttributeVisitor != null)
+ {
+ optionalAttributeVisitor.visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+ }
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
if (optionalAttributeVisitor != null)
diff --git a/src/proguard/classfile/attribute/visitor/StackSizeComputer.java b/core/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
similarity index 99%
rename from src/proguard/classfile/attribute/visitor/StackSizeComputer.java
rename to core/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
index 009666c..a2cf434 100644
--- a/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
+++ b/core/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -151,7 +151,7 @@ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAt
int codeLength = codeAttribute.u4codeLength;
// Make sure the global arrays are sufficiently large.
- evaluated = ArrayUtil.ensureArraySize(evaluated, codeLength, false);
+ evaluated = ArrayUtil.ensureArraySize(evaluated, codeLength, false);
stackSizesBefore = ArrayUtil.ensureArraySize(stackSizesBefore, codeLength, 0);
stackSizesAfter = ArrayUtil.ensureArraySize(stackSizesAfter, codeLength, 0);
diff --git a/src/proguard/classfile/attribute/visitor/package.html b/core/src/proguard/classfile/attribute/visitor/package.html
similarity index 100%
rename from src/proguard/classfile/attribute/visitor/package.html
rename to core/src/proguard/classfile/attribute/visitor/package.html
diff --git a/src/proguard/classfile/constant/ClassConstant.java b/core/src/proguard/classfile/constant/ClassConstant.java
similarity index 98%
rename from src/proguard/classfile/constant/ClassConstant.java
rename to core/src/proguard/classfile/constant/ClassConstant.java
index b499374..a3d0790 100644
--- a/src/proguard/classfile/constant/ClassConstant.java
+++ b/core/src/proguard/classfile/constant/ClassConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/Constant.java b/core/src/proguard/classfile/constant/Constant.java
similarity index 97%
rename from src/proguard/classfile/constant/Constant.java
rename to core/src/proguard/classfile/constant/Constant.java
index 86acf9d..44eb3c3 100644
--- a/src/proguard/classfile/constant/Constant.java
+++ b/core/src/proguard/classfile/constant/Constant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/DoubleConstant.java b/core/src/proguard/classfile/constant/DoubleConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/DoubleConstant.java
rename to core/src/proguard/classfile/constant/DoubleConstant.java
index a9eca1e..45e0abe 100644
--- a/src/proguard/classfile/constant/DoubleConstant.java
+++ b/core/src/proguard/classfile/constant/DoubleConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/FieldrefConstant.java b/core/src/proguard/classfile/constant/FieldrefConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/FieldrefConstant.java
rename to core/src/proguard/classfile/constant/FieldrefConstant.java
index 6cc30a3..6e35254 100644
--- a/src/proguard/classfile/constant/FieldrefConstant.java
+++ b/core/src/proguard/classfile/constant/FieldrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/FloatConstant.java b/core/src/proguard/classfile/constant/FloatConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/FloatConstant.java
rename to core/src/proguard/classfile/constant/FloatConstant.java
index 8dbe933..2406b1d 100644
--- a/src/proguard/classfile/constant/FloatConstant.java
+++ b/core/src/proguard/classfile/constant/FloatConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/IntegerConstant.java b/core/src/proguard/classfile/constant/IntegerConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/IntegerConstant.java
rename to core/src/proguard/classfile/constant/IntegerConstant.java
index 9c09149..28ffbe7 100644
--- a/src/proguard/classfile/constant/IntegerConstant.java
+++ b/core/src/proguard/classfile/constant/IntegerConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/InterfaceMethodrefConstant.java b/core/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/InterfaceMethodrefConstant.java
rename to core/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
index 0436ffe..7e6ae6e 100644
--- a/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
+++ b/core/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/InvokeDynamicConstant.java b/core/src/proguard/classfile/constant/InvokeDynamicConstant.java
old mode 100755
new mode 100644
similarity index 98%
rename from src/proguard/classfile/constant/InvokeDynamicConstant.java
rename to core/src/proguard/classfile/constant/InvokeDynamicConstant.java
index 26c46d3..e98e67e
--- a/src/proguard/classfile/constant/InvokeDynamicConstant.java
+++ b/core/src/proguard/classfile/constant/InvokeDynamicConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/LongConstant.java b/core/src/proguard/classfile/constant/LongConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/LongConstant.java
rename to core/src/proguard/classfile/constant/LongConstant.java
index 977d013..7795495 100644
--- a/src/proguard/classfile/constant/LongConstant.java
+++ b/core/src/proguard/classfile/constant/LongConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/MethodHandleConstant.java b/core/src/proguard/classfile/constant/MethodHandleConstant.java
old mode 100755
new mode 100644
similarity index 98%
rename from src/proguard/classfile/constant/MethodHandleConstant.java
rename to core/src/proguard/classfile/constant/MethodHandleConstant.java
index 950136a..b823417
--- a/src/proguard/classfile/constant/MethodHandleConstant.java
+++ b/core/src/proguard/classfile/constant/MethodHandleConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/MethodTypeConstant.java b/core/src/proguard/classfile/constant/MethodTypeConstant.java
similarity index 98%
rename from src/proguard/classfile/constant/MethodTypeConstant.java
rename to core/src/proguard/classfile/constant/MethodTypeConstant.java
index eba5d11..2edabc5 100644
--- a/src/proguard/classfile/constant/MethodTypeConstant.java
+++ b/core/src/proguard/classfile/constant/MethodTypeConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/MethodrefConstant.java b/core/src/proguard/classfile/constant/MethodrefConstant.java
similarity index 97%
rename from src/proguard/classfile/constant/MethodrefConstant.java
rename to core/src/proguard/classfile/constant/MethodrefConstant.java
index a3a0b7c..899747e 100644
--- a/src/proguard/classfile/constant/MethodrefConstant.java
+++ b/core/src/proguard/classfile/constant/MethodrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/constant/ModuleConstant.java b/core/src/proguard/classfile/constant/ModuleConstant.java
new file mode 100644
index 0000000..6340286
--- /dev/null
+++ b/core/src/proguard/classfile/constant/ModuleConstant.java
@@ -0,0 +1,74 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * This Constant represents a module constant in the constant pool.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class ModuleConstant extends Constant
+{
+ public int u2nameIndex;
+
+
+ /**
+ * Creates an uninitialized ModuleConstant.
+ */
+ public ModuleConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new ModuleConstant with the given name index.
+ * @param u2nameIndex the index of the name in the constant pool.
+ */
+ public ModuleConstant(int u2nameIndex)
+ {
+ this.u2nameIndex = u2nameIndex;
+ }
+
+
+ /**
+ * Returns the name.
+ */
+ public String getName(Clazz clazz)
+ {
+ return clazz.getString(u2nameIndex);
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Module;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitModuleConstant(clazz, this);
+ }
+}
diff --git a/src/proguard/classfile/constant/NameAndTypeConstant.java b/core/src/proguard/classfile/constant/NameAndTypeConstant.java
similarity index 98%
rename from src/proguard/classfile/constant/NameAndTypeConstant.java
rename to core/src/proguard/classfile/constant/NameAndTypeConstant.java
index f52c3eb..4c3218a 100644
--- a/src/proguard/classfile/constant/NameAndTypeConstant.java
+++ b/core/src/proguard/classfile/constant/NameAndTypeConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/constant/PackageConstant.java b/core/src/proguard/classfile/constant/PackageConstant.java
new file mode 100644
index 0000000..362fedf
--- /dev/null
+++ b/core/src/proguard/classfile/constant/PackageConstant.java
@@ -0,0 +1,74 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * This Constant represents a package constant in the constant pool.
+ *
+ * @author Joachim Vandersmissen
+ */
+public class PackageConstant extends Constant
+{
+ public int u2nameIndex;
+
+
+ /**
+ * Creates an uninitialized PackageConstant.
+ */
+ public PackageConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new PackageConstant with the given name index.
+ * @param u2nameIndex the index of the name in the constant pool.
+ */
+ public PackageConstant(int u2nameIndex)
+ {
+ this.u2nameIndex = u2nameIndex;
+ }
+
+
+ /**
+ * Returns the name.
+ */
+ public String getName(Clazz clazz)
+ {
+ return clazz.getString(u2nameIndex);
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Package;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitPackageConstant(clazz, this);
+ }
+}
diff --git a/core/src/proguard/classfile/constant/PrimitiveArrayConstant.java b/core/src/proguard/classfile/constant/PrimitiveArrayConstant.java
new file mode 100644
index 0000000..1bb6029
--- /dev/null
+++ b/core/src/proguard/classfile/constant/PrimitiveArrayConstant.java
@@ -0,0 +1,230 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant;
+
+import proguard.classfile.ClassConstants;
+import proguard.classfile.Clazz;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.constant.visitor.PrimitiveArrayConstantElementVisitor;
+import proguard.classfile.constant.visitor.PrimitiveArrayConstantVisitor;
+
+/**
+ * This unofficial Constant represents an array of primitives in the constant
+ * pool. It is not supported by any Java specification and therefore only for
+ * internal use.
+ *
+ * @author Eric Lafortune
+ */
+public class PrimitiveArrayConstant extends Constant
+{
+ public Object values;
+
+
+ /**
+ * Creates an uninitialized PrimitiveArrayConstant.
+ */
+ public PrimitiveArrayConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new PrimitiveArrayConstant with the given array of values.
+ */
+ public PrimitiveArrayConstant(Object values)
+ {
+ this.values = values;
+ }
+
+
+ /**
+ * Returns the type of the elements of the primitive array.
+ */
+ public char getPrimitiveType()
+ {
+ return values instanceof boolean[] ? ClassConstants.TYPE_BOOLEAN :
+ values instanceof byte[] ? ClassConstants.TYPE_BYTE :
+ values instanceof char[] ? ClassConstants.TYPE_CHAR :
+ values instanceof short[] ? ClassConstants.TYPE_SHORT :
+ values instanceof int[] ? ClassConstants.TYPE_INT :
+ values instanceof float[] ? ClassConstants.TYPE_FLOAT :
+ values instanceof long[] ? ClassConstants.TYPE_LONG :
+ values instanceof double[] ? ClassConstants.TYPE_DOUBLE :
+ 0;
+ }
+
+
+ /**
+ * Returns the length of the primitive array.
+ */
+ public int getLength()
+ {
+ return values instanceof boolean[] ? ((boolean[])values).length :
+ values instanceof byte[] ? ((byte[] )values).length :
+ values instanceof char[] ? ((char[] )values).length :
+ values instanceof short[] ? ((short[] )values).length :
+ values instanceof int[] ? ((int[] )values).length :
+ values instanceof float[] ? ((float[] )values).length :
+ values instanceof long[] ? ((long[] )values).length :
+ values instanceof double[] ? ((double[] )values).length :
+ 0;
+ }
+
+
+ /**
+ * Returns the values.
+ */
+ public Object getValues()
+ {
+ return values;
+ }
+
+
+ /**
+ * Applies the given PrimitiveArrayConstantVisitor to the primitive array.
+ */
+ public void primitiveArrayAccept(Clazz clazz, PrimitiveArrayConstantVisitor primitiveArrayConstantVisitor)
+ {
+ // The primitive arrays themselves don't accept visitors, so we have to
+ // use instanceof tests.
+ if (values instanceof boolean[])
+ {
+ primitiveArrayConstantVisitor.visitBooleanArrayConstant(clazz, this, (boolean[])values);
+ }
+ else if (values instanceof byte[])
+ {
+ primitiveArrayConstantVisitor.visitByteArrayConstant(clazz, this, (byte[])values);
+ }
+ else if (values instanceof char[])
+ {
+ primitiveArrayConstantVisitor.visitCharArrayConstant(clazz, this, (char[])values);
+ }
+ else if (values instanceof short[])
+ {
+ primitiveArrayConstantVisitor.visitShortArrayConstant(clazz, this, (short[])values);
+ }
+ else if (values instanceof int[])
+ {
+ primitiveArrayConstantVisitor.visitIntArrayConstant(clazz, this, (int[])values);
+ }
+ else if (values instanceof float[])
+ {
+ primitiveArrayConstantVisitor.visitFloatArrayConstant(clazz, this, (float[])values);
+ }
+ else if (values instanceof long[])
+ {
+ primitiveArrayConstantVisitor.visitLongArrayConstant(clazz, this, (long[])values);
+ }
+ else if (values instanceof double[])
+ {
+ primitiveArrayConstantVisitor.visitDoubleArrayConstant(clazz, this, (double[])values);
+ }
+ }
+
+
+ /**
+ * Applies the given PrimitiveArrayConstantElementVisitor to all elements
+ * of the primitive array.
+ */
+ public void primitiveArrayElementsAccept(Clazz clazz, PrimitiveArrayConstantElementVisitor primitiveArrayConstantElementVisitor)
+ {
+ // The primitive arrays themselves don't accept visitors, so we have to
+ // use instanceof tests.
+ if (values instanceof boolean[])
+ {
+ boolean[] booleanValues = (boolean[])this.values;
+ for (int index = 0; index < booleanValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitBooleanArrayConstantElement(clazz, this, index, booleanValues[index]);
+ }
+ }
+ else if (values instanceof byte[])
+ {
+ byte[] byteValues = (byte[])this.values;
+ for (int index = 0; index < byteValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitByteArrayConstantElement(clazz, this, index, byteValues[index]);
+ }
+ }
+ else if (values instanceof char[])
+ {
+ char[] charValues = (char[])this.values;
+ for (int index = 0; index < charValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitCharArrayConstantElement(clazz, this, index, charValues[index]);
+ }
+ }
+ else if (values instanceof short[])
+ {
+ short[] shortValues = (short[])this.values;
+ for (int index = 0; index < shortValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitShortArrayConstantElement(clazz, this, index, shortValues[index]);
+ }
+ }
+ else if (values instanceof int[])
+ {
+ int[] intValues = (int[])this.values;
+ for (int index = 0; index < intValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitIntArrayConstantElement(clazz, this, index, intValues[index]);
+ }
+ }
+ else if (values instanceof float[])
+ {
+ float[] floatValues = (float[])this.values;
+ for (int index = 0; index < floatValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitFloatArrayConstantElement(clazz, this, index, floatValues[index]);
+ }
+ }
+ else if (values instanceof long[])
+ {
+ long[] longValues = (long[])this.values;
+ for (int index = 0; index < longValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitLongArrayConstantElement(clazz, this, index, longValues[index]);
+ }
+ }
+ else if (values instanceof double[])
+ {
+ double[] doubleValues = (double[])this.values;
+ for (int index = 0; index < doubleValues.length; index++)
+ {
+ primitiveArrayConstantElementVisitor.visitDoubleArrayConstantElement(clazz, this, index, doubleValues[index]);
+ }
+ }
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_PrimitiveArray;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitPrimitiveArrayConstant(clazz, this);
+ }
+}
diff --git a/src/proguard/classfile/constant/RefConstant.java b/core/src/proguard/classfile/constant/RefConstant.java
similarity index 98%
rename from src/proguard/classfile/constant/RefConstant.java
rename to core/src/proguard/classfile/constant/RefConstant.java
index 11c5934..599c763 100644
--- a/src/proguard/classfile/constant/RefConstant.java
+++ b/core/src/proguard/classfile/constant/RefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/StringConstant.java b/core/src/proguard/classfile/constant/StringConstant.java
similarity index 98%
rename from src/proguard/classfile/constant/StringConstant.java
rename to core/src/proguard/classfile/constant/StringConstant.java
index 42509a1..ec7f7c9 100644
--- a/src/proguard/classfile/constant/StringConstant.java
+++ b/core/src/proguard/classfile/constant/StringConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/Utf8Constant.java b/core/src/proguard/classfile/constant/Utf8Constant.java
similarity index 99%
rename from src/proguard/classfile/constant/Utf8Constant.java
rename to core/src/proguard/classfile/constant/Utf8Constant.java
index 848312c..12911a4 100644
--- a/src/proguard/classfile/constant/Utf8Constant.java
+++ b/core/src/proguard/classfile/constant/Utf8Constant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -114,7 +114,7 @@ public byte[] getBytes()
public void setString(String utf8String)
{
this.bytes = null;
- this.string = (utf8String == null) ? null : utf8String.intern();
+ this.string = (utf8String == null) ? null : utf8String.intern();;
}
diff --git a/src/proguard/classfile/constant/visitor/BootstrapMethodArgumentVisitor.java b/core/src/proguard/classfile/constant/visitor/AllBootstrapMethodArgumentVisitor.java
similarity index 83%
rename from src/proguard/classfile/constant/visitor/BootstrapMethodArgumentVisitor.java
rename to core/src/proguard/classfile/constant/visitor/AllBootstrapMethodArgumentVisitor.java
index 8bbb34c..c417925 100644
--- a/src/proguard/classfile/constant/visitor/BootstrapMethodArgumentVisitor.java
+++ b/core/src/proguard/classfile/constant/visitor/AllBootstrapMethodArgumentVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,19 +28,18 @@
* This BootstrapMethodInfoVisitor lets a given ConstantVisitor visit all
* constant pool entries of the bootstrap methods it visits.
*
- *
* @author Eric Lafortune
*/
-public class BootstrapMethodArgumentVisitor
+public class AllBootstrapMethodArgumentVisitor
implements BootstrapMethodInfoVisitor
{
private ConstantVisitor constantVisitor;
/**
- * Creates a new BootstrapMethodArgumentVisitor that will delegate to the
- * given constant visitor.
+ * Creates a new AllBootstrapMethodArgumentVisitor that will delegate to
+ * the given constant visitor.
*/
- public BootstrapMethodArgumentVisitor(ConstantVisitor constantVisitor)
+ public AllBootstrapMethodArgumentVisitor(ConstantVisitor constantVisitor)
{
this.constantVisitor = constantVisitor;
}
@@ -50,7 +49,6 @@ public BootstrapMethodArgumentVisitor(ConstantVisitor constantVisitor)
public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
{
- // Check bootstrap method.
bootstrapMethodInfo.methodArgumentsAccept(clazz, constantVisitor);
}
}
diff --git a/src/proguard/classfile/constant/visitor/AllConstantVisitor.java b/core/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
similarity index 96%
rename from src/proguard/classfile/constant/visitor/AllConstantVisitor.java
rename to core/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
index 90d4124..5497151 100644
--- a/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
+++ b/core/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/visitor/BootstrapMethodHandleTraveler.java b/core/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
similarity index 98%
rename from src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
rename to core/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
index 032dafb..080b7d8 100644
--- a/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
+++ b/core/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/constant/visitor/ConstantCounter.java b/core/src/proguard/classfile/constant/visitor/ConstantCounter.java
new file mode 100644
index 0000000..3433790
--- /dev/null
+++ b/core/src/proguard/classfile/constant/visitor/ConstantCounter.java
@@ -0,0 +1,58 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.Counter;
+
+/**
+ * This ConstantVisitor counts the number of constants that have been visited.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantCounter
+extends SimplifiedVisitor
+implements ConstantVisitor,
+ Counter
+{
+ private int count;
+
+
+ // Implementations for Counter.
+
+ /**
+ * Returns the number of class members that has been visited so far.
+ */
+ public int getCount()
+ {
+ return count;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant)
+ {
+ count++;
+ }
+}
diff --git a/src/proguard/classfile/constant/visitor/ConstantTagFilter.java b/core/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
similarity index 98%
rename from src/proguard/classfile/constant/visitor/ConstantTagFilter.java
rename to core/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
index 43a95f9..6c774e2 100644
--- a/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
+++ b/core/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/visitor/ConstantVisitor.java b/core/src/proguard/classfile/constant/visitor/ConstantVisitor.java
similarity index 87%
rename from src/proguard/classfile/constant/visitor/ConstantVisitor.java
rename to core/src/proguard/classfile/constant/visitor/ConstantVisitor.java
index 2e74e3b..19b0e89 100644
--- a/src/proguard/classfile/constant/visitor/ConstantVisitor.java
+++ b/core/src/proguard/classfile/constant/visitor/ConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,6 +36,7 @@ public interface ConstantVisitor
public void visitLongConstant( Clazz clazz, LongConstant longConstant);
public void visitFloatConstant( Clazz clazz, FloatConstant floatConstant);
public void visitDoubleConstant( Clazz clazz, DoubleConstant doubleConstant);
+ public void visitPrimitiveArrayConstant( Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant);
public void visitStringConstant( Clazz clazz, StringConstant stringConstant);
public void visitUtf8Constant( Clazz clazz, Utf8Constant utf8Constant);
public void visitInvokeDynamicConstant( Clazz clazz, InvokeDynamicConstant invokeDynamicConstant);
@@ -46,4 +47,6 @@ public interface ConstantVisitor
public void visitClassConstant( Clazz clazz, ClassConstant classConstant);
public void visitMethodTypeConstant( Clazz clazz, MethodTypeConstant methodTypeConstant);
public void visitNameAndTypeConstant( Clazz clazz, NameAndTypeConstant nameAndTypeConstant);
+ public void visitModuleConstant( Clazz clazz, ModuleConstant moduleConstant);
+ public void visitPackageConstant( Clazz clazz, PackageConstant packageConstant);
}
diff --git a/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java b/core/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
similarity index 97%
rename from src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
rename to core/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
index b49c478..609bc5d 100644
--- a/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
+++ b/core/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/visitor/MethodrefTraveler.java b/core/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
similarity index 97%
rename from src/proguard/classfile/constant/visitor/MethodrefTraveler.java
rename to core/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
index 4d8b0c6..17135ce 100644
--- a/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
+++ b/core/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantElementVisitor.java b/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantElementVisitor.java
new file mode 100644
index 0000000..0dd58f2
--- /dev/null
+++ b/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantElementVisitor.java
@@ -0,0 +1,42 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.constant.PrimitiveArrayConstant;
+
+/**
+ * This interface specifies the methods for a visitor of primitive elements
+ * of the array of a PrimitiveArrayConstant.
+ *
+ * @author Eric Lafortune
+ */
+public interface PrimitiveArrayConstantElementVisitor
+{
+ public void visitBooleanArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, boolean value);
+ public void visitByteArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, byte value);
+ public void visitCharArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, char value);
+ public void visitShortArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, short value);
+ public void visitIntArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, int value);
+ public void visitFloatArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, float value);
+ public void visitLongArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, long value);
+ public void visitDoubleArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, double value);
+}
diff --git a/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantVisitor.java b/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantVisitor.java
new file mode 100644
index 0000000..79d015d
--- /dev/null
+++ b/core/src/proguard/classfile/constant/visitor/PrimitiveArrayConstantVisitor.java
@@ -0,0 +1,42 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.constant.visitor;
+
+import proguard.classfile.Clazz;
+import proguard.classfile.constant.PrimitiveArrayConstant;
+
+/**
+ * This interface specifies the methods for a visitor of PrimitiveArrayConstant
+ * instances containing different types of arrays.
+ *
+ * @author Eric Lafortune
+ */
+public interface PrimitiveArrayConstantVisitor
+{
+ public void visitBooleanArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, boolean[] values);
+ public void visitByteArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, byte[] values);
+ public void visitCharArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, char[] values);
+ public void visitShortArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, short[] values);
+ public void visitIntArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int[] values);
+ public void visitFloatArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, float[] values);
+ public void visitLongArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, long[] values);
+ public void visitDoubleArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, double[] values);
+}
diff --git a/src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java b/core/src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java
similarity index 97%
rename from src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java
rename to core/src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java
index 7e826c9..90ce726 100644
--- a/src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java
+++ b/core/src/proguard/classfile/constant/visitor/SuperClassConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/constant/visitor/package.html b/core/src/proguard/classfile/constant/visitor/package.html
similarity index 100%
rename from src/proguard/classfile/constant/visitor/package.html
rename to core/src/proguard/classfile/constant/visitor/package.html
diff --git a/core/src/proguard/classfile/editor/AccessFixer.java b/core/src/proguard/classfile/editor/AccessFixer.java
new file mode 100644
index 0000000..ea69f2e
--- /dev/null
+++ b/core/src/proguard/classfile/editor/AccessFixer.java
@@ -0,0 +1,324 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.annotation.visitor.AllElementValueVisitor;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassVisitor fixes the access modifiers of all classes and class
+ * members that are referenced by the classes that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AccessFixer
+implements ClassVisitor
+{
+ private final ClassVisitor referencedClassFixer =
+ new ReferencedClassVisitor(
+ new MyReferencedClassAccessFixer());
+
+ private final ClassVisitor referencedMemberFixer =
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new AllInstructionVisitor(
+ new MyReferencedMemberVisitor(
+ new MyReferencedMemberAccessFixer()))));
+
+ private final ClassVisitor referencedAnnotationMethodFixer =
+ new AllAttributeVisitor(true,
+ new AllElementValueVisitor(
+ new MyReferencedMemberVisitor(
+ new MyReferencedMemberAccessFixer())));
+
+ private final ClassVisitor methodHierarchyFixer =
+ new AllMethodVisitor(
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC,
+ new InitializerMethodFilter(null,
+ new SimilarMemberVisitor(false, true, false, true,
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC,
+ new MyReferencedMemberAccessFixer())))));
+
+
+ // Fields acting as parameters for the visitors.
+
+ private Clazz referencingClass;
+ private int referencingMethodAccessFlags;
+ private Clazz referencedClass;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Remember the referencing class.
+ referencingClass = programClass;
+
+ // Fix the referenced classes.
+ referencedClassFixer.visitProgramClass(programClass);
+
+ // Fix the referenced class members.
+ referencedMemberFixer.visitProgramClass(programClass);
+
+ // Fix the referenced annotation methods.
+ referencedAnnotationMethodFixer.visitProgramClass(programClass);
+
+ // Fix overridden and overriding methods up and down the hierarchy.
+ // They are referenced implicitly and need to be accessible too.
+ referencingMethodAccessFlags = 0;
+ referencedClass = null;
+
+ methodHierarchyFixer.visitProgramClass(programClass);
+ }
+
+
+ /**
+ * This ReferencedMemberVisitor is an InstructionVisitor that also
+ * remembers the access flags of the referencing methods, and the
+ * referenced class.
+ */
+ private class MyReferencedMemberVisitor
+ extends ReferencedMemberVisitor
+ implements InstructionVisitor
+ {
+ public MyReferencedMemberVisitor(MemberVisitor memberVisitor)
+ {
+ super(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)
+ {
+ // Remember the access flags.
+ referencingMethodAccessFlags = method.getAccessFlags();
+
+ // Fix the referenced classes and class members.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
+
+
+ // Overridden methods for ConstantVisitor.
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ // Remember the referenced class. Note that we're interested in the
+ // class of the invocation, not in the class in which the member was
+ // actually found, unless it is an array type.
+ if (ClassUtil.isInternalArrayType(refConstant.getClassName(clazz)))
+ {
+ // For an array type, the class will be java.lang.Object.
+ referencedClass = refConstant.referencedClass;
+ }
+ else
+ {
+ // Remember the referenced class.
+ clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
+ }
+
+ // Fix the access flags of referenced class member.
+ super.visitAnyRefConstant(clazz, refConstant);
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Remember the referenced class.
+ referencedClass = classConstant.referencedClass;
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue)
+ {
+ // Set the referencing access flags and set the referenced class.
+ referencingMethodAccessFlags = ClassConstants.ACC_STATIC;
+ referencedClass = elementValue.referencedClass;
+
+ // Fix the access flags of referenced annotation method.
+ super.visitAnyElementValue(clazz, annotation, elementValue);
+ }
+ }
+
+
+ /**
+ * This ClassVisitor fixes the access flags of the classes that it visits,
+ * relative to the referencing class.
+ */
+ private class MyReferencedClassAccessFixer
+ extends SimplifiedVisitor
+ implements ClassVisitor,
+ AttributeVisitor,
+ InnerClassesInfoVisitor
+ {
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Do we need to update the access flags?
+ int currentAccessFlags = programClass.getAccessFlags();
+ int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
+ if (currentAccessLevel < AccessUtil.PUBLIC)
+ {
+ // Compute the required access level.
+ int requiredAccessLevel =
+ inSamePackage(programClass, referencingClass) ?
+ AccessUtil.PACKAGE_VISIBLE :
+ AccessUtil.PUBLIC;
+
+ // Fix the class access flags if necessary.
+ if (currentAccessLevel < requiredAccessLevel)
+ {
+ programClass.u2accessFlags =
+ AccessUtil.replaceAccessFlags(currentAccessFlags,
+ AccessUtil.accessFlags(requiredAccessLevel));
+ }
+ }
+
+ // Also check the InnerClasses attribute, if any.
+ programClass.attributesAccept(this);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ innerClassesAttribute.innerClassEntriesAccept(clazz, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
+ {
+ // Is this an inner class?
+ int innerClassIndex = innerClassesInfo.u2innerClassIndex;
+ if (innerClassIndex != 0)
+ {
+ String innerClassName = clazz.getClassName(innerClassIndex);
+ if (innerClassName.equals(clazz.getName()))
+ {
+ // Do we need to update the access flags?
+ int currentAccessFlags = innerClassesInfo.u2innerClassAccessFlags;
+ int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
+ if (currentAccessLevel < AccessUtil.PUBLIC)
+ {
+ // Compute the required access level.
+ int requiredAccessLevel =
+ inSamePackage(clazz, referencingClass) ?
+ AccessUtil.PACKAGE_VISIBLE :
+ AccessUtil.PUBLIC;
+
+ // Fix the inner class access flags if necessary.
+ if (currentAccessLevel < requiredAccessLevel)
+ {
+ innerClassesInfo.u2innerClassAccessFlags =
+ AccessUtil.replaceAccessFlags(currentAccessFlags,
+ AccessUtil.accessFlags(requiredAccessLevel));
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This MemberVisitor fixes the access flags of the class members that it
+ * visits, relative to the referencing class and method.
+ */
+ private class MyReferencedMemberAccessFixer
+ extends SimplifiedVisitor
+ implements MemberVisitor
+ {
+ // Implementations for MemberVisitor.
+
+ public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {}
+
+
+ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
+ {
+ // Do we need to update the access flags?
+ int currentAccessFlags = programMember.getAccessFlags();
+ int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
+ if (currentAccessLevel < AccessUtil.PUBLIC)
+ {
+ // Compute the required access level.
+ // For protected access, the referencing method may not be
+ // static. We're also taking into account the class in the
+ // invocation and the class that actually contains the member.
+ int requiredAccessLevel =
+ programClass.equals(referencingClass) ? AccessUtil.PRIVATE :
+ inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE :
+ (referencingMethodAccessFlags & ClassConstants.ACC_STATIC) == 0 &&
+ (referencedClass == null ||
+ referencingClass.extends_(referencedClass)) &&
+ referencingClass.extends_(programClass) ? AccessUtil.PROTECTED :
+ AccessUtil.PUBLIC;
+
+ // Fix the class member access flags if necessary.
+ if (currentAccessLevel < requiredAccessLevel)
+ {
+ programMember.u2accessFlags =
+ AccessUtil.replaceAccessFlags(currentAccessFlags,
+ AccessUtil.accessFlags(requiredAccessLevel));
+ }
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the two given classes are in the same package.
+ */
+ private boolean inSamePackage(Clazz class1, Clazz class2)
+ {
+ return ClassUtil.internalPackageName(class1.getName()).equals(
+ ClassUtil.internalPackageName(class2.getName()));
+ }
+}
diff --git a/src/proguard/classfile/editor/AnnotationAdder.java b/core/src/proguard/classfile/editor/AnnotationAdder.java
similarity index 99%
rename from src/proguard/classfile/editor/AnnotationAdder.java
rename to core/src/proguard/classfile/editor/AnnotationAdder.java
index 3cd4d2f..89430c5 100644
--- a/src/proguard/classfile/editor/AnnotationAdder.java
+++ b/core/src/proguard/classfile/editor/AnnotationAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/AnnotationsAttributeEditor.java b/core/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/AnnotationsAttributeEditor.java
rename to core/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
index bdd08b5..35114c3 100644
--- a/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/AttributeAdder.java b/core/src/proguard/classfile/editor/AttributeAdder.java
similarity index 91%
rename from src/proguard/classfile/editor/AttributeAdder.java
rename to core/src/proguard/classfile/editor/AttributeAdder.java
index 9c84df3..bb189ca 100644
--- a/src/proguard/classfile/editor/AttributeAdder.java
+++ b/core/src/proguard/classfile/editor/AttributeAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -481,6 +481,42 @@ public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Meth
}
+ public void visitRuntimeVisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute)
+ {
+ // Create a new type annotations attribute.
+ RuntimeVisibleTypeAnnotationsAttribute newTypeAnnotationsAttribute =
+ new RuntimeVisibleTypeAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeVisibleTypeAnnotationsAttribute.u2attributeNameIndex),
+ 0,
+ new TypeAnnotation[runtimeVisibleTypeAnnotationsAttribute.u2annotationsCount]);
+
+ // Add the annotations.
+ runtimeVisibleTypeAnnotationsAttribute.typeAnnotationsAccept(clazz,
+ new TypeAnnotationAdder(targetClass,
+ newTypeAnnotationsAttribute));
+
+ // Add it to the target.
+ attributesEditor.addAttribute(newTypeAnnotationsAttribute);
+ }
+
+
+ public void visitRuntimeInvisibleTypeAnnotationsAttribute(Clazz clazz, RuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute)
+ {
+ // Create a new type annotations attribute.
+ RuntimeInvisibleTypeAnnotationsAttribute newTypeAnnotationsAttribute =
+ new RuntimeInvisibleTypeAnnotationsAttribute(constantAdder.addConstant(clazz, runtimeInvisibleTypeAnnotationsAttribute.u2attributeNameIndex),
+ 0,
+ new TypeAnnotation[runtimeInvisibleTypeAnnotationsAttribute.u2annotationsCount]);
+
+ // Add the annotations.
+ runtimeInvisibleTypeAnnotationsAttribute.typeAnnotationsAccept(clazz,
+ new TypeAnnotationAdder(targetClass,
+ newTypeAnnotationsAttribute));
+
+ // Add it to the target.
+ attributesEditor.addAttribute(newTypeAnnotationsAttribute);
+ }
+
+
public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
{
// Create a new annotation default attribute.
diff --git a/src/proguard/classfile/editor/AttributeSorter.java b/core/src/proguard/classfile/editor/AttributeSorter.java
similarity index 98%
rename from src/proguard/classfile/editor/AttributeSorter.java
rename to core/src/proguard/classfile/editor/AttributeSorter.java
index 4da8dcd..ce444ac 100644
--- a/src/proguard/classfile/editor/AttributeSorter.java
+++ b/core/src/proguard/classfile/editor/AttributeSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/AttributesEditor.java b/core/src/proguard/classfile/editor/AttributesEditor.java
similarity index 99%
rename from src/proguard/classfile/editor/AttributesEditor.java
rename to core/src/proguard/classfile/editor/AttributesEditor.java
index 9944549..8471854 100644
--- a/src/proguard/classfile/editor/AttributesEditor.java
+++ b/core/src/proguard/classfile/editor/AttributesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/BootstrapMethodInfoAdder.java b/core/src/proguard/classfile/editor/BootstrapMethodInfoAdder.java
similarity index 98%
rename from src/proguard/classfile/editor/BootstrapMethodInfoAdder.java
rename to core/src/proguard/classfile/editor/BootstrapMethodInfoAdder.java
index 05f0fcb..003c4d8 100644
--- a/src/proguard/classfile/editor/BootstrapMethodInfoAdder.java
+++ b/core/src/proguard/classfile/editor/BootstrapMethodInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/BootstrapMethodRemapper.java b/core/src/proguard/classfile/editor/BootstrapMethodRemapper.java
similarity index 67%
rename from src/proguard/classfile/editor/BootstrapMethodRemapper.java
rename to core/src/proguard/classfile/editor/BootstrapMethodRemapper.java
index c13310b..a978510 100644
--- a/src/proguard/classfile/editor/BootstrapMethodRemapper.java
+++ b/core/src/proguard/classfile/editor/BootstrapMethodRemapper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,18 +21,9 @@
package proguard.classfile.editor;
import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.attribute.annotation.visitor.*;
-import proguard.classfile.attribute.preverification.*;
-import proguard.classfile.attribute.preverification.visitor.*;
-import proguard.classfile.attribute.visitor.*;
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 ConstantVisitor remaps all possible indices of bootstrap methods
@@ -44,16 +35,30 @@ public class BootstrapMethodRemapper
extends SimplifiedVisitor
implements ConstantVisitor
{
- private int[] constantIndexMap;
+ private int[] bootstrapMethodIndexMap;
+
+ // Ignore (skip) lingering InvokeDynamic constants that
+ // refer to removed bootstrap methods.
+ private final boolean ignoreDanglingConstants;
+
+ public BootstrapMethodRemapper()
+ {
+ this(false);
+ }
+
+ public BootstrapMethodRemapper(boolean ignoreDanglingConstants)
+ {
+ this.ignoreDanglingConstants = ignoreDanglingConstants;
+ }
/**
* Sets the given mapping of old constant pool entry indexes to their new
* indexes.
*/
- public void setConstantIndexMap(int[] constantIndexMap)
+ public void setBootstrapMethodIndexMap(int[] bootstrapMethodIndexMap)
{
- this.constantIndexMap = constantIndexMap;
+ this.bootstrapMethodIndexMap = bootstrapMethodIndexMap;
}
@@ -72,15 +77,22 @@ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invoke
// Small utility methods.
/**
- * Returns the new bootstrap method index of the entry at the
+ * Returns the latest bootstrap method index of the entry at the
* given index.
*/
private int remapConstantIndex(int constantIndex)
{
- int remappedConstantIndex = constantIndexMap[constantIndex];
+ int remappedConstantIndex = bootstrapMethodIndexMap[constantIndex];
if (remappedConstantIndex < 0)
{
- throw new IllegalArgumentException("Can't remap constant index ["+constantIndex+"]");
+ if (ignoreDanglingConstants)
+ {
+ return constantIndex;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Can't remap bootstrap method index ["+constantIndex+"]");
+ }
}
return remappedConstantIndex;
diff --git a/src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java
similarity index 98%
rename from src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java
rename to core/src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java
index 5ac2281..9f64885 100644
--- a/src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java
+++ b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/BootstrapMethodsAttributeEditor.java b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeEditor.java
similarity index 55%
rename from src/proguard/classfile/editor/BootstrapMethodsAttributeEditor.java
rename to core/src/proguard/classfile/editor/BootstrapMethodsAttributeEditor.java
index c2ed13a..870762b 100644
--- a/src/proguard/classfile/editor/BootstrapMethodsAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,8 +24,8 @@
import proguard.util.ArrayUtil;
/**
- * This class can add bootstrap methods to a given bootstrap methods attribute.
- * Bootstrap methods to be added must have been filled out beforehand.
+ * This class can add/remove bootstrap methods to/from a given bootstrap methods
+ * attribute. Bootstrap methods to be added must have been filled out beforehand.
*
* @author Eric Lafortune
*/
@@ -51,10 +51,41 @@ public BootstrapMethodsAttributeEditor(BootstrapMethodsAttribute targetBootstrap
public int addBootstrapMethodInfo(BootstrapMethodInfo bootstrapMethodInfo)
{
targetBootstrapMethodsAttribute.bootstrapMethods =
- (BootstrapMethodInfo[])ArrayUtil.add(targetBootstrapMethodsAttribute.bootstrapMethods,
- targetBootstrapMethodsAttribute.u2bootstrapMethodsCount,
- bootstrapMethodInfo);
+ ArrayUtil.add(targetBootstrapMethodsAttribute.bootstrapMethods,
+ targetBootstrapMethodsAttribute.u2bootstrapMethodsCount,
+ bootstrapMethodInfo);
return targetBootstrapMethodsAttribute.u2bootstrapMethodsCount++;
}
+
+
+ /**
+ * Removes the given bootstrap method from the bootstrap method attribute.
+ */
+ public void removeBootstrapMethodInfo(BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ ArrayUtil.remove(targetBootstrapMethodsAttribute.bootstrapMethods,
+ targetBootstrapMethodsAttribute.u2bootstrapMethodsCount--,
+ findBootstrapMethodInfoIndex(bootstrapMethodInfo));
+ }
+
+
+ /**
+ * Finds the index of the given bootstrap method info in the target attribute.
+ */
+ private int findBootstrapMethodInfoIndex(BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ int methodsCount = targetBootstrapMethodsAttribute.u2bootstrapMethodsCount;
+ BootstrapMethodInfo[] methodInfos = targetBootstrapMethodsAttribute.bootstrapMethods;
+
+ for (int index = 0; index < methodsCount; index++)
+ {
+ if (methodInfos[index].equals(bootstrapMethodInfo))
+ {
+ return index;
+ }
+ }
+
+ return methodsCount;
+ }
}
\ No newline at end of file
diff --git a/core/src/proguard/classfile/editor/BootstrapMethodsAttributeShrinker.java b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeShrinker.java
new file mode 100644
index 0000000..7020f50
--- /dev/null
+++ b/core/src/proguard/classfile/editor/BootstrapMethodsAttributeShrinker.java
@@ -0,0 +1,339 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.classfile.VisitorAccepter;
+
+import java.util.Arrays;
+
+/**
+ * This ClassVisitor removes all unused entries from the bootstrap method attribute.
+ *
+ * If all bootstrap methods are removed, it also removes the BootstrapMethodsAttribute from
+ * the visited class. Additionally, the java/lang/MethodHandles$Lookup class will be
+ * removed from the InnerClasses attribute and the InnerClassesAttribute will be removed if
+ * it was the only entry.
+ *
+ * @author Tim Van Den Broecke
+ */
+public class BootstrapMethodsAttributeShrinker
+extends SimplifiedVisitor
+implements ClassVisitor,
+
+ // Implementation interfaces.
+ MemberVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ BootstrapMethodInfoVisitor
+{
+ // A visitor info flag to indicate the bootstrap method is being used.
+ private static final Object USED = new Object();
+
+ private int[] bootstrapMethodIndexMap = new int[ClassConstants.TYPICAL_BOOTSTRAP_METHODS_ATTRIBUTE_SIZE];
+ private final BootstrapMethodRemapper bootstrapMethodRemapper = new BootstrapMethodRemapper(true);
+
+ private int referencedBootstrapMethodIndex = -1;
+ private boolean modified = false;
+
+
+ // Implementations for ClassVisitor.
+
+ @Override
+ public void visitLibraryClass(LibraryClass libaryClass) {}
+
+
+ @Override
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Clear the fields from any previous runs.
+ modified = false;
+ bootstrapMethodIndexMap = new int[ClassConstants.TYPICAL_BOOTSTRAP_METHODS_ATTRIBUTE_SIZE];
+
+ // Remove any previous visitor info.
+ programClass.accept(new ClassCleaner());
+
+ // Mark the bootstrap methods referenced by invokeDynamic instructions.
+ programClass.methodsAccept(this);
+
+ // Shrink the bootstrap methods attribute
+ programClass.attributesAccept(this);
+
+ if (modified)
+ {
+ // Clean up dangling and freed up constants
+ programClass.accept(new ConstantPoolShrinker());
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ @Override
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ programMethod.attributesAccept(programClass, this);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ @Override
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ @Override
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttribute.instructionsAccept(clazz, method, this);
+ }
+
+
+ @Override
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ if (referencedBootstrapMethodIndex > -1)
+ {
+ // We're marking bootstrap methods
+ bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz, referencedBootstrapMethodIndex, this);
+ }
+ else
+ {
+ // The bootstrap methods have been marked, so now we shrink the array of BootstrapMethodInfo objects.
+ int newBootstrapMethodsCount =
+ shrinkBootstrapMethodArray(bootstrapMethodsAttribute.bootstrapMethods,
+ bootstrapMethodsAttribute.u2bootstrapMethodsCount);
+
+ if (newBootstrapMethodsCount < bootstrapMethodsAttribute.u2bootstrapMethodsCount)
+ {
+ modified = true;
+
+ bootstrapMethodsAttribute.u2bootstrapMethodsCount = newBootstrapMethodsCount;
+
+ if (bootstrapMethodsAttribute.u2bootstrapMethodsCount == 0)
+ {
+ // Remove the entire attribute.
+ AttributesEditor attributesEditor = new AttributesEditor((ProgramClass)clazz, false);
+ attributesEditor.deleteAttribute(ClassConstants.ATTR_BootstrapMethods);
+
+ // Only bootstrap methods require the java/lang/MethodHandles$Lookup
+ // inner class, so we can remove it.
+ clazz.attributesAccept(new MethodHandlesLookupInnerClassRemover(attributesEditor));
+ }
+ else
+ {
+ // Remap all constant pool references to remaining bootstrap methods.
+ bootstrapMethodRemapper.setBootstrapMethodIndexMap(bootstrapMethodIndexMap);
+ clazz.constantPoolEntriesAccept(bootstrapMethodRemapper);
+ }
+ }
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ @Override
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ @Override
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ if (constantInstruction.opcode == InstructionConstants.OP_INVOKEDYNAMIC)
+ {
+ ProgramClass programClass = (ProgramClass)clazz;
+
+ InvokeDynamicConstant invokeDynamicConstant =
+ (InvokeDynamicConstant)programClass.getConstant(constantInstruction.constantIndex);
+
+ referencedBootstrapMethodIndex = invokeDynamicConstant.getBootstrapMethodAttributeIndex();
+
+ programClass.attributesAccept(this);
+
+ referencedBootstrapMethodIndex = -1;
+ }
+ }
+
+
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ @Override
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ markAsUsed(bootstrapMethodInfo);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given visitor accepter as being used.
+ */
+ private void markAsUsed(BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ bootstrapMethodInfo.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given visitor accepter has been marked as being used.
+ */
+ private boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+
+
+ /**
+ * Removes all entries that are not marked as being used from the given
+ * array of bootstrap methods. Creates a map from the old indices to the
+ * new indices as a side effect.
+ * @return the new number of entries.
+ */
+ private int shrinkBootstrapMethodArray(BootstrapMethodInfo[] bootstrapMethods, int length)
+ {
+ if (bootstrapMethodIndexMap.length < length)
+ {
+ bootstrapMethodIndexMap = new int[length];
+ }
+
+ int counter = 0;
+
+ // Shift the used bootstrap methods together.
+ for (int index = 0; index < length; index++)
+ {
+ BootstrapMethodInfo bootstrapMethod = bootstrapMethods[index];
+
+ // Is the entry being used?
+ if (isUsed(bootstrapMethod))
+ {
+ // Remember the new index.
+ bootstrapMethodIndexMap[index] = counter;
+
+ // Shift the entry.
+ bootstrapMethods[counter++] = bootstrapMethod;
+ }
+ else
+ {
+ // Remember an invalid index.
+ bootstrapMethodIndexMap[index] = -1;
+ }
+ }
+
+ // Clear the remaining bootstrap methods.
+ Arrays.fill(bootstrapMethods, counter, length, null);
+
+ return counter;
+ }
+
+ private class MethodHandlesLookupInnerClassRemover
+ extends SimplifiedVisitor
+ implements AttributeVisitor,
+
+ // Implementation interfaces.
+ InnerClassesInfoVisitor
+ {
+ private static final String METHOD_HANDLES_CLASS = "java/lang/invoke/MethodHandles";
+
+ private final Object methodHandleLookupMarker = new Object();
+
+ private final AttributesEditor attributesEditor;
+
+ public MethodHandlesLookupInnerClassRemover(AttributesEditor attributesEditor)
+ {
+ this.attributesEditor = attributesEditor;
+ }
+
+ // Implementations for AttributeVisitor
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ // Mark inner class infos that refer to Lookup.
+ innerClassesAttribute.innerClassEntriesAccept(clazz, this);
+
+ // Remove all marked inner classes.
+ InnerClassesAttributeEditor editor =
+ new InnerClassesAttributeEditor(innerClassesAttribute);
+ for (int index = innerClassesAttribute.u2classesCount - 1; index >= 0; index--)
+ {
+ InnerClassesInfo innerClassesInfo = innerClassesAttribute.classes[index];
+ if (shouldBeRemoved(innerClassesInfo))
+ {
+ editor.removeInnerClassesInfo(innerClassesInfo);
+ }
+ }
+
+ // Remove the attribute if it is empty.
+ if (innerClassesAttribute.u2classesCount == 0)
+ {
+ attributesEditor.deleteAttribute(ClassConstants.ATTR_InnerClasses);
+ }
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
+ {
+ ProgramClass programClass = (ProgramClass) clazz;
+
+ ClassConstant innerClass =
+ (ClassConstant) programClass.getConstant(innerClassesInfo.u2innerClassIndex);
+ ClassConstant outerClass =
+ (ClassConstant) programClass.getConstant(innerClassesInfo.u2outerClassIndex);
+
+ if (isMethodHandleClass(innerClass, clazz) ||
+ isMethodHandleClass(outerClass, clazz))
+ {
+ markForRemoval(innerClassesInfo);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private void markForRemoval(InnerClassesInfo innerClassesInfo)
+ {
+ innerClassesInfo.setVisitorInfo(methodHandleLookupMarker);
+ }
+
+ private boolean shouldBeRemoved(InnerClassesInfo innerClassesInfo)
+ {
+ return innerClassesInfo.getVisitorInfo() == methodHandleLookupMarker;
+ }
+
+ public boolean isMethodHandleClass(ClassConstant classConstant, Clazz clazz)
+ {
+ return classConstant != null &&
+ classConstant.getName(clazz).startsWith(METHOD_HANDLES_CLASS);
+ }
+ }
+}
diff --git a/src/proguard/classfile/editor/BridgeMethodFixer.java b/core/src/proguard/classfile/editor/BridgeMethodFixer.java
similarity index 98%
rename from src/proguard/classfile/editor/BridgeMethodFixer.java
rename to core/src/proguard/classfile/editor/BridgeMethodFixer.java
index f58ee97..e11eea4 100644
--- a/src/proguard/classfile/editor/BridgeMethodFixer.java
+++ b/core/src/proguard/classfile/editor/BridgeMethodFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ClassEditor.java b/core/src/proguard/classfile/editor/ClassEditor.java
similarity index 99%
rename from src/proguard/classfile/editor/ClassEditor.java
rename to core/src/proguard/classfile/editor/ClassEditor.java
index 086a031..aa0b82d 100644
--- a/src/proguard/classfile/editor/ClassEditor.java
+++ b/core/src/proguard/classfile/editor/ClassEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ClassElementSorter.java b/core/src/proguard/classfile/editor/ClassElementSorter.java
similarity index 97%
rename from src/proguard/classfile/editor/ClassElementSorter.java
rename to core/src/proguard/classfile/editor/ClassElementSorter.java
index a9cdf0c..2492453 100644
--- a/src/proguard/classfile/editor/ClassElementSorter.java
+++ b/core/src/proguard/classfile/editor/ClassElementSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ClassMemberSorter.java b/core/src/proguard/classfile/editor/ClassMemberSorter.java
similarity index 97%
rename from src/proguard/classfile/editor/ClassMemberSorter.java
rename to core/src/proguard/classfile/editor/ClassMemberSorter.java
index 4efcf91..281466b 100644
--- a/src/proguard/classfile/editor/ClassMemberSorter.java
+++ b/core/src/proguard/classfile/editor/ClassMemberSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ClassReferenceFixer.java b/core/src/proguard/classfile/editor/ClassReferenceFixer.java
similarity index 99%
rename from src/proguard/classfile/editor/ClassReferenceFixer.java
rename to core/src/proguard/classfile/editor/ClassReferenceFixer.java
index ffe7aa8..fb68461 100644
--- a/src/proguard/classfile/editor/ClassReferenceFixer.java
+++ b/core/src/proguard/classfile/editor/ClassReferenceFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/CodeAttributeComposer.java b/core/src/proguard/classfile/editor/CodeAttributeComposer.java
similarity index 99%
rename from src/proguard/classfile/editor/CodeAttributeComposer.java
rename to core/src/proguard/classfile/editor/CodeAttributeComposer.java
index a3de9a9..f8977f9 100644
--- a/src/proguard/classfile/editor/CodeAttributeComposer.java
+++ b/core/src/proguard/classfile/editor/CodeAttributeComposer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/CodeAttributeEditor.java b/core/src/proguard/classfile/editor/CodeAttributeEditor.java
similarity index 72%
rename from src/proguard/classfile/editor/CodeAttributeEditor.java
rename to core/src/proguard/classfile/editor/CodeAttributeEditor.java
index b374705..1d4ba36 100644
--- a/src/proguard/classfile/editor/CodeAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/CodeAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,12 +34,40 @@
import proguard.classfile.util.SimplifiedVisitor;
import proguard.util.ArrayUtil;
-import java.util.Arrays;
+import java.util.*;
/**
* This AttributeVisitor accumulates specified changes to code, and then applies
* these accumulated changes to the code attributes that it visits.
*
+ * The class also supports labels ({@link #label()}) and exception handlers
+ * ({@link #catch_(int,int,int)}) in replacement sequences. They provide
+ * local branch offsets inside the replacement sequences
+ * ({@link Label#offset()}). For example, creating a replacement sequence
+ * with the help of {@link InstructionSequenceBuilder}:
+ *
+ * final CodeAttributeEditor.Label TRY_START = codeAttributeEditor.label();
+ * final CodeAttributeEditor.Label TRY_END = codeAttributeEditor.label();
+ * final CodeAttributeEditor.Label CATCH_END = codeAttributeEditor.label();
+ *
+ * final CodeAttributeEditor.Label CATCH_EXCEPTION =
+ * codeAttributeEditor.catch_(TRY_START.offset(),
+ * TRY_END.offset(),
+ * constantPoolEditor.addClassConstant("java/lang/Exception", null));
+ *
+ * Instructions[] replacementInstructions = builder
+ * .label(TRY_START)
+ * ......
+ * .label(TRY_END)
+ * .goto_(CATCH_END.offset())
+ * .catch_(CATCH_EXCEPTION)
+ * ......
+ * .athrow()
+ * .label(CATCH_END)
+ * ......
+ * .instructions();
+ *
+ *
* @author Eric Lafortune
*/
public class CodeAttributeEditor
@@ -59,9 +87,11 @@ public class CodeAttributeEditor
//*
private static final boolean DEBUG = false;
/*/
- public static boolean DEBUG = false;
+ public static boolean DEBUG = System.getProperty("cae") != null;
//*/
+ private static final int LABEL_FLAG = 0x20000000;
+
private final boolean updateFrameSizes;
private final boolean shrinkInstructions;
@@ -70,10 +100,14 @@ public class CodeAttributeEditor
private boolean modified;
private boolean simple;
- /*private*/public Instruction[] preInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
- /*private*/public Instruction[] replacements = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
- /*private*/public Instruction[] postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
- /*private*/public boolean[] deleted = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private Map labels = new HashMap();
+
+ /*private*/public Instruction[] preOffsetInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
+ /*private*/public Instruction[] preInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
+ /*private*/public Instruction[] replacements = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
+ /*private*/public Instruction[] postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
+ /*private*/public boolean[] deleted = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+
private int[] newInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private int newOffset;
@@ -112,25 +146,31 @@ public CodeAttributeEditor(boolean updateFrameSizes,
/**
- * Resets the accumulated code changes.
+ * Resets the accumulated code changes for a given anticipated maximum
+ * code length. If necessary, the size may still be extended while
+ * editing the code, with {@link #extend(int)}.
* @param codeLength the length of the code that will be edited next.
*/
public void reset(int codeLength)
{
+ labels.clear();
+
// Try to reuse the previous arrays.
if (preInsertions.length < codeLength)
{
- preInsertions = new Instruction[codeLength];
- replacements = new Instruction[codeLength];
- postInsertions = new Instruction[codeLength];
- deleted = new boolean[codeLength];
+ preOffsetInsertions = new Instruction[codeLength];
+ preInsertions = new Instruction[codeLength];
+ replacements = new Instruction[codeLength];
+ postInsertions = new Instruction[codeLength];
+ deleted = new boolean[codeLength];
}
else
{
- Arrays.fill(preInsertions, 0, codeLength, null);
- Arrays.fill(replacements, 0, codeLength, null);
- Arrays.fill(postInsertions, 0, codeLength, null);
- Arrays.fill(deleted, 0, codeLength, false);
+ Arrays.fill(preOffsetInsertions, 0, codeLength, null);
+ Arrays.fill(preInsertions, 0, codeLength, null);
+ Arrays.fill(replacements, 0, codeLength, null);
+ Arrays.fill(postInsertions, 0, codeLength, null);
+ Arrays.fill(deleted, 0, codeLength, false);
}
this.codeLength = codeLength;
@@ -149,17 +189,19 @@ public void extend(int codeLength)
// Try to reuse the previous arrays.
if (preInsertions.length < codeLength)
{
- preInsertions = (Instruction[])ArrayUtil.extendArray(preInsertions, codeLength);
- replacements = (Instruction[])ArrayUtil.extendArray(replacements, codeLength);
- postInsertions = (Instruction[])ArrayUtil.extendArray(postInsertions, codeLength);
- deleted = ArrayUtil.extendArray(deleted, codeLength);
+ preOffsetInsertions = ArrayUtil.extendArray(preOffsetInsertions, codeLength);
+ preInsertions = ArrayUtil.extendArray(preInsertions, codeLength);
+ replacements = ArrayUtil.extendArray(replacements, codeLength);
+ postInsertions = ArrayUtil.extendArray(postInsertions, codeLength);
+ deleted = ArrayUtil.extendArray(deleted, codeLength);
}
else
{
- Arrays.fill(preInsertions, this.codeLength, codeLength, null);
- Arrays.fill(replacements, this.codeLength, codeLength, null);
- Arrays.fill(postInsertions, this.codeLength, codeLength, null);
- Arrays.fill(deleted, this.codeLength, codeLength, false);
+ Arrays.fill(preOffsetInsertions, this.codeLength, codeLength, null);
+ Arrays.fill(preInsertions, this.codeLength, codeLength, null);
+ Arrays.fill(replacements, this.codeLength, codeLength, null);
+ Arrays.fill(postInsertions, this.codeLength, codeLength, null);
+ Arrays.fill(deleted, this.codeLength, codeLength, false);
}
this.codeLength = codeLength;
@@ -168,7 +210,36 @@ public void extend(int codeLength)
/**
* Remembers to place the given instruction right before the instruction
- * at the given offset.
+ * at the given offset. Any branches to the existing instruction will
+ * land after the new instruction. Similarly, any try blocks that start at
+ * the existing instruction will not include the new instruction. However,
+ * any try blocks that end right before the existing instruction wil now
+ * include the new instruction.
+ * @param instructionOffset the offset of the instruction.
+ * @param instruction the new instruction.
+ */
+ public void insertBeforeOffset(int instructionOffset, Instruction instruction)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ preOffsetInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
+
+ modified = true;
+ simple = false;
+ }
+
+
+ /**
+ * Remembers to place the given instruction right before the instruction
+ * at the given offset. Any branches to the existing instruction will
+ * also go to the new instruction. Similarly, any try blocks that include
+ * the existing instruction will also include the new instruction.
* @param instructionOffset the offset of the instruction.
* @param instruction the new instruction.
*/
@@ -191,7 +262,39 @@ public void insertBeforeInstruction(int instructionOffset, Instruction instructi
/**
* Remembers to place the given instructions right before the instruction
- * at the given offset.
+ * at the given offset. Any branches to the existing instruction will
+ * land after the new instructions. Similarly, any try blocks that start at
+ * the existing instruction will not include the new instructions. However,
+ * any try blocks that end right before the existing instruction wil now
+ * include the new instructions.
+ * @param instructionOffset the offset of the instruction.
+ * @param instructions the new instructions.
+ */
+ public void insertBeforeOffset(int instructionOffset, Instruction[] instructions)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ CompositeInstruction instruction =
+ new CompositeInstruction(instructions);
+
+ preOffsetInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
+
+ modified = true;
+ simple = false;
+ }
+
+
+ /**
+ * Remembers to place the given instructions right before the instruction
+ * at the given offset. Any branches to the existing instruction will
+ * also go to the new instructions. Similarly, any try blocks that include
+ * the existing instruction will also include the new instructions.
* @param instructionOffset the offset of the instruction.
* @param instructions the new instructions.
*/
@@ -358,10 +461,11 @@ public void clearModifications(int instructionOffset)
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- preInsertions[instructionOffset] = null;
- replacements[instructionOffset] = null;
- postInsertions[instructionOffset] = null;
- deleted[instructionOffset] = false;
+ preOffsetInsertions[instructionOffset] = null;
+ preInsertions[instructionOffset] = null;
+ replacements[instructionOffset] = null;
+ postInsertions[instructionOffset] = null;
+ deleted[instructionOffset] = false;
}
@@ -380,9 +484,10 @@ public boolean isModified()
*/
public boolean isModified(int instructionOffset)
{
- return preInsertions[instructionOffset] != null ||
- replacements[instructionOffset] != null ||
- postInsertions[instructionOffset] != null ||
+ return preOffsetInsertions[instructionOffset] != null ||
+ preInsertions[instructionOffset] != null ||
+ replacements[instructionOffset] != null ||
+ postInsertions[instructionOffset] != null ||
deleted[instructionOffset];
}
@@ -674,6 +779,13 @@ private int mapInstructions(byte[] oldCode, int oldLength)
private void mapInstruction(int oldOffset,
Instruction instruction)
{
+ // Account for the pre-offset-inserted instruction, if any.
+ Instruction preOffsetInstruction = preOffsetInsertions[oldOffset];
+ if (preOffsetInstruction != null)
+ {
+ newOffset += preOffsetInstruction.length(newOffset);
+ }
+
newInstructionOffsets[oldOffset] = newOffset;
// Account for the pre-inserted instruction, if any.
@@ -756,6 +868,19 @@ private void moveInstruction(Clazz clazz,
int oldOffset,
Instruction instruction)
{
+ // Update and insert the pre-inserted instruction, if any.
+ Instruction preOffsetInstruction = preOffsetInsertions[oldOffset];
+ if (preOffsetInstruction != null)
+ {
+ if (DEBUG)
+ {
+ System.out.println(" Pre-inserted ["+oldOffset+"] -> "+preOffsetInstruction.toString(newOffset));
+ }
+
+ // Update the instruction.
+ preOffsetInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
+ }
+
// Update and insert the pre-inserted instruction, if any.
Instruction preInstruction = preInsertions[oldOffset];
if (preInstruction != null)
@@ -1097,7 +1222,12 @@ private int newBranchOffset(int oldInstructionOffset,
int oldBranchOffset,
int newInstructionOffset)
{
- return newInstructionOffset(oldInstructionOffset + oldBranchOffset) -
+ // Compute the old branch target.
+ // Pass a label offset unchanged.
+ int oldBranchTargetOffset = isLabel(oldBranchOffset) ? oldBranchOffset :
+ oldInstructionOffset + oldBranchOffset;
+
+ return newInstructionOffset(oldBranchTargetOffset) -
newInstructionOffset;
}
@@ -1108,6 +1238,21 @@ private int newBranchOffset(int oldInstructionOffset,
*/
private int newInstructionOffset(int oldInstructionOffset)
{
+ // Special case: is it actually a label?
+ if (isLabel(oldInstructionOffset))
+ {
+ // Retrieve the new offset from the label.
+ int labelIdentifier = labelIdentifier(oldInstructionOffset);
+ Label label = (Label)labels.get(labelIdentifier);
+ if (label == null)
+ {
+ throw new IllegalArgumentException("Reference to unknown label identifier ["+labelIdentifier+"]");
+ }
+
+ return label.newOffset;
+ }
+
+ // Otherwise retrieve the new instruction offset.
if (oldInstructionOffset < 0 ||
oldInstructionOffset > codeLength)
{
@@ -1166,8 +1311,8 @@ private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos,
/**
- * This instruction is a composite of other instructions, for local use
- * inside the editor class only.
+ * This pseudo-instruction is a composite of other instructions, for local
+ * use inside the editor class only.
*/
private class CompositeInstruction
extends Instruction
@@ -1244,8 +1389,6 @@ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int
Instruction instruction = instructions[index];
instruction.accept(clazz, method, codeAttribute, offset, CodeAttributeEditor.this);
-
- offset += instruction.length(offset);
}
}
@@ -1264,4 +1407,265 @@ public String toString()
return stringBuffer.toString();
}
}
+
+
+ // For convenience, we also define two pseudo-instructions, to conveniently
+ // mark local labels and create new exceptions handlers.
+
+ /**
+ * Creates a new label that can be used as a pseudo-instruction to mark
+ * a local offset. Its offset can be used as a branch target in
+ * replacement instructions ({@link Label#offset()}).
+ */
+ public Label label()
+ {
+ return label(labels.size());
+ }
+
+
+ /**
+ * Creates a new label that can be used as a pseudo-instruction to mark
+ * a local offset. Its offset can be used as a branch target in
+ * replacement instructions ({@link Label#offset()}).
+ */
+ public Label label(int identifier)
+ {
+ Label label = new Label(identifier);
+
+ // Remember the label, so we can retrieve its offset later on.
+ labels.put(new Integer(identifier), label);
+
+ return label;
+ }
+
+
+ /**
+ * Creates a new catch instance that can be used as a pseudo-instruction
+ * to mark the start of an exception handler. Its offset can be used as
+ * a branch target in replacement instructions ({@link Label#offset()}).
+ */
+ public Label catch_(int startOffset,
+ int endOffset,
+ int catchType)
+ {
+ return catch_(labels.size(),
+ startOffset,
+ endOffset,
+ catchType);
+ }
+
+
+ /**
+ * Creates a new catch instance that can be used as a pseudo-instruction
+ * to mark the start of an exception handler. Its offset can be used as
+ * a branch target in replacement instructions ({@link Label#offset()}).
+ */
+ public Label catch_(int identifier,
+ int startOffset,
+ int endOffset,
+ int catchType)
+ {
+ Label catch_ = new Catch(identifier, startOffset, endOffset, catchType);
+
+ // Remember the label, so we can retrieve its offset later on.
+ labels.put(new Integer(identifier), catch_);
+
+ return catch_;
+ }
+
+
+ /**
+ * Returns whether the given instruction offset actually represents a
+ * label (which contains the actual offset).
+ */
+ private static boolean isLabel(int instructionOffset)
+ {
+ return (instructionOffset & 0xff000000) == LABEL_FLAG;
+ }
+
+
+ /**
+ * Returns the label identifier that corrresponds to the given
+ * instruction offset.
+ */
+ private static int labelIdentifier(int instructionOffset)
+ {
+ return instructionOffset & ~LABEL_FLAG;
+ }
+
+
+ /**
+ * This pseudo-instruction represents a label that marks an instruction
+ * offset, for use in the context of the code attribute editor only.
+ */
+ private static class Label
+ extends Instruction
+ {
+ protected final int identifier;
+
+ private int newOffset;
+
+
+ /**
+ * Creates a new Label.
+ * @param identifier an identifier that can be chosen freely.
+ */
+ public Label(int identifier)
+ {
+ this.identifier = identifier;
+ }
+
+
+ /**
+ * Returns the offset that can then be used as a branch target in
+ * other replacement instructions.
+ */
+ public int offset()
+ {
+ return LABEL_FLAG | identifier;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ return this;
+ }
+
+
+ public void write(byte[] code, int offset)
+ {
+ }
+
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ throw new UnsupportedOperationException("Can't read label instruction");
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ throw new UnsupportedOperationException("Can't write label instruction");
+ }
+
+
+ public int length(int offset)
+ {
+ // Remember the offset, so we can retrieve it later on.
+ newOffset = offset;
+
+ return 0;
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ if (instructionVisitor.getClass() != CodeAttributeEditor.class)
+ {
+ throw new UnsupportedOperationException("Unexpected visitor ["+instructionVisitor+"]");
+ }
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return "label_"+offset();
+ }
+ }
+
+
+ /**
+ * This pseudo-instruction represents an exception handler,
+ * for use in the context of the code attribute editor only.
+ */
+ private static class Catch
+ extends Label
+ {
+ private final int startOfffset;
+ private final int endOffset;
+ private final int catchType;
+
+
+ /**
+ * Creates a new Catch instance.
+ * @param identifier an identifier that can be chosen freely.
+ * @param startOffset the start offset of the catch block.
+ * @param endOffset the end offset of the catch block.
+ * @param catchType the index of the catch type in the constant pool.
+ */
+ public Catch(int identifier,
+ int startOffset,
+ int endOffset,
+ int catchType)
+ {
+ super(identifier);
+
+ this.startOfffset = startOffset;
+ this.endOffset = endOffset;
+ this.catchType = catchType;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ return this;
+ }
+
+
+ public void write(byte[] code, int offset)
+ {
+ }
+
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ throw new UnsupportedOperationException("Can't read catch instruction");
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ throw new UnsupportedOperationException("Can't write catch instruction");
+ }
+
+
+ public int length(int offset)
+ {
+ return super.length(offset);
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ if (instructionVisitor.getClass() != CodeAttributeEditor.class)
+ {
+ throw new UnsupportedOperationException("Unexpected visitor ["+instructionVisitor+"]");
+ }
+
+ // Add the exception. Its offsets will still be updated later on,
+ // like any other exception.
+ new ExceptionInfoEditor(codeAttribute).prependException(
+ new ExceptionInfo(startOfffset,
+ endOffset,
+ offset(),
+ catchType));
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return "catch " +
+ (isLabel(startOfffset) ? "label_" : "") + startOfffset + ", " +
+ (isLabel(endOffset) ? "label_" : "") + endOffset + ", #" +
+ catchType;
+ }
+ }
}
diff --git a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java b/core/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
similarity index 97%
rename from src/proguard/classfile/editor/CodeAttributeEditorResetter.java
rename to core/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
index 8abb3f6..1d0e692 100644
--- a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
+++ b/core/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/CompactCodeAttributeComposer.java b/core/src/proguard/classfile/editor/CompactCodeAttributeComposer.java
new file mode 100644
index 0000000..03f82e7
--- /dev/null
+++ b/core/src/proguard/classfile/editor/CompactCodeAttributeComposer.java
@@ -0,0 +1,2075 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+
+import static proguard.classfile.ClassConstants.*;
+
+/**
+ * This AttributeVisitor accumulates instructions and exceptions, and then
+ * copies them into code attributes that it visits.
+ *
+ * @see CodeAttributeComposer
+ *
+ * @author Eric Lafortune
+ */
+public class CompactCodeAttributeComposer
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final ConstantPoolEditor constantPoolEditor;
+ private final CodeAttributeComposer codeAttributeComposer;
+
+
+ /**
+ * Creates a new CompactCodeAttributeComposer that doesn't allow external
+ * branch targets or exception handlers and that automatically shrinks
+ * instructions.
+ */
+ public CompactCodeAttributeComposer(ProgramClass targetClass)
+ {
+ this(targetClass, false, false, true);
+ }
+
+
+ /**
+ * Creates a new CompactCodeAttributeComposer.
+ * @param allowExternalBranchTargets specifies whether branch targets
+ * can lie outside the code fragment
+ * of the branch instructions.
+ * @param allowExternalExceptionHandlers specifies whether exception
+ * handlers can lie outside the code
+ * fragment in which exceptions are
+ * defined.
+ * @param shrinkInstructions specifies whether instructions
+ * should automatically be shrunk
+ * before being written.
+ */
+ public CompactCodeAttributeComposer(ProgramClass targetClass,
+ boolean allowExternalBranchTargets,
+ boolean allowExternalExceptionHandlers,
+ boolean shrinkInstructions)
+ {
+ constantPoolEditor =
+ new ConstantPoolEditor(targetClass);
+
+ codeAttributeComposer =
+ new CodeAttributeComposer(allowExternalBranchTargets,
+ allowExternalExceptionHandlers,
+ shrinkInstructions);
+ }
+
+
+ /**
+ * Starts a new code definition.
+ */
+ public CompactCodeAttributeComposer reset()
+ {
+ codeAttributeComposer.reset();
+
+ return this;
+ }
+
+
+ /**
+ * Starts a new code fragment. Branch instructions that are added are
+ * assumed to be relative within such code fragments.
+ * @param maximumCodeFragmentLength the maximum length of the code that will
+ * be added as part of this fragment (more
+ * precisely, the maximum old instruction
+ * offset or label that is specified, plus
+ * one).
+ */
+ public CompactCodeAttributeComposer beginCodeFragment(int maximumCodeFragmentLength)
+ {
+ codeAttributeComposer.beginCodeFragment(maximumCodeFragmentLength);
+
+ return this;
+ }
+
+
+ /**
+ * Appends the given instruction with the given old offset.
+ * Branch instructions must fit, for instance by enabling automatic
+ * shrinking of instructions.
+ * @param oldInstructionOffset the old offset of the instruction, to which
+ * branches and other references in the current
+ * code fragment are pointing.
+ * @param instruction the instruction to be appended.
+ */
+ public CompactCodeAttributeComposer appendInstruction(int oldInstructionOffset,
+ Instruction instruction)
+ {
+ codeAttributeComposer.appendInstruction(oldInstructionOffset, instruction);
+
+ return this;
+ }
+
+
+ /**
+ * Appends the given label with the given old offset.
+ * @param oldInstructionOffset the old offset of the label, to which
+ * branches and other references in the current
+ * code fragment are pointing.
+ */
+ public CompactCodeAttributeComposer appendLabel(int oldInstructionOffset)
+ {
+ codeAttributeComposer.appendLabel(oldInstructionOffset);
+
+ return this;
+ }
+
+
+ /**
+ * Appends the given instruction without defined offsets.
+ * @param instructions the instructions to be appended.
+ */
+ public CompactCodeAttributeComposer appendInstructions(Instruction[] instructions)
+ {
+ codeAttributeComposer.appendInstructions(instructions);
+
+ return this;
+ }
+
+
+ /**
+ * Appends the given instruction without a defined offset.
+ * Branch instructions should have a label, to allow computing the
+ * new relative offset.
+ * Branch instructions must fit, for instance by enabling automatic
+ * shrinking of instructions.
+ * @param instruction the instruction to be appended.
+ */
+ public CompactCodeAttributeComposer appendInstruction(Instruction instruction)
+ {
+ codeAttributeComposer.appendInstruction(instruction);
+
+ return this;
+ }
+
+
+ /**
+ * Appends the given exception to the exception table.
+ * @param exceptionInfo the exception to be appended.
+ */
+ public CompactCodeAttributeComposer appendException(ExceptionInfo exceptionInfo)
+ {
+ codeAttributeComposer.appendException(exceptionInfo);
+
+ return this;
+ }
+
+
+ /**
+ * Inserts the given line number at the appropriate position in the line
+ * number table.
+ * @param lineNumberInfo the line number to be inserted.
+ * @return the index where the line number was actually inserted.
+ */
+ public int insertLineNumber(LineNumberInfo lineNumberInfo)
+ {
+ return codeAttributeComposer.insertLineNumber(lineNumberInfo);
+ }
+
+
+ /**
+ * Inserts the given line number at the appropriate position in the line
+ * number table.
+ * @param minimumIndex the minimum index where the line number may be
+ * inserted.
+ * @param lineNumberInfo the line number to be inserted.
+ * @return the index where the line number was inserted.
+ */
+ public int insertLineNumber(int minimumIndex, LineNumberInfo lineNumberInfo)
+ {
+ return codeAttributeComposer.insertLineNumber(minimumIndex, lineNumberInfo);
+ }
+
+
+ /**
+ * Appends the given line number to the line number table.
+ * @param lineNumberInfo the line number to be appended.
+ */
+ public CompactCodeAttributeComposer appendLineNumber(LineNumberInfo lineNumberInfo)
+ {
+ codeAttributeComposer.appendLineNumber(lineNumberInfo);
+
+ return this;
+ }
+
+
+ /**
+ * Wraps up the current code fragment, continuing with the previous one on
+ * the stack.
+ */
+ public CompactCodeAttributeComposer endCodeFragment()
+ {
+ codeAttributeComposer.endCodeFragment();
+
+ return this;
+ }
+
+
+ // Methods corresponding to the bytecode opcodes.
+
+ public CompactCodeAttributeComposer nop()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_NOP));
+ }
+
+ public CompactCodeAttributeComposer aconst_null()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ACONST_NULL));
+ }
+
+ public CompactCodeAttributeComposer iconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_0, constant));
+ }
+
+ public CompactCodeAttributeComposer iconst_m1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_M1));
+ }
+
+ public CompactCodeAttributeComposer iconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_0));
+ }
+
+ public CompactCodeAttributeComposer iconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_1));
+ }
+
+ public CompactCodeAttributeComposer iconst_2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_2));
+ }
+
+ public CompactCodeAttributeComposer iconst_3()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_3));
+ }
+
+ public CompactCodeAttributeComposer iconst_4()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_4));
+ }
+
+ public CompactCodeAttributeComposer iconst_5()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_5));
+ }
+
+ public CompactCodeAttributeComposer lconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_0, constant));
+ }
+
+ public CompactCodeAttributeComposer lconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_0));
+ }
+
+ public CompactCodeAttributeComposer lconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_1));
+ }
+
+ public CompactCodeAttributeComposer fconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_0, constant));
+ }
+
+ public CompactCodeAttributeComposer fconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_0));
+ }
+
+ public CompactCodeAttributeComposer fconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_1));
+ }
+
+ public CompactCodeAttributeComposer fconst_2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_2));
+ }
+
+ public CompactCodeAttributeComposer dconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_0, constant));
+ }
+
+ public CompactCodeAttributeComposer dconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_0));
+ }
+
+ public CompactCodeAttributeComposer dconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_1));
+ }
+
+ public CompactCodeAttributeComposer bipush(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BIPUSH, constant));
+ }
+
+ public CompactCodeAttributeComposer sipush(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SIPUSH, constant));
+ }
+
+ public CompactCodeAttributeComposer ldc(int value)
+ {
+ return ldc_(constantPoolEditor.addIntegerConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc(float value)
+ {
+ return ldc_(constantPoolEditor.addFloatConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc(String string)
+ {
+ return ldc(string, null, null);
+ }
+
+ public CompactCodeAttributeComposer ldc(Object primitiveArray)
+ {
+ return ldc_(constantPoolEditor.addPrimitiveArrayConstant(primitiveArray));
+ }
+
+ public CompactCodeAttributeComposer ldc(String string, Clazz referencedClass, Method referencedMember)
+ {
+ return ldc_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
+ }
+
+ public CompactCodeAttributeComposer ldc(String className, Clazz referencedClass)
+ {
+ return ldc_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer ldc_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer ldc_w(int value)
+ {
+ return ldc_w_(constantPoolEditor.addIntegerConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc_w(float value)
+ {
+ return ldc_w_(constantPoolEditor.addFloatConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc_w(String string)
+ {
+ return ldc_w(string, null, null);
+ }
+
+ public CompactCodeAttributeComposer ldc_w(String string, Clazz referencedClass, Method referencedMember)
+ {
+ return ldc_w_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
+ }
+
+ public CompactCodeAttributeComposer ldc_w(String className, Clazz referencedClass)
+ {
+ return ldc_w_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer ldc_w_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC_W, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer ldc2_w(long value)
+ {
+ return ldc2_w(constantPoolEditor.addLongConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc2_w(double value)
+ {
+ return ldc2_w(constantPoolEditor.addDoubleConstant(value));
+ }
+
+ public CompactCodeAttributeComposer ldc2_w(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC2_W, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer iload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer lload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer fload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer dload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer aload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer iload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_0));
+ }
+
+ public CompactCodeAttributeComposer iload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_1));
+ }
+
+ public CompactCodeAttributeComposer iload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_2));
+ }
+
+ public CompactCodeAttributeComposer iload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_3));
+ }
+
+ public CompactCodeAttributeComposer lload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_0));
+ }
+
+ public CompactCodeAttributeComposer lload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_1));
+ }
+
+ public CompactCodeAttributeComposer lload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_2));
+ }
+
+ public CompactCodeAttributeComposer lload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_3));
+ }
+
+ public CompactCodeAttributeComposer fload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_0));
+ }
+
+ public CompactCodeAttributeComposer fload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_1));
+ }
+
+ public CompactCodeAttributeComposer fload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_2));
+ }
+
+ public CompactCodeAttributeComposer fload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_3));
+ }
+
+ public CompactCodeAttributeComposer dload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_0));
+ }
+
+ public CompactCodeAttributeComposer dload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_1));
+ }
+
+ public CompactCodeAttributeComposer dload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_2));
+ }
+
+ public CompactCodeAttributeComposer dload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_3));
+ }
+
+ public CompactCodeAttributeComposer aload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_0));
+ }
+
+ public CompactCodeAttributeComposer aload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_1));
+ }
+
+ public CompactCodeAttributeComposer aload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_2));
+ }
+
+ public CompactCodeAttributeComposer aload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_3));
+ }
+
+ public CompactCodeAttributeComposer iaload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IALOAD));
+ }
+
+ public CompactCodeAttributeComposer laload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LALOAD));
+ }
+
+ public CompactCodeAttributeComposer faload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FALOAD));
+ }
+
+ public CompactCodeAttributeComposer daload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DALOAD));
+ }
+
+ public CompactCodeAttributeComposer aaload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_AALOAD));
+ }
+
+ public CompactCodeAttributeComposer baload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BALOAD));
+ }
+
+ public CompactCodeAttributeComposer caload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_CALOAD));
+ }
+
+ public CompactCodeAttributeComposer saload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SALOAD));
+ }
+
+ public CompactCodeAttributeComposer istore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer lstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer fstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer dstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer astore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer istore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_0));
+ }
+
+ public CompactCodeAttributeComposer istore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_1));
+ }
+
+ public CompactCodeAttributeComposer istore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_2));
+ }
+
+ public CompactCodeAttributeComposer istore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_3));
+ }
+
+ public CompactCodeAttributeComposer lstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_0));
+ }
+
+ public CompactCodeAttributeComposer lstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_1));
+ }
+
+ public CompactCodeAttributeComposer lstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_2));
+ }
+
+ public CompactCodeAttributeComposer lstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_3));
+ }
+
+ public CompactCodeAttributeComposer fstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_0));
+ }
+
+ public CompactCodeAttributeComposer fstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_1));
+ }
+
+ public CompactCodeAttributeComposer fstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_2));
+ }
+
+ public CompactCodeAttributeComposer fstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_3));
+ }
+
+ public CompactCodeAttributeComposer dstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_0));
+ }
+
+ public CompactCodeAttributeComposer dstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_1));
+ }
+
+ public CompactCodeAttributeComposer dstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_2));
+ }
+
+ public CompactCodeAttributeComposer dstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_3));
+ }
+
+ public CompactCodeAttributeComposer astore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_0));
+ }
+
+ public CompactCodeAttributeComposer astore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_1));
+ }
+
+ public CompactCodeAttributeComposer astore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_2));
+ }
+
+ public CompactCodeAttributeComposer astore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_3));
+ }
+
+ public CompactCodeAttributeComposer iastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IASTORE));
+ }
+
+ public CompactCodeAttributeComposer lastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LASTORE));
+ }
+
+ public CompactCodeAttributeComposer fastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FASTORE));
+ }
+
+ public CompactCodeAttributeComposer dastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DASTORE));
+ }
+
+ public CompactCodeAttributeComposer aastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_AASTORE));
+ }
+
+ public CompactCodeAttributeComposer bastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BASTORE));
+ }
+
+ public CompactCodeAttributeComposer castore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_CASTORE));
+ }
+
+ public CompactCodeAttributeComposer sastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SASTORE));
+ }
+
+ public CompactCodeAttributeComposer pop()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_POP));
+ }
+
+ public CompactCodeAttributeComposer pop2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_POP2));
+ }
+
+ public CompactCodeAttributeComposer dup()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP));
+ }
+
+ public CompactCodeAttributeComposer dup_x1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP_X1));
+ }
+
+ public CompactCodeAttributeComposer dup_x2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP_X2));
+ }
+
+ public CompactCodeAttributeComposer dup2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2));
+ }
+
+ public CompactCodeAttributeComposer dup2_x1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2_X1));
+ }
+
+ public CompactCodeAttributeComposer dup2_x2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2_X2));
+ }
+
+ public CompactCodeAttributeComposer swap()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SWAP));
+ }
+
+ public CompactCodeAttributeComposer iadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IADD));
+ }
+
+ public CompactCodeAttributeComposer ladd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LADD));
+ }
+
+ public CompactCodeAttributeComposer fadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FADD));
+ }
+
+ public CompactCodeAttributeComposer dadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DADD));
+ }
+
+ public CompactCodeAttributeComposer isub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISUB));
+ }
+
+ public CompactCodeAttributeComposer lsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSUB));
+ }
+
+ public CompactCodeAttributeComposer fsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FSUB));
+ }
+
+ public CompactCodeAttributeComposer dsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DSUB));
+ }
+
+ public CompactCodeAttributeComposer imul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IMUL));
+ }
+
+ public CompactCodeAttributeComposer lmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LMUL));
+ }
+
+ public CompactCodeAttributeComposer fmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FMUL));
+ }
+
+ public CompactCodeAttributeComposer dmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DMUL));
+ }
+
+ public CompactCodeAttributeComposer idiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IDIV));
+ }
+
+ public CompactCodeAttributeComposer ldiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LDIV));
+ }
+
+ public CompactCodeAttributeComposer fdiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FDIV));
+ }
+
+ public CompactCodeAttributeComposer ddiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DDIV));
+ }
+
+ public CompactCodeAttributeComposer irem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IREM));
+ }
+
+ public CompactCodeAttributeComposer lrem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LREM));
+ }
+
+ public CompactCodeAttributeComposer frem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FREM));
+ }
+
+ public CompactCodeAttributeComposer drem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DREM));
+ }
+
+ public CompactCodeAttributeComposer ineg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_INEG));
+ }
+
+ public CompactCodeAttributeComposer lneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LNEG));
+ }
+
+ public CompactCodeAttributeComposer fneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FNEG));
+ }
+
+ public CompactCodeAttributeComposer dneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DNEG));
+ }
+
+ public CompactCodeAttributeComposer ishl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISHL));
+ }
+
+ public CompactCodeAttributeComposer lshl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSHL));
+ }
+
+ public CompactCodeAttributeComposer ishr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISHR));
+ }
+
+ public CompactCodeAttributeComposer lshr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSHR));
+ }
+
+ public CompactCodeAttributeComposer iushr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IUSHR));
+ }
+
+ public CompactCodeAttributeComposer lushr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LUSHR));
+ }
+
+ public CompactCodeAttributeComposer iand()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IAND));
+ }
+
+ public CompactCodeAttributeComposer land()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LAND));
+ }
+
+ public CompactCodeAttributeComposer ior()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IOR));
+ }
+
+ public CompactCodeAttributeComposer lor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LOR));
+ }
+
+ public CompactCodeAttributeComposer ixor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IXOR));
+ }
+
+ public CompactCodeAttributeComposer lxor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LXOR));
+ }
+
+ public CompactCodeAttributeComposer iinc(int variableIndex,
+ int constant)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_IINC, variableIndex, constant));
+ }
+
+ public CompactCodeAttributeComposer i2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2L));
+ }
+
+ public CompactCodeAttributeComposer i2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2F));
+ }
+
+ public CompactCodeAttributeComposer i2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2D));
+ }
+
+ public CompactCodeAttributeComposer l2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2I));
+ }
+
+ public CompactCodeAttributeComposer l2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2F));
+ }
+
+ public CompactCodeAttributeComposer l2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2D));
+ }
+
+ public CompactCodeAttributeComposer f2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2I));
+ }
+
+ public CompactCodeAttributeComposer f2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2L));
+ }
+
+ public CompactCodeAttributeComposer f2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2D));
+ }
+
+ public CompactCodeAttributeComposer d2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2I));
+ }
+
+ public CompactCodeAttributeComposer d2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2L));
+ }
+
+ public CompactCodeAttributeComposer d2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2F));
+ }
+
+ public CompactCodeAttributeComposer i2b()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2B));
+ }
+
+ public CompactCodeAttributeComposer i2c()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2C));
+ }
+
+ public CompactCodeAttributeComposer i2s()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2S));
+ }
+
+ public CompactCodeAttributeComposer lcmp()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCMP));
+ }
+
+ public CompactCodeAttributeComposer fcmpl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCMPL));
+ }
+
+ public CompactCodeAttributeComposer fcmpg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCMPG));
+ }
+
+ public CompactCodeAttributeComposer dcmpl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCMPL));
+ }
+
+ public CompactCodeAttributeComposer dcmpg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCMPG));
+ }
+
+ public CompactCodeAttributeComposer ifeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFEQ, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer iflt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFLT, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifge(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFGE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifgt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFGT, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifle(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFLE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmpeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPEQ, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmpne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPNE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmplt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPLT, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmpge(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPGE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmpgt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPGT, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ificmple(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPLE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifacmpeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFACMPEQ, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifacmpne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFACMPNE, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer goto_(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_GOTO, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer jsr(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_JSR, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ret(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_RET, variableIndex));
+ }
+
+ public CompactCodeAttributeComposer tableswitch(int defaultOffset,
+ int lowCase,
+ int highCase,
+ int[] jumpOffsets)
+ {
+ return add(new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH,
+ defaultOffset,
+ lowCase,
+ highCase,
+ jumpOffsets));
+ }
+
+ public CompactCodeAttributeComposer lookupswitch(int defaultOffset,
+ int[] cases,
+ int[] jumpOffsets)
+ {
+ return add(new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH,
+ defaultOffset,
+ cases,
+ jumpOffsets));
+ }
+
+ public CompactCodeAttributeComposer ireturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IRETURN));
+ }
+
+ public CompactCodeAttributeComposer lreturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LRETURN));
+ }
+
+ public CompactCodeAttributeComposer freturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FRETURN));
+ }
+
+ public CompactCodeAttributeComposer dreturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DRETURN));
+ }
+
+ public CompactCodeAttributeComposer areturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ARETURN));
+ }
+
+ public CompactCodeAttributeComposer return_()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_RETURN));
+ }
+
+ public CompactCodeAttributeComposer getstatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getstatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public CompactCodeAttributeComposer getstatic(String className,
+ String name,
+ String descriptor)
+ {
+ return getstatic(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer getstatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getstatic(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer getstatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_GETSTATIC, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer putstatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putstatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public CompactCodeAttributeComposer putstatic(String className,
+ String name,
+ String descriptor)
+ {
+ return putstatic(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer putstatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putstatic(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer putstatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer getfield(String className,
+ String name,
+ String descriptor)
+ {
+ return getfield(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer getfield(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getfield(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer getfield(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_GETFIELD, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer putfield(String className,
+ String name,
+ String descriptor)
+ {
+ return putfield(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer putfield(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putfield(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer putfield(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_PUTFIELD, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer invokevirtual(String className,
+ String name,
+ String descriptor)
+ {
+ return invokevirtual(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer invokevirtual(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokevirtual(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public CompactCodeAttributeComposer invokevirtual(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokevirtual(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer invokevirtual(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer invokespecial(String className,
+ String name,
+ String descriptor)
+ {
+ return invokespecial(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer invokespecial(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokespecial(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer invokespecial(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer invokestatic(String className,
+ String name,
+ String descriptor)
+ {
+ return invokestatic(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer invokestatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public CompactCodeAttributeComposer invokestatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer invokestaticinterface(String className,
+ String name,
+ String descriptor)
+ {
+ return invokestaticinterface(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer invokestaticinterface(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestaticinterface(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public CompactCodeAttributeComposer invokestaticinterface(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(constantPoolEditor.addInterfaceMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public CompactCodeAttributeComposer invokestatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer invokeinterface(String className,
+ String name,
+ String descriptor)
+ {
+ return invokeinterface(className, name, descriptor, null, null);
+ }
+
+ public CompactCodeAttributeComposer invokeinterface(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ int invokeinterfaceConstant =
+ (ClassUtil.internalMethodParameterSize(descriptor, false)) << 8;
+
+ return invokeinterface(constantPoolEditor.addInterfaceMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember),
+ invokeinterfaceConstant);
+ }
+
+ public CompactCodeAttributeComposer invokeinterface(int constantIndex,
+ int constant)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE, constantIndex, constant));
+ }
+
+ public CompactCodeAttributeComposer invokedynamic(int bootStrapMethodIndex,
+ String name,
+ String descriptor,
+ Clazz[] referencedClasses)
+ {
+ return invokedynamic(constantPoolEditor.addInvokeDynamicConstant(bootStrapMethodIndex,
+ name,
+ descriptor,
+ referencedClasses));
+ }
+
+ public CompactCodeAttributeComposer invokedynamic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEDYNAMIC, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer new_(String className)
+ {
+ return new_(className, null);
+ }
+
+ public CompactCodeAttributeComposer new_(String className, Clazz referencedClass)
+ {
+ return new_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer new_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_NEW, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer newarray(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_NEWARRAY, constant));
+ }
+
+ public CompactCodeAttributeComposer anewarray(String className, Clazz referencedClass)
+ {
+ return anewarray(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer anewarray(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer arraylength()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ARRAYLENGTH));
+ }
+
+ public CompactCodeAttributeComposer athrow()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ATHROW));
+ }
+
+ public CompactCodeAttributeComposer checkcast(String className)
+ {
+ return checkcast(className, null);
+ }
+
+ public CompactCodeAttributeComposer checkcast(String className, Clazz referencedClass)
+ {
+ return checkcast(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer checkcast(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_CHECKCAST, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer instanceof_(String className, Clazz referencedClass)
+ {
+ return instanceof_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer instanceof_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INSTANCEOF, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer monitorenter()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_MONITORENTER));
+ }
+
+ public CompactCodeAttributeComposer monitorexit()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_MONITOREXIT));
+ }
+
+ public CompactCodeAttributeComposer wide()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_WIDE));
+ }
+
+ public CompactCodeAttributeComposer multianewarray(String className, Clazz referencedClass)
+ {
+ return multianewarray(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public CompactCodeAttributeComposer multianewarray(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_MULTIANEWARRAY, constantIndex));
+ }
+
+ public CompactCodeAttributeComposer ifnull(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNULL, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer ifnonnull(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNONNULL, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer goto_w(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_GOTO_W, branchOffset));
+ }
+
+ public CompactCodeAttributeComposer jsr_w(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_JSR_W, branchOffset));
+ }
+
+
+ // Additional convenience methods.
+
+ /**
+ * Pushes the given primitive value on the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param primitive the primitive value to be pushed - should never be null.
+ * @param internalType the internal type of the primitive ('Z','B','I',...)
+ */
+ public CompactCodeAttributeComposer pushPrimitive(Object primitive,
+ char internalType)
+ {
+ switch (internalType)
+ {
+ case TYPE_BOOLEAN: return ((Boolean)primitive).booleanValue() ? iconst_1() : iconst_0();
+ case TYPE_BYTE: return bipush((Byte)primitive);
+ case TYPE_CHAR: return ldc(((Character)primitive).charValue());
+ case TYPE_SHORT: return sipush((Short)primitive);
+ case TYPE_INT: return ldc(((Integer)primitive).intValue());
+ case TYPE_LONG: return ldc2_w((Long)primitive);
+ case TYPE_FLOAT: return ldc(((Float)primitive).floatValue());
+ case TYPE_DOUBLE: return ldc2_w((Double)primitive);
+ default: throw new IllegalArgumentException(primitive.toString());
+ }
+ }
+
+
+ /**
+ * Pushes the given primitive int on the stack in the most efficient way
+ * (as an iconst, bipush, sipush, or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public CompactCodeAttributeComposer pushInt(int value)
+ {
+ return
+ value >= -1 &&
+ value <= 5 ? iconst(value) :
+ value == (byte)value ? bipush(value) :
+ value == (short)value ? sipush(value) :
+ ldc(value);
+ }
+
+
+ /**
+ * Pushes the given primitive float on the stack in the most efficient way
+ * (as an fconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public CompactCodeAttributeComposer pushFloat(float value)
+ {
+ return
+ value == 0f ||
+ value == 1f ? fconst((int)value) :
+ ldc(value);
+ }
+
+
+ /**
+ * Pushes the given primitive long on the stack in the most efficient way
+ * (as an lconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public CompactCodeAttributeComposer pushLong(long value)
+ {
+ return
+ value == 0L ||
+ value == 1L ? lconst((int)value) :
+ ldc2_w(value);
+ }
+
+
+ /**
+ * Pushes the given primitive double on the stack in the most efficient way
+ * (as a dconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public CompactCodeAttributeComposer pushDouble(double value)
+ {
+ return
+ value == 0. ||
+ value == 1. ? dconst((int)value) :
+ ldc2_w(value);
+ }
+
+
+ /**
+ * Pushes a new array on the stack.
+ *
+ * Operand stack:
+ * ... -> ..., array
+ *
+ * @param elementTypeOrClassName the array element type (or class name in case of objects).
+ * @param size the size of the array to be created.
+ */
+ public CompactCodeAttributeComposer pushNewArray(String elementTypeOrClassName,
+ int size)
+ {
+ // Create new array.
+ pushInt(size);
+
+ return ClassUtil.isInternalPrimitiveType(elementTypeOrClassName) ?
+ newarray(InstructionUtil.arrayTypeFromInternalType(elementTypeOrClassName.charAt(0))) :
+ anewarray(elementTypeOrClassName, null);
+ }
+
+
+ /**
+ * Loads the given variable onto the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param variableIndex the index of the variable to be loaded.
+ * @param internalType the type of the variable to be loaded.
+ */
+ public CompactCodeAttributeComposer load(int variableIndex,
+ String internalType)
+ {
+ return load(variableIndex, internalType.charAt(0));
+ }
+
+
+ /**
+ * Loads the given variable of primitive type onto the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param variableIndex the index of the variable to be loaded.
+ * @param internalType the primitive type of the variable to be loaded.
+ */
+ public CompactCodeAttributeComposer load(int variableIndex,
+ char internalType)
+ {
+ switch (internalType)
+ {
+ case TYPE_BOOLEAN:
+ case TYPE_BYTE:
+ case TYPE_CHAR:
+ case TYPE_SHORT:
+ case TYPE_INT: return iload(variableIndex);
+ case TYPE_LONG: return lload(variableIndex);
+ case TYPE_FLOAT: return fload(variableIndex);
+ case TYPE_DOUBLE: return dload(variableIndex);
+ default: return aload(variableIndex);
+ }
+ }
+
+
+ /**
+ * Stores the value on top of the stack in the variable with given index.
+ *
+ * Operand stsack:
+ * ..., value -> ...
+ *
+ * @param variableIndex the index of the variable where to store the
+ * value.
+ * @param internalType the type of the value to be stored.
+ */
+ public CompactCodeAttributeComposer store(int variableIndex,
+ String internalType)
+ {
+ return store(variableIndex, internalType.charAt(0));
+ }
+
+
+ /**
+ * Stores the primitve value on top of the stack in the variable with given
+ * index.
+ *
+ * Operand stack:
+ * ..., value -> ...
+ *
+ * @param variableIndex the index of the variable where to store the
+ * value.
+ * @param internalType the primitive type of the value to be stored.
+ */
+ public CompactCodeAttributeComposer store(int variableIndex,
+ char internalType)
+ {
+ switch (internalType)
+ {
+ case TYPE_BOOLEAN:
+ case TYPE_BYTE:
+ case TYPE_CHAR:
+ case TYPE_SHORT:
+ case TYPE_INT: return istore(variableIndex);
+ case TYPE_LONG: return lstore(variableIndex);
+ case TYPE_FLOAT: return fstore(variableIndex);
+ case TYPE_DOUBLE: return dstore(variableIndex);
+ default: return astore(variableIndex);
+ }
+ }
+
+
+ /**
+ * Stores an element to an array.
+ *
+ * Operand stack:
+ * ..., array, index, value -> ...
+ *
+ * @param elementType the type of the value to be stored.
+ */
+ public CompactCodeAttributeComposer storeToArray(String elementType)
+ {
+ switch (elementType.charAt(0))
+ {
+ case TYPE_BOOLEAN:
+ case TYPE_BYTE: return bastore();
+ case TYPE_CHAR: return castore();
+ case TYPE_SHORT: return sastore();
+ case TYPE_INT: return iastore();
+ case TYPE_LONG: return lastore();
+ case TYPE_FLOAT: return fastore();
+ case TYPE_DOUBLE: return dastore();
+ default: return aastore();
+ }
+ }
+
+
+ /**
+ * Appends the proper return statement for the given internal type.
+ *
+ * @param internalType the return type.
+ */
+ public CompactCodeAttributeComposer return_(String internalType)
+ {
+ switch (internalType.charAt(0))
+ {
+ case TYPE_BOOLEAN:
+ case TYPE_BYTE:
+ case TYPE_CHAR:
+ case TYPE_SHORT:
+ case TYPE_INT: return ireturn();
+ case TYPE_LONG: return lreturn();
+ case TYPE_FLOAT: return freturn();
+ case TYPE_DOUBLE: return dreturn();
+ case TYPE_VOID: return return_();
+ default: return areturn();
+ }
+ }
+
+
+ /**
+ * Appends instructions to print out the given message and the top int on
+ * the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintIntegerInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintIntegerInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message and the top int on
+ * the stack as a hexadecimal value.
+ */
+ public CompactCodeAttributeComposer appendPrintIntegerHexInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintIntegerHexInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message and the top long on
+ * the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintLongInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintLongInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message and the top String on
+ * the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintStringInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintStringInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message and the top Object on
+ * the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintObjectInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintObjectInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message and the stack trace
+ * of the top Throwable on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintStackTraceInstructions(String message)
+ {
+ appendPrintInstructions(message);
+ appendPrintStackTraceInstructions();
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the given message.
+ */
+ public CompactCodeAttributeComposer appendPrintInstructions(String message)
+ {
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ ldc(message);
+ invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the top int on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintIntegerInstructions()
+ {
+ dup();
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ swap();
+ invokevirtual("java/io/PrintStream", "println", "(I)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the top integer on the stack as a
+ * hexadecimal value.
+ */
+ public CompactCodeAttributeComposer appendPrintIntegerHexInstructions()
+ {
+ dup();
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ swap();
+ invokestatic("java/lang/Integer", "toHexString", "(I)Ljava/lang/String;");
+ invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the top long on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintLongInstructions()
+ {
+ dup2();
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ dup_x2();
+ pop();
+ invokevirtual("java/io/PrintStream", "println", "(J)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the top String on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintStringInstructions()
+ {
+ dup();
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ swap();
+ invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the top Object on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintObjectInstructions()
+ {
+ dup();
+ getstatic("java/lang/System", "err", "Ljava/io/PrintStream;");
+ swap();
+ invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/Object;)V");
+ return this;
+ }
+
+ /**
+ * Appends instructions to print out the stack trace of the top Throwable
+ * on the stack.
+ */
+ public CompactCodeAttributeComposer appendPrintStackTraceInstructions()
+ {
+ dup();
+ invokevirtual("java/lang/Throwable", "printStackTrace", "()V");
+ return this;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Adds the given instruction, shrinking it if necessary.
+ */
+ private CompactCodeAttributeComposer add(Instruction instruction)
+ {
+ codeAttributeComposer.appendInstruction(instruction);
+
+ return this;
+ }
+
+
+ public static void main(String[] args)
+ {
+ ProgramClass targetClass = new ProgramClass(0, 0, new Constant[32], 0, 0, 0);
+
+ CompactCodeAttributeComposer composer = new CompactCodeAttributeComposer(targetClass);
+
+ composer.beginCodeFragment(4);
+ composer.appendInstruction(0, new SimpleInstruction(InstructionConstants.OP_ICONST_0));
+ composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ISTORE, 0));
+ composer.appendInstruction(2, new BranchInstruction(InstructionConstants.OP_GOTO, 1));
+
+ composer.beginCodeFragment(4);
+ composer.appendInstruction(0, new VariableInstruction(InstructionConstants.OP_IINC, 0, 1));
+ composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ILOAD, 0));
+ composer.appendInstruction(2, new SimpleInstruction(InstructionConstants.OP_ICONST_5));
+ composer.appendInstruction(3, new BranchInstruction(InstructionConstants.OP_IFICMPLT, -3));
+ composer.endCodeFragment();
+
+ composer.appendInstruction(3, new SimpleInstruction(InstructionConstants.OP_RETURN));
+ composer.endCodeFragment();
+ }
+}
diff --git a/src/proguard/classfile/editor/ComparableConstant.java b/core/src/proguard/classfile/editor/ComparableConstant.java
similarity index 78%
rename from src/proguard/classfile/editor/ComparableConstant.java
rename to core/src/proguard/classfile/editor/ComparableConstant.java
index 55d3c27..5331278 100644
--- a/src/proguard/classfile/editor/ComparableConstant.java
+++ b/core/src/proguard/classfile/editor/ComparableConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.ArrayUtil;
/**
@@ -39,7 +40,7 @@ class ComparableConstant
extends SimplifiedVisitor
implements Comparable, ConstantVisitor
{
- private static final int[] PRIORITIES = new int[19];
+ private static final int[] PRIORITIES = new int[22];
static
{
PRIORITIES[ClassConstants.CONSTANT_Integer] = 0; // Possibly byte index (ldc).
@@ -55,7 +56,10 @@ class ComparableConstant
PRIORITIES[ClassConstants.CONSTANT_MethodHandle] = 10;
PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 11;
PRIORITIES[ClassConstants.CONSTANT_MethodType] = 12;
- PRIORITIES[ClassConstants.CONSTANT_Utf8] = 13;
+ PRIORITIES[ClassConstants.CONSTANT_Module] = 13;
+ PRIORITIES[ClassConstants.CONSTANT_Package] = 14;
+ PRIORITIES[ClassConstants.CONSTANT_Utf8] = 15;
+ PRIORITIES[ClassConstants.CONSTANT_PrimitiveArray] = 16;
}
private final Clazz clazz;
@@ -153,6 +157,35 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
((DoubleConstant)otherConstant).getValue());
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ PrimitiveArrayConstant otherPrimitiveArrayConstant =
+ (PrimitiveArrayConstant)otherConstant;
+
+ char primitiveType = primitiveArrayConstant.getPrimitiveType();
+ char otherPrimitiveType = otherPrimitiveArrayConstant.getPrimitiveType();
+
+ if (primitiveType != otherPrimitiveType)
+ {
+ result = primitiveType < otherPrimitiveType ? -1 : 1;
+ }
+ else
+ {
+ Object values = primitiveArrayConstant.getValues();
+ Object otherValues = otherPrimitiveArrayConstant.getValues();
+
+ result =
+ values instanceof boolean[] ? ArrayUtil.compare((boolean[])values, ((boolean[])values).length, (boolean[])otherValues, ((boolean[])otherValues).length) :
+ values instanceof byte[] ? ArrayUtil.compare((byte[]) values, ((byte[]) values).length, (byte[]) otherValues, ((byte[]) otherValues).length) :
+ values instanceof char[] ? ArrayUtil.compare((char[]) values, ((char[]) values).length, (char[]) otherValues, ((char[]) otherValues).length) :
+ values instanceof short[] ? ArrayUtil.compare((short[]) values, ((short[]) values).length, (short[]) otherValues, ((short[]) otherValues).length) :
+ values instanceof int[] ? ArrayUtil.compare((int[]) values, ((int[]) values).length, (int[]) otherValues, ((int[]) otherValues).length) :
+ values instanceof float[] ? ArrayUtil.compare((float[]) values, ((float[]) values).length, (float[]) otherValues, ((float[]) otherValues).length) :
+ values instanceof long[] ? ArrayUtil.compare((long[]) values, ((long[]) values).length, (long[]) otherValues, ((long[]) otherValues).length) :
+ /*values instanceof double[] */ ArrayUtil.compare((double[]) values, ((double[]) values).length, (double[]) otherValues, ((double[]) otherValues).length);
+ }
+ }
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
result = stringConstant.getString(clazz).compareTo(((StringConstant)otherConstant).getString(clazz));
@@ -229,6 +262,17 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ result = moduleConstant.getName(clazz).compareTo(((ModuleConstant)otherConstant).getName(clazz));
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ result = packageConstant.getName(clazz).compareTo(((PackageConstant)otherConstant).getName(clazz));
+ }
+
// Implementations for Object.
public boolean equals(Object other)
diff --git a/src/proguard/classfile/editor/ConstantAdder.java b/core/src/proguard/classfile/editor/ConstantAdder.java
similarity index 93%
rename from src/proguard/classfile/editor/ConstantAdder.java
rename to core/src/proguard/classfile/editor/ConstantAdder.java
index ed1fd93..3d15b71 100644
--- a/src/proguard/classfile/editor/ConstantAdder.java
+++ b/core/src/proguard/classfile/editor/ConstantAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -118,6 +118,13 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ constantIndex =
+ constantPoolEditor.addPrimitiveArrayConstant(primitiveArrayConstant.getValues());
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
constantIndex =
@@ -182,6 +189,20 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ constantIndex =
+ constantPoolEditor.addModuleConstant(moduleConstant.getName(clazz));
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ constantIndex =
+ constantPoolEditor.addPackageConstant(packageConstant.getName(clazz));
+ }
+
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
// First add the referenced class constant, with its own referenced class.
diff --git a/src/proguard/classfile/editor/ConstantPoolEditor.java b/core/src/proguard/classfile/editor/ConstantPoolEditor.java
similarity index 82%
rename from src/proguard/classfile/editor/ConstantPoolEditor.java
rename to core/src/proguard/classfile/editor/ConstantPoolEditor.java
index 1f6e950..bc7bd0e 100644
--- a/src/proguard/classfile/editor/ConstantPoolEditor.java
+++ b/core/src/proguard/classfile/editor/ConstantPoolEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +22,9 @@
import proguard.classfile.*;
import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.ClassReferenceInitializer;
+import proguard.optimize.peephole.WildcardConstantFilter;
/**
* This class can add constant pool entries to a given class.
@@ -32,16 +35,48 @@ public class ConstantPoolEditor
{
private static final boolean DEBUG = false;
- private ProgramClass targetClass;
+ private final ProgramClass targetClass;
+ private final ConstantVisitor constantReferenceInitializer;
/**
- * Creates a new ConstantPoolEditor that will edit constants in the given
- * target class.
+ * Creates a new ConstantPoolEditor.
+ * @param targetClass the target class in which constants are to be edited.
*/
public ConstantPoolEditor(ProgramClass targetClass)
+ {
+ this(targetClass, null, null);
+ }
+
+
+ /**
+ * Creates a new ConstantPoolEditor that automatically initializes class
+ * references and class member references in new constants.
+ * @param targetClass the target class in which constants are to be
+ * edited.
+ * @param programClassPool the program class pool from which new constants
+ * can be initialized.
+ * @param libraryClassPool the library class pool from which new constants
+ * can be initialized.
+ */
+ public ConstantPoolEditor(ProgramClass targetClass,
+ ClassPool programClassPool,
+ ClassPool libraryClassPool)
{
this.targetClass = targetClass;
+
+ constantReferenceInitializer = programClassPool == null ? null :
+ new WildcardConstantFilter(
+ new ClassReferenceInitializer(programClassPool, libraryClassPool));
+ }
+
+
+ /**
+ * Returns the target class in which constants are edited.
+ */
+ public ProgramClass getTargetClass()
+ {
+ return targetClass;
}
@@ -164,6 +199,17 @@ public int addDoubleConstant(double value)
}
+ /**
+ * Finds or creates a PrimitiveArrayConstant constant pool entry with the
+ * given values.
+ * @return the constant pool index of the PrimitiveArrayConstant.
+ */
+ public int addPrimitiveArrayConstant(Object values)
+ {
+ return addConstant(new PrimitiveArrayConstant(values));
+ }
+
+
/**
* Finds or creates a StringConstant constant pool entry with the given
* value.
@@ -185,7 +231,10 @@ public int addStringConstant(String string,
constant.getTag() == ClassConstants.CONSTANT_String)
{
StringConstant stringConstant = (StringConstant)constant;
- if (stringConstant.getString(targetClass).equals(string))
+ if (stringConstant.u2stringIndex < constantPoolCount &&
+ stringConstant.getString(targetClass).equals(string) &&
+ stringConstant.referencedClass == referencedClass &&
+ stringConstant.referencedMember == referencedMember)
{
return index;
}
@@ -238,7 +287,7 @@ public int addInvokeDynamicConstant(int bootstrapMethodIndex,
{
InvokeDynamicConstant invokeDynamicConstant = (InvokeDynamicConstant)constant;
if (invokeDynamicConstant.u2bootstrapMethodAttributeIndex == bootstrapMethodIndex &&
- invokeDynamicConstant.u2nameAndTypeIndex == nameAndTypeIndex)
+ invokeDynamicConstant.u2nameAndTypeIndex == nameAndTypeIndex)
{
return index;
}
@@ -284,6 +333,66 @@ public int addMethodHandleConstant(int referenceKind,
referenceIndex));
}
+ /**
+ * Finds or creates a ModuleConstant constant pool entry with the given name.
+ * @return the constant pool index of the ModuleConstant.
+ */
+ public int addModuleConstant(String name)
+ {
+ int constantPoolCount = targetClass.u2constantPoolCount;
+ Constant[] constantPool = targetClass.constantPool;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ Constant constant = constantPool[index];
+
+ if (constant != null &&
+ constant.getTag() == ClassConstants.CONSTANT_Module)
+ {
+ ModuleConstant moduleConstant = (ModuleConstant)constant;
+ if (moduleConstant.getName(targetClass).equals(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ int nameIndex = addUtf8Constant(name);
+
+ return addConstant(new ModuleConstant(nameIndex));
+ }
+
+ /**
+ * Finds or creates a PackageConstant constant pool entry with the given name.
+ * @return the constant pool index of the PackageConstant.
+ */
+ public int addPackageConstant(String name)
+ {
+ int constantPoolCount = targetClass.u2constantPoolCount;
+ Constant[] constantPool = targetClass.constantPool;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ Constant constant = constantPool[index];
+
+ if (constant != null &&
+ constant.getTag() == ClassConstants.CONSTANT_Package)
+ {
+ PackageConstant packageConstant = (PackageConstant)constant;
+ if (packageConstant.getName(targetClass).equals(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ int nameIndex = addUtf8Constant(name);
+
+ return addConstant(new PackageConstant(nameIndex));
+ }
+
/**
* Finds or creates a FieldrefConstant constant pool entry for the given
@@ -377,8 +486,8 @@ public int addFieldrefConstant(int classIndex,
constant.getTag() == ClassConstants.CONSTANT_Fieldref)
{
FieldrefConstant fieldrefConstant = (FieldrefConstant)constant;
- if (fieldrefConstant.u2classIndex == classIndex &&
- fieldrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
+ if (fieldrefConstant.u2classIndex == classIndex &&
+ fieldrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
{
return index;
}
@@ -481,7 +590,7 @@ public int addInterfaceMethodrefConstant(int classIndex,
Constant constant = constantPool[index];
if (constant != null &&
- constant.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
+ constant.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
{
InterfaceMethodrefConstant methodrefConstant = (InterfaceMethodrefConstant)constant;
if (methodrefConstant.u2classIndex == classIndex &&
@@ -636,7 +745,8 @@ public int addClassConstant(String name,
constant.getTag() == ClassConstants.CONSTANT_Class)
{
ClassConstant classConstant = (ClassConstant)constant;
- if (classConstant.getName(targetClass).equals(name))
+ if (classConstant.u2nameIndex < constantPoolCount &&
+ classConstant.getName(targetClass).equals(name))
{
return index;
}
@@ -669,7 +779,8 @@ public int addMethodTypeConstant(String type,
constant.getTag() == ClassConstants.CONSTANT_MethodType)
{
MethodTypeConstant methodTypeConstant = (MethodTypeConstant)constant;
- if (methodTypeConstant.getType(targetClass).equals(type))
+ if (methodTypeConstant.u2descriptorIndex < constantPoolCount &&
+ methodTypeConstant.getType(targetClass).equals(type))
{
return index;
}
@@ -701,7 +812,9 @@ public int addNameAndTypeConstant(String name,
constant.getTag() == ClassConstants.CONSTANT_NameAndType)
{
NameAndTypeConstant nameAndTypeConstant = (NameAndTypeConstant)constant;
- if (nameAndTypeConstant.getName(targetClass).equals(name) &&
+ if (nameAndTypeConstant.u2nameIndex < constantPoolCount &&
+ nameAndTypeConstant.u2descriptorIndex < constantPoolCount &&
+ nameAndTypeConstant.getName(targetClass).equals(name) &&
nameAndTypeConstant.getType(targetClass).equals(type))
{
return index;
@@ -744,7 +857,7 @@ public int addUtf8Constant(String string)
/**
- * Adds a given constant pool entry to the end of the constant pool/
+ * Adds a given constant pool entry to the end of the constant pool.
* @return the constant pool index for the added entry.
*/
public int addConstant(Constant constant)
@@ -755,19 +868,23 @@ public int addConstant(Constant constant)
// Make sure there is enough space for another constant pool entry.
if (constantPool.length < constantPoolCount+2)
{
- targetClass.constantPool = new Constant[constantPoolCount+2];
+ Constant[] newConstantPool = new Constant[constantPoolCount+2];
System.arraycopy(constantPool, 0,
- targetClass.constantPool, 0,
+ newConstantPool, 0,
constantPoolCount);
- constantPool = targetClass.constantPool;
+
+ // Assign the newly created constant pool after all entries
+ // have been copied to avoid race-conditions.
+ targetClass.constantPool = newConstantPool;
+ constantPool = targetClass.constantPool;
}
if (DEBUG)
{
- System.out.println(targetClass.getName()+": adding ["+constant.getClass().getName()+"] at index "+targetClass.u2constantPoolCount);
+ System.out.println("ConstantPoolEditor: ["+(targetClass.u2thisClass > 0 ? targetClass.getName() : "(dummy)")+"] adding ["+constant.getClass().getName()+"] at index "+targetClass.u2constantPoolCount);
}
- // Create a new Utf8Constant for the given string.
+ // Add the new entry to the end of the constant pool.
constantPool[targetClass.u2constantPoolCount++] = constant;
// Long constants and double constants take up two entries in the
@@ -779,6 +896,13 @@ public int addConstant(Constant constant)
constantPool[targetClass.u2constantPoolCount++] = null;
}
+ // Initialize the class references and class member references in the
+ // constant, if necessary.
+ if (constantReferenceInitializer != null)
+ {
+ constant.accept(targetClass, constantReferenceInitializer);
+ }
+
return constantPoolCount;
}
}
diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/core/src/proguard/classfile/editor/ConstantPoolRemapper.java
similarity index 86%
rename from src/proguard/classfile/editor/ConstantPoolRemapper.java
rename to core/src/proguard/classfile/editor/ConstantPoolRemapper.java
index 562854d..f794fda 100644
--- a/src/proguard/classfile/editor/ConstantPoolRemapper.java
+++ b/core/src/proguard/classfile/editor/ConstantPoolRemapper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,8 @@
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
@@ -34,6 +36,8 @@
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
+import java.util.Arrays;
+
/**
* This ClassVisitor remaps all possible references to constant pool entries
* of the classes that it visits, based on a given index map. It is assumed that
@@ -56,6 +60,10 @@ public class ConstantPoolRemapper
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
+ RequiresInfoVisitor,
+ ExportsInfoVisitor,
+ OpensInfoVisitor,
+ ProvidesInfoVisitor,
AnnotationVisitor,
ElementValueVisitor
{
@@ -85,7 +93,7 @@ public void visitProgramClass(ProgramClass programClass)
remapConstantIndexArray(programClass.u2interfaces,
programClass.u2interfacesCount);
- // Remap the references of the contant pool entries themselves.
+ // Remap the references of the constant pool entries themselves.
programClass.constantPoolEntriesAccept(this);
// Remap the references in all fields, methods, and attributes.
@@ -126,6 +134,12 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ // Nothing to do.
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
stringConstant.u2stringIndex =
@@ -152,6 +166,18 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
remapConstantIndex(methodHandleConstant.u2referenceIndex);
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ moduleConstant.u2nameIndex =
+ remapConstantIndex(moduleConstant.u2nameIndex);
+ }
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ packageConstant.u2nameIndex =
+ remapConstantIndex(packageConstant.u2nameIndex);
+ }
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
@@ -302,6 +328,43 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.u2attributeNameIndex =
+ remapConstantIndex(moduleAttribute.u2attributeNameIndex);
+ moduleAttribute.u2moduleNameIndex =
+ remapConstantIndex(moduleAttribute.u2moduleNameIndex);
+
+ if (moduleAttribute.u2moduleVersionIndex != 0)
+ {
+ moduleAttribute.u2moduleVersionIndex =
+ remapConstantIndex(moduleAttribute.u2moduleVersionIndex);
+ }
+ moduleAttribute.requiresAccept(clazz, this);
+ moduleAttribute.exportsAccept(clazz, this);
+ moduleAttribute.opensAccept(clazz, this);
+ remapConstantIndexArray(moduleAttribute.u2uses, moduleAttribute.u2usesCount);
+ moduleAttribute.providesAccept(clazz, this);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ moduleMainClassAttribute.u2attributeNameIndex =
+ remapConstantIndex(moduleMainClassAttribute.u2attributeNameIndex);
+ moduleMainClassAttribute.u2mainClass =
+ remapConstantIndex(moduleMainClassAttribute.u2mainClass);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ modulePackagesAttribute.u2attributeNameIndex =
+ remapConstantIndex(modulePackagesAttribute.u2attributeNameIndex);
+ remapConstantIndexArray(modulePackagesAttribute.u2packages, modulePackagesAttribute.u2packagesCount);
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
deprecatedAttribute.u2attributeNameIndex =
@@ -594,6 +657,46 @@ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute
}
+ // Implementations for RequiresInfoVisitor.
+
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo)
+ {
+ requiresInfo.u2requiresIndex =
+ remapConstantIndex(requiresInfo.u2requiresIndex);
+ requiresInfo.u2requiresVersionIndex =
+ remapConstantIndex(requiresInfo.u2requiresVersionIndex);
+ }
+
+
+ // Implementations for ExportsInfoVisitor.
+
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo)
+ {
+ exportsInfo.u2exportsIndex =
+ remapConstantIndex(exportsInfo.u2exportsIndex);
+ remapConstantIndexArray(exportsInfo.u2exportsToIndex, exportsInfo.u2exportsToCount);
+ }
+
+
+ // Implementations for OpensInfoVisitor.
+
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo)
+ {
+ opensInfo.u2opensIndex =
+ remapConstantIndex(opensInfo.u2opensIndex);
+ remapConstantIndexArray(opensInfo.u2opensToIndex, opensInfo.u2opensToCount);
+ }
+
+
+ // Implementations for ProvidesInfoVisitor.
+
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo)
+ {
+ providesInfo.u2providesIndex =
+ remapConstantIndex(providesInfo.u2providesIndex);
+ remapConstantIndexArray(providesInfo.u2providesWithIndex, providesInfo.u2providesWithCount);
+ }
+
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
diff --git a/src/proguard/classfile/editor/ConstantPoolShrinker.java b/core/src/proguard/classfile/editor/ConstantPoolShrinker.java
similarity index 84%
rename from src/proguard/classfile/editor/ConstantPoolShrinker.java
rename to core/src/proguard/classfile/editor/ConstantPoolShrinker.java
index 0823164..9bad8e7 100644
--- a/src/proguard/classfile/editor/ConstantPoolShrinker.java
+++ b/core/src/proguard/classfile/editor/ConstantPoolShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,8 @@
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
@@ -44,6 +46,8 @@
public class ConstantPoolShrinker
extends SimplifiedVisitor
implements ClassVisitor,
+
+ // Implementation interfaces.
MemberVisitor,
ConstantVisitor,
AttributeVisitor,
@@ -55,12 +59,17 @@ public class ConstantPoolShrinker
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
+ RequiresInfoVisitor,
+ ExportsInfoVisitor,
+ OpensInfoVisitor,
+ ProvidesInfoVisitor,
AnnotationVisitor,
ElementValueVisitor,
InstructionVisitor
{
- // A visitor info flag to indicate the constant is being used.
- private static final Object USED = new Object();
+ // A visitor info flag to indicate that the constant is being used.
+ // Don't make a static instance, so we don't need to clear any old flags.
+ private final Object USED = new Object();
private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE];
private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
@@ -186,6 +195,22 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ markAsUsed(moduleConstant);
+
+ markConstant(clazz, moduleConstant.u2nameIndex);
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ markAsUsed(packageConstant);
+
+ markConstant(clazz, packageConstant.u2nameIndex);
+ }
+
+
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute)
@@ -238,6 +263,46 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ markConstant(clazz, moduleAttribute.u2attributeNameIndex);
+ markConstant(clazz, moduleAttribute.u2moduleNameIndex);
+
+ if (moduleAttribute.u2moduleVersionIndex != 0)
+ {
+ markConstant(clazz, moduleAttribute.u2moduleVersionIndex);
+ }
+ moduleAttribute.requiresAccept(clazz, this);
+ moduleAttribute.exportsAccept(clazz, this);
+ moduleAttribute.opensAccept(clazz, this);
+
+ for (int index = 0; index < moduleAttribute.u2usesCount; index++)
+ {
+ markConstant(clazz, moduleAttribute.u2uses[index]);
+ }
+
+ moduleAttribute.providesAccept(clazz, this);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ markConstant(clazz, moduleMainClassAttribute.u2attributeNameIndex);
+ markConstant(clazz, moduleMainClassAttribute.u2mainClass);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ markConstant(clazz, modulePackagesAttribute.u2attributeNameIndex);
+
+ for (int index = 0; index < modulePackagesAttribute.u2packagesCount; index++)
+ {
+ markConstant(clazz, modulePackagesAttribute.u2packages[index]);
+ }
+ }
+
+
public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
{
markConstant(clazz, signatureAttribute.u2attributeNameIndex);
@@ -419,7 +484,10 @@ public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttrib
public void visitParameterInfo(Clazz clazz, Method method, int parameterIndex, ParameterInfo parameterInfo)
{
- markConstant(clazz, parameterInfo.u2nameIndex);
+ if (parameterInfo.u2nameIndex != 0)
+ {
+ markConstant(clazz, parameterInfo.u2nameIndex);
+ }
}
@@ -441,6 +509,54 @@ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute
}
+ // Implementations for RequiresInfoVisitor.
+
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo)
+ {
+ markConstant(clazz, requiresInfo.u2requiresIndex);
+ markConstant(clazz, requiresInfo.u2requiresVersionIndex);
+ }
+
+
+ // Implementations for ExportsInfoVisitor.
+
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo)
+ {
+ markConstant(clazz, exportsInfo.u2exportsIndex);
+
+ for (int index = 0; index < exportsInfo.u2exportsToCount; index++)
+ {
+ markConstant(clazz, exportsInfo.u2exportsToIndex[index]);
+ }
+ }
+
+
+ // Implementations for OpensInfoVisitor.
+
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo)
+ {
+ markConstant(clazz, opensInfo.u2opensIndex);
+
+ for (int index = 0; index < opensInfo.u2opensToCount; index++)
+ {
+ markConstant(clazz, opensInfo.u2opensToIndex[index]);
+ }
+ }
+
+
+ // Implementations for ProvidesInfoVisitor.
+
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo)
+ {
+ markConstant(clazz, providesInfo.u2providesIndex);
+
+ for (int index = 0; index < providesInfo.u2providesWithCount; index++)
+ {
+ markConstant(clazz, providesInfo.u2providesWithIndex[index]);
+ }
+ }
+
+
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
diff --git a/src/proguard/classfile/editor/ConstantPoolSorter.java b/core/src/proguard/classfile/editor/ConstantPoolSorter.java
similarity index 98%
rename from src/proguard/classfile/editor/ConstantPoolSorter.java
rename to core/src/proguard/classfile/editor/ConstantPoolSorter.java
index 9fc2e33..ea2f4e1 100644
--- a/src/proguard/classfile/editor/ConstantPoolSorter.java
+++ b/core/src/proguard/classfile/editor/ConstantPoolSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ElementValueAdder.java b/core/src/proguard/classfile/editor/ElementValueAdder.java
similarity index 99%
rename from src/proguard/classfile/editor/ElementValueAdder.java
rename to core/src/proguard/classfile/editor/ElementValueAdder.java
index 808adbd..54d2a84 100644
--- a/src/proguard/classfile/editor/ElementValueAdder.java
+++ b/core/src/proguard/classfile/editor/ElementValueAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ElementValuesEditor.java b/core/src/proguard/classfile/editor/ElementValuesEditor.java
similarity index 99%
rename from src/proguard/classfile/editor/ElementValuesEditor.java
rename to core/src/proguard/classfile/editor/ElementValuesEditor.java
index 4a4d0f7..69c1d89 100644
--- a/src/proguard/classfile/editor/ElementValuesEditor.java
+++ b/core/src/proguard/classfile/editor/ElementValuesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ExceptionAdder.java b/core/src/proguard/classfile/editor/ExceptionAdder.java
similarity index 97%
rename from src/proguard/classfile/editor/ExceptionAdder.java
rename to core/src/proguard/classfile/editor/ExceptionAdder.java
index 74b6ca2..af08c68 100644
--- a/src/proguard/classfile/editor/ExceptionAdder.java
+++ b/core/src/proguard/classfile/editor/ExceptionAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ExceptionInfoAdder.java b/core/src/proguard/classfile/editor/ExceptionInfoAdder.java
similarity index 97%
rename from src/proguard/classfile/editor/ExceptionInfoAdder.java
rename to core/src/proguard/classfile/editor/ExceptionInfoAdder.java
index 2784bd3..e51efe4 100644
--- a/src/proguard/classfile/editor/ExceptionInfoAdder.java
+++ b/core/src/proguard/classfile/editor/ExceptionInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/ExceptionInfoEditor.java b/core/src/proguard/classfile/editor/ExceptionInfoEditor.java
new file mode 100644
index 0000000..8fd1a63
--- /dev/null
+++ b/core/src/proguard/classfile/editor/ExceptionInfoEditor.java
@@ -0,0 +1,92 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.attribute.*;
+import proguard.util.ArrayUtil;
+
+/**
+ * This class can add exceptions to the exception table of a given code
+ * attribute. The exceptions must have been filled out beforehand.
+ *
+ * @author Eric Lafortune
+ */
+public class ExceptionInfoEditor
+{
+ private final CodeAttribute codeAttribute;
+
+
+ /**
+ * Creates a new ExceptionInfoEditor that can add exceptions to the
+ * given code attribute.
+ */
+ public ExceptionInfoEditor(CodeAttribute codeAttribute)
+ {
+ this.codeAttribute = codeAttribute;
+ }
+
+
+ /**
+ * Prepends the given exception to the exception table.
+ */
+ void prependException(ExceptionInfo exceptionInfo)
+ {
+ ExceptionInfo[] exceptionTable = codeAttribute.exceptionTable;
+ int exceptionTableLength = codeAttribute.u2exceptionTableLength;
+
+ int newExceptionTableLength = exceptionTableLength + 1;
+
+ // Is the exception table large enough?
+ if (exceptionTable.length < newExceptionTableLength)
+ {
+ ExceptionInfo[] newExceptionTable =
+ new ExceptionInfo[newExceptionTableLength];
+
+ System.arraycopy(exceptionTable, 0,
+ newExceptionTable, 1,
+ exceptionTableLength);
+ newExceptionTable[0] = exceptionInfo;
+
+ codeAttribute.exceptionTable = newExceptionTable;
+ }
+ else
+ {
+ System.arraycopy(exceptionTable, 0,
+ exceptionTable, 1,
+ exceptionTableLength);
+ exceptionTable[0] = exceptionInfo;
+ }
+
+ codeAttribute.u2exceptionTableLength = newExceptionTableLength;
+ }
+
+
+ /**
+ * Appends the given exception to the exception table.
+ */
+ void appendException(ExceptionInfo exceptionInfo)
+ {
+ codeAttribute.exceptionTable =
+ ArrayUtil.add(codeAttribute.exceptionTable,
+ codeAttribute.u2exceptionTableLength++,
+ exceptionInfo);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/ExceptionsAttributeEditor.java b/core/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/ExceptionsAttributeEditor.java
rename to core/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
index 783f714..5c3a49e 100644
--- a/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/InnerClassesAccessFixer.java b/core/src/proguard/classfile/editor/InnerClassesAccessFixer.java
similarity index 97%
rename from src/proguard/classfile/editor/InnerClassesAccessFixer.java
rename to core/src/proguard/classfile/editor/InnerClassesAccessFixer.java
index 29364cb..e520bc7 100644
--- a/src/proguard/classfile/editor/InnerClassesAccessFixer.java
+++ b/core/src/proguard/classfile/editor/InnerClassesAccessFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/InnerClassesAttributeEditor.java b/core/src/proguard/classfile/editor/InnerClassesAttributeEditor.java
new file mode 100644
index 0000000..e26d3ac
--- /dev/null
+++ b/core/src/proguard/classfile/editor/InnerClassesAttributeEditor.java
@@ -0,0 +1,92 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.attribute.*;
+import proguard.util.ArrayUtil;
+
+/**
+ * This class can add/remove bootstrap methods to/from a given inner classes
+ * attribute. Inner classes to be added must have been filled out beforehand.
+ *
+ * @author Thomas Neidhart
+ */
+public class InnerClassesAttributeEditor
+{
+ private InnerClassesAttribute targetInnerClassesAttribute;
+
+
+ /**
+ * Creates a new InnerClassesAttributeEditor that will edit inner
+ * classes in the given inner classes attribute.
+ */
+ public InnerClassesAttributeEditor(InnerClassesAttribute targetInnerClassesAttribute)
+ {
+ this.targetInnerClassesAttribute = targetInnerClassesAttribute;
+ }
+
+
+ /**
+ * Adds a given inner class to the inner classes attribute.
+ * @return the index of the inner class.
+ */
+ public int addInnerClassesInfo(InnerClassesInfo innerClassesInfo)
+ {
+ targetInnerClassesAttribute.classes =
+ ArrayUtil.add(targetInnerClassesAttribute.classes,
+ targetInnerClassesAttribute.u2classesCount,
+ innerClassesInfo);
+
+ return targetInnerClassesAttribute.u2classesCount++;
+ }
+
+
+ /**
+ * Removes the given inner class from the inner classes attribute.
+ */
+ public void removeInnerClassesInfo(InnerClassesInfo innerClassesInfo)
+ {
+ ArrayUtil.remove(targetInnerClassesAttribute.classes,
+ targetInnerClassesAttribute.u2classesCount--,
+ findInnerClassesInfoIndex(innerClassesInfo));
+ }
+
+
+ /**
+ * Finds the index of the given bootstrap method info in the target attribute.
+ */
+ private int findInnerClassesInfoIndex(InnerClassesInfo innerClassesInfo)
+ {
+ int innerClassesCount = targetInnerClassesAttribute.u2classesCount;
+ InnerClassesInfo[] innerClassesInfos = targetInnerClassesAttribute.classes;
+
+ for (int index = 0; index < innerClassesCount; index++)
+ {
+ if (innerClassesInfos[index].equals(innerClassesInfo))
+ {
+ return index;
+ }
+ }
+
+ return innerClassesCount;
+ }
+
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/InstructionAdder.java b/core/src/proguard/classfile/editor/InstructionAdder.java
similarity index 97%
rename from src/proguard/classfile/editor/InstructionAdder.java
rename to core/src/proguard/classfile/editor/InstructionAdder.java
index 5dae480..e059379 100644
--- a/src/proguard/classfile/editor/InstructionAdder.java
+++ b/core/src/proguard/classfile/editor/InstructionAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/InstructionSequenceBuilder.java b/core/src/proguard/classfile/editor/InstructionSequenceBuilder.java
new file mode 100644
index 0000000..17be6a0
--- /dev/null
+++ b/core/src/proguard/classfile/editor/InstructionSequenceBuilder.java
@@ -0,0 +1,1981 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.optimize.peephole.InstructionSequenceReplacer;
+
+import java.util.*;
+
+/**
+ * This utility class allows to construct sequences of instructions and
+ * their constants.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionSequenceBuilder
+{
+ private final ConstantPoolEditor constantPoolEditor;
+
+ private final List instructions = new ArrayList(256);
+
+
+ /**
+ * Creates a new InstructionSequenceBuilder.
+ */
+ public InstructionSequenceBuilder()
+ {
+ this(null, null);
+ }
+
+
+ /**
+ * Creates a new InstructionSequenceBuilder that automatically initializes
+ * class references and class member references in new constants.
+ * @param programClassPool the program class pool from which new
+ * constants can be initialized.
+ * @param libraryClassPool the library class pool from which new
+ * constants can be initialized.
+ */
+ public InstructionSequenceBuilder(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(new MyDummyClass(),
+ programClassPool,
+ libraryClassPool);
+ }
+
+
+ /**
+ * Creates a new InstructionSequenceBuilder.
+ * @param targetClass the target class for the instruction
+ * constants.
+ */
+ public InstructionSequenceBuilder(ProgramClass targetClass)
+ {
+ this(new ConstantPoolEditor(targetClass));
+ }
+
+
+ /**
+ * Creates a new InstructionSequenceBuilder that automatically initializes
+ * class references and class member references in new constants.
+ * @param targetClass the target class for the instruction
+ * constants.
+ * @param programClassPool the program class pool from which new
+ * constants can be initialized.
+ * @param libraryClassPool the library class pool from which new
+ * constants can be initialized.
+ */
+ public InstructionSequenceBuilder(ProgramClass targetClass,
+ ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(new ConstantPoolEditor(targetClass, programClassPool, libraryClassPool));
+ }
+
+
+ /**
+ * Creates a new InstructionSequenceBuilder.
+ * @param constantPoolEditor the editor to use for creating any constants
+ * for the instructions.
+ */
+ public InstructionSequenceBuilder(ConstantPoolEditor constantPoolEditor)
+ {
+ this.constantPoolEditor = constantPoolEditor;
+ }
+
+
+ /**
+ * Returns the ConstantPoolEditor used by this builder to
+ * create constants.
+ *
+ * @return the ConstantPoolEditor used by this builder to
+ * create constants.
+ */
+ public ConstantPoolEditor getConstantPoolEditor()
+ {
+ return constantPoolEditor;
+ }
+
+
+ /**
+ * Short for {@link #appendInstruction(Instruction)}.
+ *
+ * @see InstructionSequenceReplacer#label()
+ */
+ public InstructionSequenceBuilder label(Instruction instruction)
+ {
+ return appendInstruction(instruction);
+ }
+
+
+ /**
+ * Short for {@link #appendInstruction(Instruction)}.
+ *
+ * @see InstructionSequenceReplacer#catch_(int,int,int)
+ */
+ public InstructionSequenceBuilder catch_(Instruction instruction)
+ {
+ return appendInstruction(instruction);
+ }
+
+
+ /**
+ * Appends the given instruction.
+ * @param instruction the instruction to be appended.
+ * @return the builder itself.
+ */
+ public InstructionSequenceBuilder appendInstruction(Instruction instruction)
+ {
+ return add(instruction);
+ }
+
+
+ /**
+ * Appends the given instructions.
+ * @param instructions the instructions to be appended.
+ * @return the builder itself.
+ */
+ public InstructionSequenceBuilder appendInstructions(Instruction[] instructions)
+ {
+ for (Instruction instruction : instructions)
+ {
+ add(instruction);
+ }
+
+ return this;
+ }
+
+
+ /**
+ * Short for {@link #instructions()}.
+ */
+ public Instruction[] __()
+ {
+ return instructions();
+ }
+
+
+ /**
+ * Returns the accumulated sequence of instructions
+ * and resets the sequence in the builder.
+ */
+ public Instruction[] instructions()
+ {
+ Instruction[] instructions_array = new Instruction[instructions.size()];
+ instructions.toArray(instructions_array);
+
+ instructions.clear();
+
+ return instructions_array;
+ }
+
+
+ /**
+ * Returns the accumulated set of constants
+ * and resets the set in the builder.
+ */
+ public Constant[] constants()
+ {
+ ProgramClass targetClass = constantPoolEditor.getTargetClass();
+
+ Constant[] constantPool = new Constant[targetClass.u2constantPoolCount];
+ System.arraycopy(targetClass.constantPool,
+ 0,
+ constantPool,
+ 0,
+ targetClass.u2constantPoolCount);
+
+ targetClass.u2constantPoolCount = 0;
+
+ return constantPool;
+ }
+
+
+ // Methods corresponding to the bytecode opcodes.
+
+ public InstructionSequenceBuilder nop()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_NOP));
+ }
+
+ public InstructionSequenceBuilder aconst_null()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ACONST_NULL));
+ }
+
+ public InstructionSequenceBuilder iconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_0, constant));
+ }
+
+ public InstructionSequenceBuilder iconst_m1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_M1));
+ }
+
+ public InstructionSequenceBuilder iconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_0));
+ }
+
+ public InstructionSequenceBuilder iconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_1));
+ }
+
+ public InstructionSequenceBuilder iconst_2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_2));
+ }
+
+ public InstructionSequenceBuilder iconst_3()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_3));
+ }
+
+ public InstructionSequenceBuilder iconst_4()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_4));
+ }
+
+ public InstructionSequenceBuilder iconst_5()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ICONST_5));
+ }
+
+ public InstructionSequenceBuilder lconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_0, constant));
+ }
+
+ public InstructionSequenceBuilder lconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_0));
+ }
+
+ public InstructionSequenceBuilder lconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCONST_1));
+ }
+
+ public InstructionSequenceBuilder fconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_0, constant));
+ }
+
+ public InstructionSequenceBuilder fconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_0));
+ }
+
+ public InstructionSequenceBuilder fconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_1));
+ }
+
+ public InstructionSequenceBuilder fconst_2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCONST_2));
+ }
+
+ public InstructionSequenceBuilder dconst(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_0, constant));
+ }
+
+ public InstructionSequenceBuilder dconst_0()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_0));
+ }
+
+ public InstructionSequenceBuilder dconst_1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCONST_1));
+ }
+
+ public InstructionSequenceBuilder bipush(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BIPUSH, constant));
+ }
+
+ public InstructionSequenceBuilder sipush(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SIPUSH, constant));
+ }
+
+ public InstructionSequenceBuilder ldc(int value)
+ {
+ return ldc_(constantPoolEditor.addIntegerConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc(float value)
+ {
+ return ldc_(constantPoolEditor.addFloatConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc(Object primitiveArray)
+ {
+ return ldc_(constantPoolEditor.addPrimitiveArrayConstant(primitiveArray));
+ }
+
+ public InstructionSequenceBuilder ldc(String string)
+ {
+ return ldc(string, null, null);
+ }
+
+ public InstructionSequenceBuilder ldc(String string, Clazz referencedClass, Method referencedMember)
+ {
+ return ldc_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
+ }
+
+ public InstructionSequenceBuilder ldc(String className, Clazz referencedClass)
+ {
+ return ldc_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder ldc_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC, constantIndex));
+ }
+
+ public InstructionSequenceBuilder ldc_w(int value)
+ {
+ return ldc_w_(constantPoolEditor.addIntegerConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc_w(float value)
+ {
+ // If we can shrink the instruction, we may not need to create a constant.
+ return ldc_w_(constantPoolEditor.addFloatConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc_w(String string)
+ {
+ return ldc_w(string, null, null);
+ }
+
+ public InstructionSequenceBuilder ldc_w(String string, Clazz referencedClass, Method referencedMember)
+ {
+ return ldc_w_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
+ }
+
+ public InstructionSequenceBuilder ldc_w(String className, Clazz referencedClass)
+ {
+ return ldc_w_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder ldc_w_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC_W, constantIndex));
+ }
+
+ public InstructionSequenceBuilder ldc2_w(long value)
+ {
+ // If we can shrink the instruction, we may not need to create a constant.
+ return ldc2_w(constantPoolEditor.addLongConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc2_w(double value)
+ {
+ // If we can shrink the instruction, we may not need to create a constant.
+ return ldc2_w(constantPoolEditor.addDoubleConstant(value));
+ }
+
+ public InstructionSequenceBuilder ldc2_w(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_LDC2_W, constantIndex));
+ }
+
+ public InstructionSequenceBuilder iload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD, variableIndex));
+ }
+
+ public InstructionSequenceBuilder lload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD, variableIndex));
+ }
+
+ public InstructionSequenceBuilder fload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD, variableIndex));
+ }
+
+ public InstructionSequenceBuilder dload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD, variableIndex));
+ }
+
+ public InstructionSequenceBuilder aload(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD, variableIndex));
+ }
+
+ public InstructionSequenceBuilder iload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_0));
+ }
+
+ public InstructionSequenceBuilder iload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_1));
+ }
+
+ public InstructionSequenceBuilder iload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_2));
+ }
+
+ public InstructionSequenceBuilder iload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ILOAD_3));
+ }
+
+ public InstructionSequenceBuilder lload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_0));
+ }
+
+ public InstructionSequenceBuilder lload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_1));
+ }
+
+ public InstructionSequenceBuilder lload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_2));
+ }
+
+ public InstructionSequenceBuilder lload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LLOAD_3));
+ }
+
+ public InstructionSequenceBuilder fload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_0));
+ }
+
+ public InstructionSequenceBuilder fload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_1));
+ }
+
+ public InstructionSequenceBuilder fload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_2));
+ }
+
+ public InstructionSequenceBuilder fload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FLOAD_3));
+ }
+
+ public InstructionSequenceBuilder dload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_0));
+ }
+
+ public InstructionSequenceBuilder dload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_1));
+ }
+
+ public InstructionSequenceBuilder dload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_2));
+ }
+
+ public InstructionSequenceBuilder dload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DLOAD_3));
+ }
+
+ public InstructionSequenceBuilder aload_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_0));
+ }
+
+ public InstructionSequenceBuilder aload_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_1));
+ }
+
+ public InstructionSequenceBuilder aload_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_2));
+ }
+
+ public InstructionSequenceBuilder aload_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ALOAD_3));
+ }
+
+ public InstructionSequenceBuilder iaload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IALOAD));
+ }
+
+ public InstructionSequenceBuilder laload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LALOAD));
+ }
+
+ public InstructionSequenceBuilder faload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FALOAD));
+ }
+
+ public InstructionSequenceBuilder daload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DALOAD));
+ }
+
+ public InstructionSequenceBuilder aaload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_AALOAD));
+ }
+
+ public InstructionSequenceBuilder baload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BALOAD));
+ }
+
+ public InstructionSequenceBuilder caload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_CALOAD));
+ }
+
+ public InstructionSequenceBuilder saload()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SALOAD));
+ }
+
+ public InstructionSequenceBuilder istore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE, variableIndex));
+ }
+
+ public InstructionSequenceBuilder lstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE, variableIndex));
+ }
+
+ public InstructionSequenceBuilder fstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE, variableIndex));
+ }
+
+ public InstructionSequenceBuilder dstore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE, variableIndex));
+ }
+
+ public InstructionSequenceBuilder astore(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE, variableIndex));
+ }
+
+ public InstructionSequenceBuilder istore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_0));
+ }
+
+ public InstructionSequenceBuilder istore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_1));
+ }
+
+ public InstructionSequenceBuilder istore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_2));
+ }
+
+ public InstructionSequenceBuilder istore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ISTORE_3));
+ }
+
+ public InstructionSequenceBuilder lstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_0));
+ }
+
+ public InstructionSequenceBuilder lstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_1));
+ }
+
+ public InstructionSequenceBuilder lstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_2));
+ }
+
+ public InstructionSequenceBuilder lstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_LSTORE_3));
+ }
+
+ public InstructionSequenceBuilder fstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_0));
+ }
+
+ public InstructionSequenceBuilder fstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_1));
+ }
+
+ public InstructionSequenceBuilder fstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_2));
+ }
+
+ public InstructionSequenceBuilder fstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_FSTORE_3));
+ }
+
+ public InstructionSequenceBuilder dstore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_0));
+ }
+
+ public InstructionSequenceBuilder dstore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_1));
+ }
+
+ public InstructionSequenceBuilder dstore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_2));
+ }
+
+ public InstructionSequenceBuilder dstore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_DSTORE_3));
+ }
+
+ public InstructionSequenceBuilder astore_0()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_0));
+ }
+
+ public InstructionSequenceBuilder astore_1()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_1));
+ }
+
+ public InstructionSequenceBuilder astore_2()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_2));
+ }
+
+ public InstructionSequenceBuilder astore_3()
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_ASTORE_3));
+ }
+
+ public InstructionSequenceBuilder iastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IASTORE));
+ }
+
+ public InstructionSequenceBuilder lastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LASTORE));
+ }
+
+ public InstructionSequenceBuilder fastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FASTORE));
+ }
+
+ public InstructionSequenceBuilder dastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DASTORE));
+ }
+
+ public InstructionSequenceBuilder aastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_AASTORE));
+ }
+
+ public InstructionSequenceBuilder bastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_BASTORE));
+ }
+
+ public InstructionSequenceBuilder castore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_CASTORE));
+ }
+
+ public InstructionSequenceBuilder sastore()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SASTORE));
+ }
+
+ public InstructionSequenceBuilder pop()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_POP));
+ }
+
+ public InstructionSequenceBuilder pop2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_POP2));
+ }
+
+ public InstructionSequenceBuilder dup()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP));
+ }
+
+ public InstructionSequenceBuilder dup_x1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP_X1));
+ }
+
+ public InstructionSequenceBuilder dup_x2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP_X2));
+ }
+
+ public InstructionSequenceBuilder dup2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2));
+ }
+
+ public InstructionSequenceBuilder dup2_x1()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2_X1));
+ }
+
+ public InstructionSequenceBuilder dup2_x2()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DUP2_X2));
+ }
+
+ public InstructionSequenceBuilder swap()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_SWAP));
+ }
+
+ public InstructionSequenceBuilder iadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IADD));
+ }
+
+ public InstructionSequenceBuilder ladd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LADD));
+ }
+
+ public InstructionSequenceBuilder fadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FADD));
+ }
+
+ public InstructionSequenceBuilder dadd()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DADD));
+ }
+
+ public InstructionSequenceBuilder isub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISUB));
+ }
+
+ public InstructionSequenceBuilder lsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSUB));
+ }
+
+ public InstructionSequenceBuilder fsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FSUB));
+ }
+
+ public InstructionSequenceBuilder dsub()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DSUB));
+ }
+
+ public InstructionSequenceBuilder imul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IMUL));
+ }
+
+ public InstructionSequenceBuilder lmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LMUL));
+ }
+
+ public InstructionSequenceBuilder fmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FMUL));
+ }
+
+ public InstructionSequenceBuilder dmul()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DMUL));
+ }
+
+ public InstructionSequenceBuilder idiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IDIV));
+ }
+
+ public InstructionSequenceBuilder ldiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LDIV));
+ }
+
+ public InstructionSequenceBuilder fdiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FDIV));
+ }
+
+ public InstructionSequenceBuilder ddiv()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DDIV));
+ }
+
+ public InstructionSequenceBuilder irem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IREM));
+ }
+
+ public InstructionSequenceBuilder lrem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LREM));
+ }
+
+ public InstructionSequenceBuilder frem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FREM));
+ }
+
+ public InstructionSequenceBuilder drem()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DREM));
+ }
+
+ public InstructionSequenceBuilder ineg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_INEG));
+ }
+
+ public InstructionSequenceBuilder lneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LNEG));
+ }
+
+ public InstructionSequenceBuilder fneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FNEG));
+ }
+
+ public InstructionSequenceBuilder dneg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DNEG));
+ }
+
+ public InstructionSequenceBuilder ishl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISHL));
+ }
+
+ public InstructionSequenceBuilder lshl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSHL));
+ }
+
+ public InstructionSequenceBuilder ishr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ISHR));
+ }
+
+ public InstructionSequenceBuilder lshr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LSHR));
+ }
+
+ public InstructionSequenceBuilder iushr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IUSHR));
+ }
+
+ public InstructionSequenceBuilder lushr()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LUSHR));
+ }
+
+ public InstructionSequenceBuilder iand()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IAND));
+ }
+
+ public InstructionSequenceBuilder land()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LAND));
+ }
+
+ public InstructionSequenceBuilder ior()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IOR));
+ }
+
+ public InstructionSequenceBuilder lor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LOR));
+ }
+
+ public InstructionSequenceBuilder ixor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IXOR));
+ }
+
+ public InstructionSequenceBuilder lxor()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LXOR));
+ }
+
+ public InstructionSequenceBuilder iinc(int variableIndex,
+ int constant)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_IINC, variableIndex, constant));
+ }
+
+ public InstructionSequenceBuilder i2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2L));
+ }
+
+ public InstructionSequenceBuilder i2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2F));
+ }
+
+ public InstructionSequenceBuilder i2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2D));
+ }
+
+ public InstructionSequenceBuilder l2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2I));
+ }
+
+ public InstructionSequenceBuilder l2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2F));
+ }
+
+ public InstructionSequenceBuilder l2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_L2D));
+ }
+
+ public InstructionSequenceBuilder f2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2I));
+ }
+
+ public InstructionSequenceBuilder f2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2L));
+ }
+
+ public InstructionSequenceBuilder f2d()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_F2D));
+ }
+
+ public InstructionSequenceBuilder d2i()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2I));
+ }
+
+ public InstructionSequenceBuilder d2l()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2L));
+ }
+
+ public InstructionSequenceBuilder d2f()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_D2F));
+ }
+
+ public InstructionSequenceBuilder i2b()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2B));
+ }
+
+ public InstructionSequenceBuilder i2c()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2C));
+ }
+
+ public InstructionSequenceBuilder i2s()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_I2S));
+ }
+
+ public InstructionSequenceBuilder lcmp()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LCMP));
+ }
+
+ public InstructionSequenceBuilder fcmpl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCMPL));
+ }
+
+ public InstructionSequenceBuilder fcmpg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FCMPG));
+ }
+
+ public InstructionSequenceBuilder dcmpl()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCMPL));
+ }
+
+ public InstructionSequenceBuilder dcmpg()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DCMPG));
+ }
+
+ public InstructionSequenceBuilder ifeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFEQ, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder iflt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFLT, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifge(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFGE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifgt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFGT, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifle(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFLE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmpeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPEQ, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmpne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPNE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmplt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPLT, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmpge(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPGE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmpgt(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPGT, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ificmple(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFICMPLE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifacmpeq(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFACMPEQ, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifacmpne(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFACMPNE, branchOffset));
+ }
+
+ public InstructionSequenceBuilder goto_(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_GOTO, branchOffset));
+ }
+
+ public InstructionSequenceBuilder jsr(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_JSR, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ret(int variableIndex)
+ {
+ return add(new VariableInstruction(InstructionConstants.OP_RET, variableIndex));
+ }
+
+ public InstructionSequenceBuilder tableswitch(int defaultOffset,
+ int lowCase,
+ int highCase,
+ int[] jumpOffsets)
+ {
+ return add(new TableSwitchInstruction(InstructionConstants.OP_TABLESWITCH,
+ defaultOffset,
+ lowCase,
+ highCase,
+ jumpOffsets));
+ }
+
+ public InstructionSequenceBuilder lookupswitch(int defaultOffset,
+ int[] cases,
+ int[] jumpOffsets)
+ {
+ return add(new LookUpSwitchInstruction(InstructionConstants.OP_LOOKUPSWITCH,
+ defaultOffset,
+ cases,
+ jumpOffsets));
+ }
+
+ public InstructionSequenceBuilder ireturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_IRETURN));
+ }
+
+ public InstructionSequenceBuilder lreturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_LRETURN));
+ }
+
+ public InstructionSequenceBuilder freturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_FRETURN));
+ }
+
+ public InstructionSequenceBuilder dreturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_DRETURN));
+ }
+
+ public InstructionSequenceBuilder areturn()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ARETURN));
+ }
+
+ public InstructionSequenceBuilder return_()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_RETURN));
+ }
+
+ public InstructionSequenceBuilder getstatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getstatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder getstatic(String className,
+ String name,
+ String descriptor)
+ {
+ return getstatic(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder getstatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getstatic(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder getstatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_GETSTATIC, constantIndex));
+ }
+
+ public InstructionSequenceBuilder putstatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putstatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder putstatic(String className,
+ String name,
+ String descriptor)
+ {
+ return putstatic(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder putstatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putstatic(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder putstatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_PUTSTATIC, constantIndex));
+ }
+
+ public InstructionSequenceBuilder getfield(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getfield(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder getfield(String className,
+ String name,
+ String descriptor)
+ {
+ return getfield(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder getfield(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return getfield(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder getfield(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_GETFIELD, constantIndex));
+ }
+
+ public InstructionSequenceBuilder putfield(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putfield(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder putfield(String className,
+ String name,
+ String descriptor)
+ {
+ return putfield(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder putfield(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return putfield(constantPoolEditor.addFieldrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder putfield(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_PUTFIELD, constantIndex));
+ }
+
+ public InstructionSequenceBuilder invokevirtual(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokevirtual(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder invokevirtual(String className,
+ String name,
+ String descriptor)
+ {
+ return invokevirtual(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokevirtual(int classIndex,
+ String name,
+ String descriptor)
+ {
+ return invokevirtual(constantPoolEditor.addMethodrefConstant(classIndex,
+ name,
+ descriptor,
+ null,
+ null));
+ }
+
+ public InstructionSequenceBuilder invokevirtual(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokevirtual(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder invokevirtual(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, constantIndex));
+ }
+
+ public InstructionSequenceBuilder invokespecial(String className,
+ String name,
+ String descriptor)
+ {
+ return invokespecial(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokespecial(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokespecial(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder invokespecial(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokespecial(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder invokespecial_interface(String className,
+ String name,
+ String descriptor)
+ {
+ return invokespecial_interface(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokespecial_interface(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokespecial_interface(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder invokespecial_interface(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokespecial(constantPoolEditor.addInterfaceMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder invokespecial(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, constantIndex));
+ }
+
+ public InstructionSequenceBuilder invokestatic(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder invokestatic(String className,
+ String name,
+ String descriptor)
+ {
+ return invokestatic(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokestatic(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(constantPoolEditor.addMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder invokestatic_interface(String className,
+ String name,
+ String descriptor)
+ {
+ return invokestatic_interface(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokestatic_interface(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokestatic(constantPoolEditor.addInterfaceMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember));
+ }
+
+ public InstructionSequenceBuilder invokestatic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, constantIndex));
+ }
+
+ public InstructionSequenceBuilder invokeinterface(Clazz referencedClass,
+ Member referencedMember)
+ {
+ return invokeinterface(referencedClass.getName(),
+ referencedMember.getName(referencedClass),
+ referencedMember.getDescriptor(referencedClass),
+ referencedClass,
+ referencedMember);
+ }
+
+ public InstructionSequenceBuilder invokeinterface(String className,
+ String name,
+ String descriptor)
+ {
+ return invokeinterface(className, name, descriptor, null, null);
+ }
+
+ public InstructionSequenceBuilder invokeinterface(String className,
+ String name,
+ String descriptor,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ int invokeinterfaceConstant =
+ (ClassUtil.internalMethodParameterSize(descriptor, false)) << 8;
+
+ return invokeinterface(constantPoolEditor.addInterfaceMethodrefConstant(className,
+ name,
+ descriptor,
+ referencedClass,
+ referencedMember),
+ invokeinterfaceConstant);
+ }
+
+ public InstructionSequenceBuilder invokeinterface(int constantIndex, int constant)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE, constantIndex, constant));
+ }
+
+ public InstructionSequenceBuilder invokedynamic(int bootStrapMethodIndex,
+ String name,
+ String descriptor)
+ {
+ return invokedynamic(bootStrapMethodIndex, name, descriptor, null);
+ }
+
+ public InstructionSequenceBuilder invokedynamic(int bootStrapMethodIndex,
+ String name,
+ String descriptor,
+ Clazz[] referencedClasses)
+ {
+ return invokedynamic(constantPoolEditor.addInvokeDynamicConstant(bootStrapMethodIndex,
+ name,
+ descriptor,
+ referencedClasses));
+ }
+
+ public InstructionSequenceBuilder invokedynamic(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INVOKEDYNAMIC, constantIndex));
+ }
+
+ public InstructionSequenceBuilder new_(String className)
+ {
+ return new_(className, null);
+ }
+
+ public InstructionSequenceBuilder new_(String className, Clazz referencedClass)
+ {
+ return new_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder new_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_NEW, constantIndex));
+ }
+
+ public InstructionSequenceBuilder newarray(int constant)
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_NEWARRAY, constant));
+ }
+
+ public InstructionSequenceBuilder anewarray(String className, Clazz referencedClass)
+ {
+ return anewarray(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder anewarray(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, constantIndex));
+ }
+
+ public InstructionSequenceBuilder arraylength()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ARRAYLENGTH));
+ }
+
+ public InstructionSequenceBuilder athrow()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_ATHROW));
+ }
+
+ public InstructionSequenceBuilder checkcast(String className)
+ {
+ return checkcast(className, null);
+ }
+
+ public InstructionSequenceBuilder checkcast(String className, Clazz referencedClass)
+ {
+ return checkcast(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder checkcast(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_CHECKCAST, constantIndex));
+ }
+
+ public InstructionSequenceBuilder instanceof_(String className, Clazz referencedClass)
+ {
+ return instanceof_(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder instanceof_(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_INSTANCEOF, constantIndex));
+ }
+
+ public InstructionSequenceBuilder monitorenter()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_MONITORENTER));
+ }
+
+ public InstructionSequenceBuilder monitorexit()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_MONITOREXIT));
+ }
+
+ public InstructionSequenceBuilder wide()
+ {
+ return add(new SimpleInstruction(InstructionConstants.OP_WIDE));
+ }
+
+ public InstructionSequenceBuilder multianewarray(String className, Clazz referencedClass)
+ {
+ return multianewarray(constantPoolEditor.addClassConstant(className, referencedClass));
+ }
+
+ public InstructionSequenceBuilder multianewarray(int constantIndex)
+ {
+ return add(new ConstantInstruction(InstructionConstants.OP_MULTIANEWARRAY, constantIndex));
+ }
+
+ public InstructionSequenceBuilder ifnull(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNULL, branchOffset));
+ }
+
+ public InstructionSequenceBuilder ifnonnull(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_IFNONNULL, branchOffset));
+ }
+
+ public InstructionSequenceBuilder goto_w(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_GOTO_W, branchOffset));
+ }
+
+ public InstructionSequenceBuilder jsr_w(int branchOffset)
+ {
+ return add(new BranchInstruction(InstructionConstants.OP_JSR_W, branchOffset));
+ }
+
+
+ // Additional convenience methods.
+
+ /**
+ * Pushes the given primitive value on the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param value the primitive value to be pushed - should never be null.
+ * @param type the internal type of the primitive ('Z','B','I',...)
+ */
+ public InstructionSequenceBuilder pushPrimitive(Object value,
+ char type)
+ {
+ switch (type)
+ {
+ case ClassConstants.TYPE_BOOLEAN: return ((Boolean)value).booleanValue() ? iconst_1() : iconst_0();
+ case ClassConstants.TYPE_BYTE:
+ case ClassConstants.TYPE_SHORT:
+ case ClassConstants.TYPE_INT: return pushInt(((Number)value).intValue());
+ case ClassConstants.TYPE_CHAR: return ldc(((Character)value).charValue());
+ case ClassConstants.TYPE_LONG: return ldc2_w((Long)value);
+ case ClassConstants.TYPE_FLOAT: return ldc(((Float)value).floatValue());
+ case ClassConstants.TYPE_DOUBLE: return ldc2_w((Double)value);
+ default: throw new IllegalArgumentException("" + type);
+ }
+ }
+
+
+ /**
+ * Pushes the given primitive int on the stack in the most efficient way
+ * (as an iconst, bipush, sipush, or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public InstructionSequenceBuilder pushInt(int value)
+ {
+ return
+ value >= -1 &&
+ value <= 5 ? iconst(value) :
+ value == (byte)value ? bipush(value) :
+ value == (short)value ? sipush(value) :
+ ldc(value);
+ }
+
+
+ /**
+ * Pushes the given primitive float on the stack in the most efficient way
+ * (as an fconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public InstructionSequenceBuilder pushFloat(float value)
+ {
+ return
+ value == 0f ||
+ value == 1f ? fconst((int)value) :
+ ldc(value);
+ }
+
+
+ /**
+ * Pushes the given primitive long on the stack in the most efficient way
+ * (as an lconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public InstructionSequenceBuilder pushLong(long value)
+ {
+ return
+ value == 0L ||
+ value == 1L ? lconst((int)value) :
+ ldc2_w(value);
+ }
+
+
+ /**
+ * Pushes the given primitive double on the stack in the most efficient way
+ * (as a dconst or ldc instruction).
+ *
+ * @param value the int value to be pushed.
+ */
+ public InstructionSequenceBuilder pushDouble(double value)
+ {
+ return
+ value == 0. ||
+ value == 1. ? dconst((int)value) :
+ ldc2_w(value);
+ }
+
+
+ /**
+ * Pushes a new array on the stack.
+ *
+ * Operand stack:
+ * ... -> ..., array
+ *
+ * @param type the array element type (or class name in case of objects).
+ * @param size the size of the array to be created.
+ */
+ public InstructionSequenceBuilder pushNewArray(String type,
+ int size)
+ {
+ // Create new array.
+ pushInt(size);
+
+ return ClassUtil.isInternalPrimitiveType(type) ?
+ newarray(InstructionUtil.arrayTypeFromInternalType(type.charAt(0))) :
+ anewarray(type, null);
+ }
+
+
+ /**
+ * Loads the given variable onto the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param variableIndex the index of the variable to be loaded.
+ * @param type the type of the variable to be loaded.
+ */
+ public InstructionSequenceBuilder load(int variableIndex,
+ String type)
+ {
+ return load(variableIndex, type.charAt(0));
+ }
+
+
+ /**
+ * Loads the given variable of primitive type onto the stack.
+ *
+ * Operand stack:
+ * ... -> ..., value
+ *
+ * @param variableIndex the index of the variable to be loaded.
+ * @param type the type of the variable to be loaded.
+ */
+ public InstructionSequenceBuilder load(int variableIndex,
+ char type)
+ {
+ switch (type)
+ {
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE:
+ case ClassConstants.TYPE_CHAR:
+ case ClassConstants.TYPE_SHORT:
+ case ClassConstants.TYPE_INT: return iload(variableIndex);
+ case ClassConstants.TYPE_LONG: return lload(variableIndex);
+ case ClassConstants.TYPE_FLOAT: return fload(variableIndex);
+ case ClassConstants.TYPE_DOUBLE: return dload(variableIndex);
+ default: return aload(variableIndex);
+ }
+ }
+
+
+ /**
+ * Stores the value on top of the stack in the variable with given index.
+ *
+ * Operand stsack:
+ * ..., value -> ...
+ *
+ * @param variableIndex the index of the variable where to store the
+ * value.
+ * @param type the type of the value to be stored.
+ */
+ public InstructionSequenceBuilder store(int variableIndex,
+ String type)
+ {
+ return store(variableIndex, type.charAt(0));
+ }
+
+
+ /**
+ * Stores the primitve value on top of the stack in the variable with given
+ * index.
+ *
+ * Operand stack:
+ * ..., value -> ...
+ *
+ * @param variableIndex the index of the variable where to store the
+ * value.
+ * @param type the type of the value to be stored.
+ */
+ public InstructionSequenceBuilder store(int variableIndex,
+ char type)
+ {
+ switch (type)
+ {
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE:
+ case ClassConstants.TYPE_CHAR:
+ case ClassConstants.TYPE_SHORT:
+ case ClassConstants.TYPE_INT: return istore(variableIndex);
+ case ClassConstants.TYPE_LONG: return lstore(variableIndex);
+ case ClassConstants.TYPE_FLOAT: return fstore(variableIndex);
+ case ClassConstants.TYPE_DOUBLE: return dstore(variableIndex);
+ default: return astore(variableIndex);
+ }
+ }
+
+
+ /**
+ * Stores an element to an array.
+ *
+ * Operand stack:
+ * ..., array, index, value -> ...
+ *
+ * @param elementType the type of the value to be stored.
+ */
+ public InstructionSequenceBuilder storeToArray(String elementType)
+ {
+ // Store element on stack in array.
+ switch (elementType.charAt(0))
+ {
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE: return bastore();
+ case ClassConstants.TYPE_CHAR: return castore();
+ case ClassConstants.TYPE_SHORT: return sastore();
+ case ClassConstants.TYPE_INT: return iastore();
+ case ClassConstants.TYPE_LONG: return lastore();
+ case ClassConstants.TYPE_FLOAT: return fastore();
+ case ClassConstants.TYPE_DOUBLE: return dastore();
+ default: return aastore();
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Adds the given instruction, shrinking it if necessary.
+ */
+ private InstructionSequenceBuilder add(Instruction instruction)
+ {
+ instructions.add(instruction);
+
+ return this;
+ }
+
+
+ /**
+ * This main method tests the class.
+ */
+ public static void main(String[] args)
+ {
+ InstructionSequenceBuilder builder = new InstructionSequenceBuilder();
+
+ Instruction[] instructions = builder
+ .iconst_2()
+ .istore_0()
+ .iinc(0, 2)
+ .iload_0()
+ .ldc(12)
+ .iadd()
+ .putstatic("com/example/SomeClass", "someField", "I", null, null)
+ .instructions();
+
+ Constant[] constants = builder.constants();
+
+ for (Instruction instruction : instructions)
+ {
+ System.out.println(instruction);
+ }
+
+ System.out.println();
+
+ for (int index = 0; index < constants.length; index++)
+ {
+ System.out.println("#"+index+": " + constants[index]);
+ }
+ }
+
+
+ /**
+ * This ProgramClass is a dummy container for a constant pool, with a null name.
+ */
+ private static class MyDummyClass
+ extends ProgramClass
+ {
+ public MyDummyClass()
+ {
+ super(ClassConstants.CLASS_VERSION_1_0, 1, new Constant[256], 0, 0, 0);
+ }
+
+
+ // Overriding methods for Claaz.
+
+ public String getName()
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/proguard/classfile/editor/InstructionWriter.java b/core/src/proguard/classfile/editor/InstructionWriter.java
similarity index 99%
rename from src/proguard/classfile/editor/InstructionWriter.java
rename to core/src/proguard/classfile/editor/InstructionWriter.java
index c0174f3..98ac622 100644
--- a/src/proguard/classfile/editor/InstructionWriter.java
+++ b/core/src/proguard/classfile/editor/InstructionWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/InterfaceAdder.java b/core/src/proguard/classfile/editor/InterfaceAdder.java
similarity index 97%
rename from src/proguard/classfile/editor/InterfaceAdder.java
rename to core/src/proguard/classfile/editor/InterfaceAdder.java
index 7cc8de8..4b634fd 100644
--- a/src/proguard/classfile/editor/InterfaceAdder.java
+++ b/core/src/proguard/classfile/editor/InterfaceAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/InterfaceDeleter.java b/core/src/proguard/classfile/editor/InterfaceDeleter.java
similarity index 99%
rename from src/proguard/classfile/editor/InterfaceDeleter.java
rename to core/src/proguard/classfile/editor/InterfaceDeleter.java
index 5cbf068..5260a25 100644
--- a/src/proguard/classfile/editor/InterfaceDeleter.java
+++ b/core/src/proguard/classfile/editor/InterfaceDeleter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/InterfaceSorter.java b/core/src/proguard/classfile/editor/InterfaceSorter.java
similarity index 99%
rename from src/proguard/classfile/editor/InterfaceSorter.java
rename to core/src/proguard/classfile/editor/InterfaceSorter.java
index 41cef21..e4a2961 100644
--- a/src/proguard/classfile/editor/InterfaceSorter.java
+++ b/core/src/proguard/classfile/editor/InterfaceSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/InterfacesEditor.java b/core/src/proguard/classfile/editor/InterfacesEditor.java
similarity index 98%
rename from src/proguard/classfile/editor/InterfacesEditor.java
rename to core/src/proguard/classfile/editor/InterfacesEditor.java
index 7d0599b..a987499 100644
--- a/src/proguard/classfile/editor/InterfacesEditor.java
+++ b/core/src/proguard/classfile/editor/InterfacesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LineNumberInfoAdder.java b/core/src/proguard/classfile/editor/LineNumberInfoAdder.java
similarity index 98%
rename from src/proguard/classfile/editor/LineNumberInfoAdder.java
rename to core/src/proguard/classfile/editor/LineNumberInfoAdder.java
index f499d29..c85aa9a 100644
--- a/src/proguard/classfile/editor/LineNumberInfoAdder.java
+++ b/core/src/proguard/classfile/editor/LineNumberInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LineNumberTableAttributeEditor.java b/core/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
rename to core/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
index 3eded4e..023ff2d 100644
--- a/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LineNumberTableAttributeTrimmer.java b/core/src/proguard/classfile/editor/LineNumberTableAttributeTrimmer.java
similarity index 98%
rename from src/proguard/classfile/editor/LineNumberTableAttributeTrimmer.java
rename to core/src/proguard/classfile/editor/LineNumberTableAttributeTrimmer.java
index 8d860c3..0421bbf 100644
--- a/src/proguard/classfile/editor/LineNumberTableAttributeTrimmer.java
+++ b/core/src/proguard/classfile/editor/LineNumberTableAttributeTrimmer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LocalVariableInfoAdder.java b/core/src/proguard/classfile/editor/LocalVariableInfoAdder.java
similarity index 98%
rename from src/proguard/classfile/editor/LocalVariableInfoAdder.java
rename to core/src/proguard/classfile/editor/LocalVariableInfoAdder.java
index 909dc8f..459abef 100644
--- a/src/proguard/classfile/editor/LocalVariableInfoAdder.java
+++ b/core/src/proguard/classfile/editor/LocalVariableInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LocalVariableTableAttributeEditor.java b/core/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
rename to core/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
index 360d485..ba26663 100644
--- a/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LocalVariableTypeInfoAdder.java b/core/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
similarity index 98%
rename from src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
rename to core/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
index eec3c02..549477b 100644
--- a/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
+++ b/core/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/LocalVariableTypeTableAttributeEditor.java b/core/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
rename to core/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
index 5e4d6e0..abaae01 100644
--- a/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/MemberAdder.java b/core/src/proguard/classfile/editor/MemberAdder.java
similarity index 79%
rename from src/proguard/classfile/editor/MemberAdder.java
rename to core/src/proguard/classfile/editor/MemberAdder.java
index 2bd953d..4da4c56 100644
--- a/src/proguard/classfile/editor/MemberAdder.java
+++ b/core/src/proguard/classfile/editor/MemberAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
import proguard.classfile.attribute.Attribute;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
+import proguard.util.*;
/**
* This MemberVisitor copies all class members that it visits to the given
@@ -46,11 +47,10 @@ public class MemberAdder
private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0];
- private final ProgramClass targetClass;
-// private final boolean addFields;
- private final MemberVisitor extraMemberVisitor;
+ private final ProgramClass targetClass;
+ private final StringTransformer nameTransformer;
+ private final MemberVisitor extraMemberVisitor;
- private final ConstantAdder constantAdder;
private final ClassEditor classEditor;
private final ConstantPoolEditor constantPoolEditor;
@@ -76,17 +76,32 @@ public MemberAdder(ProgramClass targetClass)
* new member right after it has been added. This
* allows changing the visitor info, for instance.
*/
-// * @param addFields specifies whether fields should be added, or fused
-// * with the present fields.
- public MemberAdder(ProgramClass targetClass,
-// boolean addFields,
- MemberVisitor extraMemberVisitor)
+ public MemberAdder(ProgramClass targetClass,
+ MemberVisitor extraMemberVisitor)
+ {
+ this(targetClass, null, extraMemberVisitor);
+ }
+
+ /**
+ * Creates a new MemberAdder that will copy methods into the given target
+ * class.
+ * @param targetClass the class to which all visited class members
+ * will be added.
+ * @param nameTransformer the transformer to be applied to each member's
+ * name before copying. If null, the original
+ * name will be used.
+ * @param extraMemberVisitor an optional member visitor that visits each
+ * new member right after it has been added. This
+ * allows changing the visitor info, for instance.
+ */
+ public MemberAdder(ProgramClass targetClass,
+ StringTransformer nameTransformer,
+ MemberVisitor extraMemberVisitor)
{
this.targetClass = targetClass;
-// this.addFields = addFields;
+ this.nameTransformer = nameTransformer;
this.extraMemberVisitor = extraMemberVisitor;
- constantAdder = new ConstantAdder(targetClass);
classEditor = new ClassEditor(targetClass);
constantPoolEditor = new ConstantPoolEditor(targetClass);
}
@@ -96,10 +111,15 @@ public MemberAdder(ProgramClass targetClass,
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- //String name = programField.getName(programClass);
- //String descriptor = programField.getDescriptor(programClass);
+ String name = programField.getName(programClass);
+ String descriptor = programField.getDescriptor(programClass);
int accessFlags = programField.getAccessFlags();
+ if (nameTransformer != null)
+ {
+ name = nameTransformer.transform(name);
+ }
+
// TODO: Handle field with the same name and descriptor in the target class.
// We currently avoid this case, since renaming the identical field
// still causes confused field references.
@@ -113,14 +133,15 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
// (ClassConstants.ACC_PRIVATE |
// ClassConstants.ACC_STATIC)) != 0)
// {
+ // // Rename the private or static field.
+ // String newName = newUniqueMemberName(name, targetClass.getName());
+ //
// if (DEBUG)
// {
- // System.out.println("MemberAdder: renaming field ["+targetClass+"."+targetField.getName(targetClass)+" "+targetField.getDescriptor(targetClass)+"]");
+ // System.out.println("MemberAdder: renaming field ["+targetClass.getName()+"."+name+" "+descriptor+"] to ["+newName+"]");
// }
//
- // // Rename the private or static field.
- // targetField.u2nameIndex =
- // constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, targetClass.getName()));
+ // targetField.u2nameIndex = constantPoolEditor.addUtf8Constant(newName);
// }
// else
// {
@@ -153,8 +174,8 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
// Create a copy of the field.
ProgramField newProgramField =
new ProgramField(accessFlags,
- constantAdder.addConstant(programClass, programField.u2nameIndex),
- constantAdder.addConstant(programClass, programField.u2descriptorIndex),
+ constantPoolEditor.addUtf8Constant(name),
+ constantPoolEditor.addUtf8Constant(descriptor),
0,
programField.u2attributesCount > 0 ?
new Attribute[programField.u2attributesCount] :
@@ -187,6 +208,11 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
String descriptor = programMethod.getDescriptor(programClass);
int accessFlags = programMethod.getAccessFlags();
+ if (nameTransformer != null)
+ {
+ name = nameTransformer.transform(name);
+ }
+
// Does the target class already have such a method?
ProgramMethod targetMethod = (ProgramMethod)targetClass.findMethod(name, descriptor);
if (targetMethod != null)
@@ -197,7 +223,7 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
// Keep the target method.
if (DEBUG)
{
- System.out.println("MemberAdder: skipping abstract method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]");
+ System.out.println("MemberAdder: skipping abstract method ["+programClass.getName()+"."+name+descriptor+"] into ["+targetClass.getName()+"]");
}
// Don't add a new method.
@@ -212,7 +238,7 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
// to keep any references to it valid.
if (DEBUG)
{
- System.out.println("MemberAdder: updating method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]");
+ System.out.println("MemberAdder: updating method ["+programClass.getName()+"."+name+descriptor+"] into ["+targetClass.getName()+"]");
}
// Replace the access flags.
@@ -231,7 +257,7 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
if (DEBUG)
{
- System.out.println("MemberAdder: renaming method ["+targetClass.getName()+"."+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]");
+ System.out.println("MemberAdder: renaming method ["+targetClass.getName()+"."+name+descriptor+"]");
}
// TODO: Handle non-abstract method with the same name and descriptor in the target class.
@@ -244,21 +270,19 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
if (DEBUG)
{
- System.out.println("MemberAdder: copying method ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]");
+ System.out.println("MemberAdder: copying method ["+programClass.getName()+"."+name+descriptor+"] into ["+targetClass.getName()+"]");
}
// Create a copy of the method.
ProgramMethod newProgramMethod =
new ProgramMethod(accessFlags & ~ClassConstants.ACC_FINAL,
- constantAdder.addConstant(programClass, programMethod.u2nameIndex),
- constantAdder.addConstant(programClass, programMethod.u2descriptorIndex),
+ constantPoolEditor.addUtf8Constant(name),
+ constantPoolEditor.addUtf8Constant(descriptor),
0,
programMethod.u2attributesCount > 0 ?
new Attribute[programMethod.u2attributesCount] :
EMPTY_ATTRIBUTES,
- programMethod.referencedClasses != null ?
- (Clazz[])programMethod.referencedClasses.clone() :
- null);
+ ArrayUtil.cloneOrNull(programMethod.referencedClasses));
// Link to its visitor info.
newProgramMethod.setVisitorInfo(programMethod);
diff --git a/src/proguard/classfile/editor/MemberReferenceFixer.java b/core/src/proguard/classfile/editor/MemberReferenceFixer.java
similarity index 99%
rename from src/proguard/classfile/editor/MemberReferenceFixer.java
rename to core/src/proguard/classfile/editor/MemberReferenceFixer.java
index 107205c..4c8324f 100644
--- a/src/proguard/classfile/editor/MemberReferenceFixer.java
+++ b/core/src/proguard/classfile/editor/MemberReferenceFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/MemberRemover.java b/core/src/proguard/classfile/editor/MemberRemover.java
new file mode 100644
index 0000000..ebb2d1d
--- /dev/null
+++ b/core/src/proguard/classfile/editor/MemberRemover.java
@@ -0,0 +1,95 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+
+import java.util.*;
+
+
+/**
+ * This visitor removes all members it visits in a ProgramClass.
+ *
+ * It should be used in two steps:
+ * - in the first step, the collection step, all program fields to be removed
+ * should be visited.
+ * - in the second step, the removal step, the program class containing the
+ * program fields should be visited. This will actually delete all
+ * collected fields.
+ *
+ * For example, to remove all fields in a program class:
+ *
+ * MemberRemover remover = new MemberRemover();
+ * programClass.fieldsAccept(remover);
+ * programClass.accept(remover);
+ *
+ * @author Johan Leys
+ */
+public class MemberRemover
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor
+{
+ private Set methodsToRemove = new HashSet();
+ private Set fieldsToRemove = new HashSet();
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitAnyClass(Clazz clazz) {}
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ ClassEditor classEditor = new ClassEditor(programClass);
+
+ // Remove all collected methods.
+ for (Method method : methodsToRemove) {
+ classEditor.removeMethod(method);
+ }
+ methodsToRemove.clear();
+
+ // Remove all collected fields.
+ for (Field field : fieldsToRemove) {
+ classEditor.removeField(field);
+ }
+ fieldsToRemove.clear();
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member) {}
+
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ fieldsToRemove.add(programField);
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ methodsToRemove.add(programMethod);
+ }
+}
diff --git a/src/proguard/classfile/editor/MethodInvocationFixer.java b/core/src/proguard/classfile/editor/MethodInvocationFixer.java
similarity index 99%
rename from src/proguard/classfile/editor/MethodInvocationFixer.java
rename to core/src/proguard/classfile/editor/MethodInvocationFixer.java
index 29fb944..0dce15c 100644
--- a/src/proguard/classfile/editor/MethodInvocationFixer.java
+++ b/core/src/proguard/classfile/editor/MethodInvocationFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/NameAndTypeShrinker.java b/core/src/proguard/classfile/editor/NameAndTypeShrinker.java
similarity index 99%
rename from src/proguard/classfile/editor/NameAndTypeShrinker.java
rename to core/src/proguard/classfile/editor/NameAndTypeShrinker.java
index 6a21e07..6333a25 100644
--- a/src/proguard/classfile/editor/NameAndTypeShrinker.java
+++ b/core/src/proguard/classfile/editor/NameAndTypeShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/NamedAttributeDeleter.java b/core/src/proguard/classfile/editor/NamedAttributeDeleter.java
similarity index 97%
rename from src/proguard/classfile/editor/NamedAttributeDeleter.java
rename to core/src/proguard/classfile/editor/NamedAttributeDeleter.java
index 90b6172..0f9b947 100644
--- a/src/proguard/classfile/editor/NamedAttributeDeleter.java
+++ b/core/src/proguard/classfile/editor/NamedAttributeDeleter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ParameterAnnotationsAttributeEditor.java b/core/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
similarity index 97%
rename from src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
rename to core/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
index 6dabf96..dc5ac49 100644
--- a/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
+++ b/core/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/ParameterInfoAdder.java b/core/src/proguard/classfile/editor/ParameterInfoAdder.java
similarity index 89%
rename from src/proguard/classfile/editor/ParameterInfoAdder.java
rename to core/src/proguard/classfile/editor/ParameterInfoAdder.java
index dd72923..22e399b 100644
--- a/src/proguard/classfile/editor/ParameterInfoAdder.java
+++ b/core/src/proguard/classfile/editor/ParameterInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -52,9 +52,11 @@ public ParameterInfoAdder(ProgramClass targetClass,
public void visitParameterInfo(Clazz clazz, Method method, int parameterIndex, ParameterInfo parameterInfo)
{
// Create a new parameter.
+ int newNameIndex = parameterInfo.u2nameIndex == 0 ? 0 :
+ constantAdder.addConstant(clazz, parameterInfo.u2nameIndex);
+
ParameterInfo newParameterInfo =
- new ParameterInfo(constantAdder.addConstant(clazz, parameterInfo.u2nameIndex),
- parameterInfo.u2accessFlags);
+ new ParameterInfo(newNameIndex, parameterInfo.u2accessFlags);
// Add it to the target.
targetMethodParametersAttribute.parameters[parameterIndex] = newParameterInfo;
diff --git a/core/src/proguard/classfile/editor/SimplifiedClassEditor.java b/core/src/proguard/classfile/editor/SimplifiedClassEditor.java
new file mode 100644
index 0000000..90bca8f
--- /dev/null
+++ b/core/src/proguard/classfile/editor/SimplifiedClassEditor.java
@@ -0,0 +1,517 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.obfuscate.*;
+
+import java.util.*;
+
+import static proguard.classfile.ClassConstants.*;
+
+/**
+ * This editor allows to build and/or edit classes (ProgramClass instances).
+ * It provides methods to easily add fields and methods to classes.
+ *
+ * @author Johan Leys
+ */
+public class SimplifiedClassEditor
+extends SimplifiedVisitor
+implements
+ // Implementation interfaces.
+ AttributeVisitor
+{
+ private static final String EXTRA_INIT_METHOD_NAME = "init$";
+ private static final String EXTRA_INIT_METHOD_DESCRIPTOR = "()V";
+
+ private final ProgramClass programClass;
+ private final ClassEditor classEditor;
+ private final ConstantPoolEditor constantPoolEditor;
+ private final NameFactory nameFactory;
+
+ private String superClassName;
+
+ private final List methodComposers = new ArrayList();
+
+ private Instruction[] instructions;
+
+ /**
+ * Creates a new SimplifiedClassEditor for the Java class with the given
+ * name.
+ *
+ * @param u2accessFlags access flags for the new class.
+ * @param className the fully qualified name of the new class.
+ *
+ * @see ClassConstants
+ */
+ public SimplifiedClassEditor(int u2accessFlags, String className)
+ {
+ this(u2accessFlags, className, null);
+ }
+
+
+ /**
+ * Creates a new SimplifiedClassEditor for the Java class with the given
+ * name and super class.
+ *
+ * @param u2accessFlags access flags for the new class.
+ * @param className the fully qualified name of the new class.
+ * @param superclassName the fully qualified name of the super class.
+ *
+ * @see ClassConstants
+ */
+ public SimplifiedClassEditor(int u2accessFlags,
+ String className,
+ String superclassName)
+ {
+ this(new ProgramClass(ClassConstants.CLASS_VERSION_1_2,
+ 1,
+ new Constant[10],
+ u2accessFlags,
+ 0,
+ 0));
+
+ programClass.u2thisClass =
+ constantPoolEditor.addClassConstant(className, programClass);
+
+ if (superclassName != null)
+ {
+ programClass.u2superClass =
+ constantPoolEditor.addClassConstant(superclassName, null);
+ this.superClassName = superclassName;
+ }
+ }
+
+
+ /**
+ * Creates a new SimplifiedClassEditor for the given class.
+ *
+ * @param programClass the class to be edited.
+ */
+ public SimplifiedClassEditor(ProgramClass programClass)
+ {
+ this.programClass = programClass;
+ classEditor = new ClassEditor(programClass);
+ constantPoolEditor = new ConstantPoolEditor(programClass);
+ nameFactory = UniqueMemberNameFactory.newInjectedMemberNameFactory(programClass);
+ }
+
+
+ /**
+ * Finalizes the editing of the class. This method does not initialize
+ * references to/from related classes.
+ * At least one of the finishEditing methods should be called before
+ * calling {@link #getProgramClass}.
+ *
+ * @see #finishEditing(ClassPool, ClassPool)
+ */
+ public void finishEditing() {
+ for (CodeComposer composer : methodComposers) {
+ composer.finishEditing();
+ }
+ }
+
+ /**
+ * Finalizes the editing of the class, and initializes all references
+ * of the edited class w.r.t. the given program and library class pool.
+ * At least one of the finishEditing methods should be called before
+ * calling {@link #getProgramClass}.
+ *
+ * @param programClassPool the program class pool
+ * @param libraryClassPool the library class pool
+ */
+ public void finishEditing(ClassPool programClassPool,
+ ClassPool libraryClassPool) {
+ for (CodeComposer composer : methodComposers) {
+ composer.finishEditing();
+ }
+
+ // Initialize all references to/from the edited class.
+ if (superClassName != null)
+ {
+ new ClassSuperHierarchyInitializer(programClassPool, libraryClassPool, null, null).visitProgramClass(programClass);
+ new ClassSubHierarchyInitializer().visitProgramClass(programClass);
+ }
+ new ClassReferenceInitializer(programClassPool, libraryClassPool).visitProgramClass(programClass);
+ }
+
+ /**
+ * Returns the edited ProgramClass instance.
+ * Make sure to call one of the finishEditing methods after finishing editing,
+ * before calling this method.
+ *
+ * @return the edited ProgramClass instance.
+ *
+ * @see #finishEditing()
+ * @see #finishEditing(ClassPool, ClassPool)
+ */
+ public ProgramClass getProgramClass()
+ {
+ return programClass;
+ }
+
+
+ /**
+ * Adds the given class constant to the edited class.
+ *
+ * @param name the class name to be added.
+ * @param referencedClass the corresponding referenced class.
+ *
+ * @return the constant pool index of the ClassConstant.
+ */
+ public int addClassConstant(String name,
+ Clazz referencedClass) {
+ return constantPoolEditor.addClassConstant(name, referencedClass);
+ }
+
+ /**
+ * Adds a new field to the edited class.
+ *
+ * @param u2accessFlags acces flags for the new field.
+ * @param fieldName name of the new field.
+ * @param fieldDescriptor descriptor of the new field.
+ *
+ * @return this SimpleClassEditor.
+ */
+ public SimplifiedClassEditor addField(int u2accessFlags,
+ String fieldName,
+ String fieldDescriptor)
+ {
+ Field field = new ProgramField(u2accessFlags,
+ constantPoolEditor.addUtf8Constant(fieldName),
+ constantPoolEditor.addUtf8Constant(fieldDescriptor),
+ null);
+ classEditor.addField(field);
+ return this;
+ }
+
+
+ /**
+ * Adds a new method to the edited class. The returned composer can be used
+ * to attach code to the method.
+ *
+ * @param u2accessFlags acces flags for the new method.
+ * @param methodName name of the new method.
+ * @param methodDescriptor descriptor of the new method.
+ * @param maxCodeFragmentLength maximum length for the code fragment of the
+ * new method.
+ *
+ * @return the composer for adding code to the created method.
+ */
+ public CompactCodeAttributeComposer addMethod(int u2accessFlags,
+ String methodName,
+ String methodDescriptor,
+ int maxCodeFragmentLength)
+ {
+ return addMethod(u2accessFlags, methodName, methodDescriptor, null, maxCodeFragmentLength);
+ }
+
+ /**
+ * Adds a new method to the edited class. The returned composer can be used
+ * to attach code to the method.
+ *
+ * @param u2accessFlags acces flags for the new method.
+ * @param methodName name of the new method.
+ * @param methodDescriptor descriptor of the new method.
+ * @param referencedClasses the classes referenced by the method descriptor.
+ * @param maxCodeFragmentLength maximum length for the code fragment of the
+ * new method.
+ *
+ * @return the composer for adding code to the created method.
+ */
+ public CompactCodeAttributeComposer addMethod(int u2accessFlags,
+ String methodName,
+ String methodDescriptor,
+ Clazz[] referencedClasses,
+ int maxCodeFragmentLength)
+ {
+ ProgramMethod method = new ProgramMethod(u2accessFlags,
+ constantPoolEditor.addUtf8Constant(methodName),
+ constantPoolEditor.addUtf8Constant(methodDescriptor),
+ referencedClasses);
+ CodeComposer composer = new CodeComposer(method, maxCodeFragmentLength);
+ methodComposers.add(composer);
+ return composer;
+ }
+
+
+ /**
+ * Adds a new method to the edited class, with the given instructions array.
+ *
+ * @param u2accessFlags acces flags for the new method.
+ * @param methodName name of the new method.
+ * @param methodDescriptor descriptor of the new method.
+ * @param instructions the instructions of the new method.
+ */
+ public ProgramMethod addMethod(int u2accessFlags,
+ String methodName,
+ String methodDescriptor,
+ Instruction[] instructions)
+ {
+ return addMethod(u2accessFlags, methodName, methodDescriptor, instructions, null, null);
+ }
+
+
+ /**
+ * Adds the given static initializer instructions to the edited class.
+ * If the class already contains a static initializer, the new instructions
+ * will be appended to the existing initializer.
+ *
+ * @param instructions the instructions to be added.
+ * @param mergeIntoExistingInitializer indicates whether the instructions should
+ * be added to the existing static initializer
+ * (if it exists), or if a new method should
+ * be created, which is then called from the
+ * existing initializer.
+ */
+ public void addStaticInitializerInstructions(Instruction[] instructions,
+ boolean mergeIntoExistingInitializer)
+ {
+ Method method = programClass.findMethod(METHOD_NAME_CLINIT, METHOD_TYPE_CLINIT);
+
+ if (method == null) {
+ addMethod(ACC_STATIC, METHOD_NAME_CLINIT, METHOD_TYPE_CLINIT,
+ instructions, null,
+ new SimpleInstruction(InstructionConstants.OP_RETURN));
+ }
+ else {
+ if (!mergeIntoExistingInitializer)
+ {
+ // Create a new static initializer.
+ ProgramMethod newMethod =
+ addMethod(ACC_STATIC,
+ nameFactory.nextName(), "()V",
+ instructions,
+ null,
+ new SimpleInstruction(InstructionConstants.OP_RETURN));
+
+ // Call the new initializer from the existing one.
+ InstructionSequenceBuilder builder = new InstructionSequenceBuilder(programClass);
+ builder.invokestatic(programClass.getName(),
+ newMethod.getName(programClass),
+ "()V",
+ programClass,
+ newMethod);
+ instructions = builder.instructions();
+ }
+ CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+ ((ProgramMethod) method).attributesAccept(programClass,
+ new CodeAttributeEditorResetter(codeAttributeEditor));
+ codeAttributeEditor.insertBeforeOffset(0, instructions);
+ ((ProgramMethod) method).attributesAccept(programClass,
+ codeAttributeEditor);
+ }
+ }
+
+ /**
+ * Adds the given initialization instructions to the edited class.
+ *
+ * - If the class doesn't contain a constructor yet, it will be created,
+ * and the instructions will be added to this constructor.
+ * - If there is a single super-calling constructor, the instructions will
+ * be added at the beginning of it's code attribute.
+ * - If there are multiple super-calling constructors, a new private
+ * parameterless helper method will be created, to which the instructions
+ * will be added. An invocation to this new method will be added at the
+ * beginning of the code attribute of all super-calling constructors.
+ *
+ * @param instructions the instructions to be added.
+ */
+ public void addInitializerInstructions(Instruction[] instructions)
+ {
+ Method method = programClass.findMethod(METHOD_NAME_INIT, null);
+
+ if (method == null) {
+ // First call the super constructor.
+ Instruction[] firstInstruction = {
+ new VariableInstruction(InstructionConstants.OP_ALOAD_0),
+ new ConstantInstruction(
+ InstructionConstants.OP_INVOKESPECIAL,
+ constantPoolEditor.addMethodrefConstant(programClass.getSuperClass().getName(), METHOD_NAME_INIT, METHOD_TYPE_INIT, null, null))
+ };
+
+ // End by calling return.
+ SimpleInstruction lastInstruction =
+ new SimpleInstruction(InstructionConstants.OP_RETURN);
+
+ addMethod(ACC_PUBLIC, METHOD_NAME_INIT, METHOD_TYPE_INIT,
+ instructions,
+ firstInstruction,
+ lastInstruction);
+ }
+ else {
+ // Find all super-calling constructors.
+ Set constructors = new HashSet();
+ programClass.methodsAccept(
+ new ConstructorMethodFilter(
+ new MethodCollector(constructors), null, null));
+
+ if (constructors.size() == 1)
+ {
+ // There is only one supper-calling constructor.
+ // Add the code to this constructor.
+ this.instructions = instructions;
+ constructors.iterator().next().accept(programClass,
+ new AllAttributeVisitor(
+ this));
+ }
+ else
+ {
+ // There are multiple super-calling constructors. Add the
+ // instructions to a separate, parameterless initialization
+ // method, and invoke this method from all super-calling
+ // constructors.
+ ProgramMethod initMethod = (ProgramMethod) programClass.findMethod(EXTRA_INIT_METHOD_NAME,
+ EXTRA_INIT_METHOD_DESCRIPTOR);
+ if (initMethod == null)
+ {
+ // There is no init$ method yet. Create it now, and add the
+ // given instructions to it.
+ initMethod = addMethod(ACC_PRIVATE,
+ EXTRA_INIT_METHOD_NAME,
+ EXTRA_INIT_METHOD_DESCRIPTOR,
+ instructions,
+ null,
+ new SimpleInstruction(InstructionConstants.OP_RETURN));
+
+ // Insert a call to the new init$ method in all super-calling constructors.
+ InstructionSequenceBuilder builder = new InstructionSequenceBuilder(programClass);
+ builder.aload_0();
+ builder.invokespecial(programClass.getName(),
+ EXTRA_INIT_METHOD_NAME,
+ EXTRA_INIT_METHOD_DESCRIPTOR,
+ programClass,
+ initMethod);
+ this.instructions = builder.instructions();
+ programClass.methodsAccept(
+ new ConstructorMethodFilter(
+ new AllAttributeVisitor(
+ this), null, null));
+ }
+ else {
+ // There is already an init$ method. Add the instructions to this method.
+ this.instructions = instructions;
+ initMethod.accept(programClass,
+ new AllAttributeVisitor(
+ this));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Adds a new method to the edited class, with the given instructions array.
+ *
+ * @param u2accessFlags acces flags for the new method.
+ * @param methodName name of the new method.
+ * @param methodDescriptor descriptor of the new method.
+ * @param instructions the instructions of the new method.
+ * @param firstInstructions extra instructions to add in front of the
+ * new method.
+ * @param lastInstruction extra instruction to add at the end of the
+ * new method.
+ */
+ private ProgramMethod addMethod(int u2accessFlags,
+ String methodName,
+ String methodDescriptor,
+ Instruction[] instructions,
+ Instruction[] firstInstructions,
+ Instruction lastInstruction)
+ {
+ ProgramMethod method = new ProgramMethod(u2accessFlags,
+ constantPoolEditor.addUtf8Constant(methodName),
+ constantPoolEditor.addUtf8Constant(methodDescriptor),
+ null);
+
+ CodeAttribute codeAttribute =
+ new CodeAttribute(constantPoolEditor.addUtf8Constant(ClassConstants.ATTR_Code));
+
+ CodeAttributeComposer composer = new CodeAttributeComposer();
+ composer.reset();
+ composer.beginCodeFragment(0);
+ composer.appendInstructions(instructions);
+ if (firstInstructions != null) {
+ for (Instruction instruction : firstInstructions) {
+ composer.appendInstruction(instruction);
+ }
+ }
+ if (lastInstruction != null) {
+ composer.appendInstruction(lastInstruction);
+ }
+ composer.endCodeFragment();
+ composer.visitCodeAttribute(programClass, method, codeAttribute);
+
+ new AttributesEditor(programClass, method, false).addAttribute(codeAttribute);
+
+ classEditor.addMethod(method);
+
+ return method;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+ ((ProgramMethod) method).attributesAccept(programClass, new CodeAttributeEditorResetter(codeAttributeEditor));
+ codeAttributeEditor.insertBeforeOffset(0, instructions);
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+
+ }
+
+
+ private class CodeComposer extends CompactCodeAttributeComposer {
+
+ private final ProgramMethod method;
+
+ public CodeComposer(ProgramMethod method,
+ int maxCodeFragmentLength)
+ {
+ super(programClass);
+ this.method = method;
+ beginCodeFragment(maxCodeFragmentLength);
+ }
+
+ public void finishEditing() {
+ endCodeFragment();
+
+ CodeAttribute codeAttribute =
+ new CodeAttribute(constantPoolEditor.addUtf8Constant(ClassConstants.ATTR_Code));
+
+ visitCodeAttribute(programClass, method, codeAttribute);
+
+ new AttributesEditor(programClass, method, false).addAttribute(codeAttribute);
+
+ classEditor.addMethod(method);
+ }
+ }
+}
diff --git a/src/proguard/classfile/editor/StackSizeUpdater.java b/core/src/proguard/classfile/editor/StackSizeUpdater.java
similarity index 96%
rename from src/proguard/classfile/editor/StackSizeUpdater.java
rename to core/src/proguard/classfile/editor/StackSizeUpdater.java
index 625c533..64a177b 100644
--- a/src/proguard/classfile/editor/StackSizeUpdater.java
+++ b/core/src/proguard/classfile/editor/StackSizeUpdater.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/SubclassAdder.java b/core/src/proguard/classfile/editor/SubclassAdder.java
similarity index 96%
rename from src/proguard/classfile/editor/SubclassAdder.java
rename to core/src/proguard/classfile/editor/SubclassAdder.java
index e1de014..d07cc6e 100644
--- a/src/proguard/classfile/editor/SubclassAdder.java
+++ b/core/src/proguard/classfile/editor/SubclassAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/SubclassToAdder.java b/core/src/proguard/classfile/editor/SubclassToAdder.java
similarity index 96%
rename from src/proguard/classfile/editor/SubclassToAdder.java
rename to core/src/proguard/classfile/editor/SubclassToAdder.java
index 0fa599e..2085399 100644
--- a/src/proguard/classfile/editor/SubclassToAdder.java
+++ b/core/src/proguard/classfile/editor/SubclassToAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/editor/TargetInfoCopier.java b/core/src/proguard/classfile/editor/TargetInfoCopier.java
new file mode 100644
index 0000000..f07164c
--- /dev/null
+++ b/core/src/proguard/classfile/editor/TargetInfoCopier.java
@@ -0,0 +1,162 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.attribute.annotation.TypeAnnotation;
+import proguard.classfile.attribute.annotation.target.*;
+import proguard.classfile.attribute.annotation.target.visitor.TargetInfoVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This TargetInfoVisitor copies the target info instances that it visits to
+ * the given type annotation (each time overwriting any previous target info).
+ *
+ * @author Eric Lafortune
+ */
+public class TargetInfoCopier
+extends SimplifiedVisitor
+implements TargetInfoVisitor
+{
+ private final ProgramClass targetClass;
+ private final TypeAnnotation targetTypeAnnotation;
+
+
+ /**
+ * Creates a new TargetInfoCopier that will copy target info instances
+ * to the given target type annotation.
+ */
+ public TargetInfoCopier(ProgramClass targetClass,
+ TypeAnnotation targetTypeAnnotation)
+ {
+ this.targetClass = targetClass;
+ this.targetTypeAnnotation = targetTypeAnnotation;
+ }
+
+
+ // Implementations for TargetInfoVisitor.
+
+ public void visitTypeParameterTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, TypeParameterTargetInfo typeParameterTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new TypeParameterTargetInfo(typeParameterTargetInfo.u1targetType,
+ typeParameterTargetInfo.u1typeParameterIndex);
+ }
+
+
+ public void visitSuperTypeTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, SuperTypeTargetInfo superTypeTargetInfo)
+ {
+ // TODO: The supertype index (= interface number) is probably different in the target class.
+ targetTypeAnnotation.targetInfo =
+ new SuperTypeTargetInfo(superTypeTargetInfo.u1targetType,
+ superTypeTargetInfo.u2superTypeIndex);
+ }
+
+
+ public void visitTypeParameterBoundTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, TypeParameterBoundTargetInfo typeParameterBoundTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new TypeParameterBoundTargetInfo(typeParameterBoundTargetInfo.u1targetType,
+ typeParameterBoundTargetInfo.u1typeParameterIndex,
+ typeParameterBoundTargetInfo.u1boundIndex);
+ }
+
+
+ public void visitEmptyTargetInfo(Clazz clazz, Member member, TypeAnnotation typeAnnotation, EmptyTargetInfo emptyTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new EmptyTargetInfo();
+ }
+
+
+ public void visitFormalParameterTargetInfo(Clazz clazz, Method method, TypeAnnotation typeAnnotation, FormalParameterTargetInfo formalParameterTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new FormalParameterTargetInfo(formalParameterTargetInfo.u1targetType,
+ formalParameterTargetInfo.u1formalParameterIndex);
+ }
+
+
+ public void visitThrowsTargetInfo(Clazz clazz, Method method, TypeAnnotation typeAnnotation, ThrowsTargetInfo throwsTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new ThrowsTargetInfo(throwsTargetInfo.u1targetType,
+ throwsTargetInfo.u2throwsTypeIndex);
+ }
+
+
+ public void visitLocalVariableTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo)
+ {
+ LocalVariableTargetElement[] table =
+ localVariableTargetInfo.table;
+
+ LocalVariableTargetElement[] newTable =
+ new LocalVariableTargetElement[localVariableTargetInfo.u2tableLength];
+
+ LocalVariableTargetInfo newLocalVariableTargetInfo =
+ new LocalVariableTargetInfo(localVariableTargetInfo.u1targetType,
+ localVariableTargetInfo.u2tableLength,
+ newTable);
+
+ for (int index = 0; index < localVariableTargetInfo.u2tableLength; index++)
+ {
+ LocalVariableTargetElement element =
+ localVariableTargetInfo.table[index];
+
+ LocalVariableTargetElement newElement =
+ new LocalVariableTargetElement(element.u2startPC,
+ element.u2length,
+ element.u2index);
+
+ newTable[index] = newElement;
+ }
+
+ newLocalVariableTargetInfo.table = newTable;
+
+ targetTypeAnnotation.targetInfo = newLocalVariableTargetInfo;
+ }
+
+
+ public void visitCatchTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, CatchTargetInfo catchTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new CatchTargetInfo(catchTargetInfo.u1targetType,
+ catchTargetInfo.u2exceptionTableIndex);
+ }
+
+
+ public void visitOffsetTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, OffsetTargetInfo offsetTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new OffsetTargetInfo(offsetTargetInfo.u1targetType,
+ offsetTargetInfo.u2offset);
+ }
+
+
+ public void visitTypeArgumentTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, TypeArgumentTargetInfo typeArgumentTargetInfo)
+ {
+ targetTypeAnnotation.targetInfo =
+ new TypeArgumentTargetInfo(typeArgumentTargetInfo.u1targetType,
+ typeArgumentTargetInfo.u2offset,
+ typeArgumentTargetInfo.u1typeArgumentIndex);
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/classfile/editor/TypeAnnotationAdder.java b/core/src/proguard/classfile/editor/TypeAnnotationAdder.java
new file mode 100644
index 0000000..f0426ef
--- /dev/null
+++ b/core/src/proguard/classfile/editor/TypeAnnotationAdder.java
@@ -0,0 +1,132 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.annotation.target.TargetInfo;
+import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This TypeAnnotationVisitor adds all type annotations that it visits to the given
+ * target annotation element value, target annotation attribute, or target
+ * parameter annotation attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class TypeAnnotationAdder
+extends SimplifiedVisitor
+implements TypeAnnotationVisitor
+{
+ private static final ElementValue[] EMPTY_ELEMENT_VALUES = new ElementValue[0];
+
+
+ private final ProgramClass targetClass;
+ private final AnnotationElementValue targetAnnotationElementValue;
+ private final AnnotationsAttributeEditor annotationsAttributeEditor;
+
+ private final ConstantAdder constantAdder;
+
+
+ /**
+ * Creates a new TypeAnnotationAdder that will copy annotations into the given
+ * target annotation element value.
+ */
+ public TypeAnnotationAdder(ProgramClass targetClass,
+ AnnotationElementValue targetAnnotationElementValue)
+ {
+ this.targetClass = targetClass;
+ this.targetAnnotationElementValue = targetAnnotationElementValue;
+ this.annotationsAttributeEditor = null;
+
+ constantAdder = new ConstantAdder(targetClass);
+ }
+
+
+ /**
+ * Creates a new TypeAnnotationAdder that will copy annotations into the given
+ * target annotations attribute.
+ */
+ public TypeAnnotationAdder(ProgramClass targetClass,
+ AnnotationsAttribute targetAnnotationsAttribute)
+ {
+ this.targetClass = targetClass;
+ this.targetAnnotationElementValue = null;
+ this.annotationsAttributeEditor = new AnnotationsAttributeEditor(targetAnnotationsAttribute);
+
+ constantAdder = new ConstantAdder(targetClass);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation)
+ {
+ TypePathInfo[] typePath = typeAnnotation.typePath;
+ TypePathInfo[] newTypePath = new TypePathInfo[typePath.length];
+
+ TypeAnnotation newTypeAnnotation =
+ new TypeAnnotation(constantAdder.addConstant(clazz, typeAnnotation.u2typeIndex),
+ 0,
+ typeAnnotation.u2elementValuesCount > 0 ?
+ new ElementValue[typeAnnotation.u2elementValuesCount] :
+ EMPTY_ELEMENT_VALUES,
+ null,
+ newTypePath);
+
+ // TODO: Clone array.
+ newTypeAnnotation.referencedClasses = typeAnnotation.referencedClasses;
+
+ // Add the element values.
+ typeAnnotation.elementValuesAccept(clazz,
+ new ElementValueAdder(targetClass,
+ newTypeAnnotation,
+ false));
+
+ // Set the target info.
+ typeAnnotation.targetInfo.accept(clazz,
+ typeAnnotation,
+ new TargetInfoCopier(targetClass, newTypeAnnotation));
+
+ // Copy the type path.
+ for (int index = 0; index < typePath.length; index++)
+ {
+ TypePathInfo typePathInfo = typePath[index];
+ TypePathInfo newTypePathInfo = new TypePathInfo(typePathInfo.u1typePathKind,
+ typePathInfo.u1typeArgumentIndex);
+
+ newTypePath[index] = newTypePathInfo;
+ }
+
+ // What's the target?
+ if (targetAnnotationElementValue != null)
+ {
+ // Simply set the completed annotation.
+ targetAnnotationElementValue.annotationValue = newTypeAnnotation;
+ }
+ else
+ {
+ // Add the completed annotation.
+ annotationsAttributeEditor.addAnnotation(newTypeAnnotation);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/Utf8Shrinker.java b/core/src/proguard/classfile/editor/Utf8Shrinker.java
similarity index 99%
rename from src/proguard/classfile/editor/Utf8Shrinker.java
rename to core/src/proguard/classfile/editor/Utf8Shrinker.java
index 1f563d5..9575c3a 100644
--- a/src/proguard/classfile/editor/Utf8Shrinker.java
+++ b/core/src/proguard/classfile/editor/Utf8Shrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -172,6 +172,9 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex);
diff --git a/src/proguard/classfile/editor/VariableCleaner.java b/core/src/proguard/classfile/editor/VariableCleaner.java
similarity index 99%
rename from src/proguard/classfile/editor/VariableCleaner.java
rename to core/src/proguard/classfile/editor/VariableCleaner.java
index 991beb5..abb2b7d 100644
--- a/src/proguard/classfile/editor/VariableCleaner.java
+++ b/core/src/proguard/classfile/editor/VariableCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/VariableEditor.java b/core/src/proguard/classfile/editor/VariableEditor.java
similarity index 98%
rename from src/proguard/classfile/editor/VariableEditor.java
rename to core/src/proguard/classfile/editor/VariableEditor.java
index 0126be2..73e8197 100644
--- a/src/proguard/classfile/editor/VariableEditor.java
+++ b/core/src/proguard/classfile/editor/VariableEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/VariableRemapper.java b/core/src/proguard/classfile/editor/VariableRemapper.java
similarity index 99%
rename from src/proguard/classfile/editor/VariableRemapper.java
rename to core/src/proguard/classfile/editor/VariableRemapper.java
index dd6febd..26e93b4 100644
--- a/src/proguard/classfile/editor/VariableRemapper.java
+++ b/core/src/proguard/classfile/editor/VariableRemapper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/VariableSizeUpdater.java b/core/src/proguard/classfile/editor/VariableSizeUpdater.java
similarity index 98%
rename from src/proguard/classfile/editor/VariableSizeUpdater.java
rename to core/src/proguard/classfile/editor/VariableSizeUpdater.java
index d88077e..a4524eb 100644
--- a/src/proguard/classfile/editor/VariableSizeUpdater.java
+++ b/core/src/proguard/classfile/editor/VariableSizeUpdater.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/editor/package.html b/core/src/proguard/classfile/editor/package.html
similarity index 100%
rename from src/proguard/classfile/editor/package.html
rename to core/src/proguard/classfile/editor/package.html
diff --git a/src/proguard/classfile/instruction/BranchInstruction.java b/core/src/proguard/classfile/instruction/BranchInstruction.java
similarity index 96%
rename from src/proguard/classfile/instruction/BranchInstruction.java
rename to core/src/proguard/classfile/instruction/BranchInstruction.java
index 937fe7e..c0fa03a 100644
--- a/src/proguard/classfile/instruction/BranchInstruction.java
+++ b/core/src/proguard/classfile/instruction/BranchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +41,10 @@ public class BranchInstruction extends Instruction
public BranchInstruction() {}
+ /**
+ * Creates a BranchInstruction with the given branch offset.
+ * The branch offset is relative to this instruction's offset.
+ */
public BranchInstruction(byte opcode, int branchOffset)
{
this.opcode = opcode;
diff --git a/src/proguard/classfile/instruction/ConstantInstruction.java b/core/src/proguard/classfile/instruction/ConstantInstruction.java
similarity index 96%
rename from src/proguard/classfile/instruction/ConstantInstruction.java
rename to core/src/proguard/classfile/instruction/ConstantInstruction.java
index 0c6d5c5..8377cda 100644
--- a/src/proguard/classfile/instruction/ConstantInstruction.java
+++ b/core/src/proguard/classfile/instruction/ConstantInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -222,11 +222,14 @@ public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {
public void visitLongConstant(Clazz clazz, LongConstant longConstant) {}
public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {}
public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant) {}
public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {}
public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {}
public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) {}
public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {}
public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) {}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant) {}
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant) {}
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
diff --git a/src/proguard/classfile/instruction/Instruction.java b/core/src/proguard/classfile/instruction/Instruction.java
similarity index 99%
rename from src/proguard/classfile/instruction/Instruction.java
rename to core/src/proguard/classfile/instruction/Instruction.java
index 5fe0bba..2f8a304 100644
--- a/src/proguard/classfile/instruction/Instruction.java
+++ b/core/src/proguard/classfile/instruction/Instruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/InstructionConstants.java b/core/src/proguard/classfile/instruction/InstructionConstants.java
similarity index 99%
rename from src/proguard/classfile/instruction/InstructionConstants.java
rename to core/src/proguard/classfile/instruction/InstructionConstants.java
index 2767687..ac8e33b 100644
--- a/src/proguard/classfile/instruction/InstructionConstants.java
+++ b/core/src/proguard/classfile/instruction/InstructionConstants.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/InstructionFactory.java b/core/src/proguard/classfile/instruction/InstructionFactory.java
similarity index 99%
rename from src/proguard/classfile/instruction/InstructionFactory.java
rename to core/src/proguard/classfile/instruction/InstructionFactory.java
index 75291d1..d3b985a 100644
--- a/src/proguard/classfile/instruction/InstructionFactory.java
+++ b/core/src/proguard/classfile/instruction/InstructionFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/InstructionUtil.java b/core/src/proguard/classfile/instruction/InstructionUtil.java
similarity index 73%
rename from src/proguard/classfile/instruction/InstructionUtil.java
rename to core/src/proguard/classfile/instruction/InstructionUtil.java
index 96962d3..bd4f6a6 100644
--- a/src/proguard/classfile/instruction/InstructionUtil.java
+++ b/core/src/proguard/classfile/instruction/InstructionUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +22,9 @@
import proguard.classfile.ClassConstants;
+import static proguard.classfile.ClassConstants.*;
+import static proguard.classfile.instruction.InstructionConstants.*;
+
/**
* Utility methods for converting between representations of names and
* descriptions.
@@ -64,4 +67,29 @@ public static char internalTypeFromArrayType(byte arrayType)
default: throw new IllegalArgumentException("Unknown array type ["+arrayType+"]");
}
}
+
+ /**
+ * Returns the newarray type constant for the given internal primitive
+ * type.
+ *
+ * @param internalType a primitive type ('Z','B','I',...)
+ * @return the array type constant corresponding to the given
+ * primitive type.
+ * @see #internalTypeFromArrayType(byte)
+ */
+ public static byte arrayTypeFromInternalType(char internalType)
+ {
+ switch (internalType)
+ {
+ case TYPE_BOOLEAN: return ARRAY_T_BOOLEAN;
+ case TYPE_BYTE: return ARRAY_T_BYTE;
+ case TYPE_CHAR: return ARRAY_T_CHAR;
+ case TYPE_SHORT: return ARRAY_T_SHORT;
+ case TYPE_INT: return ARRAY_T_INT;
+ case TYPE_LONG: return ARRAY_T_LONG;
+ case TYPE_FLOAT: return ARRAY_T_FLOAT;
+ case TYPE_DOUBLE: return ARRAY_T_DOUBLE;
+ default: throw new IllegalArgumentException("Unknown primitive: " + internalType);
+ }
+ }
}
diff --git a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java b/core/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
similarity index 98%
rename from src/proguard/classfile/instruction/LookUpSwitchInstruction.java
rename to core/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
index 0533b08..83dcac2 100644
--- a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
+++ b/core/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/SimpleInstruction.java b/core/src/proguard/classfile/instruction/SimpleInstruction.java
similarity index 99%
rename from src/proguard/classfile/instruction/SimpleInstruction.java
rename to core/src/proguard/classfile/instruction/SimpleInstruction.java
index 1f3932f..543b570 100644
--- a/src/proguard/classfile/instruction/SimpleInstruction.java
+++ b/core/src/proguard/classfile/instruction/SimpleInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/SwitchInstruction.java b/core/src/proguard/classfile/instruction/SwitchInstruction.java
similarity index 97%
rename from src/proguard/classfile/instruction/SwitchInstruction.java
rename to core/src/proguard/classfile/instruction/SwitchInstruction.java
index d2a138c..2cb8abe 100644
--- a/src/proguard/classfile/instruction/SwitchInstruction.java
+++ b/core/src/proguard/classfile/instruction/SwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/TableSwitchInstruction.java b/core/src/proguard/classfile/instruction/TableSwitchInstruction.java
similarity index 98%
rename from src/proguard/classfile/instruction/TableSwitchInstruction.java
rename to core/src/proguard/classfile/instruction/TableSwitchInstruction.java
index 1231fe8..fc55f9c 100644
--- a/src/proguard/classfile/instruction/TableSwitchInstruction.java
+++ b/core/src/proguard/classfile/instruction/TableSwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/VariableInstruction.java b/core/src/proguard/classfile/instruction/VariableInstruction.java
similarity index 99%
rename from src/proguard/classfile/instruction/VariableInstruction.java
rename to core/src/proguard/classfile/instruction/VariableInstruction.java
index dd232cc..c650abb 100644
--- a/src/proguard/classfile/instruction/VariableInstruction.java
+++ b/core/src/proguard/classfile/instruction/VariableInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/package.html b/core/src/proguard/classfile/instruction/package.html
similarity index 100%
rename from src/proguard/classfile/instruction/package.html
rename to core/src/proguard/classfile/instruction/package.html
diff --git a/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java b/core/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
similarity index 97%
rename from src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
rename to core/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
index b06b957..244c7ca 100644
--- a/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
+++ b/core/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/visitor/InstructionConstantVisitor.java b/core/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
similarity index 97%
rename from src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
rename to core/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
index 439c635..50847d7 100644
--- a/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
+++ b/core/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/visitor/InstructionCounter.java b/core/src/proguard/classfile/instruction/visitor/InstructionCounter.java
similarity index 97%
rename from src/proguard/classfile/instruction/visitor/InstructionCounter.java
rename to core/src/proguard/classfile/instruction/visitor/InstructionCounter.java
index a67b5f3..a136d24 100644
--- a/src/proguard/classfile/instruction/visitor/InstructionCounter.java
+++ b/core/src/proguard/classfile/instruction/visitor/InstructionCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/visitor/InstructionVisitor.java b/core/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
similarity index 97%
rename from src/proguard/classfile/instruction/visitor/InstructionVisitor.java
rename to core/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
index 37596dd..6971968 100644
--- a/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
+++ b/core/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/instruction/visitor/MultiInstructionVisitor.java b/core/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
similarity index 80%
rename from src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
rename to core/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
index a4be540..2727cae 100644
--- a/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
+++ b/core/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.CodeAttribute;
import proguard.classfile.instruction.*;
+import proguard.util.ArrayUtil;
/**
@@ -33,19 +34,17 @@
*/
public class MultiInstructionVisitor implements InstructionVisitor
{
- private static final int ARRAY_SIZE_INCREMENT = 5;
-
-
private InstructionVisitor[] instructionVisitors;
private int instructionVisitorCount;
public MultiInstructionVisitor()
{
+ this.instructionVisitors = new InstructionVisitor[16];
}
- public MultiInstructionVisitor(InstructionVisitor[] instructionVisitors)
+ public MultiInstructionVisitor(InstructionVisitor... instructionVisitors)
{
this.instructionVisitors = instructionVisitors;
this.instructionVisitorCount = instructionVisitors.length;
@@ -54,28 +53,10 @@ public MultiInstructionVisitor(InstructionVisitor[] instructionVisitors)
public void addInstructionVisitor(InstructionVisitor instructionVisitor)
{
- ensureArraySize();
-
- instructionVisitors[instructionVisitorCount++] = instructionVisitor;
- }
-
-
- private void ensureArraySize()
- {
- if (instructionVisitors == null)
- {
- instructionVisitors = new InstructionVisitor[ARRAY_SIZE_INCREMENT];
- }
- else if (instructionVisitors.length == instructionVisitorCount)
- {
- InstructionVisitor[] newInstructionVisitors =
- new InstructionVisitor[instructionVisitorCount +
- ARRAY_SIZE_INCREMENT];
- System.arraycopy(instructionVisitors, 0,
- newInstructionVisitors, 0,
- instructionVisitorCount);
- instructionVisitors = newInstructionVisitors;
- }
+ instructionVisitors =
+ ArrayUtil.add(instructionVisitors,
+ instructionVisitorCount++,
+ instructionVisitor);
}
diff --git a/src/proguard/classfile/instruction/visitor/package.html b/core/src/proguard/classfile/instruction/visitor/package.html
similarity index 100%
rename from src/proguard/classfile/instruction/visitor/package.html
rename to core/src/proguard/classfile/instruction/visitor/package.html
diff --git a/src/proguard/classfile/io/LibraryClassReader.java b/core/src/proguard/classfile/io/LibraryClassReader.java
similarity index 90%
rename from src/proguard/classfile/io/LibraryClassReader.java
rename to core/src/proguard/classfile/io/LibraryClassReader.java
index f14d498..253acaf 100644
--- a/src/proguard/classfile/io/LibraryClassReader.java
+++ b/core/src/proguard/classfile/io/LibraryClassReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -260,6 +260,15 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ char u2primitiveType = dataInput.readChar();
+ int u4length = dataInput.readInt();
+
+ dataInput.skipBytes(primitiveSize(u2primitiveType) * u4length);
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
dataInput.skipBytes(2);
@@ -313,6 +322,17 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ dataInput.skipBytes(2);
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ dataInput.skipBytes(2);
+ }
+
// Small utility methods.
/**
@@ -357,6 +377,8 @@ private Constant createConstant()
case ClassConstants.CONSTANT_Class: return new ClassConstant();
case ClassConstants.CONSTANT_MethodType: return new MethodTypeConstant();
case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant();
+ case ClassConstants.CONSTANT_Module: return new ModuleConstant();
+ case ClassConstants.CONSTANT_Package: return new PackageConstant();
default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
}
@@ -380,4 +402,25 @@ private void skipAttribute()
int u4attributeLength = dataInput.readInt();
dataInput.skipBytes(u4attributeLength);
}
+
+
+ /**
+ * Returns the size in bytes of the given primitive type.
+ */
+ private int primitiveSize(char primitiveType)
+ {
+ switch (primitiveType)
+ {
+ case ClassConstants.TYPE_BOOLEAN:
+ case ClassConstants.TYPE_BYTE: return 1;
+ case ClassConstants.TYPE_CHAR:
+ case ClassConstants.TYPE_SHORT: return 2;
+ case ClassConstants.TYPE_INT:
+ case ClassConstants.TYPE_FLOAT: return 4;
+ case ClassConstants.TYPE_LONG:
+ case ClassConstants.TYPE_DOUBLE: return 8;
+ }
+
+ return 0;
+ }
}
diff --git a/src/proguard/classfile/io/ProgramClassReader.java b/core/src/proguard/classfile/io/ProgramClassReader.java
similarity index 79%
rename from src/proguard/classfile/io/ProgramClassReader.java
rename to core/src/proguard/classfile/io/ProgramClassReader.java
index 5a02a8c..f6a3168 100644
--- a/src/proguard/classfile/io/ProgramClassReader.java
+++ b/core/src/proguard/classfile/io/ProgramClassReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +26,8 @@
import proguard.classfile.attribute.annotation.target.*;
import proguard.classfile.attribute.annotation.target.visitor.*;
import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
@@ -57,6 +59,10 @@ public class ProgramClassReader
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
+ RequiresInfoVisitor,
+ ExportsInfoVisitor,
+ OpensInfoVisitor,
+ ProvidesInfoVisitor,
AnnotationVisitor,
TypeAnnotationVisitor,
TargetInfoVisitor,
@@ -72,7 +78,7 @@ public class ProgramClassReader
*/
public ProgramClassReader(DataInput dataInput)
{
- this.dataInput = new RuntimeDataInput(dataInput);
+ this.dataInput = new RuntimeDataInput(dataInput);
}
@@ -81,9 +87,9 @@ public ProgramClassReader(DataInput dataInput)
public void visitProgramClass(ProgramClass programClass)
{
// Read and check the magic number.
- programClass.u4magic = dataInput.readInt();
+ int u4magic = dataInput.readInt();
- ClassUtil.checkMagicNumber(programClass.u4magic);
+ ClassUtil.checkMagicNumber(u4magic);
// Read and check the version numbers.
int u2minorVersion = dataInput.readUnsignedShort();
@@ -241,6 +247,109 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ char u2primitiveType = dataInput.readChar();
+ int u4length = dataInput.readInt();
+
+ switch (u2primitiveType)
+ {
+ case ClassConstants.TYPE_BOOLEAN:
+ {
+ boolean[] values = new boolean[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readBoolean();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_BYTE:
+ {
+ byte[] values = new byte[u4length];
+ dataInput.readFully(values);
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_CHAR:
+ {
+ char[] values = new char[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readChar();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_SHORT:
+ {
+ short[] values = new short[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readShort();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_INT:
+ {
+ int[] values = new int[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readInt();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_FLOAT:
+ {
+ float[] values = new float[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readFloat();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_LONG:
+ {
+ long[] values = new long[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readLong();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ case ClassConstants.TYPE_DOUBLE:
+ {
+ double[] values = new double[u4length];
+
+ for (int index = 0; index < u4length; index++)
+ {
+ values[index] = dataInput.readDouble();
+ }
+
+ primitiveArrayConstant.values = values;
+ break;
+ }
+ }
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
stringConstant.u2stringIndex = dataInput.readUnsignedShort();
@@ -272,6 +381,18 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ moduleConstant.u2nameIndex = dataInput.readUnsignedShort();
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ packageConstant.u2nameIndex = dataInput.readUnsignedShort();
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
refConstant.u2classIndex = dataInput.readUnsignedShort();
@@ -358,6 +479,85 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ moduleAttribute.u2moduleNameIndex = dataInput.readUnsignedShort();
+ moduleAttribute.u2moduleFlags = dataInput.readUnsignedShort();
+ moduleAttribute.u2moduleVersionIndex = dataInput.readUnsignedShort();
+
+ // Read the requires.
+ moduleAttribute.u2requiresCount = dataInput.readUnsignedShort();
+
+ moduleAttribute.requires = new RequiresInfo[moduleAttribute.u2requiresCount];
+ for (int index = 0; index < moduleAttribute.u2requiresCount; index++)
+ {
+ RequiresInfo requiresInfo = new RequiresInfo();
+ visitRequiresInfo(clazz, requiresInfo);
+ moduleAttribute.requires[index] = requiresInfo;
+ }
+
+ // Read the exports.
+ moduleAttribute.u2exportsCount = dataInput.readUnsignedShort();
+
+ moduleAttribute.exports = new ExportsInfo[moduleAttribute.u2exportsCount];
+ for (int index = 0; index < moduleAttribute.u2exportsCount; index++)
+ {
+ ExportsInfo exportsInfo = new ExportsInfo();
+ visitExportsInfo(clazz, exportsInfo);
+ moduleAttribute.exports[index] = exportsInfo;
+ }
+
+ // Read the opens.
+ moduleAttribute.u2opensCount = dataInput.readUnsignedShort();
+
+ moduleAttribute.opens = new OpensInfo[moduleAttribute.u2opensCount];
+ for (int index = 0; index < moduleAttribute.u2opensCount; index++)
+ {
+ OpensInfo opensInfo = new OpensInfo();
+ visitOpensInfo(clazz, opensInfo);
+ moduleAttribute.opens[index] = opensInfo;
+ }
+
+ // Read the uses.
+ moduleAttribute.u2usesCount = dataInput.readUnsignedShort();
+
+ moduleAttribute.u2uses = new int[moduleAttribute.u2usesCount];
+ for (int index = 0; index < moduleAttribute.u2usesCount; index++)
+ {
+ moduleAttribute.u2uses[index] = dataInput.readUnsignedShort();
+ }
+
+ // Read the provides.
+ moduleAttribute.u2providesCount = dataInput.readUnsignedShort();
+
+ moduleAttribute.provides = new ProvidesInfo[moduleAttribute.u2providesCount];
+ for (int index = 0; index < moduleAttribute.u2providesCount; index++)
+ {
+ ProvidesInfo providesInfo = new ProvidesInfo();
+ visitProvidesInfo(clazz, providesInfo);
+ moduleAttribute.provides[index] = providesInfo;
+ }
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ moduleMainClassAttribute.u2mainClass = dataInput.readUnsignedShort();
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ // Read the packages.
+ modulePackagesAttribute.u2packagesCount = dataInput.readUnsignedShort();
+
+ modulePackagesAttribute.u2packages = new int[modulePackagesAttribute.u2packagesCount];
+ for (int index = 0; index < modulePackagesAttribute.u2packagesCount; index++) {
+ modulePackagesAttribute.u2packages[index] = dataInput.readUnsignedShort();
+ }
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
// This attribute does not contain any additional information.
@@ -772,6 +972,69 @@ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute
}
+ // Implementations for RequiresInfoVisitor.
+
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo)
+ {
+ requiresInfo.u2requiresIndex = dataInput.readUnsignedShort();
+ requiresInfo.u2requiresFlags = dataInput.readUnsignedShort();
+ requiresInfo.u2requiresVersionIndex = dataInput.readUnsignedShort();
+ }
+
+
+ // Implementations for ExportsInfoVisitor.
+
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo)
+ {
+ exportsInfo.u2exportsIndex = dataInput.readUnsignedShort();
+ exportsInfo.u2exportsFlags = dataInput.readUnsignedShort();
+
+ // Read the targets.
+ exportsInfo.u2exportsToCount = dataInput.readUnsignedShort();
+
+ exportsInfo.u2exportsToIndex = new int[exportsInfo.u2exportsToCount];
+ for (int index = 0; index < exportsInfo.u2exportsToCount; index++)
+ {
+ exportsInfo.u2exportsToIndex[index] = dataInput.readUnsignedShort();
+ }
+ }
+
+
+ // Implementations for OpensInfoVisitor.
+
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo)
+ {
+ opensInfo.u2opensIndex = dataInput.readUnsignedShort();
+ opensInfo.u2opensFlags = dataInput.readUnsignedShort();
+
+ // Read the targets.
+ opensInfo.u2opensToCount = dataInput.readUnsignedShort();
+
+ opensInfo.u2opensToIndex = new int[opensInfo.u2opensToCount];
+ for (int index = 0; index < opensInfo.u2opensToCount; index++)
+ {
+ opensInfo.u2opensToIndex[index] = dataInput.readUnsignedShort();
+ }
+ }
+
+
+ // Implementations for ProvidesInfoVisitor.
+
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo)
+ {
+ providesInfo.u2providesIndex = dataInput.readUnsignedShort();
+
+ // Read the withs.
+ providesInfo.u2providesWithCount = dataInput.readUnsignedShort();
+
+ providesInfo.u2providesWithIndex = new int[providesInfo.u2providesWithCount];
+ for (int index = 0; index < providesInfo.u2providesWithCount; index++)
+ {
+ providesInfo.u2providesWithIndex[index] = dataInput.readUnsignedShort();
+ }
+ }
+
+
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
@@ -967,6 +1230,7 @@ private Constant createConstant()
case ClassConstants.CONSTANT_Float: return new FloatConstant();
case ClassConstants.CONSTANT_Long: return new LongConstant();
case ClassConstants.CONSTANT_Double: return new DoubleConstant();
+ case ClassConstants.CONSTANT_PrimitiveArray: return new PrimitiveArrayConstant();
case ClassConstants.CONSTANT_String: return new StringConstant();
case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
case ClassConstants.CONSTANT_InvokeDynamic: return new InvokeDynamicConstant();
@@ -977,6 +1241,8 @@ private Constant createConstant()
case ClassConstants.CONSTANT_Class: return new ClassConstant();
case ClassConstants.CONSTANT_MethodType: return new MethodTypeConstant();
case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant();
+ case ClassConstants.CONSTANT_Module: return new ModuleConstant();
+ case ClassConstants.CONSTANT_Package: return new PackageConstant();
default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
}
@@ -990,31 +1256,34 @@ private Attribute createAttribute(Clazz clazz)
String attributeName = clazz.getString(u2attributeNameIndex);
Attribute attribute =
- attributeName.equals(ClassConstants.ATTR_BootstrapMethods) ? (Attribute)new BootstrapMethodsAttribute():
- attributeName.equals(ClassConstants.ATTR_SourceFile) ? (Attribute)new SourceFileAttribute():
- attributeName.equals(ClassConstants.ATTR_SourceDir) ? (Attribute)new SourceDirAttribute():
- attributeName.equals(ClassConstants.ATTR_InnerClasses) ? (Attribute)new InnerClassesAttribute():
- attributeName.equals(ClassConstants.ATTR_EnclosingMethod) ? (Attribute)new EnclosingMethodAttribute():
- attributeName.equals(ClassConstants.ATTR_Deprecated) ? (Attribute)new DeprecatedAttribute():
- attributeName.equals(ClassConstants.ATTR_Synthetic) ? (Attribute)new SyntheticAttribute():
- attributeName.equals(ClassConstants.ATTR_Signature) ? (Attribute)new SignatureAttribute():
- attributeName.equals(ClassConstants.ATTR_ConstantValue) ? (Attribute)new ConstantValueAttribute():
- attributeName.equals(ClassConstants.ATTR_MethodParameters) ? (Attribute)new MethodParametersAttribute():
- attributeName.equals(ClassConstants.ATTR_Exceptions) ? (Attribute)new ExceptionsAttribute():
- attributeName.equals(ClassConstants.ATTR_Code) ? (Attribute)new CodeAttribute():
- attributeName.equals(ClassConstants.ATTR_StackMap) ? (Attribute)new StackMapAttribute():
- attributeName.equals(ClassConstants.ATTR_StackMapTable) ? (Attribute)new StackMapTableAttribute():
- attributeName.equals(ClassConstants.ATTR_LineNumberTable) ? (Attribute)new LineNumberTableAttribute():
- attributeName.equals(ClassConstants.ATTR_LocalVariableTable) ? (Attribute)new LocalVariableTableAttribute():
- attributeName.equals(ClassConstants.ATTR_LocalVariableTypeTable) ? (Attribute)new LocalVariableTypeTableAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeVisibleAnnotations) ? (Attribute)new RuntimeVisibleAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleAnnotations) ? (Attribute)new RuntimeInvisibleAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations) ? (Attribute)new RuntimeVisibleParameterAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations) ? (Attribute)new RuntimeInvisibleParameterAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeVisibleTypeAnnotations) ? (Attribute)new RuntimeVisibleTypeAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleTypeAnnotations) ? (Attribute)new RuntimeInvisibleTypeAnnotationsAttribute():
- attributeName.equals(ClassConstants.ATTR_AnnotationDefault) ? (Attribute)new AnnotationDefaultAttribute():
- (Attribute)new UnknownAttribute(u2attributeNameIndex, u4attributeLength);
+ attributeName.equals(ClassConstants.ATTR_BootstrapMethods) ? (Attribute)new BootstrapMethodsAttribute():
+ attributeName.equals(ClassConstants.ATTR_SourceFile) ? (Attribute)new SourceFileAttribute():
+ attributeName.equals(ClassConstants.ATTR_SourceDir) ? (Attribute)new SourceDirAttribute():
+ attributeName.equals(ClassConstants.ATTR_InnerClasses) ? (Attribute)new InnerClassesAttribute():
+ attributeName.equals(ClassConstants.ATTR_EnclosingMethod) ? (Attribute)new EnclosingMethodAttribute():
+ attributeName.equals(ClassConstants.ATTR_Deprecated) ? (Attribute)new DeprecatedAttribute():
+ attributeName.equals(ClassConstants.ATTR_Synthetic) ? (Attribute)new SyntheticAttribute():
+ attributeName.equals(ClassConstants.ATTR_Signature) ? (Attribute)new SignatureAttribute():
+ attributeName.equals(ClassConstants.ATTR_ConstantValue) ? (Attribute)new ConstantValueAttribute():
+ attributeName.equals(ClassConstants.ATTR_MethodParameters) ? (Attribute)new MethodParametersAttribute():
+ attributeName.equals(ClassConstants.ATTR_Exceptions) ? (Attribute)new ExceptionsAttribute():
+ attributeName.equals(ClassConstants.ATTR_Code) ? (Attribute)new CodeAttribute():
+ attributeName.equals(ClassConstants.ATTR_StackMap) ? (Attribute)new StackMapAttribute():
+ attributeName.equals(ClassConstants.ATTR_StackMapTable) ? (Attribute)new StackMapTableAttribute():
+ attributeName.equals(ClassConstants.ATTR_LineNumberTable) ? (Attribute)new LineNumberTableAttribute():
+ attributeName.equals(ClassConstants.ATTR_LocalVariableTable) ? (Attribute)new LocalVariableTableAttribute():
+ attributeName.equals(ClassConstants.ATTR_LocalVariableTypeTable) ? (Attribute)new LocalVariableTypeTableAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeVisibleAnnotations) ? (Attribute)new RuntimeVisibleAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleAnnotations) ? (Attribute)new RuntimeInvisibleAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations) ? (Attribute)new RuntimeVisibleParameterAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations) ? (Attribute)new RuntimeInvisibleParameterAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeVisibleTypeAnnotations) ? (Attribute)new RuntimeVisibleTypeAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleTypeAnnotations) ? (Attribute)new RuntimeInvisibleTypeAnnotationsAttribute():
+ attributeName.equals(ClassConstants.ATTR_AnnotationDefault) ? (Attribute)new AnnotationDefaultAttribute():
+ attributeName.equals(ClassConstants.ATTR_Module) ? (Attribute)new ModuleAttribute():
+ attributeName.equals(ClassConstants.ATTR_ModuleMainClass) ? (Attribute)new ModuleMainClassAttribute():
+ attributeName.equals(ClassConstants.ATTR_ModulePackages) ? (Attribute)new ModulePackagesAttribute():
+ (Attribute)new UnknownAttribute(u2attributeNameIndex, u4attributeLength);
attribute.u2attributeNameIndex = u2attributeNameIndex;
return attribute;
diff --git a/src/proguard/classfile/io/ProgramClassWriter.java b/core/src/proguard/classfile/io/ProgramClassWriter.java
similarity index 81%
rename from src/proguard/classfile/io/ProgramClassWriter.java
rename to core/src/proguard/classfile/io/ProgramClassWriter.java
index 13fe74c..6f24b10 100644
--- a/src/proguard/classfile/io/ProgramClassWriter.java
+++ b/core/src/proguard/classfile/io/ProgramClassWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,11 +26,13 @@
import proguard.classfile.attribute.annotation.target.*;
import proguard.classfile.attribute.annotation.target.visitor.*;
import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.constant.visitor.*;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
@@ -72,7 +74,7 @@ public ProgramClassWriter(DataOutput dataOutput)
public void visitProgramClass(ProgramClass programClass)
{
// Write the magic number.
- dataOutput.writeInt(programClass.u4magic);
+ dataOutput.writeInt(ClassConstants.MAGIC);
// Write the version numbers.
dataOutput.writeShort(ClassUtil.internalMinorClassVersion(programClass.u4version));
@@ -84,7 +86,9 @@ public void visitProgramClass(ProgramClass programClass)
programClass.constantPoolEntriesAccept(this);
// Write the general class information.
- dataOutput.writeUnsignedShort(programClass.u2accessFlags);
+ // Ignore the higher bits outside the short range - these are for
+ // internal purposes only.
+ dataOutput.writeUnsignedShort(programClass.u2accessFlags & 0xffff);
dataOutput.writeUnsignedShort(programClass.u2thisClass);
dataOutput.writeUnsignedShort(programClass.u2superClass);
@@ -123,7 +127,9 @@ public void visitLibraryClass(LibraryClass libraryClass)
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
// Write the general field information.
- dataOutput.writeUnsignedShort(programField.u2accessFlags);
+ // Ignore the higher bits outside the short range - these are for
+ // internal purposes only.
+ dataOutput.writeUnsignedShort(programField.u2accessFlags & 0xffff);
dataOutput.writeUnsignedShort(programField.u2nameIndex);
dataOutput.writeUnsignedShort(programField.u2descriptorIndex);
@@ -137,7 +143,9 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
// Write the general method information.
- dataOutput.writeUnsignedShort(programMethod.u2accessFlags);
+ // Ignore the higher bits outside the short range - these are for
+ // internal purposes only.
+ dataOutput.writeUnsignedShort(programMethod.u2accessFlags & 0xffff);
dataOutput.writeUnsignedShort(programMethod.u2nameIndex);
dataOutput.writeUnsignedShort(programMethod.u2descriptorIndex);
@@ -167,7 +175,8 @@ public void visitAnyConstant(Clazz clazz, Constant constant)
private class ConstantBodyWriter
extends SimplifiedVisitor
- implements ConstantVisitor
+ implements ConstantVisitor,
+ PrimitiveArrayConstantElementVisitor
{
// Implementations for ConstantVisitor.
@@ -195,6 +204,19 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ char u2primitiveType = primitiveArrayConstant.getPrimitiveType();
+ int u4Length = primitiveArrayConstant.getLength();
+
+ dataOutput.writeUnsignedShort(u2primitiveType);
+ dataOutput.writeInt(u4Length);
+
+ // Write the array values.
+ primitiveArrayConstant.primitiveArrayElementsAccept(clazz, this);
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
dataOutput.writeUnsignedShort(stringConstant.u2stringIndex);
@@ -248,6 +270,68 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
dataOutput.writeUnsignedShort(nameAndTypeConstant.u2nameIndex);
dataOutput.writeUnsignedShort(nameAndTypeConstant.u2descriptorIndex);
}
+
+
+ // Implementations for PrimitiveArrayConstantElementVisitor.
+
+ public void visitBooleanArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, boolean value)
+ {
+ dataOutput.writeBoolean(value);
+ }
+
+
+ public void visitByteArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, byte value)
+ {
+ dataOutput.writeByte(value);
+ }
+
+
+ public void visitCharArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, char value)
+ {
+ dataOutput.writeChar(value);
+ }
+
+
+ public void visitShortArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, short value)
+ {
+ dataOutput.writeShort(value);
+ }
+
+
+ public void visitIntArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, int value)
+ {
+ dataOutput.writeInt(value);
+ }
+
+
+ public void visitFloatArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, float value)
+ {
+ dataOutput.writeFloat(value);
+ }
+
+
+ public void visitLongArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, long value)
+ {
+ dataOutput.writeLong(value);
+ }
+
+
+ public void visitDoubleArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, double value)
+ {
+ dataOutput.writeDouble(value);
+ }
+
+
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ dataOutput.writeUnsignedShort(moduleConstant.u2nameIndex);
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ dataOutput.writeUnsignedShort(packageConstant.u2nameIndex);
+ }
}
@@ -294,6 +378,10 @@ private class AttributeBodyWriter
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
+ RequiresInfoVisitor,
+ ExportsInfoVisitor,
+ OpensInfoVisitor,
+ ProvidesInfoVisitor,
AnnotationVisitor,
TypeAnnotationVisitor,
TargetInfoVisitor,
@@ -347,6 +435,60 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ dataOutput.writeUnsignedShort(moduleAttribute.u2moduleNameIndex);
+ dataOutput.writeUnsignedShort(moduleAttribute.u2moduleFlags);
+ dataOutput.writeUnsignedShort(moduleAttribute.u2moduleVersionIndex);
+
+ // Write the requires.
+ dataOutput.writeUnsignedShort(moduleAttribute.u2requiresCount);
+
+ moduleAttribute.requiresAccept(clazz, this);
+
+ // Write the exports.
+ dataOutput.writeUnsignedShort(moduleAttribute.u2exportsCount);
+
+ moduleAttribute.exportsAccept(clazz, this);
+
+ // Write the opens.
+ dataOutput.writeUnsignedShort(moduleAttribute.u2opensCount);
+
+ moduleAttribute.opensAccept(clazz, this);
+
+ // Write the uses.
+ dataOutput.writeUnsignedShort(moduleAttribute.u2usesCount);
+
+ for (int index = 0; index < moduleAttribute.u2usesCount; index++)
+ {
+ dataOutput.writeUnsignedShort(moduleAttribute.u2uses[index]);
+ }
+
+ // Write the provides.
+ dataOutput.writeUnsignedShort(moduleAttribute.u2providesCount);
+
+ moduleAttribute.providesAccept(clazz, this);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ dataOutput.writeUnsignedShort(moduleMainClassAttribute.u2mainClass);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ // Write the packages.
+ dataOutput.writeUnsignedShort(modulePackagesAttribute.u2packagesCount);
+
+ for (int index = 0; index < modulePackagesAttribute.u2packagesCount; index++)
+ {
+ dataOutput.writeUnsignedShort(modulePackagesAttribute.u2packages[index]);
+ }
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
// This attribute does not contain any additional information.
@@ -460,6 +602,58 @@ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, Cod
}
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo)
+ {
+ dataOutput.writeUnsignedShort(requiresInfo.u2requiresIndex);
+ dataOutput.writeUnsignedShort(requiresInfo.u2requiresFlags);
+ dataOutput.writeUnsignedShort(requiresInfo.u2requiresVersionIndex);
+ }
+
+
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo)
+ {
+ dataOutput.writeUnsignedShort(exportsInfo.u2exportsIndex);
+ dataOutput.writeUnsignedShort(exportsInfo.u2exportsFlags);
+
+ // Write tthe argets.
+ dataOutput.writeUnsignedShort(exportsInfo.u2exportsToCount);
+
+ for (int index = 0; index < exportsInfo.u2exportsToCount; index++)
+ {
+ dataOutput.writeUnsignedShort(exportsInfo.u2exportsToIndex[index]);
+ }
+ }
+
+
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo)
+ {
+ dataOutput.writeUnsignedShort(opensInfo.u2opensIndex);
+ dataOutput.writeUnsignedShort(opensInfo.u2opensFlags);
+
+ // Write the targets.
+ dataOutput.writeUnsignedShort(opensInfo.u2opensToCount);
+
+ for (int index = 0; index < opensInfo.u2opensToCount; index++)
+ {
+ dataOutput.writeUnsignedShort(opensInfo.u2opensToIndex[index]);
+ }
+ }
+
+
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo)
+ {
+ dataOutput.writeUnsignedShort(providesInfo.u2providesIndex);
+
+ // Write the with.
+ dataOutput.writeUnsignedShort(providesInfo.u2providesWithCount);
+
+ for (int index = 0; index < providesInfo.u2providesWithCount; index++)
+ {
+ dataOutput.writeUnsignedShort(providesInfo.u2providesWithIndex[index]);
+ }
+ }
+
+
public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
{
// Write the annotations.
@@ -561,8 +755,10 @@ public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute code
public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
{
- dataOutput.writeUnsignedShort(lineNumberInfo.u2startPC);
- dataOutput.writeUnsignedShort(lineNumberInfo.u2lineNumber);
+ // Simply suppress line number overflows, typically caused by
+ // inlined methods and their artificial line numbers.
+ dataOutput.writeUnsignedShort(lineNumberInfo.u2startPC > 0xffff ? 0 : lineNumberInfo.u2startPC);
+ dataOutput.writeUnsignedShort(lineNumberInfo.u2lineNumber > 0xffff ? 0 : lineNumberInfo.u2lineNumber);
}
diff --git a/src/proguard/classfile/io/RuntimeDataInput.java b/core/src/proguard/classfile/io/RuntimeDataInput.java
similarity index 98%
rename from src/proguard/classfile/io/RuntimeDataInput.java
rename to core/src/proguard/classfile/io/RuntimeDataInput.java
index 5796269..e496ed4 100644
--- a/src/proguard/classfile/io/RuntimeDataInput.java
+++ b/core/src/proguard/classfile/io/RuntimeDataInput.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/io/RuntimeDataOutput.java b/core/src/proguard/classfile/io/RuntimeDataOutput.java
similarity index 98%
rename from src/proguard/classfile/io/RuntimeDataOutput.java
rename to core/src/proguard/classfile/io/RuntimeDataOutput.java
index 781c6c9..b56fd9c 100644
--- a/src/proguard/classfile/io/RuntimeDataOutput.java
+++ b/core/src/proguard/classfile/io/RuntimeDataOutput.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/io/package.html b/core/src/proguard/classfile/io/package.html
similarity index 100%
rename from src/proguard/classfile/io/package.html
rename to core/src/proguard/classfile/io/package.html
diff --git a/src/proguard/classfile/package.html b/core/src/proguard/classfile/package.html
similarity index 100%
rename from src/proguard/classfile/package.html
rename to core/src/proguard/classfile/package.html
diff --git a/src/proguard/classfile/util/AccessUtil.java b/core/src/proguard/classfile/util/AccessUtil.java
similarity index 98%
rename from src/proguard/classfile/util/AccessUtil.java
rename to core/src/proguard/classfile/util/AccessUtil.java
index 6799fa7..593907d 100644
--- a/src/proguard/classfile/util/AccessUtil.java
+++ b/core/src/proguard/classfile/util/AccessUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/AllParameterVisitor.java b/core/src/proguard/classfile/util/AllParameterVisitor.java
similarity index 85%
rename from src/proguard/classfile/util/AllParameterVisitor.java
rename to core/src/proguard/classfile/util/AllParameterVisitor.java
index b665d2b..96211da 100644
--- a/src/proguard/classfile/util/AllParameterVisitor.java
+++ b/core/src/proguard/classfile/util/AllParameterVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,14 +25,15 @@
/**
* This MemberVisitor lets a given parameter visitor visit all the parameters
- * of the methods that it visits. The parameters do not include or count the
- * 'this' parameter or the return value.
+ * of the methods that it visits. The parameters optionally includes the
+ * 'this' parameter of non-static methods, but never the return value.
*
* @author Eric Lafortune
*/
public class AllParameterVisitor
implements MemberVisitor
{
+ private final boolean includeThisParameter;
private final ParameterVisitor parameterVisitor;
@@ -40,9 +41,11 @@ public class AllParameterVisitor
* Creates a new AllParameterVisitor for the given parameter
* visitor.
*/
- public AllParameterVisitor(ParameterVisitor parameterVisitor)
+ public AllParameterVisitor(boolean includeThisParameter,
+ ParameterVisitor parameterVisitor)
{
- this.parameterVisitor = parameterVisitor;
+ this.includeThisParameter = includeThisParameter;
+ this.parameterVisitor = parameterVisitor;
}
@@ -111,8 +114,8 @@ private void visitParameters(Clazz clazz,
String descriptor = method.getDescriptor(clazz);
// Count the number of parameters and their total size.
- int parameterCount = 0;
- int parameterSize = 0;
+ int parameterCount = 0;
+ int parameterSize = 0;
int index = 1;
@@ -164,10 +167,24 @@ private void visitParameters(Clazz clazz,
}
// Visit the parameters.
- int parameterIndex = 0;
- int parameterOffset = 0;
+ int parameterIndex = 0;
+ int parameterOffset = 0;
int referenceClassIndex = 0;
+ // Visit the 'this' parameter if applicable.
+ if (includeThisParameter &&
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0)
+ {
+ parameterVisitor.visitParameter(clazz,
+ method,
+ parameterIndex++,
+ ++parameterCount,
+ parameterOffset++,
+ ++parameterSize,
+ ClassUtil.internalTypeFromClassName(clazz.getName()),
+ clazz);
+ }
+
index = 1;
while (true)
diff --git a/core/src/proguard/classfile/util/ArrayInitializationMatcher.java b/core/src/proguard/classfile/util/ArrayInitializationMatcher.java
new file mode 100644
index 0000000..3f6257a
--- /dev/null
+++ b/core/src/proguard/classfile/util/ArrayInitializationMatcher.java
@@ -0,0 +1,347 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.instruction.*;
+import proguard.evaluation.TracedStack;
+import proguard.evaluation.value.*;
+import proguard.optimize.evaluation.PartialEvaluator;
+import proguard.optimize.peephole.InstructionSequenceReplacer;
+
+/**
+ * This class finds sequences of instructions that correspond to primitive
+ * array initializations. Such initializations may be represented more
+ * efficiently in other bytecode languages.
+ *
+ * @author Eric Lafortune
+ */
+public class ArrayInitializationMatcher
+{
+ private static final int X = InstructionSequenceReplacer.X;
+
+ private final PartialEvaluator partialEvaluator;
+
+ private int arrayInitializationStart;
+ private int arrayInitializationEnd;
+ private Object array;
+
+ private final Constant[] CONSTANTS = new Constant[0];
+
+ // Conversion with dex2jar might result in arrays
+ // being pre-stored to a variable before initialization:
+ //
+ // newarray
+ // astore X
+ // aload X
+ // initialization start
+ //
+ private final Instruction[] ARRAY_PRESTORE_INSTRUCTIONS = new Instruction[]
+ {
+ new VariableInstruction(InstructionConstants.OP_ASTORE, X),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, X)
+ };
+
+ private final InstructionSequenceMatcher arrayPreStoreMatcher =
+ new InstructionSequenceMatcher(CONSTANTS, ARRAY_PRESTORE_INSTRUCTIONS);
+
+
+ /**
+ * Creates a new ArrayInitializationMatcher.
+ */
+ public ArrayInitializationMatcher()
+ {
+ this(new PartialEvaluator());
+ }
+
+
+ /**
+ * Creates a new ArrayInitializationMatcher that will use the given partial
+ * evaluator. The evaluator must have been initialized before trying to
+ * match any array initializations.
+ * @param partialEvaluator the evaluator to be used for the analysis.
+ */
+ public ArrayInitializationMatcher(PartialEvaluator partialEvaluator)
+ {
+ this.partialEvaluator = partialEvaluator;
+ }
+
+
+ /**
+ * Returns whether the code fragment starting at the specified newarray
+ * instruction is followed by a static array initialization.
+ * @param clazz the class.
+ * @param method the method.
+ * @param codeAttribute the code attribute.
+ * @param newArrayOffset the offset of the newarray instruction.
+ * @param newArrayInstruction the newarray instruction.
+ * @return whether there is a static array initialization.
+ */
+ public boolean matchesArrayInitialization(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int newArrayOffset,
+ SimpleInstruction newArrayInstruction)
+ {
+ array = null;
+
+ TracedStack stackBefore =
+ partialEvaluator.getStackBefore(newArrayOffset);
+
+ IntegerValue integerValue =
+ stackBefore.getTop(0).integerValue();
+
+ if (!integerValue.isParticular())
+ {
+ return false;
+ }
+
+
+ int arrayLength = integerValue.value();
+
+ int newArrayType = newArrayInstruction.constant;
+ int arrayStoreOpcode = arrayStoreOpcode(newArrayType);
+
+ byte[] code = codeAttribute.code;
+
+ int offset = newArrayOffset;
+ Instruction instruction = newArrayInstruction;
+
+ int skipOffset = skipPreStoreInstructions(clazz, method, codeAttribute, offset + instruction.length(offset));
+ if (skipOffset > 0)
+ {
+ offset = skipOffset;
+ newArrayOffset = offset;
+ instruction = InstructionFactory.create(code, offset);
+ }
+
+ // Remember the potential initialization start.
+ int tmpInitializationStart = offset + instruction.length(offset);
+
+ // Check if all the elements in the array are initialized.
+ for (int index = 0; index < arrayLength; index++)
+ {
+ // Check if the array reference is pushed.
+ instruction = InstructionFactory.create(code, offset += instruction.length(offset));
+
+ if (instruction.stackPushCount(clazz) < 1 ||
+ !partialEvaluator.getStackAfter(offset).getTopActualProducerValue(0).instructionOffsetValue().contains(newArrayOffset))
+ {
+ return false;
+ }
+
+ // Check that the array index is pushed.
+ instruction = InstructionFactory.create(code, offset += instruction.length(offset));
+ if (instruction.stackPushCount(clazz) != 1)
+ {
+ return false;
+ }
+
+ Value indexValue = partialEvaluator.getStackAfter(offset).getTop(0);
+ if (indexValue.computationalType() != Value.TYPE_INTEGER ||
+ !indexValue.integerValue().isParticular() ||
+ indexValue.integerValue().value() != index)
+ {
+ return false;
+ }
+
+ // Check if a particular value is pushed.
+ instruction = InstructionFactory.create(code, offset += instruction.length(offset));
+ if (instruction.stackPushCount(clazz) < 1 ||
+ !partialEvaluator.getStackAfter(offset).getTop(0).isParticular())
+ {
+ return false;
+ }
+
+ Value elementValue = partialEvaluator.getStackAfter(offset).getTop(0);
+
+ // Check if the value is stored in the array.
+ instruction = InstructionFactory.create(code, offset += instruction.length(offset));
+ if (instruction.opcode != arrayStoreOpcode)
+ {
+ return false;
+ }
+
+ if (index == 0)
+ {
+ array = newArray(newArrayType, arrayLength);
+ }
+
+ arrayStore(newArrayType, array, index, elementValue);
+ }
+
+ arrayInitializationStart = tmpInitializationStart;
+ arrayInitializationEnd = offset;
+
+ return offset > newArrayOffset;
+ }
+
+
+ /**
+ * Returns the offset to skip to after a new-array instruction.
+ *
+ * This is a work-around for code converted by dex2jar. In some
+ * cases, after an array has been created, it is immediately
+ * stored into a variable and loaded again:
+ *
+ * newarray
+ * astore X
+ * aload X
+ * initialization
+ *
+ *
+ * @param clazz the class.
+ * @param method the method.
+ * @param codeAttribute the code attribute.
+ * @param startOffset the start offset.
+ * @return the offset to skip to
+ */
+ private int skipPreStoreInstructions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int startOffset)
+ {
+ final int instructionCount = arrayPreStoreMatcher.instructionCount();
+
+ arrayPreStoreMatcher.reset();
+ for (int count = 0, offset = startOffset;
+ count < instructionCount && offset < codeAttribute.u4codeLength;
+ count++)
+ {
+ Instruction instruction =
+ InstructionFactory.create(codeAttribute.code, offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset,
+ arrayPreStoreMatcher);
+
+ offset += instruction.length(offset);
+ }
+
+ if (arrayPreStoreMatcher.isMatching())
+ {
+ return arrayPreStoreMatcher.matchedInstructionOffset(instructionCount - 1);
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the first offset of the recent static array initialization, i.e. the first
+ * initialization instruction after the newarray.
+ * @see #matchesArrayInitialization
+ */
+ public int arrayInitializationStart()
+ {
+ return arrayInitializationStart;
+ }
+
+ /**
+ * Returns the last offset of the recent static array initialization.
+ * @see #matchesArrayInitialization
+ */
+ public int arrayInitializationEnd()
+ {
+ return arrayInitializationEnd;
+ }
+
+ /**
+ * Returns the recent static array initialization.
+ * @see #matchesArrayInitialization
+ */
+ public Object array()
+ {
+ return array;
+ }
+
+
+ private byte internalType(int newArrayType)
+ {
+ switch (newArrayType)
+ {
+ case InstructionConstants.ARRAY_T_BOOLEAN:
+ case InstructionConstants.ARRAY_T_BYTE:
+ case InstructionConstants.ARRAY_T_CHAR:
+ case InstructionConstants.ARRAY_T_SHORT:
+ case InstructionConstants.ARRAY_T_INT: return Value.TYPE_INTEGER;
+ case InstructionConstants.ARRAY_T_LONG: return Value.TYPE_LONG;
+ case InstructionConstants.ARRAY_T_FLOAT: return Value.TYPE_FLOAT;
+ case InstructionConstants.ARRAY_T_DOUBLE: return Value.TYPE_DOUBLE;
+ default:
+ throw new IllegalArgumentException("Unexpected new array type ["+newArrayType+"]");
+ }
+ }
+
+
+ private byte arrayStoreOpcode(int newArrayType)
+ {
+ switch (newArrayType)
+ {
+ case InstructionConstants.ARRAY_T_BOOLEAN:
+ case InstructionConstants.ARRAY_T_BYTE: return InstructionConstants.OP_BASTORE;
+ case InstructionConstants.ARRAY_T_CHAR: return InstructionConstants.OP_CASTORE;
+ case InstructionConstants.ARRAY_T_SHORT: return InstructionConstants.OP_SASTORE;
+ case InstructionConstants.ARRAY_T_INT: return InstructionConstants.OP_IASTORE;
+ case InstructionConstants.ARRAY_T_LONG: return InstructionConstants.OP_LASTORE;
+ case InstructionConstants.ARRAY_T_FLOAT: return InstructionConstants.OP_FASTORE;
+ case InstructionConstants.ARRAY_T_DOUBLE: return InstructionConstants.OP_DASTORE;
+ default:
+ throw new IllegalArgumentException("Unexpected new array type ["+newArrayType+"]");
+ }
+ }
+
+
+ private Object newArray(int newArrayType, int arrayLength)
+ {
+ switch (newArrayType)
+ {
+ case InstructionConstants.ARRAY_T_BOOLEAN: return new boolean[arrayLength];
+ case InstructionConstants.ARRAY_T_BYTE: return new byte[arrayLength];
+ case InstructionConstants.ARRAY_T_CHAR: return new char[arrayLength];
+ case InstructionConstants.ARRAY_T_SHORT: return new short[arrayLength];
+ case InstructionConstants.ARRAY_T_INT: return new int[arrayLength];
+ case InstructionConstants.ARRAY_T_LONG: return new long[arrayLength];
+ case InstructionConstants.ARRAY_T_FLOAT: return new float[arrayLength];
+ case InstructionConstants.ARRAY_T_DOUBLE: return new double[arrayLength];
+ default:
+ throw new IllegalArgumentException("Unexpected new array type ["+newArrayType+"]");
+ }
+ }
+
+
+ private void arrayStore(int newArrayType, Object array, int index, Value value)
+ {
+ switch (newArrayType)
+ {
+ case InstructionConstants.ARRAY_T_BOOLEAN: ((boolean[])array)[index] = 0 != value.integerValue().value(); break;
+ case InstructionConstants.ARRAY_T_BYTE: ((byte [])array)[index] = (byte) value.integerValue().value(); break;
+ case InstructionConstants.ARRAY_T_CHAR: ((char [])array)[index] = (char) value.integerValue().value(); break;
+ case InstructionConstants.ARRAY_T_SHORT: ((short [])array)[index] = (short)value.integerValue().value(); break;
+ case InstructionConstants.ARRAY_T_INT: ((int [])array)[index] = value.integerValue().value(); break;
+ case InstructionConstants.ARRAY_T_LONG: ((long [])array)[index] = value.longValue().value(); break;
+ case InstructionConstants.ARRAY_T_FLOAT: ((float [])array)[index] = value.floatValue().value(); break;
+ case InstructionConstants.ARRAY_T_DOUBLE: ((double [])array)[index] = value.doubleValue().value(); break;
+ default:
+ throw new IllegalArgumentException("Unexpected new array type ["+newArrayType+"]");
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/classfile/util/ArrayInitializationReplacer.java b/core/src/proguard/classfile/util/ArrayInitializationReplacer.java
new file mode 100644
index 0000000..2b273ed
--- /dev/null
+++ b/core/src/proguard/classfile/util/ArrayInitializationReplacer.java
@@ -0,0 +1,200 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+import proguard.evaluation.BasicInvocationUnit;
+import proguard.evaluation.value.*;
+import proguard.optimize.evaluation.PartialEvaluator;
+
+/**
+ * This ClassVisitor replaces array initialization instructions with optimized
+ * primitive array constants.
+ *
+ * These constants are not supported by any Java specification and therefore
+ * only for internal use.
+ *
+ * @see PrimitiveArrayConstantReplacer
+ * @author Thomas Neidhart
+ */
+public class ArrayInitializationReplacer
+extends SimplifiedVisitor
+implements ClassVisitor,
+
+ // Implementation interfaces.
+ AttributeVisitor,
+ InstructionVisitor
+{
+ private final ValueFactory valueFactory = new ParticularValueFactory(new BasicValueFactory());
+ private final PartialEvaluator partialEvaluator = new PartialEvaluator(valueFactory,
+ new BasicInvocationUnit(valueFactory),
+ true);
+ private final ArrayInitializationMatcher arrayInitializationMatcher = new ArrayInitializationMatcher(partialEvaluator);
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+
+ private ConstantPoolEditor constantPoolEditor;
+ private int lastInstructionOffset;
+ private int lastInstructionStackPushCount;
+ private int arrayInitializationStart;
+ private int arrayInitializationEnd;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ constantPoolEditor = new ConstantPoolEditor(programClass);
+
+ // Visit all methods that have "NEWARRAY" instructions.
+ programClass.methodsAccept(
+ new AllAttributeVisitor(
+ new ArrayInitializationFilter(
+ this)));
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttributeEditor.reset(codeAttribute.u4codeLength);
+
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+
+ lastInstructionOffset = -1;
+ lastInstructionStackPushCount = -1;
+ arrayInitializationStart = -1;
+ arrayInitializationEnd = -1;
+ codeAttribute.instructionsAccept(clazz, method, this);
+
+ if (codeAttributeEditor.isModified())
+ {
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ Instruction instruction)
+ {
+ // Verify that the previous instruction pushed the array size on the
+ // stack: the java compiler will always do so, but obfuscators may
+ // have reordered the instructions.
+ if (instruction.opcode == InstructionConstants.OP_NEWARRAY &&
+ lastInstructionStackPushCount == 1)
+ {
+ if (arrayInitializationMatcher.matchesArrayInitialization(clazz,
+ method,
+ codeAttribute,
+ offset,
+ (SimpleInstruction)instruction))
+ {
+ Object values = arrayInitializationMatcher.array();
+ int constantIndex = constantPoolEditor.addPrimitiveArrayConstant(values);
+
+ // We need to replace the previous instruction, which pushes
+ // the array length onto the stack.
+ codeAttributeEditor.replaceInstruction(lastInstructionOffset,
+ new ConstantInstruction(InstructionConstants.OP_LDC,
+ constantIndex));
+
+ // Remove the newarray instruction itself.
+ codeAttributeEditor.deleteInstruction(offset);
+
+ // Mark the start/end of the array initialization sequence.
+ arrayInitializationStart = arrayInitializationMatcher.arrayInitializationStart();
+ arrayInitializationEnd = arrayInitializationMatcher.arrayInitializationEnd();
+ }
+ }
+
+ // Remove any instruction inside the array initialization sequence.
+ if (arrayInitializationEnd != -1 &&
+ offset >= arrayInitializationStart &&
+ offset <= arrayInitializationEnd)
+ {
+ codeAttributeEditor.deleteInstruction(offset);
+ }
+
+ lastInstructionOffset = offset;
+ lastInstructionStackPushCount = instruction.stackPushCount(clazz);
+ }
+
+
+ /**
+ * Private utility class to visit only CodeAttributes that contain
+ * "NEWARRAY" instructions.
+ */
+ private static class ArrayInitializationFilter
+ extends SimplifiedVisitor
+ implements AttributeVisitor
+ {
+ private final AttributeVisitor acceptedVisitor;
+
+
+ public ArrayInitializationFilter(AttributeVisitor acceptedVisitor)
+ {
+ this.acceptedVisitor = acceptedVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ boolean delegateVisit = false;
+ // Directly iterate of all instructions and exit early if
+ // we encounter a "NEWARRAY" instruction.
+ for (int offset = 0; offset < codeAttribute.u4codeLength;)
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code, offset);
+ if (instruction.opcode == InstructionConstants.OP_NEWARRAY)
+ {
+ delegateVisit = true;
+ break;
+ }
+
+ offset += instruction.length(offset);
+ }
+
+ if (delegateVisit)
+ {
+ acceptedVisitor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+ }
+ }
+}
diff --git a/src/proguard/classfile/util/ClassReferenceInitializer.java b/core/src/proguard/classfile/util/ClassReferenceInitializer.java
similarity index 92%
rename from src/proguard/classfile/util/ClassReferenceInitializer.java
rename to core/src/proguard/classfile/util/ClassReferenceInitializer.java
index 5a6bf8d..beb14a8 100644
--- a/src/proguard/classfile/util/ClassReferenceInitializer.java
+++ b/core/src/proguard/classfile/util/ClassReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -71,6 +71,17 @@ public class ClassReferenceInitializer
private final MemberFinder memberFinder = new MemberFinder();
+ /**
+ * Creates a new ClassReferenceInitializer that initializes the references
+ * of all visited class files.
+ */
+ public ClassReferenceInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(programClassPool, libraryClassPool, null, null, null, null);
+ }
+
+
/**
* Creates a new ClassReferenceInitializer that initializes the references
* of all visited class files, optionally printing warnings if some classes
@@ -225,20 +236,23 @@ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
missingProgramMemberWarningPrinter :
missingLibraryMemberWarningPrinter;
- missingMemberWarningPrinter.print(clazz.getName(),
- className,
- "Warning: " +
- ClassUtil.externalClassName(clazz.getName()) +
- ": can't find referenced " +
- (isFieldRef ?
- "field '" + ClassUtil.externalFullFieldDescription(0, name, type) :
- "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) +
- "' in " +
- (isProgramClass ?
- "program" :
- "library") +
- " class " +
- ClassUtil.externalClassName(className));
+ if (missingMemberWarningPrinter != null)
+ {
+ missingMemberWarningPrinter.print(clazz.getName(),
+ className,
+ "Warning: " +
+ ClassUtil.externalClassName(clazz.getName()) +
+ ": can't find referenced " +
+ (isFieldRef ?
+ "field '" + ClassUtil.externalFullFieldDescription(0, name, type) :
+ "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) +
+ "' in " +
+ (isProgramClass ?
+ "program" :
+ "library") +
+ " class " +
+ ClassUtil.externalClassName(className));
+ }
}
}
}
@@ -294,7 +308,8 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
enclosingMethodAttribute.referencedMethod =
enclosingMethodAttribute.referencedClass.findMethod(name, type);
- if (enclosingMethodAttribute.referencedMethod == null)
+ if (enclosingMethodAttribute.referencedMethod == null &&
+ missingProgramMemberWarningPrinter != null)
{
// We couldn't find the enclosing method.
String className = clazz.getName();
diff --git a/src/proguard/classfile/util/ClassSubHierarchyInitializer.java b/core/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
similarity index 97%
rename from src/proguard/classfile/util/ClassSubHierarchyInitializer.java
rename to core/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
index ef5df7e..991ac83 100644
--- a/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
+++ b/core/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/ClassSuperHierarchyInitializer.java b/core/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
similarity index 93%
rename from src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
rename to core/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
index b5b5a08..75a26f2 100644
--- a/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
+++ b/core/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +50,16 @@ public class ClassSuperHierarchyInitializer
private final WarningPrinter dependencyWarningPrinter;
+ /**
+ * Creates a new ClassSuperHierarchyInitializer that initializes the super
+ * hierarchy of all visited class files.
+ */
+ public ClassSuperHierarchyInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(programClassPool, libraryClassPool, null, null);
+ }
+
/**
* Creates a new ClassSuperHierarchyInitializer that initializes the super
* hierarchy of all visited class files, optionally printing warnings if
diff --git a/src/proguard/classfile/util/ClassUtil.java b/core/src/proguard/classfile/util/ClassUtil.java
similarity index 71%
rename from src/proguard/classfile/util/ClassUtil.java
rename to core/src/proguard/classfile/util/ClassUtil.java
index 439c65a..de4165d 100644
--- a/src/proguard/classfile/util/ClassUtil.java
+++ b/core/src/proguard/classfile/util/ClassUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -63,59 +63,62 @@ public static int internalClassVersion(int majorVersion, int minorVersion)
/**
* Returns the major part of the given class version number.
- * @param classVersion the combined class version number.
+ * @param internalClassVersion the combined class version number.
* @return the major part of the class version number.
*/
- public static int internalMajorClassVersion(int classVersion)
+ public static int internalMajorClassVersion(int internalClassVersion)
{
- return classVersion >>> 16;
+ return internalClassVersion >>> 16;
}
/**
* Returns the internal class version number.
- * @param classVersion the external class version number.
+ * @param internalClassVersion the external class version number.
* @return the internal class version number.
*/
- public static int internalMinorClassVersion(int classVersion)
+ public static int internalMinorClassVersion(int internalClassVersion)
{
- return classVersion & 0xffff;
+ return internalClassVersion & 0xffff;
}
/**
* Returns the internal class version number.
- * @param classVersion the external class version number.
+ * @param externalClassVersion the external class version number.
* @return the internal class version number.
*/
- public static int internalClassVersion(String classVersion)
+ public static int internalClassVersion(String externalClassVersion)
{
return
- classVersion.equals(JavaConstants.CLASS_VERSION_1_0) ||
- classVersion.equals(JavaConstants.CLASS_VERSION_1_1) ? ClassConstants.CLASS_VERSION_1_0 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_2) ? ClassConstants.CLASS_VERSION_1_2 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_3) ? ClassConstants.CLASS_VERSION_1_3 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_4) ? ClassConstants.CLASS_VERSION_1_4 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_5_ALIAS) ||
- classVersion.equals(JavaConstants.CLASS_VERSION_1_5) ? ClassConstants.CLASS_VERSION_1_5 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_6_ALIAS) ||
- classVersion.equals(JavaConstants.CLASS_VERSION_1_6) ? ClassConstants.CLASS_VERSION_1_6 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_7_ALIAS) ||
- classVersion.equals(JavaConstants.CLASS_VERSION_1_7) ? ClassConstants.CLASS_VERSION_1_7 :
- classVersion.equals(JavaConstants.CLASS_VERSION_1_8_ALIAS) ||
- classVersion.equals(JavaConstants.CLASS_VERSION_1_8) ? ClassConstants.CLASS_VERSION_1_8 :
- 0;
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_0) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_1) ? ClassConstants.CLASS_VERSION_1_0 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_2) ? ClassConstants.CLASS_VERSION_1_2 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_3) ? ClassConstants.CLASS_VERSION_1_3 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_4) ? ClassConstants.CLASS_VERSION_1_4 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_5_ALIAS) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_5) ? ClassConstants.CLASS_VERSION_1_5 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_6_ALIAS) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_6) ? ClassConstants.CLASS_VERSION_1_6 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_7_ALIAS) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_7) ? ClassConstants.CLASS_VERSION_1_7 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_8_ALIAS) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_8) ? ClassConstants.CLASS_VERSION_1_8 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_9_ALIAS) ||
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_9) ? ClassConstants.CLASS_VERSION_1_9 :
+ externalClassVersion.equals(JavaConstants.CLASS_VERSION_10) ? ClassConstants.CLASS_VERSION_10 :
+ 0;
}
/**
* Returns the minor part of the given class version number.
- * @param classVersion the combined class version number.
+ * @param internalClassVersion the combined class version number.
* @return the minor part of the class version number.
*/
- public static String externalClassVersion(int classVersion)
+ public static String externalClassVersion(int internalClassVersion)
{
- switch (classVersion)
+ switch (internalClassVersion)
{
case ClassConstants.CLASS_VERSION_1_0: return JavaConstants.CLASS_VERSION_1_0;
case ClassConstants.CLASS_VERSION_1_2: return JavaConstants.CLASS_VERSION_1_2;
@@ -125,6 +128,8 @@ public static String externalClassVersion(int classVersion)
case ClassConstants.CLASS_VERSION_1_6: return JavaConstants.CLASS_VERSION_1_6;
case ClassConstants.CLASS_VERSION_1_7: return JavaConstants.CLASS_VERSION_1_7;
case ClassConstants.CLASS_VERSION_1_8: return JavaConstants.CLASS_VERSION_1_8;
+ case ClassConstants.CLASS_VERSION_1_9: return JavaConstants.CLASS_VERSION_1_9;
+ case ClassConstants.CLASS_VERSION_10: return JavaConstants.CLASS_VERSION_10;
default: return null;
}
}
@@ -132,20 +137,20 @@ public static String externalClassVersion(int classVersion)
/**
* Checks whether the given class version number is supported.
- * @param classVersion the combined class version number.
+ * @param internalClassVersion the combined class version number.
* @throws UnsupportedOperationException when the version is not supported.
*/
- public static void checkVersionNumbers(int classVersion) throws UnsupportedOperationException
+ public static void checkVersionNumbers(int internalClassVersion) throws UnsupportedOperationException
{
- if (classVersion < ClassConstants.CLASS_VERSION_1_0 ||
- classVersion > ClassConstants.CLASS_VERSION_1_8)
+ if (internalClassVersion < ClassConstants.CLASS_VERSION_1_0 ||
+ internalClassVersion > ClassConstants.CLASS_VERSION_10)
{
- throw new UnsupportedOperationException("Unsupported class version number ["+
- internalMajorClassVersion(classVersion)+"."+
- internalMinorClassVersion(classVersion)+"] (maximum "+
- ClassConstants.CLASS_VERSION_1_8_MAJOR+"."+
- ClassConstants.CLASS_VERSION_1_8_MINOR+", Java "+
- JavaConstants.CLASS_VERSION_1_8+")");
+ throw new UnsupportedOperationException("Unsupported version number ["+
+ internalMajorClassVersion(internalClassVersion)+"."+
+ internalMinorClassVersion(internalClassVersion)+"] (maximum "+
+ ClassConstants.CLASS_VERSION_10_MAJOR+"."+
+ ClassConstants.CLASS_VERSION_10_MINOR+", Java "+
+ JavaConstants.CLASS_VERSION_10+")");
}
}
@@ -300,6 +305,20 @@ public static boolean isInternalPrimitiveType(char internalType)
}
+ /**
+ * Returns whether the given internal type is a plain primitive type
+ * (not void).
+ * @param internalType the internal type,
+ * e.g. "I".
+ * @return true if the given type is a class type,
+ * false otherwise.
+ */
+ public static boolean isInternalPrimitiveType(String internalType)
+ {
+ return isInternalPrimitiveType(internalType.charAt(0));
+ }
+
+
/**
* Returns whether the given internal type is a primitive Category 2 type.
* @param internalType the internal type,
@@ -372,6 +391,30 @@ public static String internalArrayTypeFromClassName(String internalClassName,
}
+ /**
+ * Returns the internal array type of a given type, with a given number of
+ * additional dimensions.
+ * @param internalType the internal class name,
+ * e.g. "[Ljava/lang/Object;".
+ * @param dimensionDelta the number of additional array dimensions,
+ * e.g. 1.
+ * @return the internal array type of the array elements,
+ * e.g. "[[Ljava/lang/Object;".
+ */
+ public static String internalArrayTypeFromType(String internalType,
+ int dimensionDelta)
+ {
+ StringBuffer buffer = new StringBuffer(internalType.length() + dimensionDelta);
+
+ for (int dimension = 0; dimension < dimensionDelta; dimension++)
+ {
+ buffer.append(ClassConstants.TYPE_ARRAY);
+ }
+
+ return buffer.append(internalType).toString();
+ }
+
+
/**
* Returns the internal element type of a given internal array type.
* @param internalArrayType the internal array type,
@@ -384,7 +427,48 @@ public static String internalArrayTypeFromClassName(String internalClassName,
public static String internalTypeFromArrayType(String internalArrayType)
{
int index = internalArrayType.lastIndexOf(ClassConstants.TYPE_ARRAY);
- return internalArrayType.substring(index+1);
+ return internalArrayType.substring(index + 1);
+ }
+
+
+ /**
+ * Returns the internal class type (class name or array type) of a given
+ * internal type (including an array type). This is the type that can be
+ * stored in a class constant.
+ * @param internalType the internal class type,
+ * e.g. "[I",
+ * "[Ljava/lang/Object;", or
+ * "Ljava/lang/Object;".
+ * @return the internal class name,
+ * e.g. "[I",
+ * "[Ljava/lang/Object;", or
+ * "java/lang/Object".
+ */
+ public static String internalClassTypeFromType(String internalType)
+ {
+ return isInternalArrayType(internalType) ?
+ internalType :
+ internalClassNameFromClassType(internalType);
+ }
+
+
+ /**
+ * Returns the internal type of of a given class type (class name or array
+ * type). This is the type that can be stored in a class constant.
+ * @param internalType the internal class type,
+ * e.g. "[I",
+ * "[Ljava/lang/Object;", or
+ * "java/lang/Object".
+ * @return the internal class name,
+ * e.g. "[I",
+ * "[Ljava/lang/Object;", or
+ * "Ljava/lang/Object;".
+ */
+ public static String internalTypeFromClassType(String internalType)
+ {
+ return isInternalArrayType(internalType) ?
+ internalType :
+ internalTypeFromClassName(internalType);
}
@@ -435,11 +519,68 @@ public static String internalClassNameFromType(String internalClassType)
}
+ /**
+ * Returns the internal numeric (or void or array) class name corresponding
+ * to the given internal primitive type.
+ * @param internalPrimitiveType the internal class type,
+ * e.g. "I" or
+ * "V".
+ * @return the internal class name,
+ * e.g. "java/lang/Integer" or
+ * java/lang/Void.
+ */
+ public static String internalNumericClassNameFromPrimitiveType(char internalPrimitiveType)
+ {
+ switch (internalPrimitiveType)
+ {
+ case ClassConstants.TYPE_VOID: return ClassConstants.NAME_JAVA_LANG_VOID;
+ case ClassConstants.TYPE_BOOLEAN: return ClassConstants.NAME_JAVA_LANG_BOOLEAN;
+ case ClassConstants.TYPE_BYTE: return ClassConstants.NAME_JAVA_LANG_BYTE;
+ case ClassConstants.TYPE_CHAR: return ClassConstants.NAME_JAVA_LANG_CHARACTER;
+ case ClassConstants.TYPE_SHORT: return ClassConstants.NAME_JAVA_LANG_SHORT;
+ case ClassConstants.TYPE_INT: return ClassConstants.NAME_JAVA_LANG_INTEGER;
+ case ClassConstants.TYPE_LONG: return ClassConstants.NAME_JAVA_LANG_LONG;
+ case ClassConstants.TYPE_FLOAT: return ClassConstants.NAME_JAVA_LANG_FLOAT;
+ case ClassConstants.TYPE_DOUBLE: return ClassConstants.NAME_JAVA_LANG_DOUBLE;
+ case ClassConstants.TYPE_ARRAY: return ClassConstants.NAME_JAVA_LANG_REFLECT_ARRAY;
+ default:
+ throw new IllegalArgumentException("Unexpected primitive type ["+internalPrimitiveType+"]");
+ }
+ }
+
+
+ /**
+ * Returns the internal numeric (or void or array) class name corresponding
+ * to the given internal primitive type.
+ * @param internalPrimitiveClassName the internal class name,
+ * e.g. "java/lang/Integer" or
+ * java/lang/Void.
+ * @return the internal class type,
+ * e.g. "I" or
+ * "V".
+ */
+ public static char internalPrimitiveTypeFromNumericClassName(String internalPrimitiveClassName)
+ {
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_VOID)) return ClassConstants.TYPE_VOID;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_BOOLEAN)) return ClassConstants.TYPE_BOOLEAN;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_BYTE)) return ClassConstants.TYPE_BYTE;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_CHARACTER)) return ClassConstants.TYPE_CHAR;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_SHORT)) return ClassConstants.TYPE_SHORT;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_INTEGER)) return ClassConstants.TYPE_INT;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_LONG)) return ClassConstants.TYPE_LONG;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_FLOAT)) return ClassConstants.TYPE_FLOAT;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_DOUBLE)) return ClassConstants.TYPE_DOUBLE;
+ if (internalPrimitiveClassName.equals(ClassConstants.NAME_JAVA_LANG_REFLECT_ARRAY)) return ClassConstants.TYPE_ARRAY;
+
+ throw new IllegalArgumentException("Unexpected primitive class name ["+internalPrimitiveClassName+"]");
+ }
+
+
/**
* Returns whether the given method name refers to a class initializer or
* an instance initializer.
* @param internalMethodName the internal method name,
- * e.g. "<clinit>".
+ * e.g. "<clinit>".
* @return whether the method name refers to an initializer,
* e.g. true.
*/
@@ -473,7 +614,40 @@ public static String internalMethodReturnType(String internalMethodDescriptor)
*/
public static int internalMethodParameterCount(String internalMethodDescriptor)
{
- int counter = 0;
+ return internalMethodParameterCount(internalMethodDescriptor, true);
+ }
+
+
+ /**
+ * Returns the number of parameters of the given internal method descriptor.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "(ID)Z".
+ * @param accessFlags the access flags of the method,
+ * e.g. 0.
+ * @return the number of parameters,
+ * e.g. 3.
+ */
+ public static int internalMethodParameterCount(String internalMethodDescriptor,
+ int accessFlags)
+ {
+ return internalMethodParameterCount(internalMethodDescriptor,
+ (accessFlags & ClassConstants.ACC_STATIC) != 0);
+ }
+
+
+ /**
+ * Returns the number of parameters of the given internal method descriptor.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "(ID)Z".
+ * @param isStatic specifies whether the method is static,
+ * e.g. false.
+ * @return the number of parameters,
+ * e.g. 3.
+ */
+ public static int internalMethodParameterCount(String internalMethodDescriptor,
+ boolean isStatic)
+ {
+ int counter = isStatic ? 0 : 1;
int index = 1;
while (true)
@@ -712,10 +886,12 @@ public static int externalArrayTypeDimensionCount(String externalType)
/**
* Converts an internal type into an external type.
* @param internalType the internal type,
- * e.g. "[[Ljava/lang/Object;" or
+ * e.g. "Ljava/lang/Object;" or
+ * "[[Ljava/lang/Object;" or
* "[I".
* @return the external type,
- * e.g. "java.lang.Object[][]" or
+ * e.g. "java.lang.Object" or
+ * "java.lang.Object[][]" or
* "int[]".
*/
public static String externalType(String internalType)
@@ -759,6 +935,26 @@ public static String externalType(String internalType)
}
+ /**
+ * Converts an internal type into an external type, as expected by
+ * Class.forName.
+ * @param internalType the internal type,
+ * e.g. "Ljava/lang/Object;" or
+ * "[[Ljava/lang/Object;" or
+ * "[I".
+ * @return the external type,
+ * e.g. "java.lang.Object" or
+ * "[[Ljava.lang.Object;" or
+ * "[I".
+ */
+ public static String externalClassForNameType(String internalType)
+ {
+ return isInternalArrayType(internalType) ?
+ externalClassName(internalType) :
+ externalClassName(internalClassNameFromClassType(internalType));
+ }
+
+
/**
* Returns whether the given internal descriptor String represents a method
* descriptor.
@@ -862,6 +1058,34 @@ public static String internalMethodDescriptor(String externalReturnType,
}
+ /**
+ * Converts the given internal method return type and List of arguments to
+ * an internal method descriptor.
+ *
+ * @param internalReturnType the external method return type,
+ * e.g. "Z".
+ * @param internalArguments the external method arguments,
+ * e.g. { "I", "I" }.
+ * @return the internal method descriptor, e.g. "(II)Z".
+ */
+ public static String internalMethodDescriptorFromInternalTypes(String internalReturnType,
+ List internalArguments)
+ {
+ StringBuilder internalMethodDescriptor = new StringBuilder();
+ internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_OPEN);
+
+ for (String argument : internalArguments)
+ {
+ internalMethodDescriptor.append(argument);
+ }
+
+ internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_CLOSE);
+ internalMethodDescriptor.append(internalReturnType);
+
+ return internalMethodDescriptor.toString();
+ }
+
+
/**
* Converts an internal field description into an external full field description.
* @param accessFlags the access flags of the field.
@@ -963,7 +1187,7 @@ public static String externalClassAccessFlags(int accessFlags, String prefix)
{
string.append(prefix).append(JavaConstants.ACC_FINAL).append(' ');
}
- if ((accessFlags & ClassConstants.ACC_ANNOTATTION) != 0)
+ if ((accessFlags & ClassConstants.ACC_ANNOTATION) != 0)
{
string.append(prefix).append(JavaConstants.ACC_ANNOTATION);
}
@@ -983,6 +1207,10 @@ else if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0)
{
string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' ');
}
+ else if ((accessFlags & ClassConstants.ACC_MODULE) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_MODULE).append(' ');
+ }
return string.toString();
}
@@ -1194,6 +1422,190 @@ public static String externalMethodReturnType(String internalMethodDescriptor)
}
+ /**
+ * Converts internal module access flags into an external access
+ * description.
+ * @param accessFlags the module access flags.
+ * @return the external module access description,
+ * e.g. "open mandated ".
+ */
+ public static String externalModuleAccessFlags(int accessFlags)
+ {
+ return externalModuleAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal module access flags into an external access
+ * description.
+ * @param accessFlags the module access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external module access description,
+ * e.g. "final mandated ".
+ */
+ public static String externalModuleAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.ACC_OPEN) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_OPEN).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_MANDATED) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_MANDATED).append(' ');
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts internal module requires access flags into an external access
+ * description.
+ * @param accessFlags the module requires access flags.
+ * @return the external module requires access description,
+ * e.g. "static mandated ".
+ */
+ public static String externalRequiresAccessFlags(int accessFlags)
+ {
+ return externalRequiresAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal module requires access flags into an external access
+ * description.
+ * @param accessFlags the module requires access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external module requires access description,
+ * e.g. "static mandated ".
+ */
+ public static String externalRequiresAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.ACC_TRANSITIVE) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_TRANSITIVE).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_STATIC_PHASE) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_STATIC).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_MANDATED) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_MANDATED).append(' ');
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts internal module exports access flags into an external access
+ * description.
+ * @param accessFlags the module exports access flags.
+ * @return the external module exports access description,
+ * e.g. "synthetic mandated ".
+ */
+ public static String externalExportsAccessFlags(int accessFlags)
+ {
+ return externalExportsAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal module exports access flags into an external access
+ * description.
+ * @param accessFlags the module exports access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external module exports access description,
+ * e.g. "static mandated ".
+ */
+ public static String externalExportsAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_MANDATED) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_MANDATED).append(' ');
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts internal module opens access flags into an external access
+ * description.
+ * @param accessFlags the module opens access flags.
+ * @return the external module opens access description,
+ * e.g. "synthetic mandated ".
+ */
+ public static String externalOpensAccessFlags(int accessFlags)
+ {
+ return externalOpensAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal module opens access flags into an external access
+ * description.
+ * @param accessFlags the module opens access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external module opens access description,
+ * e.g. "static mandated ".
+ */
+ public static String externalOpensAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' ');
+ }
+ if ((accessFlags & ClassConstants.ACC_MANDATED) != 0)
+ {
+ string.append(prefix).append(JavaConstants.ACC_MANDATED).append(' ');
+ }
+
+ return string.toString();
+ }
+
+
/**
* Converts an internal class name, method name, and method descriptor to
* an external method return type and name.
diff --git a/src/proguard/classfile/util/DescriptorClassEnumeration.java b/core/src/proguard/classfile/util/DescriptorClassEnumeration.java
similarity index 99%
rename from src/proguard/classfile/util/DescriptorClassEnumeration.java
rename to core/src/proguard/classfile/util/DescriptorClassEnumeration.java
index 2be640c..3a820cb 100644
--- a/src/proguard/classfile/util/DescriptorClassEnumeration.java
+++ b/core/src/proguard/classfile/util/DescriptorClassEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/DynamicClassReferenceInitializer.java b/core/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
similarity index 99%
rename from src/proguard/classfile/util/DynamicClassReferenceInitializer.java
rename to core/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
index c7e1c9b..cb19543 100644
--- a/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
+++ b/core/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java b/core/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java
new file mode 100644
index 0000000..662037d
--- /dev/null
+++ b/core/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java
@@ -0,0 +1,971 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.util;
+
+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.visitor.*;
+import proguard.util.StringMatcher;
+
+/**
+ * This AttributeVisitor initializes any constant class member references of all
+ * code that it visits. It currently handles invocations of
+ * Class#get[Declared]{Field,Constructor,Method} and
+ * Atomic{Integer,Long,Reference}FieldUpdater.newUpdater
+ * with constant string arguments. It lets the corresponding string constants
+ * refer to their class members in the program class pool or in the library
+ * class pool. It may create new string constants and update the code, in order
+ * to avoid clashes between identically named class members.
+ *
+ * The class hierarchy and references must be initialized before using this
+ * visitor.
+ *
+ * @see ClassSuperHierarchyInitializer
+ * @see ClassReferenceInitializer
+ *
+ * @author Eric Lafortune
+ */
+public class DynamicMemberReferenceInitializer
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor,
+ MemberVisitor
+{
+ /*
+ private static boolean DEBUG = true;
+ /*/
+ private static final boolean DEBUG = false;
+ //*/
+
+ private static final int CLASS_INDEX = InstructionSequenceMatcher.A;
+ private static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.B;
+ private static final int MEMBER_TYPE_INDEX = InstructionSequenceMatcher.C;
+
+
+ private final ClassPool programClassPool;
+ private final ClassPool libraryClassPool;
+ private final WarningPrinter notePrinter;
+ private final StringMatcher noteFieldExceptionMatcher;
+ private final StringMatcher noteMethodExceptionMatcher;
+
+
+ // Retrieving fields or methods from known, constant classes.
+ private final InstructionSequenceMatcher knownItegerUpdaterMatcher;
+ private final InstructionSequenceMatcher knownLongUpdaterMatcher;
+ private final InstructionSequenceMatcher knownReferenceUpdaterMatcher;
+
+ // Retrieving fields or methods from unknown classes.
+ private final InstructionSequenceMatcher unknownIntegerUpdaterMatcher;
+ private final InstructionSequenceMatcher unknownLongUpdaterMatcher;
+ private final InstructionSequenceMatcher unknownReferenceUpdaterMatcher;
+
+ private final MyDynamicMemberFinder dynamicMemberFinder = new MyDynamicMemberFinder();
+
+ private final MemberFinder memberFinder = new MemberFinder(true);
+ private final MemberFinder declaredMemberFinder = new MemberFinder(false);
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+
+
+ // Fields acting as parameters for the visitors.
+ private Clazz referencedClass;
+
+
+ /**
+ * Creates a new DynamicMemberReferenceInitializer.
+ */
+ public DynamicMemberReferenceInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool,
+ WarningPrinter notePrinter,
+ StringMatcher noteFieldExceptionMatcher,
+ StringMatcher noteMethodExceptionMatcher)
+ {
+ this.programClassPool = programClassPool;
+ this.libraryClassPool = libraryClassPool;
+ this.notePrinter = notePrinter;
+ this.noteFieldExceptionMatcher = noteFieldExceptionMatcher;
+ this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
+
+ // Create the instruction sequences and matchers.
+ InstructionSequenceBuilder builder =
+ new InstructionSequenceBuilder(programClassPool, libraryClassPool);
+
+ // AtomicIntegerFieldUpdater.newUpdater(A.class, "someField").
+ Instruction[] knownItegerUpdaterInstructions = builder
+ .ldc_(CLASS_INDEX)
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_INTEGER_UPDATER)
+ .instructions();
+
+ // AtomicLongFieldUpdater.newUpdater(A.class, "someField").
+ Instruction[] knownLongUpdaterInstructions = builder
+ .ldc_(CLASS_INDEX)
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_LONG_UPDATER)
+ .instructions();
+
+ // AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField").
+ Instruction[] knownReferenceUpdaterInstructions = builder
+ .ldc_(CLASS_INDEX)
+ .ldc_(MEMBER_TYPE_INDEX)
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_REFERENCE_UPDATER)
+ .instructions();
+
+ // AtomicIntegerFieldUpdater.newUpdater(..., "someField").
+ Instruction[] unknownIntegerUpdaterInstructions = builder
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_INTEGER_UPDATER)
+ .instructions();
+
+ // AtomicLongFieldUpdater.newUpdater(..., "someField").
+ Instruction[] unknownLongUpdaterInstructions = builder
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_LONG_UPDATER)
+ .instructions();
+
+ // AtomicReferenceFieldUpdater.newUpdater(..., "someField").
+ final Instruction[] unknownReferenceUpdaterInstructions = builder
+ .ldc_(MEMBER_NAME_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER,
+ ClassConstants.METHOD_NAME_NEW_UPDATER,
+ ClassConstants.METHOD_TYPE_NEW_REFERENCE_UPDATER)
+ .instructions();
+
+ Constant[] constants = builder.constants();
+
+ knownItegerUpdaterMatcher = new InstructionSequenceMatcher(constants, knownItegerUpdaterInstructions);
+ knownLongUpdaterMatcher = new InstructionSequenceMatcher(constants, knownLongUpdaterInstructions);
+ knownReferenceUpdaterMatcher = new InstructionSequenceMatcher(constants, knownReferenceUpdaterInstructions);
+ unknownIntegerUpdaterMatcher = new InstructionSequenceMatcher(constants, unknownIntegerUpdaterInstructions);
+ unknownLongUpdaterMatcher = new InstructionSequenceMatcher(constants, unknownLongUpdaterInstructions);
+ unknownReferenceUpdaterMatcher = new InstructionSequenceMatcher(constants, unknownReferenceUpdaterInstructions);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ if (DEBUG)
+ {
+ System.out.println("DynamicMemberReferenceInitializer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ }
+
+ // Set up the code attribute editor.
+ codeAttributeEditor.reset(codeAttribute.u4codeLength);
+
+ // Find the dynamic class member references.
+ codeAttribute.instructionsAccept(clazz, method, this);
+
+ // Apply any changes to the code.
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Try to match get[Declared]{Field,Constructor,Method} constructs.
+ instruction.accept(clazz, method, codeAttribute, offset, dynamicMemberFinder);
+
+ // Try to match the AtomicIntegerFieldUpdater.newUpdater(
+ // SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ knownItegerUpdaterMatcher,
+ unknownIntegerUpdaterMatcher, true, false, false,
+ "" + ClassConstants.TYPE_INT);
+
+ // Try to match the AtomicLongFieldUpdater.newUpdater(
+ // SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ knownLongUpdaterMatcher,
+ unknownLongUpdaterMatcher, true, false, false,
+ "" + ClassConstants.TYPE_LONG);
+
+ // Try to match the AtomicReferenceFieldUpdater.newUpdater(
+ // SomeClass.class, SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ knownReferenceUpdaterMatcher,
+ unknownReferenceUpdaterMatcher, true, false, false,
+ null);
+ }
+
+
+ /**
+ * Tries to match the next instruction and fills out the string constant
+ * or prints out a note accordingly.
+ */
+ private void matchGetMember(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ Instruction instruction,
+ InstructionSequenceMatcher constantSequenceMatcher,
+ InstructionSequenceMatcher variableSequenceMatcher,
+ boolean isField,
+ boolean isConstructor,
+ boolean isDeclared,
+ String memberDescriptor)
+ {
+ if (constantSequenceMatcher != null)
+ {
+ // Try to match the next instruction in the constant sequence.
+ instruction.accept(clazz, method, codeAttribute, offset,
+ constantSequenceMatcher);
+
+ // Did we find a match to fill out the string constant?
+ if (constantSequenceMatcher.isMatching())
+ {
+ // Retrieve the offset of the instruction that loads the member
+ // name. It's currently always the last but one instruction.
+ int memberNameInstructionOffset =
+ constantSequenceMatcher.matchedInstructionOffset(
+ constantSequenceMatcher.instructionCount() - 2);
+
+ // Get the member's class.
+ int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX);
+ clazz.constantPoolEntryAccept(classIndex, this);
+
+ if (referencedClass != null)
+ {
+ // Get the field's type, if applicable.
+ int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_TYPE_INDEX);
+ if (typeClassIndex > 0)
+ {
+ memberDescriptor =
+ ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex));
+ }
+
+ // Get the member's name.
+ int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
+ String memberName = clazz.getStringString(memberNameIndex);
+
+ // Create a new string constant and update the instruction.
+ initializeDynamicMemberReference(clazz,
+ memberNameInstructionOffset,
+ referencedClass,
+ memberName,
+ memberDescriptor,
+ isField,
+ isConstructor,
+ isDeclared);
+ }
+
+ // Don't look for the dynamic construct.
+ variableSequenceMatcher.reset();
+ }
+ }
+
+ // Try to match the next instruction in the variable sequence.
+ instruction.accept(clazz, method, codeAttribute, offset,
+ variableSequenceMatcher);
+
+ // Did we find a match to print out a note?
+ if (variableSequenceMatcher.isMatching())
+ {
+ int memberNameIndex = variableSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
+ String memberName = clazz.getStringString(memberNameIndex);
+
+ // Print out a note about the dynamic invocation.
+ printDynamicMemberAccessNote(clazz,
+ memberName,
+ memberDescriptor,
+ isField,
+ isConstructor,
+ isDeclared);
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Remember the referenced class.
+ referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
+ null :
+ classConstant.referencedClass;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Creates a new string constant for the specified referenced class member,
+ * and updates the instruction that loads it.
+ */
+ private void initializeDynamicMemberReference(Clazz clazz,
+ int memberNameInstructionOffset,
+ Clazz referencedClass,
+ String memberName,
+ String memberDescriptor,
+ boolean isField,
+ boolean isConstructor,
+ boolean isDeclared)
+ {
+ // See if we can find the referenced class member locally, or
+ // somewhere in the hierarchy.
+ MemberFinder referencedMemberFinder = isDeclared ?
+ declaredMemberFinder :
+ memberFinder;
+
+ Member referencedMember =
+ referencedMemberFinder.findMember(referencedClass,
+ memberName,
+ memberDescriptor,
+ isField);
+
+ if (DEBUG)
+ {
+ System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+memberName+"]: in ["+referencedClass+"] -> ["+referencedMember+"]");
+ }
+
+ if (referencedMember != null)
+ {
+ if (!isDeclared)
+ {
+ referencedClass = referencedMemberFinder.correspondingClass();
+ }
+
+ // Update the string constant.
+ //stringConstant.referencedMember = referencedMember;
+ //stringConstant.referencedClass = referencedClass;
+
+ // Create a new string constant with the found references.
+ int stringConstantIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addStringConstant(memberName,
+ referencedClass,
+ referencedMember);
+
+ // Update the instruction.
+ codeAttributeEditor.replaceInstruction(memberNameInstructionOffset,
+ new ConstantInstruction(InstructionConstants.OP_LDC,
+ stringConstantIndex));
+ }
+ }
+
+
+ /**
+ * Prints out a note on the matched dynamic invocation of a constructor.
+ */
+ private void printDynamicConstructorAccessNote(Clazz clazz,
+ Clazz referencedClass,
+ String memberDescriptor,
+ boolean isDeclared)
+ {
+ // Print out a note about the dynamic invocation.
+ if (notePrinter != null &&
+ notePrinter.accepts(clazz.getName()))
+ {
+ // Is the class member name in the list of exceptions?
+ if (noteMethodExceptionMatcher == null ||
+ !noteMethodExceptionMatcher.matches(ClassConstants.METHOD_NAME_INIT))
+ {
+ // Print out the actual note.
+ notePrinter.print(clazz.getName(),
+ "Note: " +
+ ClassUtil.externalClassName(clazz.getName()) +
+ " retrieves a " +
+ (isDeclared ? "declared " : "") +
+ "constructor '" +
+ ClassConstants.METHOD_NAME_INIT +
+ JavaConstants.METHOD_ARGUMENTS_OPEN +
+ ClassUtil.externalMethodArguments(memberDescriptor) +
+ JavaConstants.METHOD_ARGUMENTS_CLOSE +
+ "' dynamically");
+
+ // Print out notes about potential candidates.
+ ClassVisitor classVisitor =
+ new AllMethodVisitor(
+ new MemberNameFilter(ClassConstants.METHOD_NAME_INIT,
+ new MemberDescriptorFilter(memberDescriptor, this)));
+
+ if (referencedClass != null)
+ {
+ referencedClass.hierarchyAccept(true, !isDeclared, false, false,
+ classVisitor);
+ }
+ else
+ {
+ programClassPool.classesAcceptAlphabetically(classVisitor);
+ libraryClassPool.classesAcceptAlphabetically(classVisitor);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Prints out a note on the matched dynamic access to a class member.
+ */
+ private void printDynamicMemberAccessNote(Clazz clazz,
+ String memberName,
+ String memberDescriptor,
+ boolean isField,
+ boolean isConstructor,
+ boolean isDeclared)
+ {
+ // Print out a note about the dynamic invocation.
+ if (notePrinter != null &&
+ notePrinter.accepts(clazz.getName()))
+ {
+ // Is the class member name in the list of exceptions?
+ StringMatcher noteExceptionMatcher = isField ?
+ noteFieldExceptionMatcher :
+ noteMethodExceptionMatcher;
+
+ if (noteExceptionMatcher == null ||
+ !noteExceptionMatcher.matches(memberName))
+ {
+ // Compose the external member name and partial descriptor.
+ String externalMemberDescription = memberName;
+
+ if (!isField)
+ {
+ externalMemberDescription +=
+ JavaConstants.METHOD_ARGUMENTS_OPEN +
+ ClassUtil.externalMethodArguments(memberDescriptor) +
+ JavaConstants.METHOD_ARGUMENTS_CLOSE;
+ }
+
+ // Print out the actual note.
+ notePrinter.print(clazz.getName(),
+ "Note: " +
+ ClassUtil.externalClassName(clazz.getName()) +
+ " accesses a " +
+ (isDeclared ? "declared " : "") +
+ (isField ? "field" :
+ isConstructor ? "constructor" :
+ "method") +
+ " '" +
+ externalMemberDescription +
+ "' dynamically");
+
+ // Print out notes about potential candidates.
+ ClassVisitor classVisitor;
+
+ if (isField)
+ {
+ classVisitor = memberDescriptor == null ?
+ new AllFieldVisitor(
+ new MemberNameFilter(memberName, this)) :
+ new AllFieldVisitor(
+ new MemberNameFilter(memberName,
+ new MemberDescriptorFilter(memberDescriptor, this)));
+ }
+ else
+ {
+ classVisitor =
+ new AllMethodVisitor(
+ new MemberNameFilter(memberName,
+ new MemberDescriptorFilter(memberDescriptor, this)));
+ }
+
+ programClassPool.classesAcceptAlphabetically(classVisitor);
+ libraryClassPool.classesAcceptAlphabetically(classVisitor);
+ }
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ if (notePrinter.accepts(programClass.getName()))
+ {
+ System.out.println(" Maybe this is program field '" +
+ ClassUtil.externalFullClassDescription(0, programClass.getName()) +
+ " { " +
+ ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) +
+ "; }'");
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (notePrinter.accepts(programClass.getName()))
+ {
+ System.out.println(" Maybe this is program method '" +
+ ClassUtil.externalFullClassDescription(0, programClass.getName()) +
+ " { " +
+ ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
+ "; }'");
+ }
+ }
+
+
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
+ {
+ if (notePrinter.accepts(libraryClass.getName()))
+ {
+ System.out.println(" Maybe this is library field '" +
+ ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
+ " { " +
+ ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) +
+ "; }'");
+ }
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ if (notePrinter.accepts(libraryClass.getName()))
+ {
+ System.out.println(" Maybe this is library method '" +
+ ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
+ " { " +
+ ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
+ "; }'");
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor finds get[Declared]{Field,Constructor,Method}
+ * constructs with constant arguments. It then makes sure the class member
+ * name strings point to the class members, or it prints out notes about the
+ * possible alternatives.
+ */
+ private class MyDynamicMemberFinder
+ extends SimplifiedVisitor
+ implements InstructionVisitor,
+ ConstantVisitor
+ {
+ private static final int LABEL_START = 0; // ldc SomeClass.class
+ private static final int LABEL_LOAD_MEMBER_NAME = 1; // [ ldc "someMethod"/"someField" ]
+ private static final int LABEL_LOAD_CLASS_ARRAY_SIZE = 2; // [ sipush #someParameterCount
+ private static final int LABEL_CREATE_CLASS_ARRAY = 3; // anewarray java/lang/Class
+ private static final int LABEL_DUP_CLASS_ARRAY = 4; // [ dup
+ private static final int LABEL_LOAD_PARAMETER_INDEX = 5; // sipush #someParameterIndex
+ private static final int LABEL_LOAD_PARAMETER_TYPE = 6; // ldc SomeParameterClass.class / getstatic java/lang/SomePrimitive.TYPE
+ private static final int LABEL_STORE_PARAMETER = 7; // aastore ]* ] / aconst_null
+ private static final int LABEL_GET_MEMBER = 8; // invokevirtual java/lang/Class.getField/getConstructor/getMethod
+
+ private int label;
+ private int instructionOffset;
+ private int memberNameInstructionOffset;
+ private Clazz referencedClass;
+ private String memberName;
+ private int parameterCount;
+ private int parameterIndex;
+ private StringBuffer parameterTypes = new StringBuffer();
+
+
+ public void reset()
+ {
+ label = LABEL_START;
+ referencedClass = null;
+ memberName = null;
+ parameterTypes.setLength(0);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ if (DEBUG)
+ {
+ System.out.println("Label ["+label+"] A "+instruction.toString(offset));
+ }
+
+ reset();
+ }
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (DEBUG)
+ {
+ System.out.println("Label ["+label+"] S "+simpleInstruction.toString(offset));
+ }
+
+ int transition = label | simpleInstruction.canonicalOpcode() << 8;
+
+ switch (transition)
+ {
+ case LABEL_START | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_LOAD_MEMBER_NAME | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_CREATE_CLASS_ARRAY | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_DUP_CLASS_ARRAY | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_LOAD_PARAMETER_TYPE | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_STORE_PARAMETER | InstructionConstants.OP_ICONST_0 << 8:
+ case LABEL_GET_MEMBER | InstructionConstants.OP_ICONST_0 << 8:
+ // This could be the start of creating a class array.
+ reset();
+ parameterCount = simpleInstruction.constant;
+ label = LABEL_CREATE_CLASS_ARRAY;
+ break;
+
+ case LABEL_LOAD_CLASS_ARRAY_SIZE | InstructionConstants.OP_ICONST_0 << 8:
+ parameterCount = simpleInstruction.constant;
+ label = LABEL_CREATE_CLASS_ARRAY;
+ break;
+
+ case LABEL_LOAD_CLASS_ARRAY_SIZE | InstructionConstants.OP_ACONST_NULL << 8:
+ parameterCount = 0;
+ label = LABEL_GET_MEMBER;
+ break;
+
+ case LABEL_DUP_CLASS_ARRAY | InstructionConstants.OP_DUP << 8:
+ label = LABEL_LOAD_PARAMETER_INDEX;
+ break;
+
+ case LABEL_LOAD_PARAMETER_INDEX | InstructionConstants.OP_ICONST_0 << 8:
+ // Is it pushing the expected parameter index?
+ if (parameterIndex == simpleInstruction.constant)
+ {
+ label = LABEL_LOAD_PARAMETER_TYPE;
+ }
+ else
+ {
+ // This could be the start of creating a class array.
+ reset();
+ parameterCount = simpleInstruction.constant;
+ label = LABEL_CREATE_CLASS_ARRAY;
+ }
+ break;
+
+ case LABEL_STORE_PARAMETER | InstructionConstants.OP_AASTORE << 8:
+ // Are we still expecting more parameters?
+ label = ++parameterIndex < parameterCount ?
+ LABEL_DUP_CLASS_ARRAY :
+ LABEL_GET_MEMBER;
+ break;
+
+ default:
+ reset();
+ break;
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ if (DEBUG)
+ {
+ System.out.println("Label ["+label+"] C "+constantInstruction.toString(offset));
+ }
+
+ // Let the constant figure out the transition.
+ switch (constantInstruction.canonicalOpcode())
+ {
+ case InstructionConstants.OP_LDC:
+ instructionOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ case InstructionConstants.OP_ANEWARRAY:
+ if (label == LABEL_CREATE_CLASS_ARRAY)
+ {
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
+ else
+ {
+ reset();
+ }
+ break;
+
+ default:
+ reset();
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant)
+ {
+ reset();
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Argument of ldc or anewarray instruction.
+ switch (label)
+ {
+ case LABEL_START:
+ referencedClass = classConstant.referencedClass;
+
+ label = LABEL_LOAD_MEMBER_NAME;
+ break;
+
+ case LABEL_CREATE_CLASS_ARRAY:
+ if (classConstant.getName(clazz).equals(ClassConstants.NAME_JAVA_LANG_CLASS))
+ {
+ parameterIndex = 0;
+ label = parameterCount > 0 ?
+ LABEL_DUP_CLASS_ARRAY :
+ LABEL_GET_MEMBER;
+ }
+ else
+ {
+ referencedClass = classConstant.referencedClass;
+
+ label = LABEL_LOAD_MEMBER_NAME;
+ }
+ break;
+
+ case LABEL_LOAD_PARAMETER_TYPE:
+ String parameterType =
+ ClassUtil.internalTypeFromClassType(classConstant.getName(clazz));
+
+ parameterTypes.append(parameterType);
+
+ label = LABEL_STORE_PARAMETER;
+ break;
+
+ default:
+ // For other states, we'll treat this as a potential
+ // initial class name.
+ referencedClass = classConstant.referencedClass;
+
+ label = LABEL_LOAD_MEMBER_NAME;
+ break;
+ }
+ }
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ // Argument of ldc instruction.
+ switch (label)
+ {
+ case LABEL_LOAD_MEMBER_NAME:
+ break;
+
+ default:
+ // For other states, we'll treat this as a potential
+ // initial method name, without a known class.
+ referencedClass = null;
+ break;
+ }
+
+ // Whatever state, we'll treat this as a potential method name.
+ memberNameInstructionOffset = instructionOffset;
+ memberName = stringConstant.getString(clazz);
+
+ label = LABEL_LOAD_CLASS_ARRAY_SIZE;
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ // Argument of getstatic instruction.
+ switch (label)
+ {
+ case LABEL_LOAD_PARAMETER_TYPE:
+ String className = fieldrefConstant.getClassName(clazz);
+ String fieldName = fieldrefConstant.getName(clazz);
+ String fieldType = fieldrefConstant.getType(clazz);
+
+ if (className.startsWith(ClassConstants.PACKAGE_JAVA_LANG) &&
+ fieldName.equals(ClassConstants.FIELD_NAME_TYPE) &&
+ fieldType.equals(ClassConstants.FIELD_TYPE_TYPE))
+ {
+ char parameterType =
+ ClassUtil.internalPrimitiveTypeFromNumericClassName(className);
+
+ parameterTypes.append(parameterType);
+
+ label = LABEL_STORE_PARAMETER;
+ }
+ else
+ {
+ reset();
+ }
+ break;
+
+ default:
+ reset();
+ break;
+ }
+ }
+
+
+ public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ {
+ // Argument of invokevirtual instruction.
+ String className = methodrefConstant.getClassName(clazz);
+
+ if (className.equals(ClassConstants.NAME_JAVA_LANG_CLASS))
+ {
+ String methodName = methodrefConstant.getName(clazz);
+ String methodType = methodrefConstant.getType(clazz);
+
+ if (label == LABEL_LOAD_CLASS_ARRAY_SIZE &&
+ methodType.equals(ClassConstants.METHOD_TYPE_CLASS_GET_FIELD) &&
+ memberName != null)
+ {
+ if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_FIELD))
+ {
+ resolveMemberString(clazz, true, false, false);
+ }
+ else if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_DECLARED_FIELD))
+ {
+ resolveMemberString(clazz, true, false, true);
+ }
+ else
+ {
+ reset();
+ }
+ }
+ else if (label == LABEL_GET_MEMBER &&
+ methodType.equals(ClassConstants.METHOD_TYPE_CLASS_GET_CONSTRUCTOR))
+ {
+ if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_CONSTRUCTOR))
+ {
+ resolveMemberString(clazz, false, true, false);
+ }
+ else if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_DECLARED_CONSTRUCTOR))
+ {
+ resolveMemberString(clazz, false, true, true);
+ }
+ else
+ {
+ reset();
+ }
+ }
+ else if (label == LABEL_GET_MEMBER &&
+ methodType.equals(ClassConstants.METHOD_TYPE_CLASS_GET_METHOD) &&
+ memberName != null)
+ {
+ if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_METHOD))
+ {
+ resolveMemberString(clazz, false, false, false);
+ }
+ else if (methodName.equals(ClassConstants.METHOD_NAME_CLASS_GET_DECLARED_METHOD))
+ {
+ resolveMemberString(clazz, false, false, true);
+ }
+ else
+ {
+ reset();
+ }
+ }
+ else
+ {
+ reset();
+ }
+ }
+ else
+ {
+ reset();
+ }
+ }
+
+
+ /**
+ * Links the referenced class member in the string, or prints out
+ * notes about the possible alternatives.
+ */
+ private void resolveMemberString(Clazz clazz,
+ boolean isField,
+ boolean isConstructor,
+ boolean isDeclared)
+ {
+ String memberDescriptor = isField ?
+ null :
+ ClassConstants.METHOD_ARGUMENTS_OPEN +
+ parameterTypes.toString() +
+ ClassConstants.METHOD_ARGUMENTS_CLOSE +
+ "L***;";
+
+ if (DEBUG)
+ {
+ System.out.println("DynamicMemberReferenceInitializer: found member access");
+ System.out.println(" isField = "+isField);
+ System.out.println(" isConstructor = "+isConstructor);
+ System.out.println(" isDeclared = "+isDeclared);
+ System.out.println(" referenced class = "+(referencedClass == null ? "(none)" : "["+referencedClass.getName()+"]"));
+ System.out.println(" member name = "+(memberName == null ? "(none)" : "["+memberName+"]"));
+ System.out.println(" member descriptor = "+(memberDescriptor == null ? "(none)" : "["+memberDescriptor+"]"));
+ }
+
+ if (referencedClass != null)
+ {
+ if (isConstructor)
+ {
+ // We currently can't fill out some reference to a
+ // constructor. Just print out notes instead.
+ printDynamicConstructorAccessNote(clazz,
+ referencedClass,
+ memberDescriptor,
+ isDeclared);
+ }
+ else
+ {
+ // Create a new string constant and update the instruction.
+ initializeDynamicMemberReference(clazz,
+ memberNameInstructionOffset,
+ referencedClass,
+ memberName,
+ memberDescriptor,
+ isField,
+ isConstructor,
+ isDeclared);
+ }
+ }
+ else
+ {
+ // Print out notes about the method in some unknown class.
+ printDynamicMemberAccessNote(clazz,
+ isConstructor ?
+ ClassConstants.METHOD_NAME_INIT :
+ memberName,
+ memberDescriptor,
+ isField,
+ isConstructor,
+ isDeclared);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/util/EnumFieldReferenceInitializer.java b/core/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
similarity index 99%
rename from src/proguard/classfile/util/EnumFieldReferenceInitializer.java
rename to core/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
index a633d43..e574a2a 100644
--- a/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
+++ b/core/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/ExternalTypeEnumeration.java b/core/src/proguard/classfile/util/ExternalTypeEnumeration.java
similarity index 98%
rename from src/proguard/classfile/util/ExternalTypeEnumeration.java
rename to core/src/proguard/classfile/util/ExternalTypeEnumeration.java
index 0575a7b..1dfe8db 100644
--- a/src/proguard/classfile/util/ExternalTypeEnumeration.java
+++ b/core/src/proguard/classfile/util/ExternalTypeEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/InstructionSequenceMatcher.java b/core/src/proguard/classfile/util/InstructionSequenceMatcher.java
similarity index 84%
rename from src/proguard/classfile/util/InstructionSequenceMatcher.java
rename to core/src/proguard/classfile/util/InstructionSequenceMatcher.java
index 22aadfa..da59455 100644
--- a/src/proguard/classfile/util/InstructionSequenceMatcher.java
+++ b/core/src/proguard/classfile/util/InstructionSequenceMatcher.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -45,8 +45,8 @@ public class InstructionSequenceMatcher
private static final boolean DEBUG = false;
private static final boolean DEBUG_MORE = false;
/*/
- public static boolean DEBUG = true;
- public static boolean DEBUG_MORE = true;
+ public static boolean DEBUG = System.getProperty("ism") != null;
+ public static boolean DEBUG_MORE = System.getProperty("ismm") != null;
//*/
public static final int X = 0x40000000;
@@ -57,24 +57,38 @@ public class InstructionSequenceMatcher
public static final int B = 0x40000004;
public static final int C = 0x40000005;
public static final int D = 0x40000006;
-
-
- private final Constant[] patternConstants;
- private final Instruction[] patternInstructions;
+ public static final int E = 0x40000007;
+ public static final int F = 0x40000008;
+ public static final int G = 0x40000009;
+ public static final int H = 0x4000000a;
+ public static final int I = 0x4000000b;
+ public static final int J = 0x4000000c;
+ public static final int K = 0x4000000d;
+ public static final int L = 0x4000000e;
+ public static final int M = 0x4000000f;
+ public static final int N = 0x40000010;
+ public static final int O = 0x40000011;
+ public static final int P = 0x40000012;
+ public static final int Q = 0x40000013;
+ public static final int R = 0x40000014;
+
+
+ protected final Constant[] patternConstants;
+ protected final Instruction[] patternInstructions;
private boolean matching;
private int patternInstructionIndex;
private final int[] matchedInstructionOffsets;
private int matchedArgumentFlags;
- private final int[] matchedArguments = new int[7];
+ private final int[] matchedArguments = new int[21];
private final long[] matchedConstantFlags;
private final int[] matchedConstantIndices;
private int constantFlags;
private int previousConstantFlags;
// Fields acting as a parameter and a return value for visitor methods.
- private Constant patternConstant;
- private boolean matchingConstant;
+ protected Constant patternConstant;
+ protected boolean matchingConstant;
/**
@@ -404,6 +418,20 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ //PrimitiveArrayConstant primitiveArrayPatternConstant = (PrimitiveArrayConstant)patternConstant;
+ //
+ //// Compare the primitive array values.
+ //matchingConstant =
+ // primitiveArrayConstant.getLength() == primitiveArrayPatternConstant.getLength() &&
+ // ArrayUtil.equal(primitiveArrayConstant.getValues(),
+ // primitiveArrayPatternConstant.getValues(),
+ // primitiveArrayPatternConstant.getLength());
+ throw new UnsupportedOperationException();
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
StringConstant stringPatternConstant = (StringConstant)patternConstant;
@@ -511,8 +539,8 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
// Small utility methods.
- private boolean matchingOpcodes(Instruction instruction1,
- Instruction instruction2)
+ protected boolean matchingOpcodes(Instruction instruction1,
+ Instruction instruction2)
{
// Check the opcode.
return instruction1.opcode == instruction2.opcode ||
@@ -520,8 +548,8 @@ private boolean matchingOpcodes(Instruction instruction1,
}
- private boolean matchingArguments(int argument1,
- int argument2)
+ protected boolean matchingArguments(int argument1,
+ int argument2)
{
int argumentIndex = argument2 - X;
if (argumentIndex < 0)
@@ -566,8 +594,8 @@ private boolean isMatchingArgumentIndex(int argumentIndex)
}
- private boolean matchingArguments(int[] arguments1,
- int[] arguments2)
+ protected boolean matchingArguments(int[] arguments1,
+ int[] arguments2)
{
if (arguments1.length != arguments2.length)
{
@@ -586,9 +614,9 @@ private boolean matchingArguments(int[] arguments1,
}
- private boolean matchingConstantIndices(Clazz clazz,
- int constantIndex1,
- int constantIndex2)
+ protected boolean matchingConstantIndices(Clazz clazz,
+ int constantIndex1,
+ int constantIndex2)
{
if (constantIndex2 >= X)
{
@@ -646,9 +674,9 @@ private boolean isMatchingConstantIndex(int constantIndex)
}
- private boolean matchingBranchOffsets(int offset,
- int branchOffset1,
- int branchOffset2)
+ protected boolean matchingBranchOffsets(int offset,
+ int branchOffset1,
+ int branchOffset2)
{
int argumentIndex = branchOffset2 - X;
if (argumentIndex < 0)
@@ -671,9 +699,9 @@ else if (!isMatchingArgumentIndex(argumentIndex))
}
- private boolean matchingJumpOffsets(int offset,
- int[] jumpOffsets1,
- int[] jumpOffsets2)
+ protected boolean matchingJumpOffsets(int offset,
+ int[] jumpOffsets1,
+ int[] jumpOffsets2)
{
if (jumpOffsets1.length != jumpOffsets2.length)
{
@@ -703,7 +731,7 @@ private void checkMatch(boolean condition,
{
if (DEBUG_MORE)
{
- System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+patternInstructions[patternInstructionIndex].toString(patternInstructionIndex)+(condition?"\t== ":"\t ")+instruction.toString(offset));
+ System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+instruction.toString(offset)+(condition?"\t== ":"\t ")+patternInstructions[patternInstructionIndex].toString(patternInstructionIndex));
}
// Did the instruction match?
@@ -720,6 +748,9 @@ private void checkMatch(boolean condition,
if (matching)
{
+ // Allow subclasses to perform a final check on additional constraints.
+ matching &= finalMatch(clazz, method, codeAttribute, offset, instruction);
+
if (DEBUG)
{
System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
@@ -727,6 +758,22 @@ private void checkMatch(boolean condition,
{
System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedInstructionOffsets[index]).toString(matchedInstructionOffsets[index]));
}
+
+ for (int index = 0; index < matchedArguments.length; index++)
+ {
+ if ((matchedArgumentFlags & (1 << index)) != 0)
+ {
+ System.out.println(" Arg #"+index+": "+matchedArguments[index]);
+ }
+ }
+
+ for (int index = 0; index < matchedConstantIndices.length; index++)
+ {
+ if (isMatchingConstantIndex(index))
+ {
+ System.out.println(" Constant #"+index+": "+matchedConstantIndices[index]);
+ }
+ }
}
// Start matching from the first instruction again next time.
@@ -751,4 +798,27 @@ private void checkMatch(boolean condition,
}
}
}
+
+
+ /**
+ * Performs a final check on the candidate sequence to match,
+ * after the pattern has been successfully fully matched with the
+ * sequence. Subclasses may override this method to implement
+ * additional constraints on the matched sequences.
+ *
+ * @param clazz
+ * @param method
+ * @param codeAttribute
+ * @param offset
+ * @param instruction
+ * @return
+ */
+ protected boolean finalMatch(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ Instruction instruction )
+ {
+ return true;
+ }
}
diff --git a/src/proguard/classfile/util/InternalTypeEnumeration.java b/core/src/proguard/classfile/util/InternalTypeEnumeration.java
similarity index 99%
rename from src/proguard/classfile/util/InternalTypeEnumeration.java
rename to core/src/proguard/classfile/util/InternalTypeEnumeration.java
index d1a41d9..70c9898 100644
--- a/src/proguard/classfile/util/InternalTypeEnumeration.java
+++ b/core/src/proguard/classfile/util/InternalTypeEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/MemberFinder.java b/core/src/proguard/classfile/util/MemberFinder.java
similarity index 61%
rename from src/proguard/classfile/util/MemberFinder.java
rename to core/src/proguard/classfile/util/MemberFinder.java
index d6eaa4a..32db267 100644
--- a/src/proguard/classfile/util/MemberFinder.java
+++ b/core/src/proguard/classfile/util/MemberFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,13 +36,46 @@ public class MemberFinder
private static class MemberFoundException extends RuntimeException {}
private static final MemberFoundException MEMBER_FOUND = new MemberFoundException();
+ private final boolean searchHierarchy;
+
private Clazz clazz;
private Member member;
+ /**
+ * Creates a new MemberFinder that looks in the class hierarchy.
+ */
+ public MemberFinder()
+ {
+ this(true);
+ }
+
+
+ /**
+ * Creates a new MemberFinder that looks in the class hierarchy if
+ * specified.
+ */
+ public MemberFinder(boolean searchHierarchy)
+ {
+ this.searchHierarchy = searchHierarchy;
+ }
+
+
/**
* Finds the field with the given name and descriptor in the given
- * class or its hierarchy.
+ * class or its hierarchy. The name and descriptor may contain wildcards.
+ */
+ public Field findField(Clazz clazz,
+ String name,
+ String descriptor)
+ {
+ return findField(null, clazz, name, descriptor);
+ }
+
+
+ /**
+ * Finds the field with the given name and descriptor in the given
+ * class or its hierarchy. The name and descriptor may contain wildcards.
*/
public Field findField(Clazz referencingClass,
Clazz clazz,
@@ -55,7 +88,19 @@ public Field findField(Clazz referencingClass,
/**
* Finds the method with the given name and descriptor in the given
- * class or its hierarchy.
+ * class or its hierarchy. The name and descriptor may contain wildcards.
+ */
+ public Method findMethod(Clazz clazz,
+ String name,
+ String descriptor)
+ {
+ return findMethod(null, clazz, name, descriptor);
+ }
+
+
+ /**
+ * Finds the method with the given name and descriptor in the given
+ * class or its hierarchy. The name and descriptor may contain wildcards.
*/
public Method findMethod(Clazz referencingClass,
Clazz clazz,
@@ -68,7 +113,21 @@ public Method findMethod(Clazz referencingClass,
/**
* Finds the class member with the given name and descriptor in the given
- * class or its hierarchy.
+ * class or its hierarchy. The name and descriptor may contain wildcards.
+ */
+ public Member findMember(Clazz clazz,
+ String name,
+ String descriptor,
+ boolean isField)
+ {
+ return findMember(null, clazz, name, descriptor, isField);
+ }
+
+
+ /**
+ * Finds the class member with the given name and descriptor in the given
+ * class or its hierarchy, referenced from the optional given class.
+ * The name and descriptor may contain wildcards.
*/
public Member findMember(Clazz referencingClass,
Clazz clazz,
@@ -81,13 +140,42 @@ public Member findMember(Clazz referencingClass,
// compiled with "-target 1.2" or higher (the default in JDK 1.4).
try
{
+ boolean containsWildcards =
+ (name != null && (name.indexOf('*') >= 0 || name.indexOf('?') >= 0)) ||
+ (descriptor != null && (descriptor.indexOf('*') >= 0 || descriptor.indexOf('?') >= 0));
+
this.clazz = null;
this.member = null;
- clazz.hierarchyAccept(true, true, true, false, isField ?
- (ClassVisitor)new NamedFieldVisitor(name, descriptor,
- new MemberClassAccessFilter(referencingClass, this)) :
- (ClassVisitor)new NamedMethodVisitor(name, descriptor,
- new MemberClassAccessFilter(referencingClass, this)));
+
+ // Check the accessibility from the referencing class, if any
+ // (non-dummy).
+ MemberVisitor memberVisitor =
+ referencingClass != null &&
+ referencingClass.getName() != null ?
+ new MemberClassAccessFilter(referencingClass, this) :
+ this;
+
+ clazz.hierarchyAccept(true,
+ searchHierarchy,
+ searchHierarchy,
+ false,
+ containsWildcards ?
+ isField ?
+ new AllFieldVisitor(
+ new MemberNameFilter(name,
+ new MemberDescriptorFilter(descriptor,
+ memberVisitor))) :
+
+ new AllMethodVisitor(
+ new MemberNameFilter(name,
+ new MemberDescriptorFilter(descriptor,
+ memberVisitor))) :
+ isField ?
+ new NamedFieldVisitor(name, descriptor,
+ memberVisitor) :
+
+ new NamedMethodVisitor(name, descriptor,
+ memberVisitor));
}
catch (MemberFoundException ex)
{
diff --git a/src/proguard/classfile/util/MethodLinker.java b/core/src/proguard/classfile/util/MethodLinker.java
similarity index 98%
rename from src/proguard/classfile/util/MethodLinker.java
rename to core/src/proguard/classfile/util/MethodLinker.java
index 5eaa2d3..8ddb762 100644
--- a/src/proguard/classfile/util/MethodLinker.java
+++ b/core/src/proguard/classfile/util/MethodLinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/util/PrimitiveArrayConstantReplacer.java b/core/src/proguard/classfile/util/PrimitiveArrayConstantReplacer.java
new file mode 100644
index 0000000..d6c9fbd
--- /dev/null
+++ b/core/src/proguard/classfile/util/PrimitiveArrayConstantReplacer.java
@@ -0,0 +1,218 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This ClassVisitor replaces all PrimitiveArray constants by Java bytecode
+ * compliant array store instructions.
+ *
+ * @see ArrayInitializationReplacer
+ * @author Thomas Neidhart
+ */
+public class PrimitiveArrayConstantReplacer
+extends SimplifiedVisitor
+implements ClassVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor,
+ PrimitiveArrayConstantElementVisitor
+{
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+ private final ConstantPoolShrinker constantPoolShrinker = new ConstantPoolShrinker();
+
+ // Fields acting as parameters and return values.
+
+ private boolean classModified;
+ private InstructionSequenceBuilder builder;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ ConstantCounter counter = new ConstantCounter();
+ programClass.constantPoolEntriesAccept(
+ new ConstantTagFilter(ClassConstants.CONSTANT_PrimitiveArray,
+ counter));
+
+ // Replace PrimitiveArray constants if the class has any.
+ if (counter.getCount() > 0)
+ {
+ classModified = false;
+
+ programClass.methodsAccept(new AllAttributeVisitor(this));
+
+ if (classModified)
+ {
+ // Remove the now unused PrimitiveArray constants.
+ programClass.accept(constantPoolShrinker);
+ }
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttributeEditor.reset(codeAttribute.u4codeLength);
+
+ codeAttribute.instructionsAccept(clazz, method, this);
+
+ if (codeAttributeEditor.isModified())
+ {
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+
+ classModified = true;
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ builder = null;
+
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+
+ if (builder != null)
+ {
+ codeAttributeEditor.replaceInstruction(offset, builder.instructions());
+
+ classModified = true;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ char primitiveType = primitiveArrayConstant.getPrimitiveType();
+ int arrayLength = primitiveArrayConstant.getLength();
+
+ // Start composing a new array initialization sequence.
+ builder = new InstructionSequenceBuilder((ProgramClass) clazz);
+
+ // Push the primitive array length.
+ builder.pushInt(primitiveArrayConstant.getLength());
+
+ // Create the primitive array.
+ builder.newarray(InstructionUtil.arrayTypeFromInternalType(primitiveType));
+
+ // Fill out the primitive array elements.
+ primitiveArrayConstant.primitiveArrayElementsAccept(clazz, this);
+ }
+
+
+ // Implementations for PrimitiveArrayConstantElementVisitor.
+
+ public void visitBooleanArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, boolean value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .iconst(value ? 1 : 0)
+ .bastore();
+ }
+
+
+ public void visitByteArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, byte value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushInt(value)
+ .bastore();
+ }
+
+
+ public void visitCharArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, char value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushInt(value)
+ .castore();
+ }
+
+
+ public void visitShortArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, short value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushInt(value)
+ .sastore();
+ }
+
+
+ public void visitIntArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, int value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushInt(value)
+ .iastore();
+ }
+
+
+ public void visitFloatArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, float value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushFloat(value)
+ .fastore();
+ }
+
+
+ public void visitLongArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, long value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushLong(value)
+ .lastore();
+ }
+
+
+ public void visitDoubleArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, double value)
+ {
+ builder.dup()
+ .pushInt(index)
+ .pushDouble(value)
+ .dastore();
+ }
+}
diff --git a/src/proguard/classfile/util/SimplifiedVisitor.java b/core/src/proguard/classfile/util/SimplifiedVisitor.java
similarity index 88%
rename from src/proguard/classfile/util/SimplifiedVisitor.java
rename to core/src/proguard/classfile/util/SimplifiedVisitor.java
index c18135a..55f2a31 100644
--- a/src/proguard/classfile/util/SimplifiedVisitor.java
+++ b/core/src/proguard/classfile/util/SimplifiedVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.target.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.constant.*;
import proguard.classfile.instruction.*;
@@ -146,6 +147,12 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ visitAnyConstant(clazz, primitiveArrayConstant);
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
visitAnyConstant(clazz, stringConstant);
@@ -169,6 +176,16 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
visitAnyConstant(clazz, methodHandleConstant);
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ visitAnyConstant(clazz, moduleConstant);
+ }
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ visitAnyConstant(clazz, packageConstant);
+ }
+
/**
* Visits any type of RefConstant of the given class.
@@ -224,6 +241,118 @@ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTyp
}
+ // Simplifications for PrimitiveArrayConstantVisitor.
+
+ public void visitAnyPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, Object values)
+ {
+ throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called");
+ }
+
+
+ public void visitBooleanArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, boolean[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitByteArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, byte[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitCharArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, char[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitShortArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, short[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitIntArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitFloatArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, float[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitLongArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, long[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ public void visitDoubleArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, double[] values)
+ {
+ visitAnyPrimitiveArrayConstant(clazz, primitiveArrayConstant, values);
+ }
+
+
+ // Simplifications for PrimitiveArrayConstantElementVisitor.
+
+ public void visitAnyPrimitiveArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index)
+ {
+ throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called");
+ }
+
+
+ public void visitBooleanArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, boolean value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitByteArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, byte value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitCharArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, char value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitShortArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, short value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitIntArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, int value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitFloatArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, float value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitLongArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, long value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
+ public void visitDoubleArrayConstantElement(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant, int index, double value)
+ {
+ visitAnyPrimitiveArrayConstantElement(clazz, primitiveArrayConstant, index);
+ }
+
+
// Simplifications for AttributeVisitor.
/**
@@ -271,6 +400,24 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ visitAnyAttribute(clazz, moduleAttribute);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ visitAnyAttribute(clazz, moduleMainClassAttribute);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ visitAnyAttribute(clazz, modulePackagesAttribute);
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
visitAnyAttribute(clazz, deprecatedAttribute);
diff --git a/src/proguard/classfile/util/StringReferenceInitializer.java b/core/src/proguard/classfile/util/StringReferenceInitializer.java
similarity index 98%
rename from src/proguard/classfile/util/StringReferenceInitializer.java
rename to core/src/proguard/classfile/util/StringReferenceInitializer.java
index 2cc1032..46376c6 100644
--- a/src/proguard/classfile/util/StringReferenceInitializer.java
+++ b/core/src/proguard/classfile/util/StringReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/StringSharer.java b/core/src/proguard/classfile/util/StringSharer.java
similarity index 99%
rename from src/proguard/classfile/util/StringSharer.java
rename to core/src/proguard/classfile/util/StringSharer.java
index d2d5023..4cf100e 100644
--- a/src/proguard/classfile/util/StringSharer.java
+++ b/core/src/proguard/classfile/util/StringSharer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/WarningPrinter.java b/core/src/proguard/classfile/util/WarningPrinter.java
similarity index 98%
rename from src/proguard/classfile/util/WarningPrinter.java
rename to core/src/proguard/classfile/util/WarningPrinter.java
index c4bc232..c2298cd 100644
--- a/src/proguard/classfile/util/WarningPrinter.java
+++ b/core/src/proguard/classfile/util/WarningPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/util/package.html b/core/src/proguard/classfile/util/package.html
similarity index 100%
rename from src/proguard/classfile/util/package.html
rename to core/src/proguard/classfile/util/package.html
diff --git a/src/proguard/classfile/visitor/AllClassVisitor.java b/core/src/proguard/classfile/visitor/AllClassVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/AllClassVisitor.java
rename to core/src/proguard/classfile/visitor/AllClassVisitor.java
index e7f670f..c2471d9 100644
--- a/src/proguard/classfile/visitor/AllClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/AllClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/AllFieldVisitor.java b/core/src/proguard/classfile/visitor/AllFieldVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/AllFieldVisitor.java
rename to core/src/proguard/classfile/visitor/AllFieldVisitor.java
index a449089..c86a0d2 100644
--- a/src/proguard/classfile/visitor/AllFieldVisitor.java
+++ b/core/src/proguard/classfile/visitor/AllFieldVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/AllMemberVisitor.java b/core/src/proguard/classfile/visitor/AllMemberVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/AllMemberVisitor.java
rename to core/src/proguard/classfile/visitor/AllMemberVisitor.java
index 92e31d5..c3aa557 100644
--- a/src/proguard/classfile/visitor/AllMemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/AllMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/AllMethodVisitor.java b/core/src/proguard/classfile/visitor/AllMethodVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/AllMethodVisitor.java
rename to core/src/proguard/classfile/visitor/AllMethodVisitor.java
index af34fea..346c4fa 100644
--- a/src/proguard/classfile/visitor/AllMethodVisitor.java
+++ b/core/src/proguard/classfile/visitor/AllMethodVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/BottomClassFilter.java b/core/src/proguard/classfile/visitor/BottomClassFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/BottomClassFilter.java
rename to core/src/proguard/classfile/visitor/BottomClassFilter.java
index 89f2407..5a0c418 100644
--- a/src/proguard/classfile/visitor/BottomClassFilter.java
+++ b/core/src/proguard/classfile/visitor/BottomClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassAccessFilter.java b/core/src/proguard/classfile/visitor/ClassAccessFilter.java
similarity index 98%
rename from src/proguard/classfile/visitor/ClassAccessFilter.java
rename to core/src/proguard/classfile/visitor/ClassAccessFilter.java
index 3637270..ffca52f 100644
--- a/src/proguard/classfile/visitor/ClassAccessFilter.java
+++ b/core/src/proguard/classfile/visitor/ClassAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassCleaner.java b/core/src/proguard/classfile/visitor/ClassCleaner.java
similarity index 99%
rename from src/proguard/classfile/visitor/ClassCleaner.java
rename to core/src/proguard/classfile/visitor/ClassCleaner.java
index dffe118..8f2ee4b 100644
--- a/src/proguard/classfile/visitor/ClassCleaner.java
+++ b/core/src/proguard/classfile/visitor/ClassCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassCollector.java b/core/src/proguard/classfile/visitor/ClassCollector.java
similarity index 96%
rename from src/proguard/classfile/visitor/ClassCollector.java
rename to core/src/proguard/classfile/visitor/ClassCollector.java
index 1a65fcc..0e9b628 100644
--- a/src/proguard/classfile/visitor/ClassCollector.java
+++ b/core/src/proguard/classfile/visitor/ClassCollector.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassCounter.java b/core/src/proguard/classfile/visitor/ClassCounter.java
similarity index 96%
rename from src/proguard/classfile/visitor/ClassCounter.java
rename to core/src/proguard/classfile/visitor/ClassCounter.java
index 850a64c..d765c35 100644
--- a/src/proguard/classfile/visitor/ClassCounter.java
+++ b/core/src/proguard/classfile/visitor/ClassCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassHierarchyTraveler.java b/core/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
similarity index 98%
rename from src/proguard/classfile/visitor/ClassHierarchyTraveler.java
rename to core/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
index a14e132..8511121 100644
--- a/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
+++ b/core/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassNameFilter.java b/core/src/proguard/classfile/visitor/ClassNameFilter.java
similarity index 55%
rename from src/proguard/classfile/visitor/ClassNameFilter.java
rename to core/src/proguard/classfile/visitor/ClassNameFilter.java
index 297e8fa..3db4756 100644
--- a/src/proguard/classfile/visitor/ClassNameFilter.java
+++ b/core/src/proguard/classfile/visitor/ClassNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -40,30 +40,66 @@ public class ClassNameFilter implements ClassVisitor
/**
* Creates a new ClassNameFilter.
- * @param regularExpression the regular expression against which class names
- * will be matched.
- * @param classVisitor the ClassVisitor to which visits
- * will be delegated.
+ * @param regularExpression the regular expression against which class
+ * names will be matched.
+ * @param classVisitor the ClassVisitor to which
+ * visits will be delegated.
*/
public ClassNameFilter(String regularExpression,
ClassVisitor classVisitor)
{
- this(new ListParser(new ClassNameParser()).parse(regularExpression),
+ this(regularExpression, null, classVisitor);
+ }
+
+
+ /**
+ * Creates a new ClassNameFilter.
+ * @param regularExpression the regular expression against which class
+ * names will be matched.
+ * @param variableStringMatchers an optional mutable list of
+ * VariableStringMatcher instances that match
+ * the wildcards.
+ * @param classVisitor the ClassVisitor to which
+ * visits will be delegated.
+ */
+ public ClassNameFilter(String regularExpression,
+ List variableStringMatchers,
+ ClassVisitor classVisitor)
+ {
+ this(new ListParser(new ClassNameParser(variableStringMatchers)).parse(regularExpression),
classVisitor);
}
/**
* Creates a new ClassNameFilter.
- * @param regularExpression the regular expression against which class names
- * will be matched.
- * @param classVisitor the ClassVisitor to which visits
- * will be delegated.
+ * @param regularExpression the regular expression against which class
+ * names will be matched.
+ * @param classVisitor the ClassVisitor to which
+ * visits will be delegated.
+ */
+ public ClassNameFilter(List regularExpression,
+ ClassVisitor classVisitor)
+ {
+ this(regularExpression, null, classVisitor);
+ }
+
+
+ /**
+ * Creates a new ClassNameFilter.
+ * @param regularExpression the regular expression against which class
+ * names will be matched.
+ * @param variableStringMatchers an optional mutable list of
+ * VariableStringMatcher instances that match
+ * the wildcards.
+ * @param classVisitor the ClassVisitor to which
+ * visits will be delegated.
*/
public ClassNameFilter(List regularExpression,
+ List variableStringMatchers,
ClassVisitor classVisitor)
{
- this(new ListParser(new ClassNameParser()).parse(regularExpression),
+ this(new ListParser(new ClassNameParser(variableStringMatchers)).parse(regularExpression),
classVisitor);
}
diff --git a/core/src/proguard/classfile/visitor/ClassPoolClassVisitor.java b/core/src/proguard/classfile/visitor/ClassPoolClassVisitor.java
new file mode 100644
index 0000000..0b0f830
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/ClassPoolClassVisitor.java
@@ -0,0 +1,70 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+
+/**
+ * This ClassPoolVisitor and ClassVisitor remembers the ClassPool instances
+ * that it visits and applies the given ClassPoolVisitor to the most
+ * recently remembered one, every time it visits a Clazz instance.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPoolClassVisitor
+implements ClassPoolVisitor,
+ ClassVisitor
+{
+ private ClassPoolVisitor classPoolVisitor;
+ private ClassPool classPool;
+
+
+ /**
+ * Creates a new ClassPoolClassVisitor.
+ * @param classPoolVisitor
+ */
+ public ClassPoolClassVisitor(ClassPoolVisitor classPoolVisitor)
+ {
+ this.classPoolVisitor = classPoolVisitor;
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ this.classPool = classPool;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ classPoolVisitor.visitClassPool(classPool);
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ classPoolVisitor.visitClassPool(classPool);
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassPoolFiller.java b/core/src/proguard/classfile/visitor/ClassPoolFiller.java
similarity index 96%
rename from src/proguard/classfile/visitor/ClassPoolFiller.java
rename to core/src/proguard/classfile/visitor/ClassPoolFiller.java
index b6c5352..94c5990 100644
--- a/src/proguard/classfile/visitor/ClassPoolFiller.java
+++ b/core/src/proguard/classfile/visitor/ClassPoolFiller.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassPoolRemover.java b/core/src/proguard/classfile/visitor/ClassPoolRemover.java
similarity index 96%
rename from src/proguard/classfile/visitor/ClassPoolRemover.java
rename to core/src/proguard/classfile/visitor/ClassPoolRemover.java
index 71e421d..c2afda1 100644
--- a/src/proguard/classfile/visitor/ClassPoolRemover.java
+++ b/core/src/proguard/classfile/visitor/ClassPoolRemover.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassPoolVisitor.java b/core/src/proguard/classfile/visitor/ClassPoolVisitor.java
similarity index 95%
rename from src/proguard/classfile/visitor/ClassPoolVisitor.java
rename to core/src/proguard/classfile/visitor/ClassPoolVisitor.java
index ae6a6ac..b37f6f7 100644
--- a/src/proguard/classfile/visitor/ClassPoolVisitor.java
+++ b/core/src/proguard/classfile/visitor/ClassPoolVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassPresenceFilter.java b/core/src/proguard/classfile/visitor/ClassPresenceFilter.java
similarity index 98%
rename from src/proguard/classfile/visitor/ClassPresenceFilter.java
rename to core/src/proguard/classfile/visitor/ClassPresenceFilter.java
index 115b37b..592db81 100644
--- a/src/proguard/classfile/visitor/ClassPresenceFilter.java
+++ b/core/src/proguard/classfile/visitor/ClassPresenceFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassPrinter.java b/core/src/proguard/classfile/visitor/ClassPrinter.java
similarity index 84%
rename from src/proguard/classfile/visitor/ClassPrinter.java
rename to core/src/proguard/classfile/visitor/ClassPrinter.java
index c14a67d..38014ca 100644
--- a/src/proguard/classfile/visitor/ClassPrinter.java
+++ b/core/src/proguard/classfile/visitor/ClassPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +26,8 @@
import proguard.classfile.attribute.annotation.target.*;
import proguard.classfile.attribute.annotation.target.visitor.*;
import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.module.*;
+import proguard.classfile.attribute.module.visitor.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.preverification.visitor.*;
import proguard.classfile.attribute.visitor.*;
@@ -35,7 +37,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
-import java.io.PrintStream;
+import java.io.PrintWriter;
/**
@@ -59,6 +61,10 @@ public class ClassPrinter
ParameterInfoVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor,
+ RequiresInfoVisitor,
+ ExportsInfoVisitor,
+ OpensInfoVisitor,
+ ProvidesInfoVisitor,
AnnotationVisitor,
TypeAnnotationVisitor,
TargetInfoVisitor,
@@ -69,27 +75,28 @@ public class ClassPrinter
{
private static final String INDENTATION = " ";
- private final PrintStream ps;
+ private final PrintWriter pw;
private int indentation;
/**
- * Creates a new ClassPrinter that prints to System.out.
+ * Creates a new ClassPrinter that prints to the standard output.
*/
public ClassPrinter()
{
- this(System.out);
+ // We're using the system's default character encoding for writing to
+ // the standard output.
+ this(new PrintWriter(System.out, true));
}
/**
- * Creates a new ClassPrinter that prints to the given
- * PrintStream.
+ * Creates a new ClassPrinter that prints to the given writer.
*/
- public ClassPrinter(PrintStream printStream)
+ public ClassPrinter(PrintWriter printWriter)
{
- ps = printStream;
+ pw = printWriter;
}
@@ -107,11 +114,10 @@ public void visitProgramClass(ProgramClass programClass)
println(" = target " + ClassUtil.externalClassVersion(programClass.u4version));
println("Access flags: 0x" + Integer.toHexString(programClass.u2accessFlags));
println(" = " +
- ((programClass.u2accessFlags & ClassConstants.ACC_ANNOTATTION) != 0 ? "@ " : "") +
ClassUtil.externalClassAccessFlags(programClass.u2accessFlags) +
- ((programClass.u2accessFlags & ClassConstants.ACC_ENUM) != 0 ? "enum " :
- (programClass.u2accessFlags & ClassConstants.ACC_INTERFACE) == 0 ? "class " :
- "") +
+ ((programClass.u2accessFlags & (ClassConstants.ACC_ENUM |
+ ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_MODULE)) == 0 ? "class " : "") +
ClassUtil.externalClassName(programClass.getName()) +
(programClass.u2superClass == 0 ? "" : " extends " +
ClassUtil.externalClassName(programClass.getSuperName())));
@@ -159,11 +165,10 @@ public void visitLibraryClass(LibraryClass libraryClass)
println("Superclass: " + libraryClass.getSuperName());
println("Access flags: 0x" + Integer.toHexString(libraryClass.u2accessFlags));
println(" = " +
- ((libraryClass.u2accessFlags & ClassConstants.ACC_ANNOTATTION) != 0 ? "@ " : "") +
ClassUtil.externalClassAccessFlags(libraryClass.u2accessFlags) +
- ((libraryClass.u2accessFlags & ClassConstants.ACC_ENUM) != 0 ? "enum " :
- (libraryClass.u2accessFlags & ClassConstants.ACC_INTERFACE) == 0 ? "class " :
- "") +
+ ((libraryClass.u2accessFlags & (ClassConstants.ACC_ENUM |
+ ClassConstants.ACC_INTERFACE |
+ ClassConstants.ACC_MODULE)) == 0 ? "class " : "") +
ClassUtil.externalClassName(libraryClass.getName()) +
(libraryClass.getSuperName() == null ? "" : " extends " +
ClassUtil.externalClassName(libraryClass.getSuperName())));
@@ -218,6 +223,14 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ println(visitorInfo(primitiveArrayConstant) + " PrimitiveArray " +
+ primitiveArrayConstant.getPrimitiveType() + "[" +
+ primitiveArrayConstant.getLength() + "]");
+ }
+
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
println(visitorInfo(stringConstant) + " String [" +
@@ -251,6 +264,19 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
outdent();
}
+ public void visitModuleConstant(Clazz clazz, ModuleConstant moduleConstant)
+ {
+ println(visitorInfo(moduleConstant) + " Module [" +
+ moduleConstant.getName(clazz) + "]");
+ }
+
+
+ public void visitPackageConstant(Clazz clazz, PackageConstant packageConstant)
+ {
+ println(visitorInfo(packageConstant) + " Package [" +
+ packageConstant.getName(clazz) + "]");
+ }
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
@@ -434,7 +460,7 @@ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAtt
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
println(visitorInfo(innerClassesAttribute) +
- " Inner classes attribute (count = " + innerClassesAttribute.u2classesCount + ")");
+ " Inner classes attribute (count = " + innerClassesAttribute.u2classesCount + "):");
indent();
innerClassesAttribute.innerClassEntriesAccept(clazz, this);
@@ -458,6 +484,63 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ println(visitorInfo(moduleAttribute) +
+ " Module attribute:");
+
+ indent();
+ clazz.constantPoolEntryAccept(moduleAttribute.u2moduleNameIndex, this);
+ println("Access flags: 0x" +
+ Integer.toHexString(moduleAttribute.u2moduleFlags) +
+ " = " +
+ ClassUtil.externalModuleAccessFlags(moduleAttribute.u2moduleFlags));
+
+ if (moduleAttribute.u2moduleVersionIndex != 0)
+ {
+ clazz.constantPoolEntryAccept(moduleAttribute.u2moduleVersionIndex, this);
+ }
+ println("Requires:");
+ moduleAttribute.requiresAccept(clazz, this);
+ println("Exports:");
+ moduleAttribute.exportsAccept(clazz, this);
+ println("Opens:");
+ moduleAttribute.opensAccept(clazz, this);
+ println("Uses services:");
+
+ for (int index = 0; index < moduleAttribute.u2usesCount; index++)
+ {
+ clazz.constantPoolEntryAccept(moduleAttribute.u2uses[index], this);
+ }
+
+ println("Provides services:");
+ moduleAttribute.providesAccept(clazz, this);
+ outdent();
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ println(visitorInfo(moduleMainClassAttribute) +
+ " Module main class attribute:");
+
+ indent();
+ clazz.constantPoolEntryAccept(moduleMainClassAttribute.u2mainClass, this);
+ outdent();
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ println(visitorInfo(modulePackagesAttribute) +
+ " Module packages attribute (count = " + modulePackagesAttribute.u2packagesCount + "):");
+
+ indent();
+ modulePackagesAttribute.packagesAccept(clazz, this);
+ outdent();
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
println(visitorInfo(deprecatedAttribute) +
@@ -495,7 +578,7 @@ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueA
public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodParametersAttribute methodParametersAttribute)
{
println(visitorInfo(methodParametersAttribute) +
- " Method parameters attribute (count = " + methodParametersAttribute.u1parametersCount + ")");
+ " Method parameters attribute (count = " + methodParametersAttribute.u1parametersCount + "):");
indent();
methodParametersAttribute.parametersAccept(clazz, method, this);
@@ -506,10 +589,10 @@ public void visitMethodParametersAttribute(Clazz clazz, Method method, MethodPar
public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
{
println(visitorInfo(exceptionsAttribute) +
- " Exceptions attribute (count = " + exceptionsAttribute.u2exceptionIndexTableLength + ")");
+ " Exceptions attribute (count = " + exceptionsAttribute.u2exceptionIndexTableLength + "):");
indent();
- exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this);
+ exceptionsAttribute.exceptionEntriesAccept(clazz, this);
outdent();
}
@@ -567,7 +650,7 @@ public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttrib
{
println(visitorInfo(lineNumberTableAttribute) +
" Line number table attribute (count = " +
- lineNumberTableAttribute.u2lineNumberTableLength + ")");
+ lineNumberTableAttribute.u2lineNumberTableLength + "):");
indent();
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
@@ -579,7 +662,7 @@ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAtt
{
println(visitorInfo(localVariableTableAttribute) +
" Local variable table attribute (count = " +
- localVariableTableAttribute.u2localVariableTableLength + ")");
+ localVariableTableAttribute.u2localVariableTableLength + "):");
indent();
localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
@@ -591,7 +674,7 @@ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, Cod
{
println(visitorInfo(localVariableTypeTableAttribute) +
" Local variable type table attribute (count = "+
- localVariableTypeTableAttribute.u2localVariableTypeTableLength + ")");
+ localVariableTypeTableAttribute.u2localVariableTypeTableLength + "):");
indent();
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
@@ -825,7 +908,7 @@ public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAtt
moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
- ps.println(", Stack: (empty)");
+ pw.println(", Stack: (empty)");
}
@@ -837,7 +920,7 @@ public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribu
fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
- ps.print(", Stack: ");
+ pw.print(", Stack: ");
fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
@@ -849,55 +932,55 @@ public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribu
public void visitIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, IntegerType integerType)
{
- ps.print("[i]");
+ pw.print("[i]");
}
public void visitFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FloatType floatType)
{
- ps.print("[f]");
+ pw.print("[f]");
}
public void visitLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LongType longType)
{
- ps.print("[l]");
+ pw.print("[l]");
}
public void visitDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, DoubleType doubleType)
{
- ps.print("[d]");
+ pw.print("[d]");
}
public void visitTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TopType topType)
{
- ps.print("[T]");
+ pw.print("[T]");
}
public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType)
{
- ps.print("[a:" + clazz.getClassName(objectType.u2classIndex) + "]");
+ pw.print("[a:" + clazz.getClassName(objectType.u2classIndex) + "]");
}
public void visitNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, NullType nullType)
{
- ps.print("[n]");
+ pw.print("[n]");
}
public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
{
- ps.print("[u:" + uninitializedType.u2newInstructionOffset + "]");
+ pw.print("[u:" + uninitializedType.u2newInstructionOffset + "]");
}
public void visitUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedThisType uninitializedThisType)
{
- ps.print("[u:this]");
+ pw.print("[u:this]");
}
@@ -915,9 +998,9 @@ public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAt
public void visitParameterInfo(Clazz clazz, Method method, int parameterIndex, ParameterInfo parameterInfo)
{
- println("p" + parameterIndex + ": access flags: 0x" + Integer.toHexString(parameterInfo.u2accessFlags) + " = " +
- ClassUtil.externalParameterAccessFlags(parameterInfo.u2accessFlags) +
- (parameterInfo.u2nameIndex == 0 ? "" : " [" + parameterInfo.getName(clazz) + "]"));
+ println("p" + parameterIndex + ": Access flags: 0x" + Integer.toHexString(parameterInfo.u2accessFlags) + " = " +
+ ClassUtil.externalParameterAccessFlags(parameterInfo.u2accessFlags) + " [" +
+ (parameterInfo.u2nameIndex == 0 ? "" : parameterInfo.getName(clazz)) + "]");
}
@@ -945,6 +1028,86 @@ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute
}
+ // Implementations for RequiresInfoVisitor
+
+ public void visitRequiresInfo(Clazz clazz, RequiresInfo requiresInfo)
+ {
+ println(visitorInfo(requiresInfo) +
+ " RequiresInfo:");
+
+ indent();
+ clazz.constantPoolEntryAccept(requiresInfo.u2requiresIndex, this);
+ println("Access flags: 0x" + Integer.toHexString(requiresInfo.u2requiresFlags) + " = " +
+ ClassUtil.externalRequiresAccessFlags(requiresInfo.u2requiresFlags));
+ clazz.constantPoolEntryAccept(requiresInfo.u2requiresVersionIndex, this);
+ outdent();
+ }
+
+
+ // Implementations for ExportsInfoVisitor
+
+ public void visitExportsInfo(Clazz clazz, ExportsInfo exportsInfo)
+ {
+ println(visitorInfo(exportsInfo) +
+ " ExportsInfo (targets count = " +
+ exportsInfo.u2exportsToCount + "):");
+
+ indent();
+ clazz.constantPoolEntryAccept(exportsInfo.u2exportsIndex, this);
+ println("Access flags: 0x" + Integer.toHexString(exportsInfo.u2exportsFlags) + " = " +
+ ClassUtil.externalExportsAccessFlags(exportsInfo.u2exportsFlags));
+
+ for (int index = 0; index < exportsInfo.u2exportsToCount; index++)
+ {
+ clazz.constantPoolEntryAccept(exportsInfo.u2exportsToIndex[index], this);
+ }
+
+ outdent();
+ }
+
+
+ // Implementations for ExportsOpensVisitor
+
+ public void visitOpensInfo(Clazz clazz, OpensInfo opensInfo)
+ {
+ println(visitorInfo(opensInfo) +
+ " OpensInfo (targets count = " +
+ opensInfo.u2opensToCount + "):");
+
+ indent();
+ clazz.constantPoolEntryAccept(opensInfo.u2opensIndex, this);
+ println("Access flags: 0x" + Integer.toHexString(opensInfo.u2opensFlags) + " = " +
+ ClassUtil.externalOpensAccessFlags(opensInfo.u2opensFlags));
+
+ for (int index = 0; index < opensInfo.u2opensToCount; index++)
+ {
+ clazz.constantPoolEntryAccept(opensInfo.u2opensToIndex[index], this);
+ }
+
+ outdent();
+ }
+
+
+ // Implementations for ProvidesInfoVisitor
+
+ public void visitProvidesInfo(Clazz clazz, ProvidesInfo providesInfo)
+ {
+ println(visitorInfo(providesInfo) +
+ " ProvidesInfo (with count = " +
+ providesInfo.u2providesWithCount + "):");
+
+ indent();
+ clazz.constantPoolEntryAccept(providesInfo.u2providesIndex, this);
+
+ for (int index = 0; index < providesInfo.u2providesWithCount; index++)
+ {
+ clazz.constantPoolEntryAccept(providesInfo.u2providesWithIndex[index], this);
+ }
+
+ outdent();
+ }
+
+
// Implementations for AnnotationVisitor.
public void visitAnnotation(Clazz clazz, Annotation annotation)
@@ -958,6 +1121,17 @@ public void visitAnnotation(Clazz clazz, Annotation annotation)
}
+ public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation)
+ {
+ println(visitorInfo(annotation) +
+ " Parameter #"+parameterIndex+", annotation [" + annotation.getType(clazz) + "]:");
+
+ indent();
+ annotation.elementValuesAccept(clazz, this);
+ outdent();
+ }
+
+
// Implementations for TypeAnnotationVisitor.
public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation)
@@ -1164,15 +1338,15 @@ private void print(String string)
{
for (int index = 0; index < indentation; index++)
{
- ps.print(INDENTATION);
+ pw.print(INDENTATION);
}
- ps.print(string);
+ pw.print(string);
}
private void println()
{
- ps.println();
+ pw.println();
}
diff --git a/src/proguard/classfile/visitor/ClassVersionFilter.java b/core/src/proguard/classfile/visitor/ClassVersionFilter.java
similarity index 98%
rename from src/proguard/classfile/visitor/ClassVersionFilter.java
rename to core/src/proguard/classfile/visitor/ClassVersionFilter.java
index 50c4961..a9fea4c 100644
--- a/src/proguard/classfile/visitor/ClassVersionFilter.java
+++ b/core/src/proguard/classfile/visitor/ClassVersionFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassVersionSetter.java b/core/src/proguard/classfile/visitor/ClassVersionSetter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ClassVersionSetter.java
rename to core/src/proguard/classfile/visitor/ClassVersionSetter.java
index 12e1c59..6021c62 100644
--- a/src/proguard/classfile/visitor/ClassVersionSetter.java
+++ b/core/src/proguard/classfile/visitor/ClassVersionSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ClassVisitor.java b/core/src/proguard/classfile/visitor/ClassVisitor.java
similarity index 95%
rename from src/proguard/classfile/visitor/ClassVisitor.java
rename to core/src/proguard/classfile/visitor/ClassVisitor.java
index 6358b3b..b3d3c98 100644
--- a/src/proguard/classfile/visitor/ClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/ClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ConcreteClassDownTraveler.java b/core/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
similarity index 98%
rename from src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
rename to core/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
index 1169d8d..3d92ff9 100644
--- a/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
+++ b/core/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/visitor/ConstructorMethodFilter.java b/core/src/proguard/classfile/visitor/ConstructorMethodFilter.java
new file mode 100644
index 0000000..7d6e0e9
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/ConstructorMethodFilter.java
@@ -0,0 +1,141 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor delegates its visits to one of three delegates, depending on whether the visited method is:
+ *
+ * - a constructor
+ * - a constructor that calls a super constructor
+ * - or another method.
+ *
+ * @author Johan Leys
+ */
+public class ConstructorMethodFilter
+extends SimplifiedVisitor
+implements MemberVisitor,
+
+ // Implementation interfaces.
+ AttributeVisitor,
+ InstructionVisitor
+{
+ private static final int FIELD_INDEX = InstructionSequenceMatcher.X;
+
+ private static final Constant[] CONSTANTS = new Constant[] {};
+
+ private static final Instruction[] INVOKE_INSTRUCTIONS = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, FIELD_INDEX),
+ };
+
+ private final InstructionSequenceMatcher invokeMatcher = new InstructionSequenceMatcher(CONSTANTS, INVOKE_INSTRUCTIONS);
+
+ private final MemberVisitor superCallingConstructorVisitor;
+ private final MemberVisitor constructorVisitor;
+ private final MemberVisitor otherMethodVisitor;
+
+ private boolean isSuperConstructorCalled;
+
+
+ public ConstructorMethodFilter(MemberVisitor constructorVisitor)
+ {
+ this(constructorVisitor, constructorVisitor, null);
+ }
+
+
+ public ConstructorMethodFilter(MemberVisitor superCallingConstructorVisitor,
+ MemberVisitor constructorVisitor,
+ MemberVisitor otherMethodVisitor)
+ {
+ this.superCallingConstructorVisitor = superCallingConstructorVisitor;
+ this.constructorVisitor = constructorVisitor;
+ this.otherMethodVisitor = otherMethodVisitor;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Delegate the visit.
+ MemberVisitor delegateVisitor = delegateVisitor(programClass, programMethod);
+ if (delegateVisitor != null)
+ {
+ delegateVisitor.visitProgramMethod(programClass, programMethod);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttribute.instructionsAccept(clazz, method, this);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ instruction.accept(clazz, method, codeAttribute, offset, invokeMatcher);
+ if (invokeMatcher.isMatching())
+ {
+ MethodrefConstant methodrefConstant = (MethodrefConstant)((ProgramClass)clazz).getConstant(invokeMatcher.matchedArgument(FIELD_INDEX));
+ if (ClassConstants.METHOD_NAME_INIT.equals(methodrefConstant.getName(clazz)))
+ {
+ isSuperConstructorCalled |=
+ methodrefConstant.getClassName(clazz).equals(clazz.getSuperName());
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ private MemberVisitor delegateVisitor(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ isSuperConstructorCalled = false;
+
+ if (ClassConstants.METHOD_NAME_INIT.equals(programMethod.getName(programClass)))
+ {
+ // Search the code attribute for super. invocations.
+ programMethod.attributesAccept(programClass, this);
+ return isSuperConstructorCalled ? superCallingConstructorVisitor : constructorVisitor;
+ }
+ else
+ {
+ return otherMethodVisitor;
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/DotClassClassVisitor.java b/core/src/proguard/classfile/visitor/DotClassClassVisitor.java
similarity index 98%
rename from src/proguard/classfile/visitor/DotClassClassVisitor.java
rename to core/src/proguard/classfile/visitor/DotClassClassVisitor.java
index d861d33..ddbffff 100644
--- a/src/proguard/classfile/visitor/DotClassClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/DotClassClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/DynamicReturnedClassVisitor.java b/core/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java
rename to core/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java
index 8a23b02..946471e 100644
--- a/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptClassFilter.java b/core/src/proguard/classfile/visitor/ExceptClassFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptClassFilter.java
rename to core/src/proguard/classfile/visitor/ExceptClassFilter.java
index 9182a6f..15134f9 100644
--- a/src/proguard/classfile/visitor/ExceptClassFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptClassesFilter.java b/core/src/proguard/classfile/visitor/ExceptClassesFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptClassesFilter.java
rename to core/src/proguard/classfile/visitor/ExceptClassesFilter.java
index 35cf7c3..1012486 100644
--- a/src/proguard/classfile/visitor/ExceptClassesFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptClassesFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionCounter.java b/core/src/proguard/classfile/visitor/ExceptionCounter.java
similarity index 96%
rename from src/proguard/classfile/visitor/ExceptionCounter.java
rename to core/src/proguard/classfile/visitor/ExceptionCounter.java
index 9a28816..8223b21 100644
--- a/src/proguard/classfile/visitor/ExceptionCounter.java
+++ b/core/src/proguard/classfile/visitor/ExceptionCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionExcludedOffsetFilter.java b/core/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
rename to core/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
index 9f1ed68..df4f260 100644
--- a/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionHandlerConstantVisitor.java b/core/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
rename to core/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
index 956b821..79ed6ef 100644
--- a/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
+++ b/core/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionHandlerFilter.java b/core/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptionHandlerFilter.java
rename to core/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
index 87cd2ad..ae56e68 100644
--- a/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionOffsetFilter.java b/core/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptionOffsetFilter.java
rename to core/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
index d4865f2..6ea99be 100644
--- a/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ExceptionRangeFilter.java b/core/src/proguard/classfile/visitor/ExceptionRangeFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ExceptionRangeFilter.java
rename to core/src/proguard/classfile/visitor/ExceptionRangeFilter.java
index f2e31b6..542cf8c 100644
--- a/src/proguard/classfile/visitor/ExceptionRangeFilter.java
+++ b/core/src/proguard/classfile/visitor/ExceptionRangeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/visitor/FunctionalInterfaceFilter.java b/core/src/proguard/classfile/visitor/FunctionalInterfaceFilter.java
new file mode 100644
index 0000000..d571770
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/FunctionalInterfaceFilter.java
@@ -0,0 +1,96 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+
+/**
+ * This ClassVisitor delegates its visits to another given
+ * ClassVisitor, but only for functional interfaces, that
+ * is, interface classes that have exactly one abstract method.
+ *
+ * @author Eric Lafortune
+ */
+public class FunctionalInterfaceFilter implements ClassVisitor
+{
+ private final ClassVisitor classVisitor;
+
+
+ /**
+ * Creates a new ProgramClassFilter.
+ * @param classVisitor the ClassVisitor to which visits
+ * will be delegated.
+ */
+ public FunctionalInterfaceFilter(ClassVisitor classVisitor)
+ {
+ this.classVisitor = classVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (isFunctionalInterface(programClass))
+ {
+ classVisitor.visitProgramClass(programClass);
+ }
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ if (isFunctionalInterface(libraryClass))
+ {
+ classVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean isFunctionalInterface(Clazz clazz)
+ {
+ // Is it an interface?
+ if ((clazz.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0)
+ {
+ return false;
+ }
+
+ // Count the abstract methods in the interface hierarchy.
+ // Subtract any corresponding default methods, since only abstract
+ // methods that don't have a default implementation count.
+ // TODO: Find a better way to count default methods, since there may be more of them for a single abstract method, or we can find one via different paths.
+ MemberCounter abstractMethodCounter = new MemberCounter();
+ MemberCounter defaultMethodCounter = new MemberCounter();
+ clazz.hierarchyAccept(true, false, true, false,
+ new AllMethodVisitor(
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ new MultiMemberVisitor(
+ abstractMethodCounter,
+ new SimilarMemberVisitor(clazz, true, false, true, false,
+ new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT,
+ defaultMethodCounter))
+ ))));
+
+ return abstractMethodCounter.getCount() - defaultMethodCounter.getCount() == 1;
+ }
+}
diff --git a/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java b/core/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
rename to core/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
index b9fd44b..4598738 100644
--- a/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
+++ b/core/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ImplementedClassFilter.java b/core/src/proguard/classfile/visitor/ImplementedClassFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ImplementedClassFilter.java
rename to core/src/proguard/classfile/visitor/ImplementedClassFilter.java
index 74cbdf4..5d4107a 100644
--- a/src/proguard/classfile/visitor/ImplementedClassFilter.java
+++ b/core/src/proguard/classfile/visitor/ImplementedClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ImplementingClassConstantFilter.java b/core/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
rename to core/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
index 471053d..b9e796c 100644
--- a/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
+++ b/core/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/InitializerMethodFilter.java b/core/src/proguard/classfile/visitor/InitializerMethodFilter.java
similarity index 98%
rename from src/proguard/classfile/visitor/InitializerMethodFilter.java
rename to core/src/proguard/classfile/visitor/InitializerMethodFilter.java
index 87f363f..1c9ccc0 100644
--- a/src/proguard/classfile/visitor/InitializerMethodFilter.java
+++ b/core/src/proguard/classfile/visitor/InitializerMethodFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/LibraryClassFilter.java b/core/src/proguard/classfile/visitor/LibraryClassFilter.java
similarity index 96%
rename from src/proguard/classfile/visitor/LibraryClassFilter.java
rename to core/src/proguard/classfile/visitor/LibraryClassFilter.java
index f009206..a92e8bb 100644
--- a/src/proguard/classfile/visitor/LibraryClassFilter.java
+++ b/core/src/proguard/classfile/visitor/LibraryClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/LibraryMemberFilter.java b/core/src/proguard/classfile/visitor/LibraryMemberFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/LibraryMemberFilter.java
rename to core/src/proguard/classfile/visitor/LibraryMemberFilter.java
index 739e262..cdfc3e9 100644
--- a/src/proguard/classfile/visitor/LibraryMemberFilter.java
+++ b/core/src/proguard/classfile/visitor/LibraryMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MemberAccessFilter.java b/core/src/proguard/classfile/visitor/MemberAccessFilter.java
similarity index 95%
rename from src/proguard/classfile/visitor/MemberAccessFilter.java
rename to core/src/proguard/classfile/visitor/MemberAccessFilter.java
index 4b049df..c6b4635 100644
--- a/src/proguard/classfile/visitor/MemberAccessFilter.java
+++ b/core/src/proguard/classfile/visitor/MemberAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -54,9 +54,9 @@ public class MemberAccessFilter
/**
* Creates a new MemberAccessFilter.
- * @param requiredSetAccessFlags the class access flags that should be
+ * @param requiredSetAccessFlags the member access flags that should be
* set.
- * @param requiredUnsetAccessFlags the class access flags that should be
+ * @param requiredUnsetAccessFlags the member access flags that should be
* unset.
* @param memberVisitor the MemberVisitor to
* which visits will be delegated.
diff --git a/src/proguard/optimize/KeepMarker.java b/core/src/proguard/classfile/visitor/MemberAccessFlagCleaner.java
similarity index 50%
rename from src/proguard/optimize/KeepMarker.java
rename to core/src/proguard/classfile/visitor/MemberAccessFlagCleaner.java
index c04b5f7..2784afa 100644
--- a/src/proguard/optimize/KeepMarker.java
+++ b/core/src/proguard/classfile/visitor/MemberAccessFlagCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -18,86 +18,62 @@
* 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;
+package proguard.classfile.visitor;
import proguard.classfile.*;
-import proguard.classfile.util.MethodLinker;
-import proguard.classfile.visitor.*;
-import proguard.optimize.info.NoSideEffectMethodMarker;
-
/**
- * This ClassVisitor and MemberVisitor
- * marks classes and class members it visits. The marked elements
- * will remain unchanged as necessary in the optimization step.
+ * This visitor clears the specified access flags of the
+ * program classes and class members that its visits.
+ *
+ * @see ClassConstants
*
- * @see NoSideEffectMethodMarker
* @author Eric Lafortune
*/
-public class KeepMarker
+public class MemberAccessFlagCleaner
implements ClassVisitor,
MemberVisitor
{
- // A visitor info flag to indicate the visitor accepter is being kept.
- private static final Object KEPT = new Object();
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- markAsKept(programClass);
- }
+ private final int accessFlags;
- public void visitLibraryClass(LibraryClass libraryClass)
+ /**
+ * Creates a new MemberAccessFlagCleaner.
+ * @param accessFlags the member access flags to be cleared.
+ */
+ public MemberAccessFlagCleaner(int accessFlags)
{
- markAsKept(libraryClass);
+ this.accessFlags = accessFlags;
}
- // Implementations for MemberVisitor.
-
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
- {
- markAsKept(programField);
- }
-
+ // Implementations for ClassVisitor.
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ public void visitProgramClass(ProgramClass programClass)
{
- markAsKept(MethodLinker.lastMember(programMethod));
+ programClass.u2accessFlags &= ~accessFlags;
}
-
- public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
+ public void visitLibraryClass(LibraryClass libraryClass)
{
- markAsKept(libraryField);
+ libraryClass.u2accessFlags &= ~accessFlags;
}
- public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
- {
- markAsKept(MethodLinker.lastMember(libraryMethod));
- }
+ // Implementations for MemberVisitor.
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {}
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
- // Small utility methods.
- private static void markAsKept(VisitorAccepter visitorAccepter)
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- visitorAccepter.setVisitorInfo(KEPT);
+ programField.u2accessFlags &= ~accessFlags;
}
- public static boolean isKept(VisitorAccepter visitorAccepter)
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- // We're also checking for the constant in NoSideEffectMethodMarker,
- // to keep things simple.
- Object visitorInfo =
- MethodLinker.lastVisitorAccepter(visitorAccepter).getVisitorInfo();
-
- return visitorInfo == KEPT ||
- visitorInfo == NoSideEffectMethodMarker.KEPT_BUT_NO_SIDE_EFFECTS;
+ programMethod.u2accessFlags &= ~accessFlags;
}
}
diff --git a/core/src/proguard/classfile/visitor/MemberAccessFlagSetter.java b/core/src/proguard/classfile/visitor/MemberAccessFlagSetter.java
new file mode 100644
index 0000000..b28c6f7
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/MemberAccessFlagSetter.java
@@ -0,0 +1,66 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+
+/**
+ * This MemberVisitor sets the specified access flags of the
+ * program class members that it visits.
+ *
+ * @see ClassConstants
+ *
+ * @author Johan Leys
+ */
+public class MemberAccessFlagSetter
+implements MemberVisitor
+{
+ private final int accessFlags;
+
+
+ /**
+ * Creates a new MemberAccessFlagSetter.
+ *
+ * @param accessFlags the member access flags to be set.
+ */
+ public MemberAccessFlagSetter(int accessFlags)
+ {
+ this.accessFlags = accessFlags;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {}
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
+
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ programField.u2accessFlags |= accessFlags;
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ programMethod.u2accessFlags |= accessFlags;
+ }
+}
diff --git a/src/proguard/classfile/visitor/MemberClassAccessFilter.java b/core/src/proguard/classfile/visitor/MemberClassAccessFilter.java
similarity index 98%
rename from src/proguard/classfile/visitor/MemberClassAccessFilter.java
rename to core/src/proguard/classfile/visitor/MemberClassAccessFilter.java
index 3dcbf95..acb5e6b 100644
--- a/src/proguard/classfile/visitor/MemberClassAccessFilter.java
+++ b/core/src/proguard/classfile/visitor/MemberClassAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/visitor/MemberCollector.java b/core/src/proguard/classfile/visitor/MemberCollector.java
new file mode 100644
index 0000000..c0b511e
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/MemberCollector.java
@@ -0,0 +1,92 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+import java.util.Set;
+
+/**
+ * This MemberVisitor collects dot-separated classname.membername.descriptor
+ * strings of the class members that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberCollector
+extends SimplifiedVisitor
+implements MemberVisitor
+{
+ private final boolean includeClassName;
+ private final boolean includeMemberName;
+ private final boolean includeMemberDescriptor;
+
+ private final Set set;
+
+
+ /**
+ * Creates a new MemberCollector.
+ * @param includeClassName specifies whether to include the class
+ * name in each collected strings.
+ * @param includeMemberName specifies whether to include the member
+ * name in each collected strings.
+ * @param includeMemberDescriptor specifies whether to include the member
+ * descriptor in each collected strings.
+ * @param set the Set in which all strings will be
+ * collected.
+ */
+ public MemberCollector(boolean includeClassName,
+ boolean includeMemberName,
+ boolean includeMemberDescriptor,
+ Set set)
+ {
+ this.includeClassName = includeClassName;
+ this.includeMemberName = includeMemberName;
+ this.includeMemberDescriptor = includeMemberDescriptor;
+
+ this.set = set;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member)
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ if (includeClassName)
+ {
+ buffer.append(clazz.getName()).append('.');
+ }
+
+ if (includeMemberName)
+ {
+ buffer.append(member.getName(clazz)).append('.');
+ }
+
+ if (includeMemberDescriptor)
+ {
+ buffer.append(member.getDescriptor(clazz));
+ }
+
+ set.add(buffer.toString());
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/visitor/MemberCounter.java b/core/src/proguard/classfile/visitor/MemberCounter.java
similarity index 97%
rename from src/proguard/classfile/visitor/MemberCounter.java
rename to core/src/proguard/classfile/visitor/MemberCounter.java
index 535bdeb..0a5dd5e 100644
--- a/src/proguard/classfile/visitor/MemberCounter.java
+++ b/core/src/proguard/classfile/visitor/MemberCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MemberDescriptorFilter.java b/core/src/proguard/classfile/visitor/MemberDescriptorFilter.java
similarity index 72%
rename from src/proguard/classfile/visitor/MemberDescriptorFilter.java
rename to core/src/proguard/classfile/visitor/MemberDescriptorFilter.java
index 8d2318b..d37d08d 100644
--- a/src/proguard/classfile/visitor/MemberDescriptorFilter.java
+++ b/core/src/proguard/classfile/visitor/MemberDescriptorFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,8 @@
import proguard.classfile.*;
import proguard.util.*;
+import java.util.List;
+
/**
* This MemberVisitor delegates its visits to another given
@@ -39,15 +41,34 @@ public class MemberDescriptorFilter implements MemberVisitor
/**
* Creates a new MemberDescriptorFilter.
- * @param regularExpression the regular expression against which member
- * descriptors will be matched.
- * @param memberVisitor the MemberVisitor to which visits
- * will be delegated.
+ * @param regularExpression the regular expression against which member
+ * descriptors will be matched.
+ * @param memberVisitor the MemberVisitor to which
+ * visits will be delegated.
+ */
+ public MemberDescriptorFilter(String regularExpression,
+ MemberVisitor memberVisitor)
+ {
+ this(regularExpression, null, memberVisitor);
+ }
+
+
+ /**
+ * Creates a new MemberDescriptorFilter.
+ * @param regularExpression the regular expression against which member
+ * descriptors will be matched.
+ * @param variableStringMatchers an optional mutable list of
+ * VariableStringMatcher instances that match
+ * the wildcards.
+ * @param memberVisitor the MemberVisitor to which
+ * visits will be delegated.
*/
public MemberDescriptorFilter(String regularExpression,
+ List variableStringMatchers,
MemberVisitor memberVisitor)
{
- this(new ClassNameParser().parse(regularExpression), memberVisitor);
+ this(new ListParser(new ClassNameParser(variableStringMatchers)).parse(regularExpression),
+ memberVisitor);
}
diff --git a/src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java b/core/src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java
rename to core/src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java
index 6d7d377..5a49b19 100644
--- a/src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/MemberDescriptorReferencedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MemberNameFilter.java b/core/src/proguard/classfile/visitor/MemberNameFilter.java
similarity index 73%
rename from src/proguard/classfile/visitor/MemberNameFilter.java
rename to core/src/proguard/classfile/visitor/MemberNameFilter.java
index bca6120..0729aa5 100644
--- a/src/proguard/classfile/visitor/MemberNameFilter.java
+++ b/core/src/proguard/classfile/visitor/MemberNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,8 @@
import proguard.classfile.*;
import proguard.util.*;
+import java.util.List;
+
/**
* This MemberVisitor delegates its visits to another given
@@ -39,19 +41,38 @@ public class MemberNameFilter implements MemberVisitor
/**
* Creates a new MemberNameFilter.
- * @param regularExpression the regular expression against which member
- * names will be matched.
- * @param memberVisitor the MemberVisitor to which visits
- * will be delegated.
+ * @param regularExpression the regular expression against which member
+ * names will be matched.
+ * @param memberVisitor the MemberVisitor to which
+ * visits will be delegated.
*/
public MemberNameFilter(String regularExpression,
MemberVisitor memberVisitor)
{
- this(new ListParser(new NameParser()).parse(regularExpression),
+ this(regularExpression, null, memberVisitor);
+ }
+
+
+ /**
+ * Creates a new MemberNameFilter.
+ * @param regularExpression the regular expression against which member
+ * names will be matched.
+ * @param variableStringMatchers an optional mutable list of
+ * VariableStringMatcher instances that match
+ * the wildcards.
+ * @param memberVisitor the MemberVisitor to which
+ * visits will be delegated.
+ */
+ public MemberNameFilter(String regularExpression,
+ List variableStringMatchers,
+ MemberVisitor memberVisitor)
+ {
+ this(new ListParser(new NameParser(variableStringMatchers)).parse(regularExpression),
memberVisitor);
}
+ /**
/**
* Creates a new MemberNameFilter.
* @param regularExpressionMatcher the regular expression against which
diff --git a/src/proguard/classfile/visitor/MemberToClassVisitor.java b/core/src/proguard/classfile/visitor/MemberToClassVisitor.java
similarity index 65%
rename from src/proguard/classfile/visitor/MemberToClassVisitor.java
rename to core/src/proguard/classfile/visitor/MemberToClassVisitor.java
index 4f089f3..8c3d0db 100644
--- a/src/proguard/classfile/visitor/MemberToClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/MemberToClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -25,8 +25,7 @@
/**
* This MemberVisitor delegates all visits to a given ClassVisitor.
- * The latter visits the class of each visited class member, although
- * never twice in a row.
+ * The latter visits the class of each visited class member.
*
* @author Eric Lafortune
*/
@@ -34,8 +33,6 @@ public class MemberToClassVisitor implements MemberVisitor
{
private final ClassVisitor classVisitor;
- private Clazz lastVisitedClass;
-
public MemberToClassVisitor(ClassVisitor classVisitor)
{
@@ -47,44 +44,24 @@ public MemberToClassVisitor(ClassVisitor classVisitor)
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- if (!programClass.equals(lastVisitedClass))
- {
- classVisitor.visitProgramClass(programClass);
-
- lastVisitedClass = programClass;
- }
+ classVisitor.visitProgramClass(programClass);
}
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- if (!programClass.equals(lastVisitedClass))
- {
- classVisitor.visitProgramClass(programClass);
-
- lastVisitedClass = programClass;
- }
+ classVisitor.visitProgramClass(programClass);
}
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
- if (!libraryClass.equals(lastVisitedClass))
- {
- classVisitor.visitLibraryClass(libraryClass);
-
- lastVisitedClass = libraryClass;
- }
+ classVisitor.visitLibraryClass(libraryClass);
}
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
- if (!libraryClass.equals(lastVisitedClass))
- {
- classVisitor.visitLibraryClass(libraryClass);
-
- lastVisitedClass = libraryClass;
- }
+ classVisitor.visitLibraryClass(libraryClass);
}
}
diff --git a/src/proguard/classfile/visitor/MemberVisitor.java b/core/src/proguard/classfile/visitor/MemberVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/MemberVisitor.java
rename to core/src/proguard/classfile/visitor/MemberVisitor.java
index 1e14c9a..a8564be 100644
--- a/src/proguard/classfile/visitor/MemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/MemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MemberCollector.java b/core/src/proguard/classfile/visitor/MethodCollector.java
similarity index 61%
rename from src/proguard/classfile/visitor/MemberCollector.java
rename to core/src/proguard/classfile/visitor/MethodCollector.java
index 5a344a0..72a5cf6 100644
--- a/src/proguard/classfile/visitor/MemberCollector.java
+++ b/core/src/proguard/classfile/visitor/MethodCollector.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,34 +26,34 @@
import java.util.Set;
/**
- * This MemberVisitor collects the concatenated name/descriptor strings of
- * class members that have been visited.
+ * This MemberVisitor collects the methods that it visits in the
+ * given collection.
*
- * @author Eric Lafortune
+ * @author Johan Leys
*/
-public class MemberCollector
+public class MethodCollector
extends SimplifiedVisitor
implements MemberVisitor
{
- private final Set set;
+ private final Set methods;
- /**
- * Creates a new MemberCollector.
- * @param set the Set in which all method names/descriptor
- * strings will be collected.
- */
- public MemberCollector(Set set)
+ public MethodCollector(Set methods)
{
- this.set = set;
+ this.methods = methods;
}
- // Implementations for MemberVisitor.
+ // Implementations for MethodCollector.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ methods.add(programMethod);
+ }
- public void visitAnyMember(Clazz clazz, Member member)
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
- set.add(member.getName(clazz) + member.getDescriptor(clazz));
+ methods.add(libraryMethod);
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/classfile/visitor/MethodImplementationFilter.java b/core/src/proguard/classfile/visitor/MethodImplementationFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/MethodImplementationFilter.java
rename to core/src/proguard/classfile/visitor/MethodImplementationFilter.java
index 96d0a4e..fe401e5 100644
--- a/src/proguard/classfile/visitor/MethodImplementationFilter.java
+++ b/core/src/proguard/classfile/visitor/MethodImplementationFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MethodImplementationTraveler.java b/core/src/proguard/classfile/visitor/MethodImplementationTraveler.java
similarity index 98%
rename from src/proguard/classfile/visitor/MethodImplementationTraveler.java
rename to core/src/proguard/classfile/visitor/MethodImplementationTraveler.java
index 1ff7b13..199cfe1 100644
--- a/src/proguard/classfile/visitor/MethodImplementationTraveler.java
+++ b/core/src/proguard/classfile/visitor/MethodImplementationTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MultiClassPoolVisitor.java b/core/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/MultiClassPoolVisitor.java
rename to core/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
index 5fb4cc8..9bd6de8 100644
--- a/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
+++ b/core/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/MultiClassVisitor.java b/core/src/proguard/classfile/visitor/MultiClassVisitor.java
similarity index 68%
rename from src/proguard/classfile/visitor/MultiClassVisitor.java
rename to core/src/proguard/classfile/visitor/MultiClassVisitor.java
index 379b16a..658c423 100644
--- a/src/proguard/classfile/visitor/MultiClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/MultiClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
package proguard.classfile.visitor;
import proguard.classfile.*;
+import proguard.util.ArrayUtil;
/**
@@ -31,18 +32,17 @@
*/
public class MultiClassVisitor implements ClassVisitor
{
- private static final int ARRAY_SIZE_INCREMENT = 5;
-
private ClassVisitor[] classVisitors;
private int classVisitorCount;
public MultiClassVisitor()
{
+ this.classVisitors = new ClassVisitor[16];
}
- public MultiClassVisitor(ClassVisitor[] classVisitors)
+ public MultiClassVisitor(ClassVisitor... classVisitors)
{
this.classVisitors = classVisitors;
this.classVisitorCount = classVisitors.length;
@@ -51,28 +51,10 @@ public MultiClassVisitor(ClassVisitor[] classVisitors)
public void addClassVisitor(ClassVisitor classVisitor)
{
- ensureArraySize();
-
- classVisitors[classVisitorCount++] = classVisitor;
- }
-
-
- private void ensureArraySize()
- {
- if (classVisitors == null)
- {
- classVisitors = new ClassVisitor[ARRAY_SIZE_INCREMENT];
- }
- else if (classVisitors.length == classVisitorCount)
- {
- ClassVisitor[] newClassVisitors =
- new ClassVisitor[classVisitorCount +
- ARRAY_SIZE_INCREMENT];
- System.arraycopy(classVisitors, 0,
- newClassVisitors, 0,
- classVisitorCount);
- classVisitors = newClassVisitors;
- }
+ classVisitors =
+ ArrayUtil.add(classVisitors,
+ classVisitorCount++,
+ classVisitor);
}
diff --git a/core/src/proguard/classfile/visitor/MultiConstantVisitor.java b/core/src/proguard/classfile/visitor/MultiConstantVisitor.java
new file mode 100644
index 0000000..3da684b
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/MultiConstantVisitor.java
@@ -0,0 +1,74 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.ArrayUtil;
+
+
+/**
+ * This ConstantVisitor delegates all visits to each ConstantVisitor in a given list.
+ *
+ * @author Johan Leys
+ */
+public class MultiConstantVisitor
+extends SimplifiedVisitor
+implements ConstantVisitor
+{
+ private ConstantVisitor[] constantVisitors;
+ private int constantVisitorCount;
+
+
+ public MultiConstantVisitor()
+ {
+ this.constantVisitors = new ConstantVisitor[16];
+ }
+
+
+ public MultiConstantVisitor(ConstantVisitor... constantVisitors)
+ {
+ this.constantVisitors = constantVisitors;
+ this.constantVisitorCount = this.constantVisitors.length;
+ }
+
+
+ public void addClassVisitor(ConstantVisitor constantVisitor)
+ {
+ constantVisitors =
+ ArrayUtil.add(constantVisitors,
+ constantVisitorCount++,
+ constantVisitor);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant)
+ {
+ for (int index = 0; index < constantVisitorCount; index++)
+ {
+ constant.accept(clazz, constantVisitors[index]);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/MultiMemberVisitor.java b/core/src/proguard/classfile/visitor/MultiMemberVisitor.java
similarity index 73%
rename from src/proguard/classfile/visitor/MultiMemberVisitor.java
rename to core/src/proguard/classfile/visitor/MultiMemberVisitor.java
index dde3f37..7e641db 100644
--- a/src/proguard/classfile/visitor/MultiMemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/MultiMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
package proguard.classfile.visitor;
import proguard.classfile.*;
+import proguard.util.ArrayUtil;
/**
@@ -31,18 +32,17 @@
*/
public class MultiMemberVisitor implements MemberVisitor
{
- private static final int ARRAY_SIZE_INCREMENT = 5;
-
private MemberVisitor[] memberVisitors;
private int memberVisitorCount;
public MultiMemberVisitor()
{
+ this.memberVisitors = new MemberVisitor[16];
}
- public MultiMemberVisitor(MemberVisitor[] memberVisitors)
+ public MultiMemberVisitor(MemberVisitor... memberVisitors)
{
this.memberVisitors = memberVisitors;
this.memberVisitorCount = memberVisitors.length;
@@ -51,28 +51,10 @@ public MultiMemberVisitor(MemberVisitor[] memberVisitors)
public void addMemberVisitor(MemberVisitor memberVisitor)
{
- ensureArraySize();
-
- memberVisitors[memberVisitorCount++] = memberVisitor;
- }
-
-
- private void ensureArraySize()
- {
- if (memberVisitors == null)
- {
- memberVisitors = new MemberVisitor[ARRAY_SIZE_INCREMENT];
- }
- else if (memberVisitors.length == memberVisitorCount)
- {
- MemberVisitor[] newMemberVisitors =
- new MemberVisitor[memberVisitorCount +
- ARRAY_SIZE_INCREMENT];
- System.arraycopy(memberVisitors, 0,
- newMemberVisitors, 0,
- memberVisitorCount);
- memberVisitors = newMemberVisitors;
- }
+ memberVisitors =
+ ArrayUtil.add(memberVisitors,
+ memberVisitorCount++,
+ memberVisitor);
}
diff --git a/src/proguard/classfile/visitor/NamedClassVisitor.java b/core/src/proguard/classfile/visitor/NamedClassVisitor.java
similarity index 96%
rename from src/proguard/classfile/visitor/NamedClassVisitor.java
rename to core/src/proguard/classfile/visitor/NamedClassVisitor.java
index 2daeba2..5270e1b 100644
--- a/src/proguard/classfile/visitor/NamedClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/NamedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/NamedFieldVisitor.java b/core/src/proguard/classfile/visitor/NamedFieldVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/NamedFieldVisitor.java
rename to core/src/proguard/classfile/visitor/NamedFieldVisitor.java
index ed8df14..c6021bc 100644
--- a/src/proguard/classfile/visitor/NamedFieldVisitor.java
+++ b/core/src/proguard/classfile/visitor/NamedFieldVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/NamedMethodVisitor.java b/core/src/proguard/classfile/visitor/NamedMethodVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/NamedMethodVisitor.java
rename to core/src/proguard/classfile/visitor/NamedMethodVisitor.java
index 817e969..f096cf7 100644
--- a/src/proguard/classfile/visitor/NamedMethodVisitor.java
+++ b/core/src/proguard/classfile/visitor/NamedMethodVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/classfile/visitor/ParallelAllClassVisitor.java b/core/src/proguard/classfile/visitor/ParallelAllClassVisitor.java
new file mode 100644
index 0000000..b7be4d1
--- /dev/null
+++ b/core/src/proguard/classfile/visitor/ParallelAllClassVisitor.java
@@ -0,0 +1,202 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.classfile.visitor;
+
+import proguard.classfile.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+
+/**
+ * This ClassPoolVisitor will visit all Clazz objects of the class pool
+ * in a parallel way. For each thread, a separate ClassVisitor will be
+ * created using {@link ClassVisitorFactory#createClassVisitor()}.
+ *
+ * The number of parallel threads is coupled to the number of available
+ * processors:
+ *
+ * parallel_threads = Runtime.getRuntime().availableProcessors() - 1;
+ *
+ *
+ * It is possible to override the number of threads by setting the
+ * environment variable {@code parallel.threads} to an integer > 0.
+ *
+ * @author Thomas Neidhart
+ */
+public class ParallelAllClassVisitor
+implements ClassPoolVisitor
+{
+ private static final int THREAD_COUNT;
+ static {
+ Integer threads = null;
+ try {
+ String threadCountString = System.getProperty("parallel.threads");
+ if (threadCountString != null)
+ {
+ threads = Integer.parseInt(threadCountString);
+ }
+ }
+ catch (Exception ex) {}
+
+ threads = threads == null ?
+ Runtime.getRuntime().availableProcessors() - 1 :
+ Math.min(threads.intValue(), Runtime.getRuntime().availableProcessors());
+
+ THREAD_COUNT = threads.intValue();
+ }
+
+
+ /**
+ * A factory for ClassVisitor objects.
+ */
+ public interface ClassVisitorFactory
+ {
+ /**
+ * Creates a ClassVisitor that will be used during
+ * parallel visiting of classes in a ClassPool.
+ */
+ ClassVisitor createClassVisitor();
+ }
+
+
+ private final ClassVisitorFactory classVisitorFactory;
+
+
+ /**
+ * Create a new ParallelAllClassVisitor that will use the given factory
+ * to visit all classes in a ClassPool in a parallel way.
+ */
+ public ParallelAllClassVisitor(ClassVisitorFactory classVisitorFactory)
+ {
+ this.classVisitorFactory = classVisitorFactory;
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ if (THREAD_COUNT <= 1)
+ {
+ // Fallback to single thread execution if the thread count
+ // was overridden by an environment variable.
+ classPool.classesAccept(classVisitorFactory.createClassVisitor());
+ }
+ else
+ {
+ ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT, new MyThreadFactory());
+
+ MyThreadedClassVisitor classVisitor = new MyThreadedClassVisitor(executor);
+
+ classPool.classesAccept(classVisitor);
+
+ try
+ {
+ // Shutdown the executor service to release memory.
+ executor.shutdown();
+
+ // Rethrow any exception that was thrown in the executor threads.
+ classVisitor.awaitTermination();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException("Parallel execution is taking too long", e);
+ }
+ catch (ExecutionException e)
+ {
+ throw new RuntimeException(e.getCause());
+ }
+ }
+ }
+
+
+ private class MyThreadFactory
+ implements ThreadFactory
+ {
+ private int threadCounter = 0;
+
+ public Thread newThread(Runnable runnable)
+ {
+ return new MyClassVisitorThread(++threadCounter, runnable);
+ }
+ }
+
+
+ private class MyClassVisitorThread
+ extends Thread
+ {
+ private final ClassVisitor classVisitor = classVisitorFactory.createClassVisitor();
+
+ public MyClassVisitorThread(int counter, Runnable runnable)
+ {
+ super(runnable, "Parallel Class Visitor " + counter);
+ }
+ }
+
+
+ private static class MyThreadedClassVisitor
+ implements ClassVisitor
+ {
+ private final ExecutorService executorService;
+
+ private final List futures = new ArrayList();
+
+ public MyThreadedClassVisitor(ExecutorService executorService)
+ {
+ this.executorService = executorService;
+ }
+
+ public void awaitTermination() throws ExecutionException, InterruptedException
+ {
+ for (Future future : futures)
+ {
+ future.get();
+ }
+ }
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ submitClassToExecutorService(libraryClass);
+ }
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ submitClassToExecutorService(programClass);
+ }
+
+
+ private void submitClassToExecutorService(final Clazz clazz)
+ {
+ futures.add(executorService.submit(new Runnable()
+ {
+ public void run()
+ {
+ MyClassVisitorThread thread = (MyClassVisitorThread)Thread.currentThread();
+ clazz.accept(thread.classVisitor);
+ }
+ }));
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/ParameterVisitor.java b/core/src/proguard/classfile/visitor/ParameterVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/ParameterVisitor.java
rename to core/src/proguard/classfile/visitor/ParameterVisitor.java
index 805e1de..503d1ac 100644
--- a/src/proguard/classfile/visitor/ParameterVisitor.java
+++ b/core/src/proguard/classfile/visitor/ParameterVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ProgramClassFilter.java b/core/src/proguard/classfile/visitor/ProgramClassFilter.java
similarity index 96%
rename from src/proguard/classfile/visitor/ProgramClassFilter.java
rename to core/src/proguard/classfile/visitor/ProgramClassFilter.java
index 088da87..0d57634 100644
--- a/src/proguard/classfile/visitor/ProgramClassFilter.java
+++ b/core/src/proguard/classfile/visitor/ProgramClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ProgramMemberFilter.java b/core/src/proguard/classfile/visitor/ProgramMemberFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/ProgramMemberFilter.java
rename to core/src/proguard/classfile/visitor/ProgramMemberFilter.java
index 25299f4..9315b37 100644
--- a/src/proguard/classfile/visitor/ProgramMemberFilter.java
+++ b/core/src/proguard/classfile/visitor/ProgramMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ReferencedClassVisitor.java b/core/src/proguard/classfile/visitor/ReferencedClassVisitor.java
similarity index 99%
rename from src/proguard/classfile/visitor/ReferencedClassVisitor.java
rename to core/src/proguard/classfile/visitor/ReferencedClassVisitor.java
index f60c06d..9b62ff6 100644
--- a/src/proguard/classfile/visitor/ReferencedClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/ReferencedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/ReferencedMemberVisitor.java b/core/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
similarity index 95%
rename from src/proguard/classfile/visitor/ReferencedMemberVisitor.java
rename to core/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
index 768bdf4..3cce2c0 100644
--- a/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 +38,7 @@ public class ReferencedMemberVisitor
implements ConstantVisitor,
ElementValueVisitor
{
- private final MemberVisitor memberVisitor;
+ protected final MemberVisitor memberVisitor;
public ReferencedMemberVisitor(MemberVisitor memberVisitor)
diff --git a/src/proguard/classfile/visitor/SimilarMemberVisitor.java b/core/src/proguard/classfile/visitor/SimilarMemberVisitor.java
similarity index 73%
rename from src/proguard/classfile/visitor/SimilarMemberVisitor.java
rename to core/src/proguard/classfile/visitor/SimilarMemberVisitor.java
index 21abb2f..2c9e39c 100644
--- a/src/proguard/classfile/visitor/SimilarMemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/SimilarMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@
/**
* This MemberVisitor lets a given MemberVisitor
* visit all members that have the same name and type as the visited methods
- * in the class hierarchy of a given target class.
+ * in the class hierarchy of the members' classes or of a given target class.
*
* @author Eric Lafortune
*/
@@ -40,6 +40,37 @@ public class SimilarMemberVisitor
private final MemberVisitor memberVisitor;
+ /**
+ * Creates a new SimilarMemberVisitor.
+ * @param visitThisMember specifies whether to visit the class
+ * members in the members' classes themselves.
+ * @param visitSuperMembers specifies whether to visit the class
+ * members in the super classes of the
+ * members' classes.
+ * @param visitInterfaceMembers specifies whether to visit the class
+ * members in the interface classes of the
+ * members' classes.
+ * @param visitOverridingMembers specifies whether to visit the class
+ * members in the subclasses of the members'
+ * classes.
+ * @param memberVisitor the MemberVisitor to which
+ * visits will be delegated.
+ */
+ public SimilarMemberVisitor(boolean visitThisMember,
+ boolean visitSuperMembers,
+ boolean visitInterfaceMembers,
+ boolean visitOverridingMembers,
+ MemberVisitor memberVisitor)
+ {
+ this(null,
+ visitThisMember,
+ visitSuperMembers,
+ visitInterfaceMembers,
+ visitOverridingMembers,
+ memberVisitor);
+ }
+
+
/**
* Creates a new SimilarMemberVisitor.
* @param targetClass the class in whose hierarchy to look for
@@ -78,6 +109,8 @@ public SimilarMemberVisitor(Clazz targetClass,
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
+ Clazz targetClass = targetClass(programClass);
+
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
@@ -90,6 +123,8 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
+ Clazz targetClass = targetClass(libraryClass);
+
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
@@ -102,6 +137,8 @@ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryFie
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
+ Clazz targetClass = targetClass(programClass);
+
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
@@ -114,6 +151,8 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
+ Clazz targetClass = targetClass(libraryClass);
+
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
@@ -122,4 +161,14 @@ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryM
libraryMethod.getDescriptor(libraryClass),
memberVisitor));
}
+
+
+ /**
+ * Returns the target class, or the given class if the target class is
+ * null.
+ */
+ private Clazz targetClass(Clazz clazz)
+ {
+ return targetClass != null ? targetClass : clazz;
+ }
}
\ No newline at end of file
diff --git a/src/proguard/classfile/visitor/SimpleClassPrinter.java b/core/src/proguard/classfile/visitor/SimpleClassPrinter.java
similarity index 82%
rename from src/proguard/classfile/visitor/SimpleClassPrinter.java
rename to core/src/proguard/classfile/visitor/SimpleClassPrinter.java
index 9ee92fc..34fa6ef 100644
--- a/src/proguard/classfile/visitor/SimpleClassPrinter.java
+++ b/core/src/proguard/classfile/visitor/SimpleClassPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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 @@
import proguard.classfile.*;
import proguard.classfile.util.ClassUtil;
-import java.io.PrintStream;
+import java.io.PrintWriter;
/**
@@ -39,36 +39,30 @@ public class SimpleClassPrinter
MemberVisitor
{
private final boolean printAccessModifiers;
- private final PrintStream ps;
+ private final PrintWriter pw;
/**
- * Creates a new SimpleClassPrinter that prints to
- * System.out, including the access modifiers.
- */
- public SimpleClassPrinter()
- {
- this(true);
- }
-
- /**
- * Creates a new SimpleClassPrinter that prints to
- * System.out, with or without the access modifiers.
+ * Creates a new SimpleClassPrinter that prints to the standard output, with
+ * or without the access modifiers.
*/
public SimpleClassPrinter(boolean printAccessModifiers)
{
- this(printAccessModifiers, System.out);
+ // We're using the system's default character encoding for writing to
+ // the standard output.
+ this(printAccessModifiers, new PrintWriter(System.out, true));
}
+
/**
- * Creates a new SimpleClassPrinter that prints to the given
- * PrintStream, with or without the access modifiers.
+ * Creates a new SimpleClassPrinter that prints to the given writer, with
+ * or without the access modifiers.
*/
public SimpleClassPrinter(boolean printAccessModifiers,
- PrintStream printStream)
+ PrintWriter printWriter)
{
this.printAccessModifiers = printAccessModifiers;
- this.ps = printStream;
+ this.pw = printWriter;
}
@@ -76,7 +70,7 @@ public SimpleClassPrinter(boolean printAccessModifiers,
public void visitProgramClass(ProgramClass programClass)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
programClass.getAccessFlags() :
0,
@@ -86,7 +80,7 @@ public void visitProgramClass(ProgramClass programClass)
public void visitLibraryClass(LibraryClass libraryClass)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
libraryClass.getAccessFlags() :
0,
@@ -98,7 +92,7 @@ public void visitLibraryClass(LibraryClass libraryClass)
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
programClass.getAccessFlags() :
0,
@@ -115,7 +109,7 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
programClass.getAccessFlags() :
0,
@@ -133,7 +127,7 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
libraryClass.getAccessFlags() :
0,
@@ -150,7 +144,7 @@ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryFie
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
- ps.println(ClassUtil.externalFullClassDescription(
+ pw.println(ClassUtil.externalFullClassDescription(
printAccessModifiers ?
libraryClass.getAccessFlags() :
0,
diff --git a/src/proguard/optimize/KeptClassFilter.java b/core/src/proguard/classfile/visitor/SingleTimeClassVisitor.java
similarity index 67%
rename from src/proguard/optimize/KeptClassFilter.java
rename to core/src/proguard/classfile/visitor/SingleTimeClassVisitor.java
index e1c7f08..2d6ef80 100644
--- a/src/proguard/optimize/KeptClassFilter.java
+++ b/core/src/proguard/classfile/visitor/SingleTimeClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -18,31 +18,24 @@
* 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;
+package proguard.classfile.visitor;
import proguard.classfile.*;
-import proguard.classfile.visitor.ClassVisitor;
/**
- * This ClassVisitor delegates all its method calls to another ClassVisitor,
- * but only for Clazz objects that are marked as kept.
- *
- * @see KeepMarker
+ * This ClassVisitor delegates all visits to a given ClassVisitor, although
+ * only once to the same class in a row.
*
* @author Eric Lafortune
*/
-public class KeptClassFilter
-implements ClassVisitor
+public class SingleTimeClassVisitor implements ClassVisitor
{
private final ClassVisitor classVisitor;
+ private Clazz lastVisitedClass;
+
- /**
- * Creates a new KeptClassFilter.
- * @param classVisitor the class visitor to which the visiting will be
- * delegated.
- */
- public KeptClassFilter(ClassVisitor classVisitor)
+ public SingleTimeClassVisitor(ClassVisitor classVisitor)
{
this.classVisitor = classVisitor;
}
@@ -52,18 +45,22 @@ public KeptClassFilter(ClassVisitor classVisitor)
public void visitProgramClass(ProgramClass programClass)
{
- if (KeepMarker.isKept(programClass))
+ if (!programClass.equals(lastVisitedClass))
{
classVisitor.visitProgramClass(programClass);
+
+ lastVisitedClass = programClass;
}
}
public void visitLibraryClass(LibraryClass libraryClass)
{
- if (KeepMarker.isKept(libraryClass))
+ if (!libraryClass.equals(lastVisitedClass))
{
classVisitor.visitLibraryClass(libraryClass);
+
+ lastVisitedClass = libraryClass;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/classfile/visitor/SubclassFilter.java b/core/src/proguard/classfile/visitor/SubclassFilter.java
similarity index 97%
rename from src/proguard/classfile/visitor/SubclassFilter.java
rename to core/src/proguard/classfile/visitor/SubclassFilter.java
index 3ae644f..ea377fb 100644
--- a/src/proguard/classfile/visitor/SubclassFilter.java
+++ b/core/src/proguard/classfile/visitor/SubclassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/SubclassTraveler.java b/core/src/proguard/classfile/visitor/SubclassTraveler.java
similarity index 96%
rename from src/proguard/classfile/visitor/SubclassTraveler.java
rename to core/src/proguard/classfile/visitor/SubclassTraveler.java
index e3ee6b7..13c3cd9 100644
--- a/src/proguard/classfile/visitor/SubclassTraveler.java
+++ b/core/src/proguard/classfile/visitor/SubclassTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/VariableClassVisitor.java b/core/src/proguard/classfile/visitor/VariableClassVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/VariableClassVisitor.java
rename to core/src/proguard/classfile/visitor/VariableClassVisitor.java
index 31dc216..9d72f5a 100644
--- a/src/proguard/classfile/visitor/VariableClassVisitor.java
+++ b/core/src/proguard/classfile/visitor/VariableClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/VariableMemberVisitor.java b/core/src/proguard/classfile/visitor/VariableMemberVisitor.java
similarity index 97%
rename from src/proguard/classfile/visitor/VariableMemberVisitor.java
rename to core/src/proguard/classfile/visitor/VariableMemberVisitor.java
index 91d6b06..6268041 100644
--- a/src/proguard/classfile/visitor/VariableMemberVisitor.java
+++ b/core/src/proguard/classfile/visitor/VariableMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/classfile/visitor/package.html b/core/src/proguard/classfile/visitor/package.html
similarity index 100%
rename from src/proguard/classfile/visitor/package.html
rename to core/src/proguard/classfile/visitor/package.html
diff --git a/core/src/proguard/configuration/ConfigurationLogger.java b/core/src/proguard/configuration/ConfigurationLogger.java
new file mode 100644
index 0000000..0b08015
--- /dev/null
+++ b/core/src/proguard/configuration/ConfigurationLogger.java
@@ -0,0 +1,789 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.configuration;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This class can be injected in applications to log information about reflection
+ * being used in the application code, and suggest appropriate ProGuard rules for
+ * keeping the reflected classes, methods and/or fields.
+ *
+ * @author Johan Leys
+ */
+public class ConfigurationLogger implements Runnable
+{
+ public static final boolean LOG_ONCE = true;
+
+ private static final String LOG_TAG = "ProGuard";
+
+ public static final String CLASS_MAP_FILENAME = "classmap.txt";
+
+ private static final String EMPTY_LINE = "\u00a0\n";
+
+ // Set with missing class names.
+ private static final Set missingClasses = new HashSet();
+
+ // Map from class name to missing constructors.
+ private static final Map> missingConstructors = new HashMap>();
+ // Set of classes on which getConstructors or getDeclaredConstructors is invoked.
+ private static final Set constructorListingClasses = new HashSet();
+
+ // Map from class name to missing method signatures.
+ private static final Map> missingMethods = new HashMap>();
+ // Set of classes on which getMethods or getDeclaredMethods is invoked.
+ private static final Set methodListingClasses = new HashSet();
+
+ // Map from class name to missing field names.
+ private static final Map> missingFields = new HashMap>();
+ // Set of classes on which getFields or getDeclaredFields is invoked.
+ private static final Set fieldListingCLasses = new HashSet();
+
+ // Map from obfuscated class name to original class name.
+ private static Map classNameMap;
+
+ // Set of classes that have renamed or removed methods.
+ private static Set classesWithObfuscatedMethods;
+
+ // Set of classes that have renamed or removed fields.
+ private static Set classesWithObfuscatedFields;
+
+ private static Method logMethod;
+
+ // Try to find the Android logging class.
+ static
+ {
+ try
+ {
+ Class> logClass = Class.forName("android.util.Log");
+ logMethod = logClass.getMethod("w", String.class, String. class);
+ }
+ catch (Exception e) {}
+ }
+
+ // Classes.
+
+ /**
+ * Log a failed call to Class.forName().
+ *
+ * @param callingClassName
+ * @param missingClassName
+ */
+ public static void logForName(String callingClassName,
+ String missingClassName)
+ {
+ logMissingClass(callingClassName, "Class", "forName", missingClassName);
+ }
+
+ /**
+ * Log a failed call to ClassLoader.loadClass().
+ *
+ * @param callingClassName
+ * @param missingClassName
+ */
+ public static void logLoadClass(String callingClassName,
+ String missingClassName)
+ {
+ logMissingClass(callingClassName, "ClassLoader", "loadClass", missingClassName);
+ }
+
+
+ /**
+ * Log a failed call to Class.forName().
+ *
+ * @param callingClassName
+ * @param missingClassName
+ */
+ public static void logMissingClass(String callingClassName,
+ String invokedClassName,
+ String invokedMethodName,
+ String missingClassName)
+ {
+ if (!LOG_ONCE || !missingClasses.contains(missingClassName))
+ {
+ missingClasses.add(missingClassName);
+ log(
+ "The class '" + originalClassName(callingClassName) + "' is calling " + invokedClassName + "." + invokedMethodName + " to retrieve\n" +
+ "the class '" + missingClassName + "', but the latter could not be found.\n" +
+ "It may have been obfuscated or shrunk.\n" +
+ "You should consider preserving the class with its original name,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepClassRule(missingClassName) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ // Constructors.
+
+
+ /**
+ * Log a failed call to Class.getDeclaredConstructor().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param constructorParameters
+ */
+ public static void logGetDeclaredConstructor(String invokingClassName,
+ Class reflectedClass,
+ Class[] constructorParameters)
+ {
+ logGetConstructor(invokingClassName, "getDeclaredConstructor", reflectedClass, constructorParameters);
+ }
+
+
+ /**
+ * Log a failed call to Class.getConstructor().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param constructorParameters
+ */
+ public static void logGetConstructor(String invokingClassName,
+ Class reflectedClass,
+ Class[] constructorParameters)
+ {
+ logGetConstructor(invokingClassName, "getConstructor", reflectedClass, constructorParameters);
+ }
+
+
+ /**
+ * Log a failed call to one of the constructor retrieving methods on Class.
+ *
+ * @param invokingClassName
+ * @param invokedMethodName
+ * @param reflectedClass
+ * @param constructorParameters
+ */
+ public static void logGetConstructor(String invokingClassName,
+ String invokedMethodName,
+ Class reflectedClass,
+ Class[] constructorParameters)
+ {
+ MethodSignature signature = new MethodSignature("", constructorParameters);
+
+ Set constructors = missingConstructors.get(reflectedClass.getName());
+ if (constructors == null)
+ {
+ constructors = new HashSet();
+ missingConstructors.put(reflectedClass.getName(), constructors);
+ }
+
+ if ((!LOG_ONCE || !constructors.contains(signature)) && !isLibraryClass(reflectedClass))
+ {
+ constructors.add(signature);
+ log(
+ "The class '" + originalClassName(invokingClassName) + "' is calling Class." + invokedMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) + "' to retrieve\n" +
+ "the constructor with signature (" + originalSignature(signature) + "), but the latter could not be found.\n" +
+ "It may have been obfuscated or shrunk.\n" +
+ "You should consider preserving the constructor, with a setting like:\n" +
+ EMPTY_LINE +
+ keepConstructorRule(reflectedClass.getName(), signature) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ /**
+ * Log a call to Class.getDeclaredConstructors().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetDeclaredConstructors(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetConstructors(invokingClassName, reflectedClass, "getDeclaredConstructors");
+ }
+
+
+ /**
+ * Log a call to Class.getConstructors().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetConstructors(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetConstructors(invokingClassName, reflectedClass, "getConstructors");
+ }
+
+
+ /**
+ * Log a call to one of the constructor listing methods on Class.
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param reflectedMethodName
+ */
+ private static void logGetConstructors(String invokingClassName,
+ Class reflectedClass,
+ String reflectedMethodName)
+ {
+ initializeMappings();
+ if (classesWithObfuscatedMethods.contains(reflectedClass.getName()) &&
+ !constructorListingClasses.contains(reflectedClass.getName()) &&
+ !isLibraryClass(reflectedClass))
+ {
+ constructorListingClasses.add(reflectedClass.getName());
+ log(
+ "The class '" + originalClassName(invokingClassName) + "' is calling Class." + reflectedMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) + "' to retrieve its constructors.\n" +
+ "You might consider preserving all constructors with their original names,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepAllConstructorsRule(reflectedClass) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ // Methods.
+
+
+ /**
+ * Log a failed call to Class.getDeclaredMethod().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param reflectedMethodName
+ * @param methodParameters
+ */
+ public static void logGetDeclaredMethod(String invokingClassName,
+ Class reflectedClass,
+ String reflectedMethodName,
+ Class[] methodParameters )
+ {
+ logGetMethod(invokingClassName, "getDeclaredMethod", reflectedClass, reflectedMethodName, methodParameters);
+ }
+
+
+ /**
+ * Log a failed call to Class.getMethod().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param reflectedMethodName
+ * @param methodParameters
+ */
+ public static void logGetMethod(String invokingClassName,
+ Class reflectedClass,
+ String reflectedMethodName,
+ Class[] methodParameters )
+ {
+ logGetMethod(invokingClassName, "getMethod", reflectedClass, reflectedMethodName, methodParameters);
+ }
+
+
+ /**
+ * Log a failed call to one of the method retrieving methods on Class.
+ * @param invokingClassName
+ * @param invokedReflectionMethodName
+ * @param reflectedClass
+ * @param reflectedMethodName
+ * @param methodParameters
+ */
+ private static void logGetMethod(String invokingClassName,
+ String invokedReflectionMethodName,
+ Class reflectedClass,
+ String reflectedMethodName,
+ Class[] methodParameters )
+ {
+ Set methods = missingMethods.get(reflectedClass.getName());
+ if (methods == null)
+ {
+ methods = new HashSet();
+ missingMethods.put(reflectedClass.getName(), methods);
+ }
+
+ MethodSignature signature = new MethodSignature(reflectedMethodName, methodParameters);
+ if (!methods.contains(signature) && !isLibraryClass(reflectedClass))
+ {
+ methods.add(signature);
+ log(
+ "The class '" + originalClassName(invokingClassName) +
+ "' is calling Class." + invokedReflectionMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) +
+ "' to retrieve the method\n" +
+ reflectedMethodName + "(" + originalSignature(signature) + "),\n" +
+ "but the latter could not be found. It may have been obfuscated or shrunk.\n" +
+ "You should consider preserving the method with its original name,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepMethodRule(reflectedClass.getName(), reflectedMethodName, signature) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ /**
+ * Log a call to Class.getDeclaredMethods().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetDeclaredMethods(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetMethods(invokingClassName, "getDeclaredMethods", reflectedClass);
+ }
+
+
+ /**
+ * Log a call to Class.getMethods().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetMethods(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetMethods(invokingClassName, "getMethods", reflectedClass);
+ }
+
+
+ /**
+ * Log a call to one of the method listing methods on Class.
+ *
+ * @param invokingClassName
+ * @param invokedReflectionMethodName
+ * @param reflectedClass
+ */
+ private static void logGetMethods(String invokingClassName,
+ String invokedReflectionMethodName,
+ Class reflectedClass )
+ {
+ initializeMappings();
+ if (classesWithObfuscatedMethods.contains(reflectedClass.getName()) &&
+ !methodListingClasses.contains(reflectedClass.getName()) &&
+ !isLibraryClass(reflectedClass))
+ {
+ methodListingClasses.add(reflectedClass.getName());
+ log(
+ "The class '" + originalClassName(invokingClassName) +
+ "' is calling Class." + invokedReflectionMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) +
+ "' to retrieve its methods.\n" +
+ "You might consider preserving all methods with their original names,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepAllMethodsRule(reflectedClass) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ // Fields.
+
+
+ /**
+ * Log a failed call to Class.getField().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param reflectedFieldName
+ */
+ public static void logGetField(String invokingClassName,
+ Class reflectedClass,
+ String reflectedFieldName)
+ {
+ logGetField(invokingClassName, "getField", reflectedClass, reflectedFieldName);
+ }
+
+
+ /**
+ * Log a failed call to Class.getDeclaredField().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ * @param reflectedFieldName
+ */
+ public static void logGetDeclaredField(String invokingClassName,
+ Class reflectedClass,
+ String reflectedFieldName)
+ {
+ logGetField(invokingClassName, "getDeclaredField", reflectedClass, reflectedFieldName);
+ }
+
+
+ /**
+ * Log a failed call to one of the field retrieving methods of Class.
+ *
+ * @param invokingClassName
+ * @param invokedReflectionMethodName
+ * @param reflectedClass
+ * @param reflectedFieldName
+ */
+ private static void logGetField(String invokingClassName,
+ String invokedReflectionMethodName,
+ Class reflectedClass,
+ String reflectedFieldName )
+ {
+ Set fields = missingFields.get(reflectedClass.getName());
+ if (fields == null)
+ {
+ fields = new HashSet();
+ missingFields.put(reflectedClass.getName(), fields);
+ }
+
+ if ((!LOG_ONCE || !fields.contains(reflectedFieldName)) &&
+ !isLibraryClass(reflectedClass))
+ {
+ fields.add(reflectedFieldName);
+ log(
+ "The class '" + originalClassName(invokingClassName) +
+ "' is calling Class." + invokedReflectionMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) +
+ "' to retrieve the field '" + reflectedFieldName + "',\n" +
+ "but the latter could not be found. It may have been obfuscated or shrunk.\n" +
+ "You should consider preserving the field with its original name,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepFieldRule(reflectedClass.getName(), reflectedFieldName) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ /**
+ * Log a call to Class.getDeclaredFields().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetDeclaredFields(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetFields(invokingClassName, "getDeclaredFields", reflectedClass);
+ }
+
+
+ /**
+ * Log a call to Class.getFields().
+ *
+ * @param invokingClassName
+ * @param reflectedClass
+ */
+ public static void logGetFields(String invokingClassName,
+ Class reflectedClass )
+ {
+ logGetFields(invokingClassName, "getFields", reflectedClass);
+ }
+
+
+ /**
+ * Log a call to one of the field listing methods on Class.
+ *
+ * @param invokingClassName
+ * @param invokedReflectionMethodName
+ * @param reflectedClass
+ */
+ private static void logGetFields(String invokingClassName,
+ String invokedReflectionMethodName,
+ Class reflectedClass )
+ {
+ initializeMappings();
+ if (classesWithObfuscatedFields.contains(reflectedClass.getName()) &&
+ !fieldListingCLasses.contains(reflectedClass.getName()) &&
+ !isLibraryClass(reflectedClass))
+ {
+ fieldListingCLasses.add(reflectedClass.getName());
+ log(
+ "The class '" + originalClassName(invokingClassName) +
+ "' is calling Class." + invokedReflectionMethodName + "\n" +
+ "on class '" + originalClassName(reflectedClass) +
+ "' to retrieve its fields.\n" +
+ "You might consider preserving all fields with their original names,\n" +
+ "with a setting like:\n" +
+ EMPTY_LINE +
+ keepAllFieldsRule(reflectedClass) + "\n" +
+ EMPTY_LINE);
+ }
+ }
+
+
+ // Implementations for Runnable.
+
+ public void run()
+ {
+ printConfiguration();
+ }
+
+
+ private static void printConfiguration()
+ {
+ log("The following settings may help solving issues related to\n" +
+ "missing classes, methods and/or fields:\n");
+
+ for (String clazz : missingClasses)
+ {
+ log(keepClassRule(clazz) + "\n");
+ }
+
+ for (String clazz : missingConstructors.keySet())
+ {
+ for (MethodSignature constructor : missingConstructors.get(clazz))
+ {
+ log(keepConstructorRule(clazz, constructor) + "\n");
+ }
+ }
+
+ for (String clazz : missingMethods.keySet())
+ {
+ for (MethodSignature method : missingMethods.get(clazz))
+ {
+ log(keepMethodRule(clazz, method.name, method) + "\n");
+ }
+ }
+
+ for (String clazz : missingFields.keySet())
+ {
+ for (String field : missingFields.get(clazz))
+ {
+ log(keepFieldRule(clazz, field) + "\n");
+ }
+ }
+ }
+
+
+ // ProGuard rules.
+
+ private static String keepClassRule(String className)
+ {
+ return "-keep class " + className;
+ }
+
+
+ private static String keepConstructorRule(String className,
+ MethodSignature constructorParameters)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " public (" + originalSignature(constructorParameters) + ");\n" +
+ "}";
+ }
+
+
+ private static String keepMethodRule(String className,
+ String methodName,
+ MethodSignature constructorParameters)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " *** " + methodName + "(" + originalSignature(constructorParameters) + ");\n" +
+ "}";
+ }
+
+
+ private static String keepFieldRule(String className,
+ String fieldName)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " *** " + fieldName + ";\n" +
+ "}";
+ }
+
+
+ private static String keepAllConstructorsRule(Class className)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " (...);\n" +
+ "}";
+ }
+
+
+ private static String keepAllMethodsRule(Class className)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " ;\n" +
+ "}";
+ }
+
+
+ private static String keepAllFieldsRule(Class className)
+ {
+ return "-keepclassmembers class " + originalClassName(className) + " {\n" +
+ " ;\n" +
+ "}";
+ }
+
+
+ private static String originalClassName(Class className)
+ {
+ return originalClassName(className.getName());
+ }
+
+
+ private static String originalClassName(String className)
+ {
+ initializeMappings();
+ String originalClassName = classNameMap.get(className);
+ return originalClassName != null ? originalClassName : className;
+ }
+
+
+ /**
+ * Simple heuristic to see if the given class is a library class or not.
+ *
+ * @param clazz
+ * @return
+ */
+ private static boolean isLibraryClass(Class clazz)
+ {
+ return clazz.getClassLoader() == String.class.getClassLoader();
+ }
+
+
+ /**
+ * Log a message, either on the Android Logcat, if available, or on the
+ * Standard error outputstream otherwise.
+ *
+ * @param message the message to be logged.
+ */
+ private static void log(String message)
+ {
+ if (logMethod != null)
+ {
+ try
+ {
+ logMethod.invoke(null, LOG_TAG, message);
+ }
+ catch (Exception e)
+ {
+ System.err.println(message);
+ }
+ }
+ else
+ {
+ System.err.println(message);
+ }
+ }
+
+
+ private static void initializeMappings()
+ {
+ if (classNameMap == null)
+ {
+ classNameMap = new HashMap ();
+ classesWithObfuscatedMethods = new HashSet ();
+ classesWithObfuscatedFields = new HashSet ();
+
+ String line;
+ try
+ {
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(
+ ConfigurationLogger.class.getClassLoader().getResourceAsStream(CLASS_MAP_FILENAME)));
+
+ while ((line = reader.readLine()) != null)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(line, ",");
+ String originalClassName = tokenizer.nextToken();
+ String obfuscatedClassName = tokenizer.nextToken();
+ boolean hasObfuscatedMethods = tokenizer.nextToken().equals("1");
+ boolean hasObfuscatedFields = tokenizer.nextToken().equals("1");
+
+ classNameMap.put(obfuscatedClassName, originalClassName);
+
+ if (hasObfuscatedMethods)
+ {
+ classesWithObfuscatedMethods.add(obfuscatedClassName);
+ }
+
+ if (hasObfuscatedFields)
+ {
+ classesWithObfuscatedFields.add(obfuscatedClassName);
+ }
+ }
+ reader.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ private static String originalSignature(MethodSignature signature)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ boolean first = true;
+ for (String clazz : signature.parameters)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ stringBuilder.append(",");
+ }
+ stringBuilder.append(originalClassName(clazz));
+ }
+ return stringBuilder.toString();
+ }
+
+
+ public static class MethodSignature
+ {
+ private String name;
+ private String[] parameters;
+
+
+ public MethodSignature(String name, Class[] parameters)
+ {
+ this.name = name;
+ this.parameters = new String[parameters.length];
+ for (int i = 0; i < parameters.length; i++)
+ {
+ this.parameters[i] = parameters[i].getName();
+ }
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MethodSignature that = (MethodSignature)o;
+
+ if (!name.equals(that.name)) return false;
+ return Arrays.equals(parameters, that.parameters);
+ }
+
+
+ public int hashCode()
+ {
+ int result = name.hashCode();
+ result = 31 * result + Arrays.hashCode(parameters);
+ return result;
+ }
+ }
+}
diff --git a/core/src/proguard/configuration/ConfigurationLoggingAdder.java b/core/src/proguard/configuration/ConfigurationLoggingAdder.java
new file mode 100644
index 0000000..e8999df
--- /dev/null
+++ b/core/src/proguard/configuration/ConfigurationLoggingAdder.java
@@ -0,0 +1,129 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.configuration;
+
+
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.io.*;
+import proguard.optimize.peephole.*;
+import proguard.util.MultiValueMap;
+
+import java.io.IOException;
+
+import static proguard.classfile.util.ClassUtil.internalClassName;
+
+/**
+ * This class can add configuration debug logging code to all code that
+ * relies on reflection. The added code prints suggestions on which keep
+ * rules to add to ensure the reflection code will continue working after
+ * obfuscation and shrinking.
+ *
+ * @author Johan Leys
+ */
+public class ConfigurationLoggingAdder
+extends SimplifiedVisitor
+implements // Implementation interfaces.
+ InstructionVisitor
+{
+ private final Configuration configuration;
+
+ // Field acting as parameter for the visitor methods.
+ private MultiValueMap injectedClassMap;
+
+
+ /**
+ * Creates a new ConfigurationLoggingAdder.
+ */
+ public ConfigurationLoggingAdder(Configuration configuration)
+ {
+ this.configuration = configuration;
+ }
+
+
+ /**
+ * Instrumets the given program class pool.
+ */
+ public void execute(ClassPool programClassPool,
+ ClassPool libraryClassPool,
+ MultiValueMap injectedClassMap )
+ {
+ // Load the logging utility classes in the program class pool.
+ // TODO: The initialization could be incomplete if the loaded classes depend on one another.
+ ClassReader classReader =
+ new ClassReader(false, false, false, null,
+ new MultiClassVisitor(
+ new ClassPoolFiller(programClassPool),
+ new ClassReferenceInitializer(programClassPool, libraryClassPool),
+ new ClassSubHierarchyInitializer()
+ ));
+
+ try
+ {
+ classReader.read(new ClassPathDataEntry(ConfigurationLogger.MethodSignature.class));
+ classReader.read(new ClassPathDataEntry(ConfigurationLogger.class));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ // Set up the instruction sequences and their replacements.
+ ConfigurationLoggingInstructionSequenceConstants constants =
+ new ConfigurationLoggingInstructionSequenceConstants(programClassPool,
+ libraryClassPool);
+
+ BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
+ CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+
+ // Set the injected class map for the extra visitor.
+ this.injectedClassMap = injectedClassMap;
+
+ // Replace the instruction sequences in all non-ProGuard classes.
+ programClassPool.classesAccept(
+ new ClassNameFilter("!proguard/**",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor,
+ new ConfigurationLoggingInstructionSequencesReplacer(constants.CONSTANTS,
+ constants.RESOURCE,
+ branchTargetFinder,
+ codeAttributeEditor,
+ this))))));
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Add a dependency from the modified class on the logging class.
+ injectedClassMap.put(clazz.getName(), internalClassName(ConfigurationLogger.class.getName()));
+ injectedClassMap.put(clazz.getName(), internalClassName(ConfigurationLogger.MethodSignature.class.getName()));
+ }
+}
diff --git a/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceConstants.java b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceConstants.java
new file mode 100644
index 0000000..36f353f
--- /dev/null
+++ b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceConstants.java
@@ -0,0 +1,479 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.configuration;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.util.*;
+import proguard.optimize.peephole.InstructionSequenceReplacer;
+
+import static proguard.optimize.peephole.InstructionSequenceReplacer.catch_;
+
+/**
+ * This class contains a set of instruction sequences for accessing class information via reflection, and replacement instructions that add logging information on the reflection that is used.
+ *
+ * @author Johan Leys
+ */
+public class ConfigurationLoggingInstructionSequenceConstants
+{
+ private static String LOGGER_CLASS_NAME = ClassUtil.internalClassName(ConfigurationLogger.class.getName());
+
+ // Exceptions classes.
+ public static final String NAME_CLASS_NOT_FOUND_EXCEPTION = "java/lang/ClassNotFoundException";
+ public static final String NAME_NO_SUCH_FIELD_EXCEPTION = "java/lang/NoSuchFieldException";
+ public static final String NAME_NO_SUCH_METHOD_EXCEPTION = "java/lang/NoSuchMethodException";
+ public static final String NAME_RUNTIME_EXCEPTION = "java/lang/RuntimeException";
+ public static final String NAME_UNSATISFIED_LINK_ERROR = "java/lang/UnsatisfiedLinkError";
+ public static final String NAME_IO_EXCEPTION = "java/io/IOException";
+
+ // Matched constants.
+ public static final int CLASS_NAME = 0x30000000;
+ public static final int LOCAL_VARIABLE_INDEX_1 = 0x30000001;
+ public static final int LOCAL_VARIABLE_INDEX_2 = 0x30000002;
+ public static final int LOCAL_VARIABLE_INDEX_3 = 0x30000003;
+
+ public static final int CONSTANT_INDEX = InstructionSequenceMatcher.X;
+ public static final int ACCESS_MODE = InstructionSequenceMatcher.Y;
+
+ public final Instruction[][][] RESOURCE;
+ public final Constant[] CONSTANTS;
+
+ // Labels.
+ private final InstructionSequenceReplacer.Label TRY_START = InstructionSequenceReplacer.label();
+ private final InstructionSequenceReplacer.Label TRY_END = InstructionSequenceReplacer.label();
+ private final InstructionSequenceReplacer.Label CATCH_END = InstructionSequenceReplacer.label();
+
+ private final InstructionSequenceReplacer.Label CLASS_NOT_FOUND_EXCEPTION;
+ private final InstructionSequenceReplacer.Label NO_SUCH_METHOD_EXCEPTION;
+ private final InstructionSequenceReplacer.Label NO_SUCH_FIELD_EXCEPTION;
+ private final InstructionSequenceReplacer.Label IO_EXCEPTION;
+ private final InstructionSequenceReplacer.Label RUNTIME_EXCEPTION;
+ private final InstructionSequenceReplacer.Label UNSATISFIED_LINK_ERROR;
+
+ /**
+ * Creates a new instance of ResourceIdInstructionSequenceConstants,
+ * with constants that reference classes from the given class pools.
+ */
+ public ConfigurationLoggingInstructionSequenceConstants(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ InstructionSequenceBuilder ____ =
+ new InstructionSequenceBuilder(programClassPool, libraryClassPool);
+
+ ConstantPoolEditor constantPoolEditor = ____.getConstantPoolEditor();
+
+ CLASS_NOT_FOUND_EXCEPTION =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_CLASS_NOT_FOUND_EXCEPTION, null));
+ NO_SUCH_METHOD_EXCEPTION =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_NO_SUCH_METHOD_EXCEPTION, null));
+ NO_SUCH_FIELD_EXCEPTION =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_NO_SUCH_FIELD_EXCEPTION, null));
+ IO_EXCEPTION =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_IO_EXCEPTION, null));
+ RUNTIME_EXCEPTION =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_RUNTIME_EXCEPTION, null));
+ UNSATISFIED_LINK_ERROR =
+ catch_(TRY_START.offset(),
+ TRY_END.offset(),
+ constantPoolEditor.addClassConstant(NAME_UNSATISFIED_LINK_ERROR, null));
+
+ RESOURCE = new Instruction[][][]
+ {
+ // Classes.
+ {
+ ____.invokestatic("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;").__(),
+
+ ____.dup()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokestatic("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(CLASS_NOT_FOUND_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logForName", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokestatic("java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;").__(),
+
+ ____.dup_x2()
+ .pop()
+ .dup_x2()
+ .pop()
+ .dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokestatic("java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(CLASS_NOT_FOUND_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logForName", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;").__(),
+
+ ____.dup()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(CLASS_NOT_FOUND_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoadClass", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+
+ // Constructors.
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;").__(),
+
+ ____.dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_METHOD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredConstructor", "(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/Class;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;").__(),
+
+ ____.dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_METHOD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetConstructor", "(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/Class;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredConstructors", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;").__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getConstructors", "()[Ljava/lang/reflect/Constructor;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetConstructors", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getConstructors", "()[Ljava/lang/reflect/Constructor;").__()
+ },
+
+ // Methods.
+
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;").__(),
+
+ ____.dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_3)
+ .dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_METHOD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .aload(LOCAL_VARIABLE_INDEX_3)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredMethod", "(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;").__(),
+
+ ____.dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_3)
+ .dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x2()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_METHOD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .aload(LOCAL_VARIABLE_INDEX_3)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetMethod", "(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredMethods", "()[Ljava/lang/reflect/Method;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredMethods", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getDeclaredMethods", "()[Ljava/lang/reflect/Method;").__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetMethods", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;").__()
+ },
+
+ // Fields.
+
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;").__(),
+
+ ____.dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_FIELD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredField", "(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;").__(),
+
+ ____.dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_2)
+ .dup_x1()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokevirtual("java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;")
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(NO_SUCH_FIELD_EXCEPTION)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .aload(LOCAL_VARIABLE_INDEX_2)
+ .invokestatic(LOGGER_CLASS_NAME, "logGetField", "(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getDeclaredFields", "()[Ljava/lang/reflect/Field;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetDeclaredFields", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getDeclaredFields", "()[Ljava/lang/reflect/Field;").__()
+ },
+ {
+ ____.invokevirtual("java/lang/Class", "getFields", "()[Ljava/lang/reflect/Field;").__(),
+
+ ____.dup()
+ .ldc_(CLASS_NAME)
+ .swap()
+ .invokestatic(LOGGER_CLASS_NAME, "logGetFields", "(Ljava/lang/String;Ljava/lang/Class;)V")
+ .invokevirtual("java/lang/Class", "getFields", "()[Ljava/lang/reflect/Field;").__()
+ },
+
+ // Resource files.
+
+ // System.loadLibrary(String)
+ {
+ ____.ldc_(CONSTANT_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY).__(),
+
+ ____.ldc_(CONSTANT_INDEX)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .ldc_(CONSTANT_INDEX)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoadLibrary", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY).__(),
+
+ ____.dup()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoadLibrary", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+
+ // System.load(String)
+ {
+ ____.ldc_(CONSTANT_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD,
+ ClassConstants.METHOD_TYPE_LOAD).__(),
+
+ ____.ldc_(CONSTANT_INDEX)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD,
+ ClassConstants.METHOD_TYPE_LOAD)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .ldc_(CONSTANT_INDEX)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoad", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD,
+ ClassConstants.METHOD_TYPE_LOAD).__(),
+
+ ____.dup()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_SYSTEM,
+ ClassConstants.METHOD_NAME_LOAD,
+ ClassConstants.METHOD_TYPE_LOAD)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoad", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+
+ // Runtime.loadLibrary(String)
+ {
+ ____.ldc_(CONSTANT_INDEX)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_RUNTIME,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY).__(),
+
+ ____.ldc_(CONSTANT_INDEX)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_RUNTIME,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .ldc_(CONSTANT_INDEX)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoadLibrary", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ {
+ ____.invokestatic(ClassConstants.NAME_JAVA_LANG_RUNTIME,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY).__(),
+
+ ____.dup()
+ .astore(LOCAL_VARIABLE_INDEX_1)
+ .label(TRY_START)
+ .invokestatic(ClassConstants.NAME_JAVA_LANG_RUNTIME,
+ ClassConstants.METHOD_NAME_LOAD_LIBRARY,
+ ClassConstants.METHOD_TYPE_LOAD_LIBRARY)
+ .label(TRY_END)
+ .goto_(CATCH_END.offset())
+ .catch_(UNSATISFIED_LINK_ERROR)
+ .ldc_(CLASS_NAME)
+ .aload(LOCAL_VARIABLE_INDEX_1)
+ .invokestatic(LOGGER_CLASS_NAME, "logLoadLibrary", "(Ljava/lang/String;Ljava/lang/String;)V")
+ .athrow()
+ .label(CATCH_END).__()
+ },
+ };
+
+ CONSTANTS = ____.constants();
+ }
+}
diff --git a/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceReplacer.java b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceReplacer.java
new file mode 100644
index 0000000..2549296
--- /dev/null
+++ b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequenceReplacer.java
@@ -0,0 +1,130 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.configuration;
+
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.optimize.peephole.*;
+
+import static proguard.configuration.ConfigurationLoggingInstructionSequenceConstants.LOCAL_VARIABLE_INDEX_1;
+import static proguard.configuration.ConfigurationLoggingInstructionSequenceConstants.LOCAL_VARIABLE_INDEX_2;
+import static proguard.configuration.ConfigurationLoggingInstructionSequenceConstants.LOCAL_VARIABLE_INDEX_3;
+
+/**
+ * This InstructionSequencesReplacer appends logging instructions to all
+ * instructions calling reflection methods.
+ *
+ * @see InstructionSequenceReplacer
+ *
+ * @author Johan Leys
+ */
+public class ConfigurationLoggingInstructionSequenceReplacer extends InstructionSequenceReplacer
+{
+ public ConfigurationLoggingInstructionSequenceReplacer(InstructionSequenceMatcher instructionSequenceMatcher,
+ Constant[] patternConstants,
+ Instruction[] patternInstructions,
+ Constant[] replacementConstants,
+ Instruction[] replacementInstructions,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor,
+ InstructionVisitor extraInstructionVisitor )
+ {
+ super(instructionSequenceMatcher,
+ patternConstants,
+ patternInstructions,
+ replacementConstants,
+ replacementInstructions,
+ branchTargetFinder,
+ codeAttributeEditor,
+ extraInstructionVisitor );
+ }
+
+
+ public ConfigurationLoggingInstructionSequenceReplacer(Constant[] patternConstants,
+ Instruction[] patternInstructions,
+ Constant[] replacementConstants,
+ Instruction[] replacementInstructions,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor )
+ {
+ super(patternConstants,
+ patternInstructions,
+ replacementConstants,
+ replacementInstructions,
+ branchTargetFinder,
+ codeAttributeEditor );
+ }
+
+
+ public ConfigurationLoggingInstructionSequenceReplacer(Constant[] patternConstants,
+ Instruction[] patternInstructions,
+ Constant[] replacementConstants,
+ Instruction[] replacementInstructions,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor,
+ InstructionVisitor extraInstructionVisitor )
+ {
+ super(patternConstants,
+ patternInstructions,
+ replacementConstants,
+ replacementInstructions,
+ branchTargetFinder,
+ codeAttributeEditor,
+ extraInstructionVisitor );
+ }
+
+
+ @Override
+ protected int matchedArgument(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, int argument)
+ {
+ switch (argument)
+ {
+ case LOCAL_VARIABLE_INDEX_1:
+ return codeAttribute.u2maxLocals;
+ case LOCAL_VARIABLE_INDEX_2:
+ return codeAttribute.u2maxLocals + 1;
+ case LOCAL_VARIABLE_INDEX_3:
+ return codeAttribute.u2maxLocals + 2;
+ default:
+ return super.matchedArgument(clazz, argument);
+ }
+ }
+
+
+ @Override
+ protected int matchedConstantIndex(ProgramClass programClass, int constantIndex)
+ {
+ switch (constantIndex)
+ {
+ case ConfigurationLoggingInstructionSequenceConstants.CLASS_NAME:
+ return new ConstantPoolEditor(programClass)
+ .addStringConstant(ClassUtil.externalClassName(programClass.getName()), programClass, null);
+ default:
+ return super.matchedConstantIndex(programClass, constantIndex);
+ }
+ }
+}
diff --git a/core/src/proguard/configuration/ConfigurationLoggingInstructionSequencesReplacer.java b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequencesReplacer.java
new file mode 100644
index 0000000..cb397ab
--- /dev/null
+++ b/core/src/proguard/configuration/ConfigurationLoggingInstructionSequencesReplacer.java
@@ -0,0 +1,146 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.configuration;
+
+import proguard.classfile.constant.Constant;
+import proguard.classfile.editor.CodeAttributeEditor;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.*;
+import proguard.optimize.peephole.*;
+
+/**
+ * This InstructionSequencesReplacer appends logging instructions to all
+ * instructions calling reflection methods.
+ *
+ * @see InstructionSequencesReplacer
+ * @see ConfigurationLoggingInstructionSequenceReplacer
+ *
+ * @author Johan Leys
+ */
+public class ConfigurationLoggingInstructionSequencesReplacer
+extends MultiInstructionVisitor
+implements InstructionVisitor
+{
+ private static final int PATTERN_INDEX = 0;
+ private static final int REPLACEMENT_INDEX = 1;
+
+
+ /**
+ * Creates a new ConfigurationLoggingInstructionSequencesReplacer.
+ *
+ * @param constants any constants referenced by the pattern
+ * instructions and replacement instructions.
+ * @param instructionSequences the instruction sequences to be replaced,
+ * with subsequently the sequence pair index,
+ * the patten/replacement index (0 or 1),
+ * and the instruction index in the sequence.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttributeEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public ConfigurationLoggingInstructionSequencesReplacer(Constant[] constants,
+ Instruction[][][] instructionSequences,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor)
+ {
+ this(constants,
+ instructionSequences,
+ branchTargetFinder,
+ codeAttributeEditor,
+ null);
+ }
+
+
+ /**
+ * Creates a new ConfigurationLoggingInstructionSequencesReplacer.
+ *
+ * @param constants any constants referenced by the pattern
+ * instructions and replacement instructions.
+ * @param instructionSequences the instruction sequences to be replaced,
+ * with subsequently the sequence pair index,
+ * the patten/replacement index (0 or 1),
+ * and the instruction index in the sequence.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttributeEditor a code editor that can be used for
+ * accumulating changes to the code.
+ * @param extraInstructionVisitor an optional extra visitor for all deleted
+ * load instructions.
+ */
+ public ConfigurationLoggingInstructionSequencesReplacer(Constant[] constants,
+ Instruction[][][] instructionSequences,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor,
+ InstructionVisitor extraInstructionVisitor)
+ {
+ super(createInstructionSequenceReplacers(constants,
+ instructionSequences,
+ branchTargetFinder,
+ codeAttributeEditor,
+ extraInstructionVisitor));
+ }
+
+
+ /**
+ * Creates an array of InstructionSequenceReplacer instances.
+ *
+ * @param constants any constants referenced by the pattern
+ * instructions and replacement instructions.
+ * @param instructionSequences the instruction sequences to be replaced,
+ * with subsequently the sequence pair index,
+ * the from/to index (0 or 1), and the
+ * instruction index in the sequence.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttributeEditor a code editor that can be used for
+ * accumulating changes to the code.
+ * @param extraInstructionVisitor an optional extra visitor for all deleted
+ * load instructions.
+ */
+ private static InstructionVisitor[] createInstructionSequenceReplacers(Constant[] constants,
+ Instruction[][][] instructionSequences,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor,
+ InstructionVisitor extraInstructionVisitor)
+ {
+ InstructionVisitor[] instructionSequenceReplacers =
+ new InstructionSequenceReplacer[instructionSequences.length];
+
+ for (int index = 0; index < instructionSequenceReplacers.length; index++)
+ {
+ Instruction[][] instructionSequencePair = instructionSequences[index];
+ instructionSequenceReplacers[index] =
+ new ConfigurationLoggingInstructionSequenceReplacer(constants,
+ instructionSequencePair[PATTERN_INDEX],
+ constants,
+ instructionSequencePair[REPLACEMENT_INDEX],
+ branchTargetFinder,
+ codeAttributeEditor,
+ extraInstructionVisitor);
+ }
+
+ return instructionSequenceReplacers;
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/BasicBranchUnit.java b/core/src/proguard/evaluation/BasicBranchUnit.java
similarity index 73%
rename from src/proguard/evaluation/BasicBranchUnit.java
rename to core/src/proguard/evaluation/BasicBranchUnit.java
index ae07632..89b3b1a 100644
--- a/src/proguard/evaluation/BasicBranchUnit.java
+++ b/core/src/proguard/evaluation/BasicBranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,37 +26,30 @@
/**
* This BranchUnit remembers the branch unit commands that are invoked on it.
- * I doesn't consider conditions when branching.
+ * It doesn't consider conditions when branching.
*
* @author Eric Lafortune
*/
public class BasicBranchUnit
implements BranchUnit
{
- private boolean wasCalled;
- private InstructionOffsetValue traceBranchTargets;
+ protected InstructionOffsetValue traceBranchTargets;
+ protected boolean wasCalled;
/**
- * Resets the flag that tells whether any of the branch unit commands was
- * called.
+ * Resets the accumulated branch targets and the flag that tells whether
+ * any of the branch unit methods was called.
*/
- public void resetCalled()
+ public void reset()
{
- wasCalled = false;
- }
+ traceBranchTargets = InstructionOffsetValue.EMPTY_VALUE;
- /**
- * Sets the flag that tells whether any of the branch unit commands was
- * called.
- */
- protected void setCalled()
- {
- wasCalled = true;
+ wasCalled = false;
}
/**
- * Returns whether any of the branch unit commands was called.
+ * Returns whether any of the branch unit methods was called.
*/
public boolean wasCalled()
{
@@ -65,14 +58,9 @@ public boolean wasCalled()
/**
- * Sets the initial branch targets, which will be updated as the branch
- * methods of the branch unit are called.
+ * Returns the accumulated branch targets that were passed to the branch
+ * unit methods.
*/
- public void setTraceBranchTargets(InstructionOffsetValue branchTargets)
- {
- this.traceBranchTargets = branchTargets;
- }
-
public InstructionOffsetValue getTraceBranchTargets()
{
return traceBranchTargets;
@@ -101,7 +89,7 @@ public void branchConditionally(Clazz clazz,
{
// Accumulate the branch targets.
traceBranchTargets =
- traceBranchTargets.generalize(new InstructionOffsetValue(branchTarget)).instructionOffsetValue();
+ traceBranchTargets.add(branchTarget);
wasCalled = true;
}
diff --git a/core/src/proguard/evaluation/BasicInvocationUnit.java b/core/src/proguard/evaluation/BasicInvocationUnit.java
new file mode 100644
index 0000000..be38b72
--- /dev/null
+++ b/core/src/proguard/evaluation/BasicInvocationUnit.java
@@ -0,0 +1,230 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.classfile.visitor.MemberVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This InvocationUnit sets up the variables for entering a method,
+ * and it updates the stack for the invocation of a class member,
+ * using simple values.
+ *
+ * @author Eric Lafortune
+ */
+public class BasicInvocationUnit
+extends SimplifiedInvocationUnit
+implements InvocationUnit,
+ MemberVisitor
+{
+ protected final ValueFactory valueFactory;
+
+ // Field acting as parameter between the visitor methods.
+ private Clazz returnTypeClass;
+
+
+ /**
+ * Creates a new BasicInvocationUnit with the given value factory.
+ */
+ public BasicInvocationUnit(ValueFactory valueFactory)
+ {
+ this.valueFactory = valueFactory;
+ }
+
+
+ // Implementations for SimplifiedInvocationUnit.
+
+ public Value getExceptionValue(Clazz clazz,
+ ClassConstant catchClassConstant)
+ {
+ String catchClassName = catchClassConstant != null ?
+ catchClassConstant.getName(clazz) :
+ ClassConstants.NAME_JAVA_LANG_THROWABLE;
+
+ Clazz catchClass = catchClassConstant != null ?
+ catchClassConstant.referencedClass :
+ null;
+
+ return valueFactory.createReferenceValue(catchClassName,
+ catchClass,
+ true,
+ false);
+ }
+
+
+ public void setFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ ReferenceValue value)
+ {
+ // We don't care about the new value.
+ }
+
+
+ public Value getFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
+ {
+ // Try to figure out the class of the return type.
+ returnTypeClass = null;
+ refConstant.referencedMemberAccept(this);
+
+ return valueFactory.createValue(type,
+ returnTypeClass,
+ true,
+ true);
+ }
+
+
+ public void setFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ Value value)
+ {
+ // We don't care about the new field value.
+ }
+
+
+ public Value getFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
+ {
+ // Try to figure out the class of the return type.
+ returnTypeClass = null;
+ refConstant.referencedMemberAccept(this);
+
+ return valueFactory.createValue(type,
+ returnTypeClass,
+ true,
+ true);
+ }
+
+
+ public void setMethodParameterValue(Clazz clazz,
+ RefConstant refConstant,
+ int parameterIndex,
+ Value value)
+ {
+ // We don't care about the parameter value.
+ }
+
+
+ public Value getMethodParameterValue(Clazz clazz,
+ Method method,
+ int parameterIndex,
+ String type,
+ Clazz referencedClass)
+ {
+ // A "this" parameter can never be null.
+ boolean isThis =
+ parameterIndex == 0 &&
+ (method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0;
+
+ return valueFactory.createValue(type,
+ referencedClass,
+ true,
+ !isThis);
+ }
+
+
+ public void setMethodReturnValue(Clazz clazz,
+ Method method,
+ Value value)
+ {
+ // We don't care about the return value.
+ }
+
+
+ public Value getMethodReturnValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
+ {
+ // Try to figure out the class of the return type.
+ returnTypeClass = null;
+ refConstant.referencedMemberAccept(this);
+
+ return valueFactory.createValue(type,
+ returnTypeClass,
+ true,
+ true);
+ }
+
+
+ /**
+ * Returns the return value of the specified method.
+ */
+ public Value getMethodReturnValue(Clazz clazz,
+ InvokeDynamicConstant invokeDynamicConstant,
+ String type)
+ {
+ // Try to figure out the class of the return type.
+ Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses;
+
+ Clazz referencedClass =
+ referencedClasses != null &&
+ ClassUtil.isInternalClassType(type) ?
+ referencedClasses[referencedClasses.length - 1] :
+ null;
+
+ return valueFactory.createValue(type,
+ referencedClass,
+ true,
+ true);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ returnTypeClass = programField.referencedClass;
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ Clazz[] referencedClasses = programMethod.referencedClasses;
+ if (referencedClasses != null &&
+ ClassUtil.isInternalClassType(programMethod.getDescriptor(programClass)))
+ {
+ returnTypeClass = referencedClasses[referencedClasses.length - 1];
+ }
+ }
+
+
+ public void visitLibraryField(LibraryClass programClass, LibraryField libraryField)
+ {
+ returnTypeClass = libraryField.referencedClass;
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ Clazz[] referencedClasses = libraryMethod.referencedClasses;
+ if (referencedClasses != null &&
+ ClassUtil.isInternalClassType(libraryMethod.getDescriptor(libraryClass)))
+ {
+ returnTypeClass = referencedClasses[referencedClasses.length - 1];
+ }
+ }
+}
diff --git a/src/proguard/evaluation/BranchUnit.java b/core/src/proguard/evaluation/BranchUnit.java
similarity index 97%
rename from src/proguard/evaluation/BranchUnit.java
rename to core/src/proguard/evaluation/BranchUnit.java
index fb26fc9..4dbead1 100644
--- a/src/proguard/evaluation/BranchUnit.java
+++ b/core/src/proguard/evaluation/BranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/ClassConstantValueFactory.java b/core/src/proguard/evaluation/ClassConstantValueFactory.java
similarity index 94%
rename from src/proguard/evaluation/ClassConstantValueFactory.java
rename to core/src/proguard/evaluation/ClassConstantValueFactory.java
index a4e13ce..9b4738e 100644
--- a/src/proguard/evaluation/ClassConstantValueFactory.java
+++ b/core/src/proguard/evaluation/ClassConstantValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -46,6 +46,7 @@ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
// Create a Class reference instead of a reference to the class.
value = valueFactory.createReferenceValue(ClassConstants.NAME_JAVA_LANG_CLASS,
classConstant.javaLangClassClass,
+ false,
false);
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/evaluation/ConstantValueFactory.java b/core/src/proguard/evaluation/ConstantValueFactory.java
similarity index 85%
rename from src/proguard/evaluation/ConstantValueFactory.java
rename to core/src/proguard/evaluation/ConstantValueFactory.java
index 6c6dce0..3733e56 100644
--- a/src/proguard/evaluation/ConstantValueFactory.java
+++ b/core/src/proguard/evaluation/ConstantValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -83,10 +83,18 @@ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
value = valueFactory.createDoubleValue(doubleConstant.getValue());
}
+ public void visitPrimitiveArrayConstant(Clazz clazz, PrimitiveArrayConstant primitiveArrayConstant)
+ {
+ value = valueFactory.createArrayReferenceValue(""+primitiveArrayConstant.getPrimitiveType(),
+ null,
+ valueFactory.createIntegerValue(primitiveArrayConstant.getLength()));
+ }
+
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
value = valueFactory.createReferenceValue(ClassConstants.NAME_JAVA_LANG_STRING,
stringConstant.javaLangStringClass,
+ false,
false);
}
@@ -94,6 +102,7 @@ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHa
{
value = valueFactory.createReferenceValue(ClassConstants.NAME_JAVA_LANG_INVOKE_METHOD_HANDLE,
methodHandleConstant.javaLangInvokeMethodHandleClass,
+ false,
false);
}
@@ -101,13 +110,16 @@ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
value = valueFactory.createReferenceValue(classConstant.getName(clazz),
classConstant.referencedClass,
+ false,
false);
}
+
public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
{
value = valueFactory.createReferenceValue(ClassConstants.NAME_JAVA_LANG_INVOKE_METHOD_TYPE,
methodTypeConstant.javaLangInvokeMethodTypeClass,
+ false,
false);
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/evaluation/InvocationUnit.java b/core/src/proguard/evaluation/InvocationUnit.java
similarity index 81%
rename from src/proguard/evaluation/InvocationUnit.java
rename to core/src/proguard/evaluation/InvocationUnit.java
index 20cd921..1814143 100644
--- a/src/proguard/evaluation/InvocationUnit.java
+++ b/core/src/proguard/evaluation/InvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +49,17 @@ public void exitMethod(Clazz clazz,
Value returnValue);
+ /**
+ * Sets up the given stack for entering the given exception handler.
+ */
+ public void enterExceptionHandler(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ int catchType,
+ Stack stack);
+
+
/**
* Updates the given stack corresponding to the execution of the given
* field or method reference instruction.
diff --git a/src/proguard/evaluation/Processor.java b/core/src/proguard/evaluation/Processor.java
similarity index 93%
rename from src/proguard/evaluation/Processor.java
rename to core/src/proguard/evaluation/Processor.java
index 30f5322..80b7b98 100644
--- a/src/proguard/evaluation/Processor.java
+++ b/core/src/proguard/evaluation/Processor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +50,8 @@ public class Processor
* Creates a new processor that operates on the given environment.
* @param variables the local variable frame.
* @param stack the local stack.
+ * @param valueFactory the value factory that will create all values
+ * during the evaluation.
* @param branchUnit the class that can affect the program counter.
* @param invocationUnit the class that can access other program members.
* @param alwaysCast a flag that specifies whether downcasts or casts
@@ -67,7 +69,7 @@ public Processor(Variables variables,
this.valueFactory = valueFactory;
this.branchUnit = branchUnit;
this.invocationUnit = invocationUnit;
- this.alwaysCast = alwaysCast;
+ this.alwaysCast = alwaysCast;
constantValueFactory = new ConstantValueFactory(valueFactory);
classConstantValueFactory = new ClassConstantValueFactory(valueFactory);
@@ -597,31 +599,34 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
case InstructionConstants.OP_ANEWARRAY:
{
- ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
+ ReferenceValue arrayType = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
- stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(),
- referenceValue.getReferencedClass(),
+ stack.push(valueFactory.createArrayReferenceValue(arrayType.internalType(),
+ arrayType.getReferencedClass(),
stack.ipop()));
break;
}
case InstructionConstants.OP_CHECKCAST:
+ {
// TODO: Check cast.
- ReferenceValue castValue = stack.apop();
- ReferenceValue castResultValue =
- !alwaysCast &&
- castValue.isNull() == Value.ALWAYS ? castValue :
- castValue.isNull() == Value.NEVER ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() :
- constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
- stack.push(castResultValue);
+ ReferenceValue type = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
+
+ stack.push(stack.apop().cast(type.getType(),
+ type.getReferencedClass(),
+ valueFactory,
+ alwaysCast));
break;
+ }
case InstructionConstants.OP_INSTANCEOF:
{
- ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
+ ReferenceValue value = stack.apop();
+ ReferenceValue type = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
- int instanceOf = stack.apop().instanceOf(referenceValue.getType(),
- referenceValue.getReferencedClass());
+ int instanceOf = type.mayBeExtension() ? Value.MAYBE :
+ value.instanceOf(type.getType(),
+ type.getReferencedClass());
stack.push(instanceOf == Value.NEVER ? valueFactory.createIntegerValue(0) :
instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) :
@@ -764,6 +769,13 @@ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute cod
{
int branchTarget = offset + branchInstruction.branchOffset;
+ // Maybe branch to the next instruction.
+ branchUnit.branchConditionally(clazz,
+ codeAttribute,
+ offset,
+ offset + branchInstruction.length(offset),
+ Value.MAYBE);
+
switch (branchInstruction.opcode)
{
case InstructionConstants.OP_IFEQ:
@@ -874,26 +886,23 @@ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribut
{
IntegerValue indexValue = stack.ipop();
- // If there is no definite branch in any of the cases below,
- // branch to the default offset.
- branchUnit.branch(clazz, codeAttribute,
- offset,
- offset + tableSwitchInstruction.defaultOffset);
+ // Maybe branch to the default offset.
+ branchUnit.branchConditionally(clazz,
+ codeAttribute,
+ offset,
+ offset + tableSwitchInstruction.defaultOffset,
+ Value.MAYBE);
for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++)
{
int conditional = indexValue.equal(valueFactory.createIntegerValue(
tableSwitchInstruction.lowCase + index));
- branchUnit.branchConditionally(clazz, codeAttribute,
+
+ branchUnit.branchConditionally(clazz,
+ codeAttribute,
offset,
offset + tableSwitchInstruction.jumpOffsets[index],
conditional);
-
- // If this branch is always taken, we can skip the rest.
- if (conditional == Value.ALWAYS)
- {
- break;
- }
}
}
@@ -902,26 +911,23 @@ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribu
{
IntegerValue indexValue = stack.ipop();
- // If there is no definite branch in any of the cases below,
- // branch to the default offset.
- branchUnit.branch(clazz, codeAttribute,
- offset,
- offset + lookUpSwitchInstruction.defaultOffset);
+ // Maybe branch to the default offset.
+ branchUnit.branchConditionally(clazz,
+ codeAttribute,
+ offset,
+ offset + lookUpSwitchInstruction.defaultOffset,
+ Value.MAYBE);
for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++)
{
int conditional = indexValue.equal(valueFactory.createIntegerValue(
lookUpSwitchInstruction.cases[index]));
- branchUnit.branchConditionally(clazz, codeAttribute,
+
+ branchUnit.branchConditionally(clazz,
+ codeAttribute,
offset,
offset + lookUpSwitchInstruction.jumpOffsets[index],
conditional);
-
- // If this branch is always taken, we can skip the rest.
- if (conditional == Value.ALWAYS)
- {
- break;
- }
}
}
}
diff --git a/core/src/proguard/evaluation/SimplifiedInvocationUnit.java b/core/src/proguard/evaluation/SimplifiedInvocationUnit.java
new file mode 100644
index 0000000..9f7cc86
--- /dev/null
+++ b/core/src/proguard/evaluation/SimplifiedInvocationUnit.java
@@ -0,0 +1,314 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation;
+
+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.util.*;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.value.*;
+
+/**
+ * This InvocationUnit sets up the variables for entering a method,
+ * and it updates the stack for the invocation of a class member,
+ * using simple values.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class SimplifiedInvocationUnit
+extends SimplifiedVisitor
+implements InvocationUnit,
+ ParameterVisitor,
+ ConstantVisitor
+{
+ private final MemberVisitor parameterInitializer = new AllParameterVisitor(true, this);
+
+ // Fields acting as parameters between the visitor methods.
+ private Variables variables;
+ protected boolean isStatic;
+ protected boolean isLoad;
+ protected Stack stack;
+
+
+ // Implementations for InvocationUnit.
+
+ public void enterMethod(Clazz clazz, Method method, Variables variables)
+ {
+ // Count the number of parameters, taking into account their categories.
+ int parameterSize =
+ ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz),
+ method.getAccessFlags());
+
+ // Reuse the existing parameters object, ensuring the right size.
+ variables.reset(parameterSize);
+
+ // Initialize the parameters.
+ this.variables = variables;
+ method.accept(clazz, parameterInitializer);
+ this.variables = null;
+ }
+
+
+ // Implementation for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ Method method = (Method)member;
+
+ // Get the parameter value.
+ Value value = getMethodParameterValue(clazz,
+ method,
+ parameterIndex,
+ parameterType,
+ referencedClass);
+
+ // Store the value in the corresponding variable.
+ variables.store(parameterOffset, value);
+ }
+
+
+ public void exitMethod(Clazz clazz, Method method, Value returnValue)
+ {
+ setMethodReturnValue(clazz, method, returnValue);
+ }
+
+
+ public void enterExceptionHandler(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ int catchType,
+ Stack stack)
+ {
+ ClassConstant exceptionClassConstant =
+ (ClassConstant)((ProgramClass)clazz).getConstant(catchType);
+
+ stack.push(getExceptionValue(clazz, exceptionClassConstant));
+ }
+
+
+ public void invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack)
+ {
+ int constantIndex = constantInstruction.constantIndex;
+
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_GETSTATIC:
+ isStatic = true;
+ isLoad = true;
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ isStatic = true;
+ isLoad = false;
+ break;
+
+ case InstructionConstants.OP_GETFIELD:
+ isStatic = false;
+ isLoad = true;
+ break;
+
+ case InstructionConstants.OP_PUTFIELD:
+ isStatic = false;
+ isLoad = false;
+ break;
+
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
+ isStatic = true;
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ isStatic = false;
+ break;
+ }
+
+ // Pop the parameters and push the return value.
+ this.stack = stack;
+ clazz.constantPoolEntryAccept(constantIndex, this);
+ this.stack = null;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ // Pop the field value, if applicable.
+ if (!isLoad)
+ {
+ setFieldValue(clazz, fieldrefConstant, stack.pop());
+ }
+
+ // Pop the reference value, if applicable.
+ if (!isStatic)
+ {
+ setFieldClassValue(clazz, fieldrefConstant, stack.apop());
+ }
+
+ // Push the field value, if applicable.
+ if (isLoad)
+ {
+ String type = fieldrefConstant.getType(clazz);
+
+ stack.push(getFieldValue(clazz, fieldrefConstant, type));
+ }
+ }
+
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant methodrefConstant)
+ {
+ String type = methodrefConstant.getType(clazz);
+
+ // Count the number of parameters.
+ int parameterCount = ClassUtil.internalMethodParameterCount(type);
+ if (!isStatic)
+ {
+ parameterCount++;
+ }
+
+ // Pop the parameters and the class reference, in reverse order.
+ for (int parameterIndex = parameterCount-1; parameterIndex >= 0; parameterIndex--)
+ {
+ setMethodParameterValue(clazz, methodrefConstant, parameterIndex, stack.pop());
+ }
+
+ // Push the return value, if applicable.
+ String returnType = ClassUtil.internalMethodReturnType(type);
+ if (returnType.charAt(0) != ClassConstants.TYPE_VOID)
+ {
+ stack.push(getMethodReturnValue(clazz, methodrefConstant, returnType));
+ }
+ }
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ String type = invokeDynamicConstant.getType(clazz);
+
+ // Count the number of parameters.
+ int parameterCount = ClassUtil.internalMethodParameterCount(type);
+ if (!isStatic)
+ {
+ parameterCount++;
+ }
+
+ // Pop the parameters and the class reference, in reverse order.
+ for (int parameterIndex = parameterCount-1; parameterIndex >= 0; parameterIndex--)
+ {
+ stack.pop();
+ }
+
+ // Push the return value, if applicable.
+ String returnType = ClassUtil.internalMethodReturnType(type);
+ if (returnType.charAt(0) != ClassConstants.TYPE_VOID)
+ {
+ stack.push(getMethodReturnValue(clazz, invokeDynamicConstant, returnType));
+ }
+ }
+
+
+ /**
+ * Returns the value of the specified exception.
+ */
+ public abstract Value getExceptionValue(Clazz clazz,
+ ClassConstant catchClassConstant);
+
+
+ /**
+ * Sets the class through which the specified field is accessed.
+ */
+ public abstract void setFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ ReferenceValue value);
+
+
+ /**
+ * Returns the class though which the specified field is accessed.
+ */
+ public abstract Value getFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ String type);
+
+
+ /**
+ * Sets the value of the specified field.
+ */
+ public abstract void setFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ Value value);
+
+
+ /**
+ * Returns the value of the specified field.
+ */
+ public abstract Value getFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ String type);
+
+
+ /**
+ * Sets the value of the specified method parameter.
+ */
+ public abstract void setMethodParameterValue(Clazz clazz,
+ RefConstant refConstant,
+ int parameterIndex,
+ Value value);
+
+
+ /**
+ * Returns the value of the specified method parameter.
+ */
+ public abstract Value getMethodParameterValue(Clazz clazz,
+ Method method,
+ int parameterIndex,
+ String type,
+ Clazz referencedClass);
+
+
+ /**
+ * Sets the return value of the specified method.
+ */
+ public abstract void setMethodReturnValue(Clazz clazz,
+ Method method,
+ Value value);
+
+
+ /**
+ * Returns the return value of the specified method.
+ */
+ public abstract Value getMethodReturnValue(Clazz clazz,
+ RefConstant refConstant,
+ String type);
+
+
+ /**
+ * Returns the return value of the specified method.
+ */
+ public abstract Value getMethodReturnValue(Clazz clazz,
+ InvokeDynamicConstant invokeDynamicConstant,
+ String type);
+}
diff --git a/src/proguard/evaluation/Stack.java b/core/src/proguard/evaluation/Stack.java
similarity index 99%
rename from src/proguard/evaluation/Stack.java
rename to core/src/proguard/evaluation/Stack.java
index 8bac0b5..c8fcc0f 100644
--- a/src/proguard/evaluation/Stack.java
+++ b/core/src/proguard/evaluation/Stack.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/TracedStack.java b/core/src/proguard/evaluation/TracedStack.java
similarity index 99%
rename from src/proguard/evaluation/TracedStack.java
rename to core/src/proguard/evaluation/TracedStack.java
index 4d76747..6e52ae6 100644
--- a/src/proguard/evaluation/TracedStack.java
+++ b/core/src/proguard/evaluation/TracedStack.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/TracedVariables.java b/core/src/proguard/evaluation/TracedVariables.java
similarity index 99%
rename from src/proguard/evaluation/TracedVariables.java
rename to core/src/proguard/evaluation/TracedVariables.java
index da2deb8..4714c3d 100644
--- a/src/proguard/evaluation/TracedVariables.java
+++ b/core/src/proguard/evaluation/TracedVariables.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/Variables.java b/core/src/proguard/evaluation/Variables.java
similarity index 99%
rename from src/proguard/evaluation/Variables.java
rename to core/src/proguard/evaluation/Variables.java
index d61364a..e92fe7d 100644
--- a/src/proguard/evaluation/Variables.java
+++ b/core/src/proguard/evaluation/Variables.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ArrayReferenceValue.java b/core/src/proguard/evaluation/value/ArrayReferenceValue.java
similarity index 88%
rename from src/proguard/evaluation/value/ArrayReferenceValue.java
rename to core/src/proguard/evaluation/value/ArrayReferenceValue.java
index 822d006..cc021aa 100644
--- a/src/proguard/evaluation/value/ArrayReferenceValue.java
+++ b/core/src/proguard/evaluation/value/ArrayReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,9 +39,10 @@ class ArrayReferenceValue extends TypedReferenceValue
*/
public ArrayReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
IntegerValue arrayLength)
{
- super(type, referencedClass, false);
+ super(type, referencedClass, mayBeExtension, false);
this.arrayLength = arrayLength;
}
@@ -95,6 +96,7 @@ public ReferenceValue generalize(ArrayReferenceValue other)
this.type.equals(other.type) &&
this.referencedClass == other.referencedClass ? new ArrayReferenceValue(this.type,
this.referencedClass,
+ this.mayBeExtension || other.mayBeExtension,
this.arrayLength.generalize(other.arrayLength)) :
generalize((TypedReferenceValue)other);
}
@@ -145,9 +147,18 @@ public int equal(ArrayReferenceValue other)
public boolean equals(Object object)
{
- return this == object ||
- super.equals(object) &&
- this.arrayLength.equals(((ArrayReferenceValue)object).arrayLength);
+ if (this == object)
+ {
+ return true;
+ }
+
+ if (!super.equals(object))
+ {
+ return false;
+ }
+
+ ArrayReferenceValue other = (ArrayReferenceValue)object;
+ return this.arrayLength.equals(other.arrayLength);
}
diff --git a/core/src/proguard/evaluation/value/ArrayReferenceValueFactory.java b/core/src/proguard/evaluation/value/ArrayReferenceValueFactory.java
new file mode 100644
index 0000000..d564402
--- /dev/null
+++ b/core/src/proguard/evaluation/value/ArrayReferenceValueFactory.java
@@ -0,0 +1,47 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.*;
+
+/**
+ * This identified value factory creates array reference values that also
+ * represent their elements, in as far as possible.
+ *
+ * @author Eric Lafortune
+ */
+public class ArrayReferenceValueFactory
+extends TypedReferenceValueFactory
+{
+ // Implementations for ReferenceValue.
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength)
+ {
+ return type == null ?
+ REFERENCE_VALUE_NULL :
+ new ArrayReferenceValue(ClassConstants.TYPE_ARRAY + type,
+ referencedClass,
+ false,
+ arrayLength);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/ValueFactory.java b/core/src/proguard/evaluation/value/BasicValueFactory.java
similarity index 54%
rename from src/proguard/evaluation/value/ValueFactory.java
rename to core/src/proguard/evaluation/value/BasicValueFactory.java
index 888f732..64a9bf1 100644
--- a/src/proguard/evaluation/value/ValueFactory.java
+++ b/core/src/proguard/evaluation/value/BasicValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,25 +28,23 @@
*
* @author Eric Lafortune
*/
-public class ValueFactory
+public class BasicValueFactory
+implements ValueFactory
{
// Shared copies of Value objects, to avoid creating a lot of objects.
- static final IntegerValue INTEGER_VALUE = new UnknownIntegerValue();
- static final LongValue LONG_VALUE = new UnknownLongValue();
- static final FloatValue FLOAT_VALUE = new UnknownFloatValue();
- static final DoubleValue DOUBLE_VALUE = new UnknownDoubleValue();
-
- static final ReferenceValue REFERENCE_VALUE_NULL = new TypedReferenceValue(null, null, true);
- static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL = new TypedReferenceValue(ClassConstants.NAME_JAVA_LANG_OBJECT, null, true);
- static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL = new TypedReferenceValue(ClassConstants.NAME_JAVA_LANG_OBJECT, null, false);
-
-
- /**
- * Creates a new Value of the given type.
- * The type must be a fully specified internal type for primitives, classes,
- * or arrays.
- */
- public Value createValue(String type, Clazz referencedClass, boolean mayBeNull)
+ static final IntegerValue INTEGER_VALUE = new UnknownIntegerValue();
+ static final LongValue LONG_VALUE = new UnknownLongValue();
+ static final FloatValue FLOAT_VALUE = new UnknownFloatValue();
+ static final DoubleValue DOUBLE_VALUE = new UnknownDoubleValue();
+ static final ReferenceValue REFERENCE_VALUE = new UnknownReferenceValue();
+
+
+ // Implementations for BasicValueFactory.
+
+ public Value createValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
{
switch (type.charAt(0))
{
@@ -60,117 +58,97 @@ public Value createValue(String type, Clazz referencedClass, boolean mayBeNull)
case ClassConstants.TYPE_FLOAT: return createFloatValue();
case ClassConstants.TYPE_DOUBLE: return createDoubleValue();
default: return createReferenceValue(ClassUtil.isInternalArrayType(type) ?
- type :
- ClassUtil.internalClassNameFromClassType(type),
+ type :
+ ClassUtil.internalClassNameFromClassType(type),
referencedClass,
+ mayBeExtension,
mayBeNull);
}
}
- /**
- * Creates a new IntegerValue with an undefined value.
- */
+
public IntegerValue createIntegerValue()
{
return INTEGER_VALUE;
}
- /**
- * Creates a new IntegerValue with a given particular value.
- */
+
public IntegerValue createIntegerValue(int value)
{
return createIntegerValue();
}
- /**
- * Creates a new LongValue with an undefined value.
- */
public LongValue createLongValue()
{
return LONG_VALUE;
}
- /**
- * Creates a new LongValue with a given particular value.
- */
+
public LongValue createLongValue(long value)
{
return createLongValue();
}
- /**
- * Creates a new FloatValue with an undefined value.
- */
public FloatValue createFloatValue()
{
return FLOAT_VALUE;
}
- /**
- * Creates a new FloatValue with a given particular value.
- */
+
public FloatValue createFloatValue(float value)
{
return createFloatValue();
}
- /**
- * Creates a new DoubleValue with an undefined value.
- */
public DoubleValue createDoubleValue()
{
return DOUBLE_VALUE;
}
- /**
- * Creates a new DoubleValue with a given particular value.
- */
+
public DoubleValue createDoubleValue(double value)
{
return createDoubleValue();
}
- /**
- * Creates a new ReferenceValue that represents null.
- */
+ public ReferenceValue createReferenceValue()
+ {
+ return REFERENCE_VALUE;
+ }
+
+
public ReferenceValue createReferenceValueNull()
{
- return REFERENCE_VALUE_NULL;
+ return REFERENCE_VALUE;
}
- /**
- * Creates a new ReferenceValue of the given type. The type must be an
- * internal class name or an array type. If the type is null,
- * the ReferenceValue represents null.
- */
public ReferenceValue createReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
boolean mayBeNull)
{
- return type == null ? REFERENCE_VALUE_NULL :
- !type.equals(ClassConstants.NAME_JAVA_LANG_OBJECT) ? new TypedReferenceValue(type, referencedClass, mayBeNull) :
- mayBeNull ? REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
- REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL;
+ return createReferenceValue();
}
- /**
- * Creates a new ReferenceValue for arrays of the given type and length.
- * The type must be a fully specified internal type for primitives, classes,
- * or arrays.
- */
public ReferenceValue createArrayReferenceValue(String type,
Clazz referencedClass,
IntegerValue arrayLength)
{
- return createReferenceValue(ClassConstants.TYPE_ARRAY + type,
- referencedClass,
- false);
+ return createReferenceValue(type, referencedClass, false, false);
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength,
+ Value elementValue)
+ {
+ return createArrayReferenceValue(type, referencedClass, arrayLength);
}
}
diff --git a/src/proguard/evaluation/value/Category1Value.java b/core/src/proguard/evaluation/value/Category1Value.java
similarity index 95%
rename from src/proguard/evaluation/value/Category1Value.java
rename to core/src/proguard/evaluation/value/Category1Value.java
index a9b8a53..2aafb45 100644
--- a/src/proguard/evaluation/value/Category1Value.java
+++ b/core/src/proguard/evaluation/value/Category1Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/Category2Value.java b/core/src/proguard/evaluation/value/Category2Value.java
similarity index 95%
rename from src/proguard/evaluation/value/Category2Value.java
rename to core/src/proguard/evaluation/value/Category2Value.java
index 8229207..5a5835b 100644
--- a/src/proguard/evaluation/value/Category2Value.java
+++ b/core/src/proguard/evaluation/value/Category2Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ComparisonValue.java b/core/src/proguard/evaluation/value/ComparisonValue.java
similarity index 97%
rename from src/proguard/evaluation/value/ComparisonValue.java
rename to core/src/proguard/evaluation/value/ComparisonValue.java
index d52d270..97d46ea 100644
--- a/src/proguard/evaluation/value/ComparisonValue.java
+++ b/core/src/proguard/evaluation/value/ComparisonValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/CompositeDoubleValue.java b/core/src/proguard/evaluation/value/CompositeDoubleValue.java
similarity index 97%
rename from src/proguard/evaluation/value/CompositeDoubleValue.java
rename to core/src/proguard/evaluation/value/CompositeDoubleValue.java
index f060f2d..5af044c 100644
--- a/src/proguard/evaluation/value/CompositeDoubleValue.java
+++ b/core/src/proguard/evaluation/value/CompositeDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/CompositeFloatValue.java b/core/src/proguard/evaluation/value/CompositeFloatValue.java
similarity index 97%
rename from src/proguard/evaluation/value/CompositeFloatValue.java
rename to core/src/proguard/evaluation/value/CompositeFloatValue.java
index 88e6261..e461c6b 100644
--- a/src/proguard/evaluation/value/CompositeFloatValue.java
+++ b/core/src/proguard/evaluation/value/CompositeFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/CompositeIntegerValue.java b/core/src/proguard/evaluation/value/CompositeIntegerValue.java
similarity index 98%
rename from src/proguard/evaluation/value/CompositeIntegerValue.java
rename to core/src/proguard/evaluation/value/CompositeIntegerValue.java
index 50d348a..cbb87a0 100644
--- a/src/proguard/evaluation/value/CompositeIntegerValue.java
+++ b/core/src/proguard/evaluation/value/CompositeIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/CompositeLongValue.java b/core/src/proguard/evaluation/value/CompositeLongValue.java
similarity index 96%
rename from src/proguard/evaluation/value/CompositeLongValue.java
rename to core/src/proguard/evaluation/value/CompositeLongValue.java
index 49b5094..0966c38 100644
--- a/src/proguard/evaluation/value/CompositeLongValue.java
+++ b/core/src/proguard/evaluation/value/CompositeLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -43,7 +43,7 @@ final class CompositeLongValue extends SpecificLongValue
private final LongValue longValue1;
private final byte operation;
- private final Value longValue2;
+ private final Value longValue2;
/**
diff --git a/src/proguard/evaluation/value/ConvertedByteValue.java b/core/src/proguard/evaluation/value/ConvertedByteValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedByteValue.java
rename to core/src/proguard/evaluation/value/ConvertedByteValue.java
index ffcb24a..3f297fe 100644
--- a/src/proguard/evaluation/value/ConvertedByteValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedByteValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedCharacterValue.java b/core/src/proguard/evaluation/value/ConvertedCharacterValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedCharacterValue.java
rename to core/src/proguard/evaluation/value/ConvertedCharacterValue.java
index 3b0706a..68f76f6 100644
--- a/src/proguard/evaluation/value/ConvertedCharacterValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedCharacterValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedDoubleValue.java b/core/src/proguard/evaluation/value/ConvertedDoubleValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedDoubleValue.java
rename to core/src/proguard/evaluation/value/ConvertedDoubleValue.java
index 0472a26..adf6db9 100644
--- a/src/proguard/evaluation/value/ConvertedDoubleValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedFloatValue.java b/core/src/proguard/evaluation/value/ConvertedFloatValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedFloatValue.java
rename to core/src/proguard/evaluation/value/ConvertedFloatValue.java
index afa5cf7..51acd7b 100644
--- a/src/proguard/evaluation/value/ConvertedFloatValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedIntegerValue.java b/core/src/proguard/evaluation/value/ConvertedIntegerValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedIntegerValue.java
rename to core/src/proguard/evaluation/value/ConvertedIntegerValue.java
index 2ec9ab8..4c40f37 100644
--- a/src/proguard/evaluation/value/ConvertedIntegerValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedLongValue.java b/core/src/proguard/evaluation/value/ConvertedLongValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedLongValue.java
rename to core/src/proguard/evaluation/value/ConvertedLongValue.java
index 03eb4fd..168eb02 100644
--- a/src/proguard/evaluation/value/ConvertedLongValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ConvertedShortValue.java b/core/src/proguard/evaluation/value/ConvertedShortValue.java
similarity index 96%
rename from src/proguard/evaluation/value/ConvertedShortValue.java
rename to core/src/proguard/evaluation/value/ConvertedShortValue.java
index e1f1745..f8097ba 100644
--- a/src/proguard/evaluation/value/ConvertedShortValue.java
+++ b/core/src/proguard/evaluation/value/ConvertedShortValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/DetailedArrayReferenceValue.java b/core/src/proguard/evaluation/value/DetailedArrayReferenceValue.java
similarity index 84%
rename from src/proguard/evaluation/value/DetailedArrayReferenceValue.java
rename to core/src/proguard/evaluation/value/DetailedArrayReferenceValue.java
index 3f73b91..48a7246 100644
--- a/src/proguard/evaluation/value/DetailedArrayReferenceValue.java
+++ b/core/src/proguard/evaluation/value/DetailedArrayReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -43,14 +43,16 @@ class DetailedArrayReferenceValue extends IdentifiedArrayReferenceValue
*/
public DetailedArrayReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
IntegerValue arrayLength,
ValueFactory valuefactory,
int id)
{
- super(type, referencedClass, arrayLength, valuefactory, id);
+ super(type, referencedClass, mayBeExtension, arrayLength, valuefactory, id);
// Is the array short enough to analyze?
if (arrayLength.isParticular() &&
+ arrayLength.value() >= 0 &&
arrayLength.value() <= MAXIMUM_STORED_ARRAY_LENGTH)
{
// Initialize the values of the array.
@@ -182,6 +184,34 @@ public int equal(ReferenceValue other)
}
+// // Implementations of binary ReferenceValue methods with
+// // UnknownReferenceValue arguments.
+//
+// public ReferenceValue generalize(UnknownReferenceValue other)
+// {
+// return other;
+// }
+//
+//
+// public int equal(UnknownReferenceValue other)
+// {
+// return MAYBE;
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TypedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TypedReferenceValue other)
+// {
+// }
+//
+//
+// public int equal(TypedReferenceValue other)
+// {
+// }
+//
+//
// // Implementations of binary ReferenceValue methods with
// // IdentifiedReferenceValue arguments.
//
@@ -239,6 +269,21 @@ public int equal(ReferenceValue other)
// public int equal(DetailedArrayReferenceValue other)
// {
// return equal((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TracedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TracedReferenceValue other)
+// {
+// return other.generalize(this);
+// }
+//
+//
+// public int equal(TracedReferenceValue other)
+// {
+// return other.equal(this);
// }
@@ -267,9 +312,20 @@ public boolean isParticular()
public boolean equals(Object object)
{
- return this == object ||
- super.equals(object) &&
- ArrayUtil.equalOrNull(this.values, ((DetailedArrayReferenceValue)object).values);
+ if (this == object)
+ {
+ return true;
+ }
+
+ if (!super.equals(object))
+ {
+ return false;
+ }
+
+ DetailedArrayReferenceValue other =
+ (DetailedArrayReferenceValue)object;
+
+ return ArrayUtil.equalOrNull(this.values, other.values);
}
diff --git a/src/proguard/evaluation/value/DetailedValueFactory.java b/core/src/proguard/evaluation/value/DetailedArrayValueFactory.java
similarity index 89%
rename from src/proguard/evaluation/value/DetailedValueFactory.java
rename to core/src/proguard/evaluation/value/DetailedArrayValueFactory.java
index 0145523..d169f2a 100644
--- a/src/proguard/evaluation/value/DetailedValueFactory.java
+++ b/core/src/proguard/evaluation/value/DetailedArrayValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,7 @@
*
* @author Eric Lafortune
*/
-public class DetailedValueFactory
+public class DetailedArrayValueFactory
extends IdentifiedValueFactory
{
// Implementations for ReferenceValue.
@@ -38,9 +38,10 @@ public ReferenceValue createArrayReferenceValue(String type,
IntegerValue arrayLength)
{
return type == null ?
- REFERENCE_VALUE_NULL :
+ TypedReferenceValueFactory.REFERENCE_VALUE_NULL :
new DetailedArrayReferenceValue(ClassConstants.TYPE_ARRAY + type,
referencedClass,
+ false,
arrayLength,
this,
referenceID++);
diff --git a/src/proguard/evaluation/value/DoubleValue.java b/core/src/proguard/evaluation/value/DoubleValue.java
similarity index 99%
rename from src/proguard/evaluation/value/DoubleValue.java
rename to core/src/proguard/evaluation/value/DoubleValue.java
index 44912e7..fbac4b0 100644
--- a/src/proguard/evaluation/value/DoubleValue.java
+++ b/core/src/proguard/evaluation/value/DoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/FloatValue.java b/core/src/proguard/evaluation/value/FloatValue.java
similarity index 99%
rename from src/proguard/evaluation/value/FloatValue.java
rename to core/src/proguard/evaluation/value/FloatValue.java
index 515cc86..bd84574 100644
--- a/src/proguard/evaluation/value/FloatValue.java
+++ b/core/src/proguard/evaluation/value/FloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/IdentifiedArrayReferenceValue.java b/core/src/proguard/evaluation/value/IdentifiedArrayReferenceValue.java
similarity index 73%
rename from src/proguard/evaluation/value/IdentifiedArrayReferenceValue.java
rename to core/src/proguard/evaluation/value/IdentifiedArrayReferenceValue.java
index 6922dbd..da31f07 100644
--- a/src/proguard/evaluation/value/IdentifiedArrayReferenceValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedArrayReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,11 +39,12 @@ class IdentifiedArrayReferenceValue extends ArrayReferenceValue
*/
public IdentifiedArrayReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
IntegerValue arrayLength,
ValueFactory valuefactory,
int id)
{
- super(type, referencedClass, arrayLength);
+ super(type, referencedClass, mayBeExtension, arrayLength);
this.valuefactory = valuefactory;
this.id = id;
@@ -64,6 +65,34 @@ public int equal(ReferenceValue other)
}
+// // Implementations of binary ReferenceValue methods with
+// // UnknownReferenceValue arguments.
+//
+// public ReferenceValue generalize(UnknownReferenceValue other)
+// {
+// return other;
+// }
+//
+//
+// public int equal(UnknownReferenceValue other)
+// {
+// return MAYBE;
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TypedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TypedReferenceValue other)
+// {
+// }
+//
+//
+// public int equal(TypedReferenceValue other)
+// {
+// }
+//
+//
// // Implementations of binary ReferenceValue methods with
// // IdentifiedReferenceValue arguments.
//
@@ -122,6 +151,21 @@ public int equal(IdentifiedArrayReferenceValue other)
// public int equal(DetailedArrayReferenceValue other)
// {
// return equal((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TracedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TracedReferenceValue other)
+// {
+// return other.generalize(this);
+// }
+//
+//
+// public int equal(TracedReferenceValue other)
+// {
+// return other.equal(this);
// }
@@ -137,10 +181,21 @@ public boolean isSpecific()
public boolean equals(Object object)
{
- return this == object ||
- super.equals(object) &&
- this.valuefactory.equals(((IdentifiedArrayReferenceValue)object).valuefactory) &&
- this.id == ((IdentifiedArrayReferenceValue)object).id;
+ if (this == object)
+ {
+ return true;
+ }
+
+ if (!super.equals(object))
+ {
+ return false;
+ }
+
+ IdentifiedArrayReferenceValue other =
+ (IdentifiedArrayReferenceValue)object;
+
+ return this.valuefactory.equals(other.valuefactory) &&
+ this.id == other.id;
}
diff --git a/src/proguard/evaluation/value/IdentifiedDoubleValue.java b/core/src/proguard/evaluation/value/IdentifiedDoubleValue.java
similarity index 97%
rename from src/proguard/evaluation/value/IdentifiedDoubleValue.java
rename to core/src/proguard/evaluation/value/IdentifiedDoubleValue.java
index 56cceda..04be74a 100644
--- a/src/proguard/evaluation/value/IdentifiedDoubleValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/IdentifiedFloatValue.java b/core/src/proguard/evaluation/value/IdentifiedFloatValue.java
similarity index 97%
rename from src/proguard/evaluation/value/IdentifiedFloatValue.java
rename to core/src/proguard/evaluation/value/IdentifiedFloatValue.java
index cfeb9a9..aa0a86c 100644
--- a/src/proguard/evaluation/value/IdentifiedFloatValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/IdentifiedIntegerValue.java b/core/src/proguard/evaluation/value/IdentifiedIntegerValue.java
similarity index 97%
rename from src/proguard/evaluation/value/IdentifiedIntegerValue.java
rename to core/src/proguard/evaluation/value/IdentifiedIntegerValue.java
index e054e85..f92363d 100644
--- a/src/proguard/evaluation/value/IdentifiedIntegerValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/IdentifiedLongValue.java b/core/src/proguard/evaluation/value/IdentifiedLongValue.java
similarity index 97%
rename from src/proguard/evaluation/value/IdentifiedLongValue.java
rename to core/src/proguard/evaluation/value/IdentifiedLongValue.java
index d96ffdb..ad3775a 100644
--- a/src/proguard/evaluation/value/IdentifiedLongValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/IdentifiedReferenceValue.java b/core/src/proguard/evaluation/value/IdentifiedReferenceValue.java
similarity index 70%
rename from src/proguard/evaluation/value/IdentifiedReferenceValue.java
rename to core/src/proguard/evaluation/value/IdentifiedReferenceValue.java
index 13e6338..a3a2d7c 100644
--- a/src/proguard/evaluation/value/IdentifiedReferenceValue.java
+++ b/core/src/proguard/evaluation/value/IdentifiedReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,12 +23,12 @@
import proguard.classfile.Clazz;
/**
- * This TypedReferenceValue represents a reference value that is identified by a
+ * This ReferenceValue represents a reference value that is identified by a
* unique ID.
*
* @author Eric Lafortune
*/
-class IdentifiedReferenceValue extends TypedReferenceValue
+final class IdentifiedReferenceValue extends TypedReferenceValue
{
private final ValueFactory valuefactory;
private final int id;
@@ -39,11 +39,12 @@ class IdentifiedReferenceValue extends TypedReferenceValue
*/
public IdentifiedReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
boolean mayBeNull,
ValueFactory valuefactory,
int id)
{
- super(type, referencedClass, mayBeNull);
+ super(type, referencedClass, mayBeExtension, mayBeNull);
this.valuefactory = valuefactory;
this.id = id;
@@ -64,6 +65,34 @@ public int equal(ReferenceValue other)
}
+// // Implementations of binary ReferenceValue methods with
+// // UnknownReferenceValue arguments.
+//
+// public ReferenceValue generalize(UnknownReferenceValue other)
+// {
+// return other;
+// }
+//
+//
+// public int equal(UnknownReferenceValue other)
+// {
+// return MAYBE;
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TypedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TypedReferenceValue other)
+// {
+// }
+//
+//
+// public int equal(TypedReferenceValue other)
+// {
+// }
+
+
// Implementations of binary ReferenceValue methods with
// IdentifiedReferenceValue arguments.
@@ -122,6 +151,21 @@ public int equal(IdentifiedReferenceValue other)
// public int equal(DetailedArrayReferenceValue other)
// {
// return equal((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TracedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TracedReferenceValue other)
+// {
+// return other.generalize(this);
+// }
+//
+//
+// public int equal(TracedReferenceValue other)
+// {
+// return other.equal(this);
// }
@@ -137,10 +181,19 @@ public boolean isSpecific()
public boolean equals(Object object)
{
- return this == object ||
- super.equals(object) &&
- this.valuefactory.equals(((IdentifiedReferenceValue)object).valuefactory) &&
- this.id == ((IdentifiedReferenceValue)object).id;
+ if (this == object)
+ {
+ return true;
+ }
+
+ if (!super.equals(object))
+ {
+ return false;
+ }
+
+ IdentifiedReferenceValue other = (IdentifiedReferenceValue)object;
+ return this.valuefactory.equals(other.valuefactory) &&
+ this.id == other.id;
}
@@ -156,4 +209,4 @@ public String toString()
{
return super.toString()+'#'+id;
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/evaluation/value/IdentifiedValueFactory.java b/core/src/proguard/evaluation/value/IdentifiedValueFactory.java
similarity index 82%
rename from src/proguard/evaluation/value/IdentifiedValueFactory.java
rename to core/src/proguard/evaluation/value/IdentifiedValueFactory.java
index b999d89..5c43cd3 100644
--- a/src/proguard/evaluation/value/IdentifiedValueFactory.java
+++ b/core/src/proguard/evaluation/value/IdentifiedValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,10 +20,12 @@
*/
package proguard.evaluation.value;
-import proguard.classfile.*;
+import proguard.classfile.ClassConstants;
+import proguard.classfile.Clazz;
/**
- * This particular value factory attaches a unique ID to any unknown values.
+ * This class provides methods to create and reuse Value objects that are
+ * identified by unique integer IDs.
*
* @author Eric Lafortune
*/
@@ -37,7 +39,7 @@ public class IdentifiedValueFactory
protected int referenceID;
- // Implementations for ValueFactory.
+ // Implementations for BasicValueFactory.
public IntegerValue createIntegerValue()
{
@@ -65,12 +67,14 @@ public DoubleValue createDoubleValue()
public ReferenceValue createReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
boolean mayBeNull)
{
return type == null ?
- REFERENCE_VALUE_NULL :
+ TypedReferenceValueFactory.REFERENCE_VALUE_NULL :
new IdentifiedReferenceValue(type,
referencedClass,
+ mayBeExtension,
mayBeNull,
this,
referenceID++);
@@ -82,9 +86,10 @@ public ReferenceValue createArrayReferenceValue(String type,
IntegerValue arrayLength)
{
return type == null ?
- REFERENCE_VALUE_NULL :
+ TypedReferenceValueFactory.REFERENCE_VALUE_NULL :
new IdentifiedArrayReferenceValue(ClassConstants.TYPE_ARRAY + type,
referencedClass,
+ false,
arrayLength,
this,
referenceID++);
diff --git a/src/proguard/evaluation/value/InitialValueFactory.java b/core/src/proguard/evaluation/value/InitialValueFactory.java
similarity index 97%
rename from src/proguard/evaluation/value/InitialValueFactory.java
rename to core/src/proguard/evaluation/value/InitialValueFactory.java
index 725b392..983c86f 100644
--- a/src/proguard/evaluation/value/InitialValueFactory.java
+++ b/core/src/proguard/evaluation/value/InitialValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/InstructionOffsetValue.java b/core/src/proguard/evaluation/value/InstructionOffsetValue.java
similarity index 53%
rename from src/proguard/evaluation/value/InstructionOffsetValue.java
rename to core/src/proguard/evaluation/value/InstructionOffsetValue.java
index 69e76bd..429dea1 100644
--- a/src/proguard/evaluation/value/InstructionOffsetValue.java
+++ b/core/src/proguard/evaluation/value/InstructionOffsetValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,44 +24,63 @@
/**
* This class represents a partially evaluated instruction offset. It can
- * contain 0 or more specific instruction offsets.
+ * contain 0 or more specific instruction offsets. Each instruction offset
+ * can be flagged as an ordinary offset, a method parameter, a method return
+ * value, a field value, a new instance value, or an exception handler.
*
* @author Eric Lafortune
*/
public class InstructionOffsetValue extends Category1Value
{
- public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue();
+ private static final int[] EMPTY_OFFSETS = new int[0];
+ public static final InstructionOffsetValue EMPTY_VALUE = new InstructionOffsetValue(EMPTY_OFFSETS);
-
- private int[] values;
+ public static final int INSTRUCTION_OFFSET_MASK = 0x01ffffff;
+ public static final int METHOD_PARAMETER = 0x01000000; // Method parameter indices are not really instruction offsets.
+ public static final int METHOD_RETURN_VALUE = 0x02000000;
+ public static final int FIELD_VALUE = 0x04000000;
+ public static final int NEW_INSTANCE = 0x08000000;
+ public static final int CAST = 0x10000000;
+ public static final int EXCEPTION_HANDLER = 0x20000000;
- private InstructionOffsetValue()
- {
- }
+ private int[] values;
+ /**
+ * Creates a new InstructionOffsetValue with the given instruction offset.
+ */
public InstructionOffsetValue(int value)
{
this.values = new int[] { value };
}
+ /**
+ * Creates a new InstructionOffsetValue with the given list of instruction
+ * offsets.
+ */
public InstructionOffsetValue(int[] values)
{
this.values = values;
}
+ /**
+ * Returns the number of instruction offsets of this value.
+ */
public int instructionOffsetCount()
{
- return values == null ? 0 : values.length;
+ return values.length;
}
+ /**
+ * Returns the specified instruction offset of this value.
+ */
public int instructionOffset(int index)
{
- return values[index];
+ return values[index] & INSTRUCTION_OFFSET_MASK;
}
@@ -71,14 +90,11 @@ public int instructionOffset(int index)
*/
public boolean contains(int value)
{
- if (values != null)
+ for (int index = 0; index < values.length; index++)
{
- for (int index = 0; index < values.length; index++)
+ if (values[index] == value)
{
- if (values[index] == value)
- {
- return true;
- }
+ return true;
}
}
@@ -94,16 +110,13 @@ public int minimumValue()
{
int minimumValue = Integer.MAX_VALUE;
- if (values != null)
+ for (int index = 0; index < values.length; index++)
{
- for (int index = 0; index < values.length; index++)
- {
- int value = values[index];
+ int value = values[index] & INSTRUCTION_OFFSET_MASK;
- if (minimumValue > value)
- {
- minimumValue = value;
- }
+ if (minimumValue > value)
+ {
+ minimumValue = value;
}
}
@@ -119,16 +132,13 @@ public int maximumValue()
{
int maximumValue = Integer.MIN_VALUE;
- if (values != null)
+ for (int index = 0; index < values.length; index++)
{
- for (int index = 0; index < values.length; index++)
- {
- int value = values[index];
+ int value = values[index] & INSTRUCTION_OFFSET_MASK;
- if (maximumValue < value)
- {
- maximumValue = value;
- }
+ if (maximumValue < value)
+ {
+ maximumValue = value;
}
}
@@ -136,22 +146,131 @@ public int maximumValue()
}
+ /**
+ * Returns whether the specified instruction offset corresponds to a method
+ * parameter.
+ */
+ public boolean isMethodParameter(int index)
+ {
+ return (values[index] & METHOD_PARAMETER) != 0;
+ }
+
+
+ /**
+ * Returns the specified method parameter (assuming it is one).
+ */
+ public int methodParameter(int index)
+ {
+ return values[index] & ~METHOD_PARAMETER;
+ }
+
+
+ /**
+ * Returns whether the specified instruction offset corresponds to a method
+ * return value.
+ */
+ public boolean isMethodReturnValue(int index)
+ {
+ return (values[index] & METHOD_RETURN_VALUE) != 0;
+ }
+
+
+ /**
+ * Returns whether the specified instruction offset corresponds to a field
+ * value.
+ */
+ public boolean isFieldValue(int index)
+ {
+ return (values[index] & FIELD_VALUE) != 0;
+ }
+
+
+ /**
+ * Returns whether the specified instruction offset corresponds to a new
+ * instance.
+ */
+ public boolean isNewinstance(int index)
+ {
+ return (values[index] & NEW_INSTANCE) != 0;
+ }
+
+
+ /**
+ * Returns whether the specified instruction offset corresponds to a cast.
+ */
+ public boolean isCast(int index)
+ {
+ return (values[index] & CAST) != 0;
+ }
+
+
+ /**
+ * Returns whether the specified instruction offset corresponds to an
+ * exception handler.
+ */
+ public boolean isExceptionHandler(int index)
+ {
+ return (values[index] & EXCEPTION_HANDLER) != 0;
+ }
+
+
+ /**
+ * Returns an InstructionOffsetValue that contains the instructions offsets
+ * of this value and the given instruction offset.
+ */
+ public InstructionOffsetValue add(int value)
+ {
+ if (contains(value))
+ {
+ return this;
+ }
+
+ int[] newValues = new int[values.length+1];
+ System.arraycopy(values, 0, newValues, 0, values.length);
+ newValues[values.length] = value;
+
+ return new InstructionOffsetValue(newValues);
+ }
+
+
+ /**
+ * Returns an InstructionOffsetValue that contains the instructions offsets
+ * of this value but not the given instruction offset.
+ */
+ public InstructionOffsetValue remove(int value)
+ {
+ for (int index = 0; index < values.length; index++)
+ {
+ if (values[index] == value)
+ {
+ int[] newValues = new int[values.length-1];
+ System.arraycopy(values, 0, newValues, 0, index);
+ System.arraycopy(values, index+1, newValues, index, values.length-index-1);
+
+ return new InstructionOffsetValue(newValues);
+ }
+ }
+
+ return this;
+ }
+
+
/**
* Returns the generalization of this InstructionOffsetValue and the given
* other InstructionOffsetValue. The values of the other InstructionOffsetValue
* are guaranteed to remain at the end of the list, in the same order.
*/
- public final Value generalize(InstructionOffsetValue other)
+ public final InstructionOffsetValue generalize(InstructionOffsetValue other)
{
- // If the values array of either is null, we can return the other one.
+ // If the values array of either is empty, we can return the other one.
int[] thisValues = this.values;
- if (thisValues == null)
+ if (thisValues.length == 0)
{
return other;
}
int[] otherValues = other.values;
- if (otherValues == null)
+ if (otherValues.length == 0)
{
return this;
}
@@ -311,7 +430,45 @@ public String toString()
{
buffer.append(',');
}
- buffer.append(values[index]);
+
+ if (values[index] < 0)
+ {
+ buffer.append(values[index]);
+ }
+ else
+ {
+ if (isMethodParameter(index))
+ {
+ buffer.append('P');
+ }
+
+ if (isMethodReturnValue(index))
+ {
+ buffer.append('M');
+ }
+
+ if (isFieldValue(index))
+ {
+ buffer.append('F');
+ }
+
+ if (isNewinstance(index))
+ {
+ buffer.append('N');
+ }
+
+ if (isCast(index))
+ {
+ buffer.append('C');
+ }
+
+ if (isExceptionHandler(index))
+ {
+ buffer.append('E');
+ }
+
+ buffer.append(values[index] & 0xffff);
+ }
}
}
diff --git a/src/proguard/evaluation/value/IntegerValue.java b/core/src/proguard/evaluation/value/IntegerValue.java
similarity index 99%
rename from src/proguard/evaluation/value/IntegerValue.java
rename to core/src/proguard/evaluation/value/IntegerValue.java
index ecc68b0..dedd5ab 100644
--- a/src/proguard/evaluation/value/IntegerValue.java
+++ b/core/src/proguard/evaluation/value/IntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/LongValue.java b/core/src/proguard/evaluation/value/LongValue.java
similarity index 99%
rename from src/proguard/evaluation/value/LongValue.java
rename to core/src/proguard/evaluation/value/LongValue.java
index be57950..fd0f406 100644
--- a/src/proguard/evaluation/value/LongValue.java
+++ b/core/src/proguard/evaluation/value/LongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/NegatedDoubleValue.java b/core/src/proguard/evaluation/value/NegatedDoubleValue.java
similarity index 97%
rename from src/proguard/evaluation/value/NegatedDoubleValue.java
rename to core/src/proguard/evaluation/value/NegatedDoubleValue.java
index f26e8fc..6b27dc2 100644
--- a/src/proguard/evaluation/value/NegatedDoubleValue.java
+++ b/core/src/proguard/evaluation/value/NegatedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/NegatedFloatValue.java b/core/src/proguard/evaluation/value/NegatedFloatValue.java
similarity index 96%
rename from src/proguard/evaluation/value/NegatedFloatValue.java
rename to core/src/proguard/evaluation/value/NegatedFloatValue.java
index 0443a09..68007e4 100644
--- a/src/proguard/evaluation/value/NegatedFloatValue.java
+++ b/core/src/proguard/evaluation/value/NegatedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/NegatedIntegerValue.java b/core/src/proguard/evaluation/value/NegatedIntegerValue.java
similarity index 97%
rename from src/proguard/evaluation/value/NegatedIntegerValue.java
rename to core/src/proguard/evaluation/value/NegatedIntegerValue.java
index 746c906..a16da1f 100644
--- a/src/proguard/evaluation/value/NegatedIntegerValue.java
+++ b/core/src/proguard/evaluation/value/NegatedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/NegatedLongValue.java b/core/src/proguard/evaluation/value/NegatedLongValue.java
similarity index 96%
rename from src/proguard/evaluation/value/NegatedLongValue.java
rename to core/src/proguard/evaluation/value/NegatedLongValue.java
index c23cc31..0ab6384 100644
--- a/src/proguard/evaluation/value/NegatedLongValue.java
+++ b/core/src/proguard/evaluation/value/NegatedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ParticularDoubleValue.java b/core/src/proguard/evaluation/value/ParticularDoubleValue.java
similarity index 98%
rename from src/proguard/evaluation/value/ParticularDoubleValue.java
rename to core/src/proguard/evaluation/value/ParticularDoubleValue.java
index f61628f..afe2ea9 100644
--- a/src/proguard/evaluation/value/ParticularDoubleValue.java
+++ b/core/src/proguard/evaluation/value/ParticularDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -137,7 +137,7 @@ public DoubleValue generalize(ParticularDoubleValue other)
// Also handle NaN and Infinity.
return Double.doubleToRawLongBits(this.value) ==
Double.doubleToRawLongBits(other.value) ?
- this : ValueFactory.DOUBLE_VALUE;
+ this : BasicValueFactory.DOUBLE_VALUE;
}
public DoubleValue add(ParticularDoubleValue other)
diff --git a/src/proguard/evaluation/value/ParticularFloatValue.java b/core/src/proguard/evaluation/value/ParticularFloatValue.java
similarity index 98%
rename from src/proguard/evaluation/value/ParticularFloatValue.java
rename to core/src/proguard/evaluation/value/ParticularFloatValue.java
index 98875be..895c560 100644
--- a/src/proguard/evaluation/value/ParticularFloatValue.java
+++ b/core/src/proguard/evaluation/value/ParticularFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -137,7 +137,7 @@ public FloatValue generalize(ParticularFloatValue other)
// Also handle NaN and Infinity.
return Float.floatToRawIntBits(this.value) ==
Float.floatToRawIntBits(other.value) ?
- this : ValueFactory.FLOAT_VALUE;
+ this : BasicValueFactory.FLOAT_VALUE;
}
public FloatValue add(ParticularFloatValue other)
diff --git a/src/proguard/evaluation/value/ParticularIntegerValue.java b/core/src/proguard/evaluation/value/ParticularIntegerValue.java
similarity index 99%
rename from src/proguard/evaluation/value/ParticularIntegerValue.java
rename to core/src/proguard/evaluation/value/ParticularIntegerValue.java
index 95cf5c5..16f7e2e 100644
--- a/src/proguard/evaluation/value/ParticularIntegerValue.java
+++ b/core/src/proguard/evaluation/value/ParticularIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ParticularLongValue.java b/core/src/proguard/evaluation/value/ParticularLongValue.java
similarity index 99%
rename from src/proguard/evaluation/value/ParticularLongValue.java
rename to core/src/proguard/evaluation/value/ParticularLongValue.java
index b733dd9..656c255 100644
--- a/src/proguard/evaluation/value/ParticularLongValue.java
+++ b/core/src/proguard/evaluation/value/ParticularLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/evaluation/value/ParticularValueFactory.java b/core/src/proguard/evaluation/value/ParticularValueFactory.java
similarity index 62%
rename from src/proguard/evaluation/value/ParticularValueFactory.java
rename to core/src/proguard/evaluation/value/ParticularValueFactory.java
index 294ab1b..72a8fcd 100644
--- a/src/proguard/evaluation/value/ParticularValueFactory.java
+++ b/core/src/proguard/evaluation/value/ParticularValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,15 +20,17 @@
*/
package proguard.evaluation.value;
-import proguard.classfile.*;
+import proguard.classfile.Clazz;
/**
- * This value factory creates particular values.
+ * This class provides methods to create and reuse Value objects that have
+ * particular values, whenever they are known.
*
* @author Eric Lafortune
*/
public class ParticularValueFactory
-extends ValueFactory
+extends BasicValueFactory
+implements ValueFactory
{
// Shared copies of Value objects, to avoid creating a lot of objects.
static final IntegerValue INTEGER_VALUE_M1 = new ParticularIntegerValue(-1);
@@ -51,6 +53,28 @@ public class ParticularValueFactory
private static long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0);
+ private final ValueFactory referenceValueFactory;
+
+
+ /**
+ * Creates a new ParticularValueFactory.
+ */
+ public ParticularValueFactory()
+ {
+ this(new ArrayReferenceValueFactory());
+ }
+
+
+ /**
+ * Creates a new ParticularValueFactory that delegates to the given
+ * value factory for creating reference values.
+ */
+ public ParticularValueFactory(ValueFactory referenceValueFactory)
+ {
+ this.referenceValueFactory = referenceValueFactory;
+ }
+
+
// Implementations for ValueFactory.
public IntegerValue createIntegerValue(int value)
@@ -98,14 +122,48 @@ public DoubleValue createDoubleValue(double value)
}
+ public ReferenceValue createReferenceValue()
+ {
+ return referenceValueFactory.createReferenceValue();
+ }
+
+
+ public ReferenceValue createReferenceValueNull()
+ {
+ return referenceValueFactory.createReferenceValueNull();
+ }
+
+
+ public ReferenceValue createReferenceValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
+ {
+ return referenceValueFactory.createReferenceValue(type,
+ referencedClass,
+ mayBeExtension,
+ mayBeNull);
+ }
+
+
public ReferenceValue createArrayReferenceValue(String type,
Clazz referencedClass,
IntegerValue arrayLength)
{
- return type == null ?
- REFERENCE_VALUE_NULL :
- new ArrayReferenceValue(ClassConstants.TYPE_ARRAY + type,
- referencedClass,
- arrayLength);
+ return referenceValueFactory.createArrayReferenceValue(type,
+ referencedClass,
+ arrayLength);
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength,
+ Value elementValue)
+ {
+ return referenceValueFactory.createArrayReferenceValue(type,
+ referencedClass,
+ arrayLength,
+ elementValue);
}
}
diff --git a/core/src/proguard/evaluation/value/PrimitiveTypedReferenceValueFactory.java b/core/src/proguard/evaluation/value/PrimitiveTypedReferenceValueFactory.java
new file mode 100644
index 0000000..0e18174
--- /dev/null
+++ b/core/src/proguard/evaluation/value/PrimitiveTypedReferenceValueFactory.java
@@ -0,0 +1,70 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+
+/**
+ * This class provides methods to create and reuse Value objects.
+ * Its ReferenceValue objects have types if they represent primitive arrays.
+ *
+ * @author Eric Lafortune
+ */
+public class PrimitiveTypedReferenceValueFactory
+extends BasicValueFactory
+{
+ static final ReferenceValue REFERENCE_VALUE_NULL = new TypedReferenceValue(null, null, false, true);
+
+ // Implementations for BasicValueFactory.
+
+
+ public ReferenceValue createReferenceValueNull()
+ {
+ return REFERENCE_VALUE_NULL;
+ }
+
+
+ public ReferenceValue createReferenceValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
+ {
+ return type == null ? REFERENCE_VALUE_NULL :
+ !ClassUtil.isInternalArrayType(type) ||
+ ClassUtil.isInternalClassType(type) ? REFERENCE_VALUE :
+ new TypedReferenceValue(type, referencedClass, mayBeExtension, mayBeNull);
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength)
+ {
+ return type == null ?
+ REFERENCE_VALUE_NULL :
+ new ArrayReferenceValue(ClassConstants.TYPE_ARRAY + type,
+ referencedClass,
+ false,
+ arrayLength);
+ }
+
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/ReferenceValue.java b/core/src/proguard/evaluation/value/ReferenceValue.java
similarity index 77%
rename from src/proguard/evaluation/value/ReferenceValue.java
rename to core/src/proguard/evaluation/value/ReferenceValue.java
index 2f7c4f7..4431dce 100644
--- a/src/proguard/evaluation/value/ReferenceValue.java
+++ b/core/src/proguard/evaluation/value/ReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,11 +29,13 @@
*/
public abstract class ReferenceValue extends Category1Value
{
+ // Basic unary methods.
+
/**
* Returns the type.
*/
public abstract String getType();
-;
+
/**
* Returns the class that is referenced by the type.
@@ -41,10 +43,16 @@ public abstract class ReferenceValue extends Category1Value
public abstract Clazz getReferencedClass();
- // Basic unary methods.
+ /**
+ * Returns whether the actual type of this ReferenceValue may be an
+ * extension of its type.
+ */
+ public abstract boolean mayBeExtension();
+
/**
- * Returns whether the type is null.
+ * Returns whether this ReferenceValue is null.
+ * @return NEVER, MAYBE, or ALWAYS.
*/
public abstract int isNull();
@@ -56,10 +64,9 @@ public abstract class ReferenceValue extends Category1Value
/**
- * Returns a generalization of this ReferenceValue that may be null,
- * depending on the flag.
+ * Returns this ReferenceValue, cast to the given type.
*/
- public abstract ReferenceValue generalizeMayBeNull(boolean mayBeNull);
+ public abstract ReferenceValue cast(String type, Clazz referencedClass, ValueFactory valueFactory, boolean alwaysCast);
/**
@@ -115,7 +122,10 @@ public DoubleValue doubleArrayLoad(IntegerValue indexValue, ValueFactory valueFa
* Returns the value of the array at the given index, assuming this type
* is a reference array.
*/
- public abstract ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory);
+ public ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ return valueFactory.createReferenceValue();
+ }
/**
@@ -168,6 +178,29 @@ public final int notEqual(ReferenceValue other)
}
+ // Similar binary methods, but this time with unknown arguments.
+
+ /**
+ * Returns the generalization of this ReferenceValue and the given other
+ * UnknownReferenceValue.
+ */
+ public ReferenceValue generalize(UnknownReferenceValue other)
+ {
+ return other;
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue is equal to the given other
+ * UnknownReferenceValue.
+ * @return NEVER, MAYBE, or ALWAYS.
+ */
+ public int equal(UnknownReferenceValue other)
+ {
+ return MAYBE;
+ }
+
+
// Similar binary methods, but this time with typed reference arguments.
/**
@@ -286,6 +319,29 @@ public int equal(DetailedArrayReferenceValue other)
}
+ // Similar binary methods, but this time with traced arguments.
+
+ /**
+ * Returns the generalization of this ReferenceValue and the given other
+ * TracedReferenceValue.
+ */
+ public ReferenceValue generalize(TracedReferenceValue other)
+ {
+ return generalize((ReferenceValue)other);
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue is equal to the given other
+ * TracedReferenceValue.
+ * @return NEVER, MAYBE, or ALWAYS.
+ */
+ public int equal(TracedReferenceValue other)
+ {
+ return equal((ReferenceValue)other);
+ }
+
+
// Implementations for Value.
public final ReferenceValue referenceValue()
@@ -302,4 +358,25 @@ public final int computationalType()
{
return TYPE_REFERENCE;
}
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass();
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode();
+ }
+
+
+ public String toString()
+ {
+ return "a";
+ }
}
diff --git a/src/proguard/evaluation/value/SpecificDoubleValue.java b/core/src/proguard/evaluation/value/SpecificDoubleValue.java
similarity index 96%
rename from src/proguard/evaluation/value/SpecificDoubleValue.java
rename to core/src/proguard/evaluation/value/SpecificDoubleValue.java
index 746cd43..0eda32f 100644
--- a/src/proguard/evaluation/value/SpecificDoubleValue.java
+++ b/core/src/proguard/evaluation/value/SpecificDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -108,7 +108,7 @@ public IntegerValue compare(DoubleValue other)
public DoubleValue generalize(SpecificDoubleValue other)
{
- return this.equals(other) ? this : ValueFactory.DOUBLE_VALUE;
+ return this.equals(other) ? this : BasicValueFactory.DOUBLE_VALUE;
}
public DoubleValue add(SpecificDoubleValue other)
@@ -153,7 +153,7 @@ public DoubleValue remainderOf(SpecificDoubleValue other)
public IntegerValue compare(SpecificDoubleValue other)
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
// Not handling NaN properly.
//return this.equals(other) ?
diff --git a/src/proguard/evaluation/value/SpecificFloatValue.java b/core/src/proguard/evaluation/value/SpecificFloatValue.java
similarity index 96%
rename from src/proguard/evaluation/value/SpecificFloatValue.java
rename to core/src/proguard/evaluation/value/SpecificFloatValue.java
index 6c6dd9c..76a7f99 100644
--- a/src/proguard/evaluation/value/SpecificFloatValue.java
+++ b/core/src/proguard/evaluation/value/SpecificFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -108,7 +108,7 @@ public IntegerValue compare(FloatValue other)
public FloatValue generalize(SpecificFloatValue other)
{
- return this.equals(other) ? this : ValueFactory.FLOAT_VALUE;
+ return this.equals(other) ? this : BasicValueFactory.FLOAT_VALUE;
}
public FloatValue add(SpecificFloatValue other)
@@ -153,7 +153,7 @@ public FloatValue remainderOf(SpecificFloatValue other)
public IntegerValue compare(SpecificFloatValue other)
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
// Not handling NaN properly.
//return this.equals(other) ?
diff --git a/src/proguard/evaluation/value/SpecificIntegerValue.java b/core/src/proguard/evaluation/value/SpecificIntegerValue.java
similarity index 98%
rename from src/proguard/evaluation/value/SpecificIntegerValue.java
rename to core/src/proguard/evaluation/value/SpecificIntegerValue.java
index b4befcf..c5c33ad 100644
--- a/src/proguard/evaluation/value/SpecificIntegerValue.java
+++ b/core/src/proguard/evaluation/value/SpecificIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -197,7 +197,7 @@ public int lessThanOrEqual(IntegerValue other)
public IntegerValue generalize(SpecificIntegerValue other)
{
- return this.equals(other) ? this : ValueFactory.INTEGER_VALUE;
+ return this.equals(other) ? this : BasicValueFactory.INTEGER_VALUE;
}
public IntegerValue add(SpecificIntegerValue other)
diff --git a/src/proguard/evaluation/value/SpecificLongValue.java b/core/src/proguard/evaluation/value/SpecificLongValue.java
similarity index 98%
rename from src/proguard/evaluation/value/SpecificLongValue.java
rename to core/src/proguard/evaluation/value/SpecificLongValue.java
index c63ce03..0e0420a 100644
--- a/src/proguard/evaluation/value/SpecificLongValue.java
+++ b/core/src/proguard/evaluation/value/SpecificLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -142,7 +142,7 @@ public IntegerValue compare(LongValue other)
public LongValue generalize(SpecificLongValue other)
{
- return this.equals(other) ? this : ValueFactory.LONG_VALUE;
+ return this.equals(other) ? this : BasicValueFactory.LONG_VALUE;
}
public LongValue add(SpecificLongValue other)
diff --git a/src/proguard/evaluation/value/TopValue.java b/core/src/proguard/evaluation/value/TopValue.java
similarity index 97%
rename from src/proguard/evaluation/value/TopValue.java
rename to core/src/proguard/evaluation/value/TopValue.java
index eb3a7ea..35d7989 100644
--- a/src/proguard/evaluation/value/TopValue.java
+++ b/core/src/proguard/evaluation/value/TopValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/evaluation/value/TracedReferenceValue.java b/core/src/proguard/evaluation/value/TracedReferenceValue.java
new file mode 100644
index 0000000..f5f9c24
--- /dev/null
+++ b/core/src/proguard/evaluation/value/TracedReferenceValue.java
@@ -0,0 +1,335 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.Clazz;
+import proguard.optimize.evaluation.ReferenceTracingValueFactory;
+
+/**
+ * This ReferenceValue represents a reference value that is tagged with a trace
+ * value.
+ *
+ * @author Eric Lafortune
+ */
+public class TracedReferenceValue extends ReferenceValue
+{
+ private final ReferenceValue referenceValue;
+ private final Value traceValue;
+
+
+ /**
+ * Creates a new reference value with the given ID.
+ */
+ public TracedReferenceValue(ReferenceValue referenceValue,
+ Value traceValue)
+ {
+ this.referenceValue = referenceValue;
+ this.traceValue = traceValue;
+ }
+
+
+ /**
+ * Returns the reference value.
+ */
+ public ReferenceValue getReferenceValue()
+ {
+ return referenceValue;
+ }
+
+
+ /**
+ * Returns the trace value.
+ */
+ public Value getTraceValue()
+ {
+ return traceValue;
+ }
+
+
+ // Implementations for ReferenceValue.
+
+ public String getType()
+ {
+ return referenceValue.getType();
+ }
+
+
+ public Clazz getReferencedClass()
+ {
+ return referenceValue.getReferencedClass();
+ }
+
+
+ public boolean mayBeExtension()
+ {
+ return referenceValue.mayBeExtension();
+ }
+
+
+ public int isNull()
+ {
+ return referenceValue.isNull();
+ }
+
+
+ public int instanceOf(String otherType, Clazz otherReferencedClass)
+ {
+ return referenceValue.instanceOf(otherType, otherReferencedClass);
+ }
+
+
+ public ReferenceValue cast(String type, Clazz referencedClass, ValueFactory valueFactory, boolean alwaysCast)
+ {
+ // We're letting the value factory do the cast (either preserving the
+ // trace value or setting a new one).
+ return ((ReferenceTracingValueFactory)valueFactory).cast(this,
+ type,
+ referencedClass,
+ alwaysCast);
+ }
+
+
+ public IntegerValue arrayLength(ValueFactory valueFactory)
+ {
+ return referenceValue.arrayLength(valueFactory);
+ }
+
+
+ public IntegerValue integerArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ return referenceValue.integerArrayLoad(indexValue, valueFactory);
+ }
+
+
+ public LongValue longArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ return referenceValue.longArrayLoad(indexValue, valueFactory);
+ }
+
+
+ public FloatValue floatArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ return referenceValue.floatArrayLoad(indexValue, valueFactory);
+ }
+
+
+ public DoubleValue doubleArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ return referenceValue.doubleArrayLoad(indexValue, valueFactory);
+ }
+
+
+ public ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
+ {
+ ReferenceValue value =
+ referenceValue.referenceArrayLoad(indexValue, valueFactory);
+
+ // We're keeping the existing trace value, if any, or attaching a new
+ // one otherwise.
+ return value instanceof TracedReferenceValue ?
+ value :
+ ((ReferenceTracingValueFactory)valueFactory).trace(value);
+ }
+
+
+ public void arrayStore(IntegerValue indexValue, Value value)
+ {
+ referenceValue.arrayStore(indexValue, value);
+ }
+
+
+ // Implementations of binary methods of ReferenceValue.
+
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public int equal(ReferenceValue other)
+ {
+ return other.equal(this);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // UnknownReferenceValue arguments.
+
+ public ReferenceValue generalize(UnknownReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+ public int equal(UnknownReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // TypedReferenceValue arguments.
+
+ public ReferenceValue generalize(TypedReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+ public int equal(TypedReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // IdentifiedReferenceValue arguments.
+
+ public ReferenceValue generalize(IdentifiedReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+
+ public int equal(IdentifiedReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // ArrayReferenceValue arguments.
+
+ public ReferenceValue generalize(ArrayReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+
+ public int equal(ArrayReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // IdentifiedArrayReferenceValue arguments.
+
+ public ReferenceValue generalize(IdentifiedArrayReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+
+ public int equal(IdentifiedArrayReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // DetailedArrayReferenceValue arguments.
+
+ public ReferenceValue generalize(DetailedArrayReferenceValue other)
+ {
+ return new TracedReferenceValue(referenceValue.generalize(other),
+ traceValue);
+ }
+
+
+ public int equal(DetailedArrayReferenceValue other)
+ {
+ return referenceValue.equal(other);
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // TracedReferenceValue arguments.
+
+ public ReferenceValue generalize(TracedReferenceValue other)
+ {
+ if (this.equals(other))
+ {
+ return this;
+ }
+
+ return new TracedReferenceValue(this.referenceValue.generalize(other.referenceValue),
+ this.traceValue .generalize(other.traceValue));
+ }
+
+ public int equal(TracedReferenceValue other)
+ {
+ return this.referenceValue.equal(other.referenceValue);
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return referenceValue.isSpecific();
+ }
+
+ public boolean isParticular()
+ {
+ return referenceValue.isParticular();
+ }
+
+ public String internalType()
+ {
+ return referenceValue.internalType();
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this == object)
+ {
+ return true;
+ }
+
+ if (!super.equals(object))
+ {
+ return false;
+ }
+
+ TracedReferenceValue other = (TracedReferenceValue)object;
+ return this.referenceValue.equals(other.referenceValue) &&
+ this.traceValue .equals(other.traceValue);
+ }
+
+
+ public int hashCode()
+ {
+ return referenceValue.hashCode() ^
+ traceValue.hashCode();
+ }
+
+
+ public String toString()
+ {
+ return traceValue.toString() + referenceValue.toString();
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/evaluation/value/TracingValue.java b/core/src/proguard/evaluation/value/TracingValue.java
new file mode 100644
index 0000000..bb4bdc0
--- /dev/null
+++ b/core/src/proguard/evaluation/value/TracingValue.java
@@ -0,0 +1,165 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+/**
+ * This class represents a value that has been tagged with a sticky trace
+ * value.
+ *
+ * @author Eric Lafortune
+ */
+public class TracingValue extends Value
+{
+ private Value traceValue;
+ private Value value;
+
+
+ /**
+ * Creates a new TracingValue with the given trace value and value.
+ */
+ public TracingValue(Value traceValue, Value value)
+ {
+
+ this.traceValue = traceValue;
+ this.value = value;
+ }
+
+
+ /**
+ * Returns the generalization of this TracingValue and the given other
+ * TracingValue.
+ */
+ public final TracingValue generalize(TracingValue other)
+ {
+ return this.equals(other) ? this :
+ new TracingValue(this.traceValue.generalize(other.traceValue),
+ this.value .generalize(other.value));
+ }
+
+
+ // Implementations for Value.
+
+ public Category1Value category1Value()
+ {
+ return value.category1Value();
+ }
+
+ public Category2Value category2Value()
+ {
+ return value.category2Value();
+ }
+
+ public IntegerValue integerValue()
+ {
+ return value.integerValue();
+ }
+
+ public LongValue longValue()
+ {
+ return value.longValue();
+ }
+
+ public FloatValue floatValue()
+ {
+ return value.floatValue();
+ }
+
+ public DoubleValue doubleValue()
+ {
+ return value.doubleValue();
+ }
+
+ public ReferenceValue referenceValue()
+ {
+ return value.referenceValue();
+ }
+
+ public final InstructionOffsetValue instructionOffsetValue()
+ {
+ return value.instructionOffsetValue();
+ }
+
+ public boolean isSpecific()
+ {
+ return value.isSpecific();
+ }
+
+ public boolean isParticular()
+ {
+ return value.isParticular();
+ }
+
+ public final Value generalize(Value other)
+ {
+ return
+ other instanceof TracingValue ? generalize((TracingValue)other) :
+ value.equals(other) ? this :
+ new TracingValue(traceValue,
+ value.generalize(other));
+ }
+
+ public boolean isCategory2()
+ {
+ return value.isCategory2();
+ }
+
+ public final int computationalType()
+ {
+ return value.computationalType();
+ }
+
+ public final String internalType()
+ {
+ return value.internalType();
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (object == null ||
+ this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ TracingValue other = (TracingValue)object;
+ return
+ this.traceValue.equals(other.traceValue) &&
+ this.value .equals(other.value);
+ }
+
+
+ public int hashCode()
+ {
+ return
+ this.getClass().hashCode() ^
+ traceValue.hashCode() ^
+ value .hashCode();
+ }
+
+
+ public String toString()
+ {
+ return 'P' + traceValue.toString() + value.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/TypedReferenceValue.java b/core/src/proguard/evaluation/value/TypedReferenceValue.java
similarity index 60%
rename from src/proguard/evaluation/value/TypedReferenceValue.java
rename to core/src/proguard/evaluation/value/TypedReferenceValue.java
index c899701..62e1603 100644
--- a/src/proguard/evaluation/value/TypedReferenceValue.java
+++ b/core/src/proguard/evaluation/value/TypedReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,11 +36,14 @@
*/
public class TypedReferenceValue extends ReferenceValue
{
+ private static final boolean ALLOW_INCOMPLETE_CLASS_HIERARCHY = System.getProperty("allow.incomplete.class.hierarchy") != null;
+
private static final boolean DEBUG = false;
protected final String type;
protected final Clazz referencedClass;
+ protected final boolean mayBeExtension;
protected final boolean mayBeNull;
@@ -49,10 +52,12 @@ public class TypedReferenceValue extends ReferenceValue
*/
public TypedReferenceValue(String type,
Clazz referencedClass,
+ boolean mayBeExtension,
boolean mayBeNull)
{
this.type = type == null ? null : type.intern();
this.referencedClass = referencedClass;
+ this.mayBeExtension = mayBeExtension;
this.mayBeNull = mayBeNull;
}
@@ -73,6 +78,11 @@ public Clazz getReferencedClass()
// Implementations of unary methods of ReferenceValue.
+ public boolean mayBeExtension()
+ {
+ return mayBeExtension;
+ }
+
public int isNull()
{
return type == null ? ALWAYS :
@@ -140,24 +150,15 @@ public int instanceOf(String otherType, Clazz otherReferencedClass)
return NEVER;
}
- // If this type may be null, it might not be an instance of any class.
- if (mayBeNull)
- {
- return MAYBE;
- }
-
// If this type is equal to the other type, or if the other type is
- // java.lang.Object, this type is always an instance.
- if (thisType.equals(otherType) ||
- ClassConstants.NAME_JAVA_LANG_OBJECT.equals(otherType))
- {
- return ALWAYS;
- }
-
- // If this type is an array type, it's ok.
- if (thisDimensionCount > otherDimensionCount)
+ // java.lang.Object, or if this type is an array type, then this type
+ // is always an instance (unless it may be null).
+ if (thisType.equals(otherType) ||
+ ClassConstants.NAME_JAVA_LANG_OBJECT.equals(otherType) ||
+ thisDimensionCount > otherDimensionCount)
{
- return ALWAYS;
+ return mayBeNull ? MAYBE :
+ ALWAYS;
}
// If the other type is an array type, it might be ok.
@@ -166,12 +167,34 @@ public int instanceOf(String otherType, Clazz otherReferencedClass)
return MAYBE;
}
- // If the value extends the type, we're sure.
- return referencedClass != null &&
- otherReferencedClass != null &&
- referencedClass.extendsOrImplements(otherReferencedClass) ?
- ALWAYS :
- MAYBE;
+ // If the value extends the type, we're sure (unless it may be null).
+ // Otherwise, if the value type is final, it can never be an instance.
+ // Also, if the types are not interfaces and not in the same hierarchy,
+ // the value can never be an instance.
+ return referencedClass == null ||
+ otherReferencedClass == null ? MAYBE :
+ referencedClass.extendsOrImplements(otherReferencedClass) ? mayBeNull ? MAYBE : ALWAYS :
+ (referencedClass.getAccessFlags() & ClassConstants.ACC_FINAL) != 0 ? NEVER :
+ (referencedClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 &&
+ (otherReferencedClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 &&
+ !otherReferencedClass.extendsOrImplements(referencedClass) ? NEVER :
+ MAYBE;
+ }
+
+
+ public ReferenceValue cast(String type, Clazz referencedClass, ValueFactory valueFactory, boolean alwaysCast)
+ {
+ // Just return this value if it's the same type.
+ // Also return this value if it is null or more specific.
+ return (this.type != null &&
+ this.type.equals(type)) ||
+ (!alwaysCast &&
+ (this.type == null ||
+ instanceOf(this.type, referencedClass) == ALWAYS)) ? this :
+ valueFactory.createReferenceValue(type,
+ referencedClass,
+ true,
+ mayBeNull);
}
@@ -179,17 +202,18 @@ public ReferenceValue generalizeMayBeNull(boolean mayBeNull)
{
return this.mayBeNull == mayBeNull ?
this :
- new TypedReferenceValue(type, referencedClass, true);
+ new TypedReferenceValue(type, referencedClass, mayBeExtension, true);
}
public ReferenceValue referenceArrayLoad(IntegerValue indexValue, ValueFactory valueFactory)
{
return
- type == null ? ValueFactory.REFERENCE_VALUE_NULL :
- !ClassUtil.isInternalArrayType(type) ? ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
+ type == null ? TypedReferenceValueFactory.REFERENCE_VALUE_NULL :
+ !ClassUtil.isInternalArrayType(type) ? TypedReferenceValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
valueFactory.createValue(type.substring(1),
referencedClass,
+ true,
true).referenceValue();
}
@@ -208,6 +232,21 @@ public int equal(ReferenceValue other)
}
+// // Implementations of binary ReferenceValue methods with
+// // UnknownReferenceValue arguments.
+//
+// public ReferenceValue generalize(UnknownReferenceValue other)
+// {
+// return other;
+// }
+//
+//
+// public int equal(UnknownReferenceValue other)
+// {
+// return MAYBE;
+// }
+
+
// Implementations of binary ReferenceValue methods with TypedReferenceValue
// arguments.
@@ -222,10 +261,10 @@ public ReferenceValue generalize(TypedReferenceValue other)
String thisType = this.type;
String otherType = other.type;
- // If both types are nul, the generalization is null too.
+ // If both types are null, the generalization is null too.
if (thisType == null && otherType == null)
{
- return ValueFactory.REFERENCE_VALUE_NULL;
+ return TypedReferenceValueFactory.REFERENCE_VALUE_NULL;
}
// If this type is null, the generalization is the other type, maybe null.
@@ -240,12 +279,14 @@ public ReferenceValue generalize(TypedReferenceValue other)
return this.generalizeMayBeNull(true);
}
- boolean mayBeNull = this.mayBeNull || other.mayBeNull;
+ boolean mayBeExtension = this.mayBeExtension || other.mayBeExtension;
+ boolean mayBeNull = this.mayBeNull || other.mayBeNull;
- // If the two types are equal, the generalization remains the same, maybe null.
+ // If the two types are equal, the generalization remains the same,
+ // maybe an extension, maybe null.
if (thisType.equals(otherType))
{
- return typedReferenceValue(this, mayBeNull);
+ return typedReferenceValue(this, mayBeExtension, mayBeNull);
}
// Start taking into account the type dimensions.
@@ -259,50 +300,58 @@ public ReferenceValue generalize(TypedReferenceValue other)
Clazz thisReferencedClass = this.referencedClass;
Clazz otherReferencedClass = other.referencedClass;
- // Is one class simply an extension of the other one?
- // We're checking the class name instead of the referenced class,
- // in case the referenced class is not set, e.g. for a caught
- // java.lang.Throwable.
- if (thisReferencedClass != null &&
- thisReferencedClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(otherType)))
- {
- return typedReferenceValue(other, mayBeNull);
- }
-
- if (otherReferencedClass != null &&
- otherReferencedClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(thisType)))
- {
- return typedReferenceValue(this, mayBeNull);
- }
-
- // Otherwise, we really need both referenced classes,
- // so we can investigate their hierarchies.
if (thisReferencedClass != null &&
otherReferencedClass != null)
{
- // Do the classes have a non-trivial common superclass?
- Clazz commonClass = findCommonClass(thisReferencedClass,
- otherReferencedClass,
- false);
+ // Is one class simply an extension of the other one?
+ if (thisReferencedClass.extendsOrImplements(otherReferencedClass))
+ {
+ return typedReferenceValue(other, true, mayBeNull);
+ }
+
+ if (otherReferencedClass.extendsOrImplements(thisReferencedClass))
+ {
+ return typedReferenceValue(this, true, mayBeNull);
+ }
- if (commonClass.getName().equals(ClassConstants.NAME_JAVA_LANG_OBJECT))
+ try
{
- // Otherwise, do the classes have a common interface?
- Clazz commonInterface = findCommonClass(thisReferencedClass,
- otherReferencedClass,
- true);
- if (commonInterface != null)
+ // Do the classes have a non-trivial common superclass?
+ Clazz commonClass = findCommonClass(thisReferencedClass,
+ otherReferencedClass,
+ false);
+
+ if (commonClass.getName().equals(ClassConstants.NAME_JAVA_LANG_OBJECT))
{
- commonClass = commonInterface;
+ // Otherwise, do the classes have a common interface?
+ Clazz commonInterface = findCommonClass(thisReferencedClass,
+ otherReferencedClass,
+ true);
+ if (commonInterface != null)
+ {
+ commonClass = commonInterface;
+ }
}
+
+ return new TypedReferenceValue(commonDimensionCount == 0 ?
+ commonClass.getName() :
+ ClassUtil.internalArrayTypeFromClassName(commonClass.getName(),
+ commonDimensionCount),
+ commonClass,
+ mayBeExtension,
+ mayBeNull);
}
+ catch (IllegalArgumentException e)
+ {
+ // The class hierarchy seems to be incomplete.
+ if (ALLOW_INCOMPLETE_CLASS_HIERARCHY)
+ {
+ // We'll return an unknown reference value.
+ return BasicValueFactory.REFERENCE_VALUE;
+ }
- return new TypedReferenceValue(commonDimensionCount == 0 ?
- commonClass.getName() :
- ClassUtil.internalArrayTypeFromClassName(commonClass.getName(),
- commonDimensionCount),
- commonClass,
- mayBeNull);
+ throw e;
+ }
}
}
else if (thisDimensionCount > otherDimensionCount)
@@ -310,7 +359,7 @@ else if (thisDimensionCount > otherDimensionCount)
// See if the other type is an interface type of arrays.
if (ClassUtil.isInternalArrayInterfaceName(ClassUtil.internalClassNameFromClassType(otherType)))
{
- return typedReferenceValue(other, mayBeNull);
+ return typedReferenceValue(other, true, mayBeNull);
}
}
else if (thisDimensionCount < otherDimensionCount)
@@ -318,7 +367,7 @@ else if (thisDimensionCount < otherDimensionCount)
// See if this type is an interface type of arrays.
if (ClassUtil.isInternalArrayInterfaceName(ClassUtil.internalClassNameFromClassType(thisType)))
{
- return typedReferenceValue(this, mayBeNull);
+ return typedReferenceValue(this, true, mayBeNull);
}
}
@@ -336,10 +385,11 @@ else if (thisDimensionCount < otherDimensionCount)
commonDimensionCount != 0 ?
new TypedReferenceValue(ClassUtil.internalArrayTypeFromClassName(ClassConstants.NAME_JAVA_LANG_OBJECT, commonDimensionCount),
null,
+ true,
mayBeNull) :
mayBeNull ?
- ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
- ValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL;
+ TypedReferenceValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
+ TypedReferenceValueFactory.REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL;
}
@@ -443,6 +493,33 @@ else if (class2.getSuperName() != null)
}
}
+ if (commonClass == null)
+ {
+ // No common superclass could be found. This usually happens
+ // when classes are missing in the classpool due to incomplete
+ // configurations.
+
+ // In case one of the two classes is java/lang/Object itself,
+ // or is a final class that extends java/lang/Object, we can
+ // safely assume that java/lang/Object must be the common
+ // superclass of both.
+
+ for (Clazz clazz : Arrays.asList(class1, class2))
+ {
+ if (ClassConstants.NAME_JAVA_LANG_OBJECT.equals(clazz.getName()))
+ {
+ commonClass = clazz;
+ break;
+ }
+ else if ((clazz.getAccessFlags() & ClassConstants.ACC_FINAL) != 0 &&
+ ClassConstants.NAME_JAVA_LANG_OBJECT.equals(clazz.getSuperName()))
+ {
+ commonClass = clazz.getSuperClass();
+ break;
+ }
+ }
+ }
+
if (commonClass == null)
{
throw new IllegalArgumentException("Can't find common super class of ["+
@@ -464,12 +541,15 @@ else if (class2.getSuperName() != null)
* that it is a TypedReferenceValue, not a subclass.
*/
private static ReferenceValue typedReferenceValue(TypedReferenceValue referenceValue,
+ boolean mayBeExtension,
boolean mayBeNull)
{
- return referenceValue.getClass() == TypedReferenceValue.class ?
+ return referenceValue.getClass() == TypedReferenceValue.class &&
+ referenceValue.mayBeExtension == mayBeExtension ?
referenceValue.generalizeMayBeNull(mayBeNull) :
new TypedReferenceValue(referenceValue.type,
referenceValue.referencedClass,
+ mayBeExtension,
mayBeNull);
}
@@ -499,68 +579,94 @@ private int superClassCount(Clazz subClass, Set classes)
public int equal(TypedReferenceValue other)
{
- return this.type == null && other.type == null ? ALWAYS : MAYBE;
- }
-
-
- // Implementations of binary ReferenceValue methods with
- // IdentifiedReferenceValue arguments.
-
- public ReferenceValue generalize(IdentifiedReferenceValue other)
- {
- return generalize((TypedReferenceValue)other);
- }
-
-
- public int equal(IdentifiedReferenceValue other)
- {
- return equal((TypedReferenceValue)other);
- }
-
-
- // Implementations of binary ReferenceValue methods with
- // ArrayReferenceValue arguments.
-
- public ReferenceValue generalize(ArrayReferenceValue other)
- {
- return generalize((TypedReferenceValue)other);
- }
-
-
- public int equal(ArrayReferenceValue other)
- {
- return equal((TypedReferenceValue)other);
- }
-
-
- // Implementations of binary ReferenceValue methods with
- // IdentifiedArrayReferenceValue arguments.
-
- public ReferenceValue generalize(IdentifiedArrayReferenceValue other)
- {
- return generalize((ArrayReferenceValue)other);
- }
-
-
- public int equal(IdentifiedArrayReferenceValue other)
- {
- return equal((ArrayReferenceValue)other);
- }
-
-
- // Implementations of binary ReferenceValue methods with
- // DetailedArrayReferenceValue arguments.
-
- public ReferenceValue generalize(DetailedArrayReferenceValue other)
- {
- return generalize((IdentifiedArrayReferenceValue)other);
+ return
+ this.type == null ?
+ other.type == null ? ALWAYS :
+ other.mayBeNull ? MAYBE :
+ NEVER :
+ other.type == null ?
+ this.mayBeNull ? MAYBE :
+ NEVER :
+ this.mayBeExtension ||
+ other.mayBeExtension ||
+ this.type.equals(other.type) ? MAYBE :
+ NEVER;
}
- public int equal(DetailedArrayReferenceValue other)
- {
- return equal((IdentifiedArrayReferenceValue)other);
- }
+// // Implementations of binary ReferenceValue methods with
+// // IdentifiedReferenceValue arguments.
+//
+// public ReferenceValue generalize(IdentifiedReferenceValue other)
+// {
+// return generalize((TypedReferenceValue)other);
+// }
+//
+//
+// public int equal(IdentifiedReferenceValue other)
+// {
+// return equal((TypedReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // ArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(ArrayReferenceValue other)
+// {
+// return generalize((TypedReferenceValue)other);
+// }
+//
+//
+// public int equal(ArrayReferenceValue other)
+// {
+// return equal((TypedReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // IdentifiedArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(IdentifiedArrayReferenceValue other)
+// {
+// return generalize((ArrayReferenceValue)other);
+// }
+//
+//
+// public int equal(IdentifiedArrayReferenceValue other)
+// {
+// return equal((ArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // DetailedArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(DetailedArrayReferenceValue other)
+// {
+// return generalize((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// public int equal(DetailedArrayReferenceValue other)
+// {
+// return equal((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TracedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TracedReferenceValue other)
+// {
+// return other.generalize(this);
+// }
+//
+//
+// public int equal(TracedReferenceValue other)
+// {
+// return other.equal(this);
+// }
// Implementations for Value.
@@ -575,7 +681,7 @@ public final String internalType()
{
return
type == null ? ClassConstants.TYPE_JAVA_LANG_OBJECT :
- ClassUtil.isInternalArrayType(type) ? type :
+ ClassUtil.isInternalArrayType(type) ? type :
ClassConstants.TYPE_CLASS_START +
type +
ClassConstants.TYPE_CLASS_END;
@@ -591,15 +697,15 @@ public boolean equals(Object object)
return true;
}
- if (object == null ||
- this.getClass() != object.getClass())
+ if (!super.equals(object))
{
return false;
}
TypedReferenceValue other = (TypedReferenceValue)object;
return this.type == null ? other.type == null :
- (this.mayBeNull == other.mayBeNull &&
+ (this.mayBeExtension == other.mayBeExtension &&
+ this.mayBeNull == other.mayBeNull &&
this.type.equals(other.type));
}
@@ -607,14 +713,18 @@ public boolean equals(Object object)
public int hashCode()
{
return this.getClass().hashCode() ^
- (type == null ? 0 : type.hashCode() ^ (mayBeNull ? 0 : 1));
+ (type == null ? 0 : type.hashCode() ^
+ (mayBeExtension ? 0 : 1) ^
+ (mayBeNull ? 0 : 2));
}
public String toString()
{
- return type == null ?
- "null" :
- type + (referencedClass == null ? "?" : "") + (mayBeNull ? "" : "!");
+ return type == null ? "n" :
+ type +
+ (referencedClass == null ? "?" : "") +
+ (mayBeExtension ? "" : "=") +
+ (mayBeNull ? "" : "!");
}
}
diff --git a/core/src/proguard/evaluation/value/TypedReferenceValueFactory.java b/core/src/proguard/evaluation/value/TypedReferenceValueFactory.java
new file mode 100644
index 0000000..d631168
--- /dev/null
+++ b/core/src/proguard/evaluation/value/TypedReferenceValueFactory.java
@@ -0,0 +1,84 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.*;
+
+/**
+ * This class provides methods to create and reuse Value objects.
+ * Its ReferenceValue objects have types.
+ *
+ * @author Eric Lafortune
+ */
+public class TypedReferenceValueFactory
+extends BasicValueFactory
+{
+ static final ReferenceValue REFERENCE_VALUE_NULL = new TypedReferenceValue(null, null, false, true);
+ static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL = new TypedReferenceValue(ClassConstants.NAME_JAVA_LANG_OBJECT, null, true, true);
+ static final ReferenceValue REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL = new TypedReferenceValue(ClassConstants.NAME_JAVA_LANG_OBJECT, null, true, false);
+
+
+ // Implementations for BasicValueFactory.
+
+ public ReferenceValue createReferenceValueNull()
+ {
+ return REFERENCE_VALUE_NULL;
+ }
+
+
+ public ReferenceValue createReferenceValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
+ {
+ return type == null ? REFERENCE_VALUE_NULL :
+ !type.equals(ClassConstants.NAME_JAVA_LANG_OBJECT) ||
+ !mayBeExtension ? new TypedReferenceValue(type, referencedClass, mayBeExtension, mayBeNull) :
+ mayBeNull ? REFERENCE_VALUE_JAVA_LANG_OBJECT_MAYBE_NULL :
+ REFERENCE_VALUE_JAVA_LANG_OBJECT_NOT_NULL;
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength)
+ {
+ return createArrayReferenceValue(type,
+ referencedClass,
+ arrayLength,
+ createValue(type,
+ referencedClass,
+ true,
+ true));
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength,
+ Value elementValue)
+ {
+ return createReferenceValue(ClassConstants.TYPE_ARRAY + type,
+ referencedClass,
+ false,
+ false);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/UnknownDoubleValue.java b/core/src/proguard/evaluation/value/UnknownDoubleValue.java
similarity index 91%
rename from src/proguard/evaluation/value/UnknownDoubleValue.java
rename to core/src/proguard/evaluation/value/UnknownDoubleValue.java
index 7760bac..34807d1 100644
--- a/src/proguard/evaluation/value/UnknownDoubleValue.java
+++ b/core/src/proguard/evaluation/value/UnknownDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,17 +36,17 @@ public DoubleValue negate()
public IntegerValue convertToInteger()
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
public LongValue convertToLong()
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public FloatValue convertToFloat()
{
- return ValueFactory.FLOAT_VALUE;
+ return BasicValueFactory.FLOAT_VALUE;
}
@@ -99,7 +99,7 @@ public DoubleValue remainderOf(DoubleValue other)
public IntegerValue compare(DoubleValue other)
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
diff --git a/src/proguard/evaluation/value/UnknownFloatValue.java b/core/src/proguard/evaluation/value/UnknownFloatValue.java
similarity index 91%
rename from src/proguard/evaluation/value/UnknownFloatValue.java
rename to core/src/proguard/evaluation/value/UnknownFloatValue.java
index b343f89..0891b75 100644
--- a/src/proguard/evaluation/value/UnknownFloatValue.java
+++ b/core/src/proguard/evaluation/value/UnknownFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,17 +36,17 @@ public FloatValue negate()
public IntegerValue convertToInteger()
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
public LongValue convertToLong()
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public DoubleValue convertToDouble()
{
- return ValueFactory.DOUBLE_VALUE;
+ return BasicValueFactory.DOUBLE_VALUE;
}
@@ -99,7 +99,7 @@ public FloatValue remainderOf(FloatValue other)
public IntegerValue compare(FloatValue other)
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
diff --git a/src/proguard/evaluation/value/UnknownIntegerValue.java b/core/src/proguard/evaluation/value/UnknownIntegerValue.java
similarity index 92%
rename from src/proguard/evaluation/value/UnknownIntegerValue.java
rename to core/src/proguard/evaluation/value/UnknownIntegerValue.java
index 51a55a0..9a04834 100644
--- a/src/proguard/evaluation/value/UnknownIntegerValue.java
+++ b/core/src/proguard/evaluation/value/UnknownIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -51,17 +51,17 @@ public IntegerValue convertToShort()
public LongValue convertToLong()
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public FloatValue convertToFloat()
{
- return ValueFactory.FLOAT_VALUE;
+ return BasicValueFactory.FLOAT_VALUE;
}
public DoubleValue convertToDouble()
{
- return ValueFactory.DOUBLE_VALUE;
+ return BasicValueFactory.DOUBLE_VALUE;
}
@@ -150,17 +150,17 @@ public IntegerValue unsignedShiftRightOf(IntegerValue other)
public LongValue shiftLeftOf(LongValue other)
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public LongValue shiftRightOf(LongValue other)
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public LongValue unsignedShiftRightOf(LongValue other)
{
- return ValueFactory.LONG_VALUE;
+ return BasicValueFactory.LONG_VALUE;
}
public IntegerValue and(IntegerValue other)
diff --git a/src/proguard/evaluation/value/UnknownLongValue.java b/core/src/proguard/evaluation/value/UnknownLongValue.java
similarity index 92%
rename from src/proguard/evaluation/value/UnknownLongValue.java
rename to core/src/proguard/evaluation/value/UnknownLongValue.java
index f431eb6..3715aee 100644
--- a/src/proguard/evaluation/value/UnknownLongValue.java
+++ b/core/src/proguard/evaluation/value/UnknownLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -36,17 +36,17 @@ public LongValue negate()
public IntegerValue convertToInteger()
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
public FloatValue convertToFloat()
{
- return ValueFactory.FLOAT_VALUE;
+ return BasicValueFactory.FLOAT_VALUE;
}
public DoubleValue convertToDouble()
{
- return ValueFactory.DOUBLE_VALUE;
+ return BasicValueFactory.DOUBLE_VALUE;
}
@@ -134,7 +134,7 @@ public LongValue xor(LongValue other)
public IntegerValue compare(LongValue other)
{
- return ValueFactory.INTEGER_VALUE;
+ return BasicValueFactory.INTEGER_VALUE;
}
diff --git a/core/src/proguard/evaluation/value/UnknownReferenceValue.java b/core/src/proguard/evaluation/value/UnknownReferenceValue.java
new file mode 100644
index 0000000..02b4ee6
--- /dev/null
+++ b/core/src/proguard/evaluation/value/UnknownReferenceValue.java
@@ -0,0 +1,206 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.*;
+
+/**
+ * This class represents a partially evaluated reference value.
+ *
+ * @author Eric Lafortune
+ */
+public class UnknownReferenceValue extends ReferenceValue
+{
+ // Implementations of unary methods of ReferenceValue.
+
+ public String getType()
+ {
+ return ClassConstants.NAME_JAVA_LANG_OBJECT;
+ }
+
+ public Clazz getReferencedClass()
+ {
+ return null;
+ }
+
+
+ public boolean mayBeExtension()
+ {
+ return true;
+ }
+
+
+ public int isNull()
+ {
+ return MAYBE;
+ }
+
+ public int instanceOf(String otherType, Clazz otherReferencedClass)
+ {
+ return MAYBE;
+ }
+
+ public ReferenceValue cast(String type, Clazz referencedClass, ValueFactory valueFactory, boolean alwaysCast)
+ {
+ return valueFactory.createReferenceValue(type,
+ referencedClass,
+ true,
+ true);
+ }
+
+
+ // Implementations of binary methods of ReferenceValue.
+
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public int equal(ReferenceValue other)
+ {
+ return other.equal(this);
+ }
+
+
+// // Implementations of binary ReferenceValue methods with
+// // UnknownReferenceValue arguments.
+//
+// public ReferenceValue generalize(UnknownReferenceValue other)
+// {
+// return other;
+// }
+//
+//
+// public int equal(UnknownReferenceValue other)
+// {
+// return MAYBE;
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TypedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TypedReferenceValue other)
+// {
+// }
+//
+//
+// public int equal(TypedReferenceValue other)
+// {
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // IdentifiedReferenceValue arguments.
+//
+// public ReferenceValue generalize(IdentifiedReferenceValue other)
+// {
+// return generalize((TypedReferenceValue)other);
+// }
+//
+//
+// public int equal(IdentifiedReferenceValue other)
+// {
+// return equal((TypedReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // ArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(ArrayReferenceValue other)
+// {
+// return generalize((TypedReferenceValue)other);
+// }
+//
+//
+// public int equal(ArrayReferenceValue other)
+// {
+// return equal((TypedReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // IdentifiedArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(IdentifiedArrayReferenceValue other)
+// {
+// return generalize((ArrayReferenceValue)other);
+// }
+//
+//
+// public int equal(IdentifiedArrayReferenceValue other)
+// {
+// return equal((ArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // DetailedArrayReferenceValue arguments.
+//
+// public ReferenceValue generalize(DetailedArrayReferenceValue other)
+// {
+// return generalize((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// public int equal(DetailedArrayReferenceValue other)
+// {
+// return equal((IdentifiedArrayReferenceValue)other);
+// }
+//
+//
+// // Implementations of binary ReferenceValue methods with
+// // TracedReferenceValue arguments.
+//
+// public ReferenceValue generalize(TracedReferenceValue other)
+// {
+// return other.generalize(this);
+// }
+//
+//
+// public int equal(TracedReferenceValue other)
+// {
+// return other.equal(this);
+// }
+
+
+ // Implementations for Value.
+
+ public boolean isParticular()
+ {
+ return false;
+ }
+
+
+ public final String internalType()
+ {
+ return ClassConstants.TYPE_JAVA_LANG_OBJECT;
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return "a";
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/Value.java b/core/src/proguard/evaluation/value/Value.java
similarity index 98%
rename from src/proguard/evaluation/value/Value.java
rename to core/src/proguard/evaluation/value/Value.java
index 58f09a8..30ac648 100644
--- a/src/proguard/evaluation/value/Value.java
+++ b/core/src/proguard/evaluation/value/Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/evaluation/value/ValueFactory.java b/core/src/proguard/evaluation/value/ValueFactory.java
new file mode 100644
index 0000000..edadfeb
--- /dev/null
+++ b/core/src/proguard/evaluation/value/ValueFactory.java
@@ -0,0 +1,132 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.evaluation.value;
+
+import proguard.classfile.Clazz;
+
+/**
+ * This interface provides methods to create Value objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface ValueFactory
+{
+ /**
+ * Creates a new Value of the given type.
+ * The type must be a fully specified internal type for primitives, classes,
+ * or arrays.
+ */
+ public Value createValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull);
+
+
+ /**
+ * Creates a new IntegerValue with an undefined value.
+ */
+ public IntegerValue createIntegerValue();
+
+
+ /**
+ * Creates a new IntegerValue with a given particular value.
+ */
+ public IntegerValue createIntegerValue(int value);
+
+
+ /**
+ * Creates a new LongValue with an undefined value.
+ */
+ public LongValue createLongValue();
+
+
+ /**
+ * Creates a new LongValue with a given particular value.
+ */
+ public LongValue createLongValue(long value);
+
+
+ /**
+ * Creates a new FloatValue with an undefined value.
+ */
+ public FloatValue createFloatValue();
+
+
+ /**
+ * Creates a new FloatValue with a given particular value.
+ */
+ public FloatValue createFloatValue(float value);
+
+
+ /**
+ * Creates a new DoubleValue with an undefined value.
+ */
+ public DoubleValue createDoubleValue();
+
+
+ /**
+ * Creates a new DoubleValue with a given particular value.
+ */
+ public DoubleValue createDoubleValue(double value);
+
+
+ /**
+ * Creates a new ReferenceValue of an undefined type.
+ */
+ public ReferenceValue createReferenceValue();
+
+
+ /**
+ * Creates a new ReferenceValue that represents null.
+ */
+ public ReferenceValue createReferenceValueNull();
+
+
+ /**
+ * Creates a new ReferenceValue that represents the given type. The type
+ * must be an internal class name or an array type. If the type is
+ * null, the ReferenceValue represents null.
+ */
+ public ReferenceValue createReferenceValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull);
+
+
+ /**
+ * Creates a new ReferenceValue that represents a non-null array with
+ * elements of the given type, with the given length.
+ */
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength);
+
+
+ /**
+ * Creates a new ReferenceValue that represents a non-null array with
+ * elements of the given type, with the given length and initial element
+ * values.
+ */
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength,
+ Value elementValue);
+}
diff --git a/src/proguard/evaluation/value/package.html b/core/src/proguard/evaluation/value/package.html
similarity index 100%
rename from src/proguard/evaluation/value/package.html
rename to core/src/proguard/evaluation/value/package.html
diff --git a/src/proguard/io/CascadingDataEntryWriter.java b/core/src/proguard/io/CascadingDataEntryWriter.java
similarity index 78%
rename from src/proguard/io/CascadingDataEntryWriter.java
rename to core/src/proguard/io/CascadingDataEntryWriter.java
index bb1c851..bd01339 100644
--- a/src/proguard/io/CascadingDataEntryWriter.java
+++ b/core/src/proguard/io/CascadingDataEntryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -52,7 +52,6 @@ public CascadingDataEntryWriter(DataEntryWriter dataEntryWriter1,
// Implementations for DataEntryWriter.
-
public boolean createDirectory(DataEntry dataEntry) throws IOException
{
// Try to create a directory with the first data entry writer, or
@@ -62,24 +61,26 @@ public boolean createDirectory(DataEntry dataEntry) throws IOException
}
- public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
{
- return getOutputStream(dataEntry, null);
+ return dataEntryWriter1.sameOutputStream(dataEntry1, dataEntry2) ||
+ dataEntryWriter2.sameOutputStream(dataEntry1, dataEntry2);
}
- public OutputStream getOutputStream(DataEntry dataEntry,
- Finisher finisher) throws IOException
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
{
// Try to get an output stream from the first data entry writer.
OutputStream outputStream =
- dataEntryWriter1.getOutputStream(dataEntry, finisher);
+ dataEntryWriter1.createOutputStream(dataEntry);
// Return it, if it's not null. Otherwise try to get an output stream
// from the second data entry writer.
return outputStream != null ?
outputStream :
- dataEntryWriter2.getOutputStream(dataEntry, finisher);
+ dataEntryWriter2.createOutputStream(dataEntry);
}
@@ -91,4 +92,12 @@ public void close() throws IOException
dataEntryWriter1 = null;
dataEntryWriter2 = null;
}
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "CascadingDataEntryWriter");
+ dataEntryWriter1.println(pw, prefix + " ");
+ dataEntryWriter2.println(pw, prefix + " ");
+ }
}
diff --git a/core/src/proguard/io/ClassDataEntryWriter.java b/core/src/proguard/io/ClassDataEntryWriter.java
new file mode 100644
index 0000000..df76f41
--- /dev/null
+++ b/core/src/proguard/io/ClassDataEntryWriter.java
@@ -0,0 +1,135 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.classfile.*;
+import proguard.classfile.io.ProgramClassWriter;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter finds received class entries in the given class pool
+ * and writes them out to the given data entry writer. For resource entries,
+ * it returns valid output streams. For class entries, it returns output
+ * streams that must not be used.
+ *
+ * @see IdleRewriter
+ * @author Eric Lafortune
+ */
+public class ClassDataEntryWriter implements DataEntryWriter
+{
+ private final ClassPool classPool;
+ private final DataEntryWriter dataEntryWriter;
+
+
+ /**
+ * Creates a new ClassDataEntryWriter.
+ * @param classPool the class pool in which classes are found.
+ * @param dataEntryWriter the writer to which the class file is written.
+ */
+ public ClassDataEntryWriter(ClassPool classPool,
+ DataEntryWriter dataEntryWriter)
+ {
+ this.classPool = classPool;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createDirectory(dataEntry);
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(dataEntry1, dataEntry2);
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ String inputName = dataEntry.getName();
+
+ // Is it a class entry?
+ String name = dataEntry.getName();
+ if (name.endsWith(ClassConstants.CLASS_FILE_EXTENSION))
+ {
+ // Does it still have a corresponding class?
+ String className = inputName.substring(0, inputName.length() - ClassConstants.CLASS_FILE_EXTENSION.length());
+ Clazz clazz = classPool.getClass(className);
+ if (clazz != null)
+ {
+ // Rename the data entry if necessary.
+ String newClassName = clazz.getName();
+ if (!className.equals(newClassName))
+ {
+ dataEntry = new RenamedDataEntry(dataEntry, newClassName + ClassConstants.CLASS_FILE_EXTENSION);
+ }
+
+ // Get the output stream for this input entry.
+ OutputStream outputStream = dataEntryWriter.createOutputStream(dataEntry);
+ if (outputStream != null)
+ {
+ // Write the class to the output stream.
+ DataOutputStream classOutputStream = new DataOutputStream(outputStream);
+ try
+ {
+ clazz.accept(new ProgramClassWriter(classOutputStream));
+ }
+ catch (RuntimeException e)
+ {
+ throw (RuntimeException)new RuntimeException("Unexpected error while writing class ["+className+"] ("+e.getMessage()+")").initCause(e);
+ }
+ finally
+ {
+ classOutputStream.close();
+ }
+ }
+ }
+
+ // Return a dummy, non-null output stream (to work with cascading
+ // output writers).
+ return new FilterOutputStream(null);
+ }
+
+ // Delegate for resource entries.
+ return dataEntryWriter.createOutputStream(dataEntry);
+ }
+
+
+ public void close() throws IOException
+ {
+ // Close the delegate writer.
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "ClassDataEntryWriter");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/io/ClassFilter.java b/core/src/proguard/io/ClassFilter.java
similarity index 96%
rename from src/proguard/io/ClassFilter.java
rename to core/src/proguard/io/ClassFilter.java
index f5a78a3..99b78ea 100644
--- a/src/proguard/io/ClassFilter.java
+++ b/core/src/proguard/io/ClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/io/ClassMapDataEntryWriter.java b/core/src/proguard/io/ClassMapDataEntryWriter.java
new file mode 100644
index 0000000..7716026
--- /dev/null
+++ b/core/src/proguard/io/ClassMapDataEntryWriter.java
@@ -0,0 +1,164 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberVisitor;
+
+import java.io.*;
+import java.util.Iterator;
+
+
+/**
+ * This DataEntryWriter writes a class mapping to the given data entry, used
+ * for debugging of the configuration.
+ *
+ * Syntax of the mapping file (one line per class):
+ *
+ * originalClassName,newClassName,hasObfuscatedMethods,hasObfuscatedFields
+ *
+ * hasObfuscatedMethods and hasObfuscatedFields can either take the value
+ * 0 (false) or 1 (true).
+ *
+ * @author Johan Leys
+ */
+public class ClassMapDataEntryWriter
+extends SimplifiedVisitor
+implements DataEntryWriter,
+
+ // Implementation interfaces.
+ MemberVisitor
+{
+ private final ClassPool programClassPool;
+
+ private final DataEntryWriter dataEntryWriter;
+
+ private boolean obfuscatedMethods = false;
+ private boolean obfuscatedFields = false;
+
+
+ public ClassMapDataEntryWriter(ClassPool programClassPool,
+ DataEntryWriter dataEntryWriter )
+ {
+ this.programClassPool = programClassPool;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+
+
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createDirectory(dataEntry);
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1, DataEntry dataEntry2) throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(dataEntry1, dataEntry2);
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ OutputStream os = dataEntryWriter.createOutputStream(dataEntry);
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(os));
+ writeClassMap(writer, programClassPool);
+ writer.close();
+ return os;
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "ClassMapDataEntryWriter");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
+
+
+ // Private utility methods.
+
+ private void writeClassMap(PrintWriter writer, ClassPool classPool)
+ {
+ Iterator iterator = classPool.classNames();
+ while (iterator.hasNext())
+ {
+ String className = (String)iterator.next();
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(ClassUtil.externalClassName(className));
+ builder.append(",");
+
+ ProgramClass clazz = (ProgramClass)classPool.getClass(className);
+ builder.append(ClassUtil.externalClassName(clazz.getName()));
+ builder.append(",");
+
+ boolean hasRemovedMethods = (clazz.u2accessFlags & ClassConstants.ACC_REMOVED_METHODS) != 0;
+ builder.append(hasRemovedMethods || hasObfuscatedMethods(clazz) ? 1 : 0);
+ builder.append(",");
+
+ boolean hasRemovedFields = (clazz.u2accessFlags & ClassConstants.ACC_REMOVED_FIELDS) != 0;
+ builder.append(hasRemovedFields || hasObfuscatedFields(clazz) ? 1 : 0);
+ writer.println(builder.toString());
+ }
+ }
+
+
+ private boolean hasObfuscatedMethods(ProgramClass clazz)
+ {
+ obfuscatedMethods = false;
+ clazz.methodsAccept(this);
+ return obfuscatedMethods;
+ }
+
+
+ private boolean hasObfuscatedFields(ProgramClass clazz)
+ {
+ obfuscatedFields = false;
+ clazz.fieldsAccept(this);
+ return obfuscatedFields;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member) {}
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ obfuscatedMethods |= (programMethod.getAccessFlags() & ClassConstants.ACC_RENAMED) != 0;
+ }
+
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ obfuscatedFields |= (programField.getAccessFlags() & ClassConstants.ACC_RENAMED) != 0;
+ }
+}
diff --git a/core/src/proguard/io/ClassPathDataEntry.java b/core/src/proguard/io/ClassPathDataEntry.java
new file mode 100644
index 0000000..df1046f
--- /dev/null
+++ b/core/src/proguard/io/ClassPathDataEntry.java
@@ -0,0 +1,118 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import java.io.*;
+
+import static proguard.classfile.ClassConstants.CLASS_FILE_EXTENSION;
+import static proguard.classfile.util.ClassUtil.internalClassName;
+
+/**
+ * DataEntry implementation which loads an input stream from the classpath of
+ * the running VM.
+ *
+ * @author Johan Leys
+ */
+public class ClassPathDataEntry implements DataEntry
+{
+ private final String name;
+
+ private InputStream inputStream;
+
+
+ /**
+ * Creas an new ClassPathDataEntry for the given class.
+ *
+ * @param clazz the class for which to create a data entry.
+ */
+ public ClassPathDataEntry(Class clazz)
+ {
+ this(internalClassName(clazz.getName()) + CLASS_FILE_EXTENSION);
+ }
+
+
+ /**
+ * Creates a new ClassPathDataEntry for the entry with the given name.
+ *
+ * @param name the name of the class for which to create a data entry.
+ */
+ public ClassPathDataEntry(String name)
+ {
+ this.name = name;
+ }
+
+
+ // Implementations for DataEntry.
+
+ public String getName()
+ {
+ return name;
+ }
+
+
+ public String getOriginalName()
+ {
+ return name;
+ }
+
+
+ public long getSize()
+ {
+ return -1;
+ }
+
+
+ public boolean isDirectory()
+ {
+ return false;
+ }
+
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (inputStream == null)
+ {
+ inputStream = getClass().getClassLoader().getResourceAsStream(name);
+ }
+ return inputStream;
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ inputStream.close();
+ inputStream = null;
+ }
+
+
+ public DataEntry getParent()
+ {
+ return null;
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName();
+ }
+}
diff --git a/src/proguard/io/ClassReader.java b/core/src/proguard/io/ClassReader.java
similarity index 92%
rename from src/proguard/io/ClassReader.java
rename to core/src/proguard/io/ClassReader.java
index fbb900f..ac288a5 100644
--- a/src/proguard/io/ClassReader.java
+++ b/core/src/proguard/io/ClassReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -95,7 +95,9 @@ public void read(DataEntry dataEntry) throws IOException
String className = clazz.getName();
if (className != null)
{
- if (!dataEntry.getName().replace(File.pathSeparatorChar, ClassConstants.PACKAGE_SEPARATOR).equals(className+ClassConstants.CLASS_FILE_EXTENSION) &&
+ String dataEntryName = dataEntry.getName();
+ if (!dataEntryName.equals("module-info.class") &&
+ !dataEntryName.replace(File.pathSeparatorChar, ClassConstants.PACKAGE_SEPARATOR).equals(className + ClassConstants.CLASS_FILE_EXTENSION) &&
warningPrinter != null)
{
warningPrinter.print(className,
diff --git a/src/proguard/io/DataEntry.java b/core/src/proguard/io/DataEntry.java
similarity index 83%
rename from src/proguard/io/DataEntry.java
rename to core/src/proguard/io/DataEntry.java
index 7ce278a..09d1b98 100644
--- a/src/proguard/io/DataEntry.java
+++ b/core/src/proguard/io/DataEntry.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -35,6 +35,20 @@ public interface DataEntry
*/
public String getName();
+
+ /**
+ * Returns the original name of this data entry, i.e. the name of the
+ * data entry before any renaming or obfuscation.
+ */
+ public String getOriginalName();
+
+
+ /**
+ * Returns the size of this data entry, in bytes, or -1 if unknown.
+ */
+ public long getSize();
+
+
/**
* Returns whether the data entry represents a directory.
*/
diff --git a/src/proguard/io/DataEntryClassWriter.java b/core/src/proguard/io/DataEntryClassWriter.java
similarity index 87%
rename from src/proguard/io/DataEntryClassWriter.java
rename to core/src/proguard/io/DataEntryClassWriter.java
index 2a07871..36cf77a 100644
--- a/src/proguard/io/DataEntryClassWriter.java
+++ b/core/src/proguard/io/DataEntryClassWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -66,15 +66,19 @@ public void visitProgramClass(ProgramClass programClass)
try
{
// Get the output entry corresponding to this input entry.
- OutputStream outputStream = dataEntryWriter.getOutputStream(actualDataEntry);
+ OutputStream outputStream = dataEntryWriter.createOutputStream(actualDataEntry);
if (outputStream != null)
{
// Write the class to the output entry.
DataOutputStream classOutputStream = new DataOutputStream(outputStream);
-
- new ProgramClassWriter(classOutputStream).visitProgramClass(programClass);
-
- classOutputStream.flush();
+ try
+ {
+ new ProgramClassWriter(classOutputStream).visitProgramClass(programClass);
+ }
+ finally
+ {
+ classOutputStream.close();
+ }
}
}
catch (IOException e)
diff --git a/src/proguard/io/DataEntryCopier.java b/core/src/proguard/io/DataEntryCopier.java
similarity index 74%
rename from src/proguard/io/DataEntryCopier.java
rename to core/src/proguard/io/DataEntryCopier.java
index 3915960..7674b3d 100644
--- a/src/proguard/io/DataEntryCopier.java
+++ b/core/src/proguard/io/DataEntryCopier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,11 +20,11 @@
*/
package proguard.io;
+import proguard.classfile.ClassConstants;
import proguard.util.ExtensionMatcher;
import java.io.*;
-
/**
* This DataEntryReader writes the ZIP entries and files that it reads to a
* given DataEntryWriter.
@@ -39,7 +39,9 @@ public class DataEntryCopier implements DataEntryReader
private final byte[] buffer = new byte[BUFFER_SIZE];
-
+ /**
+ * Creates a new DataEntryCopier.
+ */
public DataEntryCopier(DataEntryWriter dataEntryWriter)
{
this.dataEntryWriter = dataEntryWriter;
@@ -59,20 +61,31 @@ public void read(DataEntry dataEntry) throws IOException
else
{
// Get the output entry corresponding to this input entry.
- OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry);
+ OutputStream outputStream = dataEntryWriter.createOutputStream(dataEntry);
if (outputStream != null)
{
- InputStream inputStream = dataEntry.getInputStream();
-
try
{
- // Copy the data from the input entry to the output entry.
- copyData(inputStream, outputStream);
+ InputStream inputStream = dataEntry.getInputStream();
+
+ try
+ {
+ // Copy the data from the input entry to the output entry.
+ copyData(inputStream, outputStream);
+
+ // Flush the output stream, just to be sure.
+ outputStream.flush();
+ }
+ finally
+ {
+ // Close the input stream.
+ dataEntry.closeInputStream();
+ }
}
finally
{
- // Close the data entries.
- dataEntry.closeInputStream();
+ // Close the output stream.
+ outputStream.close();
}
}
}
@@ -90,7 +103,10 @@ public void read(DataEntry dataEntry) throws IOException
/**
* Copies all data that it can read from the given input stream to the
- * given output stream.
+ * given output stream. The caller of this method will open and
+ * afterwards flush and close the input stream and the output stream.
+ * The implementation of this method needs to make sure that any wrapping
+ * output streams are flushed before returning.
*/
protected void copyData(InputStream inputStream,
OutputStream outputStream)
@@ -105,13 +121,11 @@ protected void copyData(InputStream inputStream,
}
outputStream.write(buffer, 0, count);
}
-
- outputStream.flush();
}
/**
- * A main method for testing file/jar/war/directory copying.
+ * A main method for testing file/archive/directory copying.
*/
public static void main(String[] args)
{
@@ -120,20 +134,22 @@ public static void main(String[] args)
String input = args[0];
String output = args[1];
- boolean outputIsApk = output.endsWith(".apk") ||
- output.endsWith(".ap_");
- boolean outputIsJar = output.endsWith(".jar");
- boolean outputIsAar = output.endsWith(".aar");
- boolean outputIsWar = output.endsWith(".war");
- boolean outputIsEar = output.endsWith(".ear");
- boolean outputIsZip = output.endsWith(".zip");
+ boolean outputIsApk = output.endsWith(".apk") ||
+ output.endsWith(".ap_");
+ boolean outputIsJar = output.endsWith(".jar");
+ boolean outputIsAar = output.endsWith(".aar");
+ boolean outputIsWar = output.endsWith(".war");
+ boolean outputIsEar = output.endsWith(".ear");
+ boolean outputIsJmod = output.endsWith(".jmod");
+ boolean outputIsZip = output.endsWith(".zip");
DataEntryWriter writer = new DirectoryWriter(new File(output),
- outputIsApk ||
- outputIsJar ||
- outputIsAar ||
- outputIsWar ||
- outputIsEar ||
+ outputIsApk ||
+ outputIsJar ||
+ outputIsAar ||
+ outputIsWar ||
+ outputIsEar ||
+ outputIsJmod ||
outputIsZip);
// Zip up any zips, if necessary.
@@ -153,20 +169,20 @@ public static void main(String[] args)
writer);
}
- // Zip up any ears, if necessary.
- DataEntryWriter earWriter = new JarWriter(writer);
- if (outputIsEar)
+ // Zip up any jmods, if necessary.
+ DataEntryWriter jmodWriter = new JarWriter(ClassConstants.JMOD_HEADER, writer);
+ if (outputIsJmod)
{
// Always zip.
- writer = earWriter;
+ writer = jmodWriter;
}
else
{
- // Only zip up ears.
+ // Only zip up jmods.
writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
new DataEntryNameFilter(
- new ExtensionMatcher(".ear"))),
- earWriter,
+ new ExtensionMatcher(".jmod"))),
+ jmodWriter,
writer);
}
@@ -189,7 +205,7 @@ public static void main(String[] args)
// Zip up any aars, if necessary.
DataEntryWriter aarWriter = new JarWriter(writer);
- if (outputIsAar)
+ if (outputIsWar)
{
// Always zip.
writer = aarWriter;
@@ -242,13 +258,14 @@ public static void main(String[] args)
// Create the copying DataEntryReader.
DataEntryReader reader = new DataEntryCopier(writer);
- boolean inputIsApk = input.endsWith(".apk") ||
- input.endsWith(".ap_");
- boolean inputIsJar = input.endsWith(".jar");
- boolean inputIsAar = input.endsWith(".aar");
- boolean inputIsWar = input.endsWith(".war");
- boolean inputIsEar = input.endsWith(".ear");
- boolean inputIsZip = input.endsWith(".zip");
+ boolean inputIsApk = input.endsWith(".apk") ||
+ input.endsWith(".ap_");
+ boolean inputIsJar = input.endsWith(".jar");
+ boolean inputIsAar = input.endsWith(".aar");
+ boolean inputIsWar = input.endsWith(".war");
+ boolean inputIsEar = input.endsWith(".ear");
+ boolean inputIsJmod = input.endsWith(".jmod");
+ boolean inputIsZip = input.endsWith(".zip");
// Unzip any apks, if necessary.
DataEntryReader apkReader = new JarReader(reader);
@@ -325,20 +342,36 @@ public static void main(String[] args)
earReader,
reader);
- // Unzip any zips, if necessary.
- DataEntryReader zipReader = new JarReader(reader);
- if (inputIsZip)
+ // Unzip any jmods, if necessary.
+ DataEntryReader jmodReader = new JarReader(reader, true);
+ if (inputIsJmod)
{
// Always unzip.
- reader = zipReader;
+ reader = jmodReader;
}
else
{
- // Only unzip zip entries.
+ // Only unzip jmod entries.
reader = new FilteredDataEntryReader(new DataEntryNameFilter(
- new ExtensionMatcher(".zip")),
- zipReader,
+ new ExtensionMatcher(".jmod")),
+ jmodReader,
reader);
+
+ // Unzip any zips, if necessary.
+ DataEntryReader zipReader = new JarReader(reader);
+ if (inputIsZip)
+ {
+ // Always unzip.
+ reader = zipReader;
+ }
+ else
+ {
+ // Only unzip zip entries.
+ reader = new FilteredDataEntryReader(new DataEntryNameFilter(
+ new ExtensionMatcher(".zip")),
+ zipReader,
+ reader);
+ }
}
}
}
diff --git a/src/proguard/io/DataEntryDirectoryFilter.java b/core/src/proguard/io/DataEntryDirectoryFilter.java
similarity index 95%
rename from src/proguard/io/DataEntryDirectoryFilter.java
rename to core/src/proguard/io/DataEntryDirectoryFilter.java
index beefc3b..62f9904 100644
--- a/src/proguard/io/DataEntryDirectoryFilter.java
+++ b/core/src/proguard/io/DataEntryDirectoryFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryFilter.java b/core/src/proguard/io/DataEntryFilter.java
similarity index 95%
rename from src/proguard/io/DataEntryFilter.java
rename to core/src/proguard/io/DataEntryFilter.java
index fe9f647..1bc5d7f 100644
--- a/src/proguard/io/DataEntryFilter.java
+++ b/core/src/proguard/io/DataEntryFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryNameFilter.java b/core/src/proguard/io/DataEntryNameFilter.java
similarity index 96%
rename from src/proguard/io/DataEntryNameFilter.java
rename to core/src/proguard/io/DataEntryNameFilter.java
index e7f65c0..9dd97f0 100644
--- a/src/proguard/io/DataEntryNameFilter.java
+++ b/core/src/proguard/io/DataEntryNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryParentFilter.java b/core/src/proguard/io/DataEntryParentFilter.java
similarity index 96%
rename from src/proguard/io/DataEntryParentFilter.java
rename to core/src/proguard/io/DataEntryParentFilter.java
index b01bc71..e2be6f9 100644
--- a/src/proguard/io/DataEntryParentFilter.java
+++ b/core/src/proguard/io/DataEntryParentFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryPump.java b/core/src/proguard/io/DataEntryPump.java
similarity index 96%
rename from src/proguard/io/DataEntryPump.java
rename to core/src/proguard/io/DataEntryPump.java
index b6cb532..e644857 100644
--- a/src/proguard/io/DataEntryPump.java
+++ b/core/src/proguard/io/DataEntryPump.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryReader.java b/core/src/proguard/io/DataEntryReader.java
similarity index 95%
rename from src/proguard/io/DataEntryReader.java
rename to core/src/proguard/io/DataEntryReader.java
index e41b6eb..5dd1701 100644
--- a/src/proguard/io/DataEntryReader.java
+++ b/core/src/proguard/io/DataEntryReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DataEntryRewriter.java b/core/src/proguard/io/DataEntryRewriter.java
similarity index 93%
rename from src/proguard/io/DataEntryRewriter.java
rename to core/src/proguard/io/DataEntryRewriter.java
index 827a932..f9117dd 100644
--- a/src/proguard/io/DataEntryRewriter.java
+++ b/core/src/proguard/io/DataEntryRewriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import java.io.*;
+import java.nio.charset.Charset;
/**
* This DataEntryReader writes the resource data entries that it reads to a
@@ -34,17 +35,20 @@
public class DataEntryRewriter extends DataEntryCopier
{
private final ClassPool classPool;
+ private final Charset charset;
/**
* Creates a new DataEntryRewriter.
*/
public DataEntryRewriter(ClassPool classPool,
+ Charset charset,
DataEntryWriter dataEntryWriter)
{
super(dataEntryWriter);
this.classPool = classPool;
+ this.charset = charset;
}
@@ -54,13 +58,12 @@ protected void copyData(InputStream inputStream,
OutputStream outputStream)
throws IOException
{
- Reader reader = new BufferedReader(new InputStreamReader(inputStream));
- Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
+ Reader reader = new BufferedReader(new InputStreamReader(inputStream, charset));
+ Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, charset));
copyData(reader, writer);
writer.flush();
- outputStream.flush();
}
@@ -127,7 +130,7 @@ private void writeUpdatedWord(Writer writer, String word)
word.replace('.', ClassConstants.PACKAGE_SEPARATOR) :
word;
- // Find the class corrsponding to the word.
+ // Find the class corresponding to the word.
Clazz clazz = classPool.getClass(className);
if (clazz != null)
{
diff --git a/src/proguard/io/DataEntryWriter.java b/core/src/proguard/io/DataEntryWriter.java
similarity index 57%
rename from src/proguard/io/DataEntryWriter.java
rename to core/src/proguard/io/DataEntryWriter.java
index 1fe2ea6..819a5d4 100644
--- a/src/proguard/io/DataEntryWriter.java
+++ b/core/src/proguard/io/DataEntryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 @@
import java.io.*;
-
/**
* This interface provides methods for writing data entries, such as ZIP entries
* or files. The implementation determines to which type of data entry the
@@ -41,33 +40,36 @@ public interface DataEntryWriter
/**
- * Returns an output stream for writing data. The caller must not close
- * the output stream; closing the output stream is the responsibility of
- * the implementation of this interface.
- * @param dataEntry the data entry for which the output stream is to be created.
- * @return the output stream. The stream may be null to indicate
- * that the data entry should not be written.
+ * Returns whether the two given data entries would result in the same
+ * output stream.
+ * @param dataEntry1 the first data entry.
+ * @param dataEntry2 the second data entry.
*/
- public OutputStream getOutputStream(DataEntry dataEntry) throws IOException;
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2) throws IOException;
/**
- * Returns an output stream for writing data. The caller must not close
- * the output stream; closing the output stream is the responsibility of
- * the implementation of this interface.
- * @param dataEntry the data entry for which the output stream is to be created.
- * @param finisher the optional finisher that will be called before this
- * class closes the output stream (at some later point in
- * time) that will be returned (now).
- * @return the output stream. The stream may be null to indicate
- * that the data entry should not be written.
+ * Creates a new output stream for writing data. The caller is responsible
+ * for closing the stream.
+ * @param dataEntry the data entry for which the output stream is to be
+ * created.
+ * @return the output stream. The stream may be null to
+ * indicate that the data entry should not be written.
*/
- public OutputStream getOutputStream(DataEntry dataEntry,
- Finisher finisher) throws IOException;
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException;
/**
* Finishes writing all data entries.
*/
public void close() throws IOException;
+
+
+ /**
+ * Prints out the structure of the data entry writer.
+ * @param pw the print stream to which the structure should be printed.
+ * @param prefix a prefix for every printed line.
+ */
+ public void println(PrintWriter pw, String prefix);
}
diff --git a/src/proguard/io/DirectoryFilter.java b/core/src/proguard/io/DirectoryFilter.java
similarity index 96%
rename from src/proguard/io/DirectoryFilter.java
rename to core/src/proguard/io/DirectoryFilter.java
index a973b5c..1cc5aea 100644
--- a/src/proguard/io/DirectoryFilter.java
+++ b/core/src/proguard/io/DirectoryFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/DirectoryPump.java b/core/src/proguard/io/DirectoryPump.java
similarity index 90%
rename from src/proguard/io/DirectoryPump.java
rename to core/src/proguard/io/DirectoryPump.java
index f191fab..cfab974 100644
--- a/src/proguard/io/DirectoryPump.java
+++ b/core/src/proguard/io/DirectoryPump.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@ public void pumpDataEntries(DataEntryReader dataEntryReader)
{
if (!directory.exists())
{
- throw new IOException("No such file or directory");
+ throw new IOException("No such file or directory: " + directory);
}
readFiles(directory, dataEntryReader);
@@ -78,7 +78,7 @@ private void readFiles(File file, DataEntryReader dataEntryReader)
}
catch (IOException e)
{
- throw (IOException)new IOException("Can't read ["+listedFile.getName()+"] ("+e.getMessage()+")").initCause(e);
+ throw new IOException("Can't read ["+listedFile.getName()+"] ("+e.getMessage()+")", e);
}
}
}
diff --git a/src/proguard/io/DirectoryWriter.java b/core/src/proguard/io/DirectoryWriter.java
similarity index 53%
rename from src/proguard/io/DirectoryWriter.java
rename to core/src/proguard/io/DirectoryWriter.java
index c4383ce..dfedcef 100644
--- a/src/proguard/io/DirectoryWriter.java
+++ b/core/src/proguard/io/DirectoryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,7 +24,6 @@
import java.io.*;
-
/**
* This DataEntryWriter writes data entries to individual files in a given
* directory.
@@ -36,10 +35,6 @@ public class DirectoryWriter implements DataEntryWriter
private final File baseFile;
private final boolean isFile;
- private File currentFile;
- private OutputStream currentOutputStream;
- private Finisher currentFinisher;
-
/**
* Creates a new DirectoryWriter.
@@ -57,13 +52,6 @@ public DirectoryWriter(File baseFile,
public boolean createDirectory(DataEntry dataEntry) throws IOException
{
- // Should we close the current file?
- if (!isFile &&
- currentFile != null)
- {
- closeEntry();
- }
-
File directory = getFile(dataEntry);
if (!directory.exists() &&
!directory.mkdirs())
@@ -75,54 +63,41 @@ public boolean createDirectory(DataEntry dataEntry) throws IOException
}
- public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
{
- return getOutputStream(dataEntry, null);
+ return getFile(dataEntry1).equals(getFile(dataEntry2));
}
- public OutputStream getOutputStream(DataEntry dataEntry,
- Finisher finisher) throws IOException
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
{
File file = getFile(dataEntry);
- // Should we close the current file?
- if (!isFile &&
- currentFile != null &&
- !currentFile.equals(file))
+ // Make sure the parent directories exist.
+ File parentDirectory = file.getParentFile();
+ if (parentDirectory != null &&
+ !parentDirectory.exists() &&
+ !parentDirectory.mkdirs())
{
- closeEntry();
+ throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]");
}
- // Do we need a new stream?
- if (currentOutputStream == null)
- {
- // Make sure the parent directories exist.
- File parentDirectory = file.getParentFile();
- if (parentDirectory != null &&
- !parentDirectory.exists() &&
- !parentDirectory.mkdirs())
- {
- throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]");
- }
-
- // Open a new output stream for writing to the file.
- currentOutputStream =
- new BufferedOutputStream(
- new FileOutputStream(file));
-
- currentFinisher = finisher;
- currentFile = file;
- }
-
- return currentOutputStream;
+ return
+ new BufferedOutputStream(
+ new FileOutputStream(file));
}
public void close() throws IOException
{
- // Close the file stream, if any.
- closeEntry();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "DirectoryWriter (base " + (isFile?"file ":"directory") + " ["+baseFile+"])");
}
@@ -140,26 +115,4 @@ private File getFile(DataEntry dataEntry)
dataEntry.getName().replace(ClassConstants.PACKAGE_SEPARATOR,
File.separatorChar));
}
-
-
- /**
- * Closes the previous file, if any.
- */
- private void closeEntry() throws IOException
- {
- // Close the file stream, if any.
- if (currentOutputStream != null)
- {
- // Let any finisher finish up first.
- if (currentFinisher != null)
- {
- currentFinisher.finish();
- currentFinisher = null;
- }
-
- currentOutputStream.close();
- currentOutputStream = null;
- currentFile = null;
- }
- }
}
diff --git a/core/src/proguard/io/ExtraDataEntryWriter.java b/core/src/proguard/io/ExtraDataEntryWriter.java
new file mode 100644
index 0000000..fcfd9b3
--- /dev/null
+++ b/core/src/proguard/io/ExtraDataEntryWriter.java
@@ -0,0 +1,182 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.util.MultiValueMap;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This DataEntryWriter writes out all data entries to a delegate
+ * DataEntryWriter, inserting additional data entries that are attached
+ * to the written data entry. The output stream of the additional data
+ * entry is not used.
+ *
+ * @author Eric Lafortune
+ */
+public class ExtraDataEntryWriter implements DataEntryWriter
+{
+ private final MultiValueMap extraEntryNameMap;
+ private final Set extraEntryNamesWritten = new HashSet();
+
+ private final DataEntryWriter dataEntryWriter;
+ private final DataEntryWriter extraDataEntryWriter;
+
+ private final String entrySuffix;
+
+ /**
+ * Creates a new ExtraDataEntryWriter that writes one given extra data entry
+ * together with the first data entry that is written.
+ *
+ * @param extraEntryName the name of the extra data entry.
+ * @param dataEntryWriter the writer to which the entries are
+ * written, including the extra data entry.
+ */
+ public ExtraDataEntryWriter(String extraEntryName,
+ DataEntryWriter dataEntryWriter)
+ {
+ this(extraEntryName, dataEntryWriter, dataEntryWriter);
+ }
+
+
+ /**
+ * Creates a new ExtraDataEntryWriter that writes one given extra data entry
+ * together with the first data entry that is written.
+ *
+ * @param extraEntryName the name of the extra data entry.
+ * @param dataEntryWriter the writer to which the entries are
+ * written.
+ * @param extraDataEntryWriter the writer to which the extra data entry
+ * will be written.
+ */
+ public ExtraDataEntryWriter(String extraEntryName,
+ DataEntryWriter dataEntryWriter,
+ DataEntryWriter extraDataEntryWriter)
+ {
+ this(new MultiValueMap(),
+ dataEntryWriter,
+ extraDataEntryWriter,
+ null);
+ extraEntryNameMap.put(null, extraEntryName);
+ }
+
+ /**
+ * Creates a new ExtraDataEntryWriter.
+ *
+ * @param extraEntryNameMap a map with data entry names and their
+ * associated extra data entries. An extra
+ * data entry that is associated with multiple
+ * entries is only written once.
+ * @param dataEntryWriter the writer to which the entries are
+ * written.
+ * @param extraDataEntryWriter the writer to which the extra data entry
+ * will be written.
+ * @param entrySuffix an optional file suffix. It is stripped
+ * from the entry name when looking up the
+ * entry in the map, and added to all extra
+ * entry names.
+ */
+ public ExtraDataEntryWriter(MultiValueMap extraEntryNameMap,
+ DataEntryWriter dataEntryWriter,
+ DataEntryWriter extraDataEntryWriter,
+ String entrySuffix )
+ {
+ this.extraEntryNameMap = extraEntryNameMap;
+ this.dataEntryWriter = dataEntryWriter;
+ this.extraDataEntryWriter = extraDataEntryWriter;
+ this.entrySuffix = entrySuffix;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createDirectory(dataEntry);
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(dataEntry1, dataEntry2);
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ // Write all default extra entries.
+ writeExtraEntries(dataEntry, null);
+
+ // Write all extra entries attached to the current data entry.
+ writeExtraEntries(dataEntry);
+
+ // Delegate to write out the actual entry.
+ return dataEntryWriter.createOutputStream(dataEntry);
+ }
+
+
+ private void writeExtraEntries(DataEntry dataEntry) throws IOException
+ {
+ String mapKey = dataEntry.getName();
+ if (entrySuffix != null && mapKey.endsWith(entrySuffix))
+ {
+ mapKey = mapKey.substring(0, mapKey.length() - entrySuffix.length());
+ }
+
+ writeExtraEntries(dataEntry, mapKey);
+ }
+
+
+ private void writeExtraEntries(DataEntry dataEntry,
+ String key) throws IOException
+ {
+ Set extraEntryNames = extraEntryNameMap.get(key);
+ if (extraEntryNames != null)
+ {
+ for (String extraEntryName : extraEntryNames)
+ {
+ if (!extraEntryNamesWritten.contains(extraEntryName))
+ {
+ String fullEntryName = entrySuffix != null ? extraEntryName + entrySuffix : extraEntryName;
+ RenamedDataEntry extraEntry = new RenamedDataEntry(dataEntry, fullEntryName);
+ extraDataEntryWriter.createOutputStream(extraEntry);
+ extraEntryNamesWritten.add(extraEntryName);
+ writeExtraEntries(extraEntry);
+ }
+ }
+ }
+ }
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "ExtraDataEntryWriter");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
+}
diff --git a/src/proguard/io/FileDataEntry.java b/core/src/proguard/io/FileDataEntry.java
similarity index 71%
rename from src/proguard/io/FileDataEntry.java
rename to core/src/proguard/io/FileDataEntry.java
index cc3e853..a530910 100644
--- a/src/proguard/io/FileDataEntry.java
+++ b/core/src/proguard/io/FileDataEntry.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -44,6 +44,17 @@ public FileDataEntry(File directory,
}
+ /**
+ * Returns the complete file, including its directory.
+ */
+ public File getFile()
+ {
+ return file.equals(directory) ?
+ file :
+ new File(directory, getRelativeFilePath());
+ }
+
+
// Implementations for DataEntry.
public String getName()
@@ -51,9 +62,33 @@ public String getName()
// Chop the directory name from the file name and get the right separators.
return file.equals(directory) ?
file.getName() :
+ getRelativeFilePath();
+ }
+
+
+ /**
+ * Returns the file path of this data entry, relative to the base directory.
+ * If the file equals the base directory, an empty string is returned.
+ */
+ private String getRelativeFilePath()
+ {
+ return file.equals(directory) ?
+ "" :
file.getPath()
- .substring(directory.getPath().length() + File.separator.length())
- .replace(File.separatorChar, ClassConstants.PACKAGE_SEPARATOR);
+ .substring(directory.getPath().length() + File.separator.length())
+ .replace(File.separatorChar, ClassConstants.PACKAGE_SEPARATOR);
+ }
+
+
+ public String getOriginalName()
+ {
+ return getName();
+ }
+
+
+ public long getSize()
+ {
+ return file.length();
}
diff --git a/src/proguard/io/FilteredDataEntryReader.java b/core/src/proguard/io/FilteredDataEntryReader.java
similarity index 98%
rename from src/proguard/io/FilteredDataEntryReader.java
rename to core/src/proguard/io/FilteredDataEntryReader.java
index c2449bd..f5426bb 100644
--- a/src/proguard/io/FilteredDataEntryReader.java
+++ b/core/src/proguard/io/FilteredDataEntryReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/io/FilteredDataEntryWriter.java b/core/src/proguard/io/FilteredDataEntryWriter.java
similarity index 78%
rename from src/proguard/io/FilteredDataEntryWriter.java
rename to core/src/proguard/io/FilteredDataEntryWriter.java
index 7b0dfc9..59bcb5a 100644
--- a/src/proguard/io/FilteredDataEntryWriter.java
+++ b/core/src/proguard/io/FilteredDataEntryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -87,14 +87,19 @@ public boolean createDirectory(DataEntry dataEntry) throws IOException
}
- public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
{
- return getOutputStream(dataEntry, null);
+ boolean accepts1 = dataEntryFilter.accepts(dataEntry1);
+ boolean accepts2 = dataEntryFilter.accepts(dataEntry2);
+ return
+ accepts1 ? !accepts2 || acceptedDataEntryWriter == null || acceptedDataEntryWriter.sameOutputStream(dataEntry1, dataEntry2) :
+ accepts2 || rejectedDataEntryWriter == null || rejectedDataEntryWriter.sameOutputStream(dataEntry1, dataEntry2);
}
- public OutputStream getOutputStream(DataEntry dataEntry,
- Finisher finisher) throws IOException
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
{
// Get the right data entry writer.
DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ?
@@ -103,7 +108,7 @@ public OutputStream getOutputStream(DataEntry dataEntry,
// Delegate to it, if it's not null.
return dataEntryWriter != null ?
- dataEntryWriter.getOutputStream(dataEntry, finisher) :
+ dataEntryWriter.createOutputStream(dataEntry) :
null;
}
@@ -122,4 +127,18 @@ public void close() throws IOException
rejectedDataEntryWriter = null;
}
}
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "FilteredDataEntryWriter (filter = "+dataEntryFilter+")");
+ if (acceptedDataEntryWriter != null)
+ {
+ acceptedDataEntryWriter.println(pw, prefix + " ");
+ }
+ if (rejectedDataEntryWriter != null)
+ {
+ rejectedDataEntryWriter.println(pw, prefix + " ");
+ }
+ }
}
diff --git a/src/proguard/io/Finisher.java b/core/src/proguard/io/Finisher.java
similarity index 95%
rename from src/proguard/io/Finisher.java
rename to core/src/proguard/io/Finisher.java
index c92632c..52eaedf 100644
--- a/src/proguard/io/Finisher.java
+++ b/core/src/proguard/io/Finisher.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/io/IdleRewriter.java b/core/src/proguard/io/IdleRewriter.java
new file mode 100644
index 0000000..11e1ee2
--- /dev/null
+++ b/core/src/proguard/io/IdleRewriter.java
@@ -0,0 +1,51 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import java.io.IOException;
+
+/**
+ * This DataEntryReader reads data entries and requests their corresponding
+ * output streams from a given DataEntryWriter, without actually using the
+ * output stream.
+ *
+ * @author Eric Lafortune
+ */
+public class IdleRewriter implements DataEntryReader
+{
+ private final DataEntryWriter dataEntryWriter;
+
+
+ public IdleRewriter(DataEntryWriter dataEntryWriter)
+ {
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ // Get the output entry corresponding to this input entry, but don't
+ // even try to close it.
+ dataEntryWriter.createOutputStream(dataEntry);
+ }
+}
diff --git a/src/proguard/io/JarReader.java b/core/src/proguard/io/JarReader.java
similarity index 82%
rename from src/proguard/io/JarReader.java
rename to core/src/proguard/io/JarReader.java
index 718af32..89e03fa 100644
--- a/src/proguard/io/JarReader.java
+++ b/core/src/proguard/io/JarReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -32,14 +32,26 @@
public class JarReader implements DataEntryReader
{
private final DataEntryReader dataEntryReader;
+ private final boolean jmod;
/**
- * Creates a new JarReader.
+ * Creates a new JarReader that doesn't read jmods.
*/
public JarReader(DataEntryReader dataEntryReader)
+ {
+ this(dataEntryReader, false);
+ }
+
+
+ /**
+ * Creates a new JarReader.
+ */
+ public JarReader(DataEntryReader dataEntryReader,
+ boolean jmod)
{
this.dataEntryReader = dataEntryReader;
+ this.jmod = jmod;
}
@@ -47,6 +59,12 @@ public JarReader(DataEntryReader dataEntryReader)
public void read(DataEntry dataEntry) throws IOException
{
+ if (jmod)
+ {
+ // Eat the magic bytes
+ dataEntry.getInputStream().read(new byte[4]);
+ }
+
ZipInputStream zipInputStream = new ZipInputStream(dataEntry.getInputStream());
try
diff --git a/core/src/proguard/io/JarWriter.java b/core/src/proguard/io/JarWriter.java
new file mode 100644
index 0000000..82f668f
--- /dev/null
+++ b/core/src/proguard/io/JarWriter.java
@@ -0,0 +1,220 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.classfile.ClassConstants;
+
+import java.io.*;
+import java.util.Date;
+
+/**
+ * This DataEntryWriter sends data entries to a the jar/zip files specified by
+ * their parents.
+ *
+ * @author Eric Lafortune
+ */
+public class JarWriter implements DataEntryWriter
+{
+ private final byte[] header;
+ private final int modificationTime;
+ private final DataEntryWriter dataEntryWriter;
+
+ private DataEntry currentParentEntry;
+ private ZipOutput currentZipOutput;
+
+
+ /**
+ * Creates a new JarWriter.
+ * @param dataEntryWriter the data entry writer that can provide
+ * output streams for the jar/zip archives.
+ */
+ public JarWriter(DataEntryWriter dataEntryWriter)
+ {
+ this(null, dataEntryWriter);
+ }
+
+
+ /**
+ * Creates a new JarWriter.
+ * @param header an optional header for the jar file.
+ * @param dataEntryWriter the data entry writer that can provide
+ * output streams for the jar/zip archives.
+ */
+ public JarWriter(byte[] header,
+ DataEntryWriter dataEntryWriter)
+ {
+ this(header, currentTime(), dataEntryWriter);
+ }
+
+
+ /**
+ * Creates a new JarWriter.
+ * @param header an optional header for the jar file.
+ * @param modificationTime the modification date and time of the zip
+ * entries, in DOS format.
+ * @param dataEntryWriter the data entry writer that can provide
+ * output streams for the jar/zip archives.
+ */
+ public JarWriter(byte[] header,
+ int modificationTime,
+ DataEntryWriter dataEntryWriter)
+ {
+ this.header = header;
+ this.modificationTime = modificationTime;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
+ {
+ finishIfNecessary(dataEntry);
+ setUp(dataEntry);
+
+ // Did we get a zip output?
+ if (currentZipOutput == null)
+ {
+ return false;
+ }
+
+ // Get the directory entry name.
+ String name = dataEntry.getName() + ClassConstants.PACKAGE_SEPARATOR;
+
+ // Create a new directory entry.
+ OutputStream outputStream =
+ currentZipOutput.createOutputStream(name,
+ false,
+ modificationTime);
+ outputStream.close();
+
+ return true;
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
+ {
+ return dataEntry1 != null &&
+ dataEntry2 != null &&
+ dataEntry1.getName().equals(dataEntry2.getName()) &&
+ dataEntryWriter.sameOutputStream(dataEntry1.getParent(),
+ dataEntry2.getParent());
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ finishIfNecessary(dataEntry);
+ setUp(dataEntry);
+
+ // Did we get a zip output?
+ if (currentZipOutput == null)
+ {
+ return null;
+ }
+
+ // Create a new zip entry.
+ return currentZipOutput.createOutputStream(dataEntry.getName(),
+ true,
+ modificationTime);
+ }
+
+
+ public void close() throws IOException
+ {
+ finish();
+
+ // Close the delegate writer.
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "JarWriter");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Sets up the zip output for the given parent entry.
+ */
+ protected void setUp(DataEntry dataEntry) throws IOException
+ {
+ if (currentZipOutput == null)
+ {
+ // Create a new zip output.
+ currentParentEntry = dataEntry.getParent();
+ currentZipOutput = new ZipOutput(dataEntryWriter.createOutputStream(currentParentEntry),
+ header,
+ null,
+ 1);
+ }
+ }
+
+
+ private void finishIfNecessary(DataEntry dataEntry) throws IOException
+ {
+ // Would the new data entry end up in a different jar?
+ if (currentParentEntry != null &&
+ !dataEntryWriter.sameOutputStream(currentParentEntry, dataEntry.getParent()))
+ {
+ finish();
+ }
+ }
+
+
+ /**
+ * Closes the zip output, if any.
+ */
+ protected void finish() throws IOException
+ {
+ // Finish the zip output, if any.
+ if (currentZipOutput != null)
+ {
+ // Close the zip output and its underlying output stream.
+ currentZipOutput.close();
+
+ currentParentEntry = null;
+ currentZipOutput = null;
+ }
+ }
+
+
+ /**
+ * Returns the current time in DOS format.
+ */
+ private static int currentTime()
+ {
+ // Convert the current time into DOS date and time.
+ Date currentDate = new Date();
+ return
+ (currentDate.getYear() - 80) << 25 |
+ (currentDate.getMonth() + 1) << 21 |
+ currentDate.getDate() << 16 |
+ currentDate.getHours() << 11 |
+ currentDate.getMinutes() << 5 |
+ currentDate.getSeconds() >> 1;
+ }}
diff --git a/src/proguard/io/ManifestRewriter.java b/core/src/proguard/io/ManifestRewriter.java
similarity index 96%
rename from src/proguard/io/ManifestRewriter.java
rename to core/src/proguard/io/ManifestRewriter.java
index 1d79064..7fbe315 100644
--- a/src/proguard/io/ManifestRewriter.java
+++ b/core/src/proguard/io/ManifestRewriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.ClassPool;
import java.io.*;
+import java.nio.charset.Charset;
/**
* This DataEntryReader writes the manifest data entries that it reads to a
@@ -37,9 +38,10 @@ public class ManifestRewriter extends DataEntryRewriter
* Creates a new ManifestRewriter.
*/
public ManifestRewriter(ClassPool classPool,
+ Charset charset,
DataEntryWriter dataEntryWriter)
{
- super(classPool, dataEntryWriter);
+ super(classPool, charset, dataEntryWriter);
}
diff --git a/src/proguard/io/NameFilter.java b/core/src/proguard/io/NameFilter.java
similarity index 98%
rename from src/proguard/io/NameFilter.java
rename to core/src/proguard/io/NameFilter.java
index e30606b..f7caaeb 100644
--- a/src/proguard/io/NameFilter.java
+++ b/core/src/proguard/io/NameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/io/NameFilteredDataEntryWriter.java b/core/src/proguard/io/NameFilteredDataEntryWriter.java
new file mode 100644
index 0000000..b006c15
--- /dev/null
+++ b/core/src/proguard/io/NameFilteredDataEntryWriter.java
@@ -0,0 +1,108 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.util.*;
+
+import java.util.List;
+
+/**
+ * This DataEntryWriter delegates to one of two other DataEntryWriter instances,
+ * depending on the name of the data entry.
+ *
+ * @author Eric Lafortune
+ */
+public class NameFilteredDataEntryWriter extends FilteredDataEntryWriter
+{
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to the given
+ * writer, depending on the given list of filters.
+ */
+ public NameFilteredDataEntryWriter(String regularExpression,
+ DataEntryWriter acceptedDataEntryWriter)
+ {
+ this(regularExpression, acceptedDataEntryWriter, null);
+ }
+
+
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to either of
+ * the two given writers, depending on the given list of filters.
+ */
+ public NameFilteredDataEntryWriter(String regularExpression,
+ DataEntryWriter acceptedDataEntryWriter,
+ DataEntryWriter rejectedDataEntryWriter)
+ {
+ this(new ListParser(new FileNameParser()).parse(regularExpression),
+ acceptedDataEntryWriter,
+ rejectedDataEntryWriter);
+ }
+
+
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to the given
+ * writer, depending on the given list of filters.
+ */
+ public NameFilteredDataEntryWriter(List regularExpressions,
+ DataEntryWriter acceptedDataEntryWriter)
+ {
+ this(regularExpressions, acceptedDataEntryWriter, null);
+ }
+
+
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to either of
+ * the two given writers, depending on the given list of filters.
+ */
+ public NameFilteredDataEntryWriter(List regularExpressions,
+ DataEntryWriter acceptedDataEntryWriter,
+ DataEntryWriter rejectedDataEntryWriter)
+ {
+ this(new ListParser(new FileNameParser()).parse(regularExpressions),
+ acceptedDataEntryWriter,
+ rejectedDataEntryWriter);
+ }
+
+
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to the given
+ * writer, depending on the given string matcher.
+ */
+ public NameFilteredDataEntryWriter(StringMatcher stringMatcher,
+ DataEntryWriter acceptedDataEntryWriter)
+ {
+ this(stringMatcher, acceptedDataEntryWriter, null);
+ }
+
+
+ /**
+ * Creates a new NameFilteredDataEntryWriter that delegates to either of
+ * the two given writers, depending on the given string matcher.
+ */
+ public NameFilteredDataEntryWriter(StringMatcher stringMatcher,
+ DataEntryWriter acceptedDataEntryWriter,
+ DataEntryWriter rejectedDataEntryWriter)
+ {
+ super(new DataEntryNameFilter(stringMatcher),
+ acceptedDataEntryWriter,
+ rejectedDataEntryWriter);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/io/ParentDataEntryWriter.java b/core/src/proguard/io/ParentDataEntryWriter.java
similarity index 70%
rename from src/proguard/io/ParentDataEntryWriter.java
rename to core/src/proguard/io/ParentDataEntryWriter.java
index 8590296..1d06635 100644
--- a/src/proguard/io/ParentDataEntryWriter.java
+++ b/core/src/proguard/io/ParentDataEntryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -46,24 +46,24 @@ public ParentDataEntryWriter(DataEntryWriter dataEntryWriter)
// Implementations for DataEntryWriter.
-
public boolean createDirectory(DataEntry dataEntry) throws IOException
{
- return getOutputStream(dataEntry) != null;
+ return dataEntryWriter.createDirectory(dataEntry.getParent());
}
- public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
{
- return getOutputStream(dataEntry, null);
+ return dataEntryWriter.sameOutputStream(dataEntry1.getParent(),
+ dataEntry2.getParent());
}
- public OutputStream getOutputStream(DataEntry dataEntry,
- Finisher finisher) throws IOException
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
{
- return dataEntryWriter.getOutputStream(dataEntry.getParent(),
- finisher);
+ return dataEntryWriter.createOutputStream(dataEntry.getParent());
}
@@ -72,4 +72,11 @@ public void close() throws IOException
dataEntryWriter.close();
dataEntryWriter = null;
}
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "ParentDataEntryWriter");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
}
diff --git a/core/src/proguard/io/PrefixAddingDataEntryWriter.java b/core/src/proguard/io/PrefixAddingDataEntryWriter.java
new file mode 100644
index 0000000..2afdfbf
--- /dev/null
+++ b/core/src/proguard/io/PrefixAddingDataEntryWriter.java
@@ -0,0 +1,95 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter delegates to a given DataEntryWriter, each time
+ * adding a prefix of the written data entry name.
+ *
+ * @author Eric Lafortune
+ */
+public class PrefixAddingDataEntryWriter implements DataEntryWriter
+{
+ private final String prefix;
+ private final DataEntryWriter dataEntryWriter;
+
+
+ /**
+ * Creates a new PrefixAddingDataEntryWriter.
+ */
+ public PrefixAddingDataEntryWriter(String prefix,
+ DataEntryWriter dataEntryWriter)
+ {
+ this.prefix = prefix;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public boolean createDirectory(DataEntry dataEntry)
+ throws IOException
+ {
+ return dataEntryWriter.createDirectory(renamedDataEntry(dataEntry));
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1,
+ DataEntry dataEntry2)
+ throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(renamedDataEntry(dataEntry1),
+ renamedDataEntry(dataEntry2));
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry)
+ throws IOException
+ {
+ return dataEntryWriter.createOutputStream(renamedDataEntry(dataEntry));
+ }
+
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ pw.println(prefix + "PrefixAddingDataEntryWriter (prefix = "+prefix+")");
+ dataEntryWriter.println(pw, prefix + " ");
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Adds the prefix to the given data entry name.
+ */
+ private DataEntry renamedDataEntry(DataEntry dataEntry)
+ {
+ return new RenamedDataEntry(dataEntry, prefix + dataEntry.getName());
+ }
+}
diff --git a/core/src/proguard/io/PrefixStrippingDataEntryReader.java b/core/src/proguard/io/PrefixStrippingDataEntryReader.java
new file mode 100644
index 0000000..8fdfd1f
--- /dev/null
+++ b/core/src/proguard/io/PrefixStrippingDataEntryReader.java
@@ -0,0 +1,65 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.util.ArrayUtil;
+
+import java.io.IOException;
+
+/**
+ * This DataEntryReader delegates to a given DataEntryReader, each time
+ * stripping a possible prefix from the read data entry name.
+ *
+ * @author Eric Lafortune
+ */
+public class PrefixStrippingDataEntryReader implements DataEntryReader
+{
+ private final String prefix;
+ private final DataEntryReader dataEntryReader;
+
+
+ /**
+ * Creates a new PrefixStrippingDataEntryReader.
+ */
+ public PrefixStrippingDataEntryReader(String prefix,
+ DataEntryReader dataEntryReader)
+ {
+ this.prefix = prefix;
+ this.dataEntryReader = dataEntryReader;
+ }
+
+
+ // Implementation for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ // Strip the prefix if necessary.
+ String name = dataEntry.getName();
+ if (name.startsWith(prefix))
+ {
+ dataEntry = new RenamedDataEntry(dataEntry,
+ name.substring(prefix.length()));
+ }
+
+ // Read the data entry.
+ dataEntryReader.read(dataEntry);
+ }
+}
diff --git a/src/proguard/io/RenamedDataEntry.java b/core/src/proguard/io/RenamedDataEntry.java
similarity index 66%
rename from src/proguard/io/RenamedDataEntry.java
rename to core/src/proguard/io/RenamedDataEntry.java
index 3ac3f18..238e593 100644
--- a/src/proguard/io/RenamedDataEntry.java
+++ b/core/src/proguard/io/RenamedDataEntry.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,25 +20,22 @@
*/
package proguard.io;
-import java.io.*;
-
/**
* This DataEntry wraps another data entry, returning a different name instead
* of the wrapped data entry's name.
*
* @author Eric Lafortune
*/
-public class RenamedDataEntry implements DataEntry
+public class RenamedDataEntry extends WrappedDataEntry
{
- private final DataEntry dataEntry;
private final String name;
public RenamedDataEntry(DataEntry dataEntry,
String name)
{
- this.dataEntry = dataEntry;
- this.name = name;
+ super(dataEntry);
+ this.name = name;
}
@@ -50,34 +47,10 @@ public String getName()
}
- public boolean isDirectory()
- {
- return dataEntry.isDirectory();
- }
-
-
- public InputStream getInputStream() throws IOException
- {
- return dataEntry.getInputStream();
- }
-
-
- public void closeInputStream() throws IOException
- {
- dataEntry.closeInputStream();
- }
-
-
- public DataEntry getParent()
- {
- return dataEntry.getParent();
- }
-
-
// Implementations for Object.
public String toString()
{
- return name + " == " + dataEntry;
+ return name + " == " + wrappedEntry;
}
}
diff --git a/src/proguard/io/DataEntryRenamer.java b/core/src/proguard/io/RenamedDataEntryReader.java
similarity index 71%
rename from src/proguard/io/DataEntryRenamer.java
rename to core/src/proguard/io/RenamedDataEntryReader.java
index 386fdfc..b537dec 100644
--- a/src/proguard/io/DataEntryRenamer.java
+++ b/core/src/proguard/io/RenamedDataEntryReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -32,41 +32,41 @@
*
* @author Eric Lafortune
*/
-public class DataEntryRenamer implements DataEntryReader
+public class RenamedDataEntryReader implements DataEntryReader
{
private final Map nameMap;
- private final DataEntryReader renamedDataEntryReader;
+ private final DataEntryReader dataEntryReader;
private final DataEntryReader missingDataEntryReader;
/**
- * Creates a new DataEntryRenamer.
- * @param nameMap the map from old names to new names.
- * @param renamedDataEntryReader the DataEntryReader to which renamed data
- * entries will be passed.
+ * Creates a new RenamedDataEntryReader.
+ * @param nameMap the map from old names to new names.
+ * @param dataEntryReader the DataEntryReader to which renamed data
+ * entries will be passed.
*/
- public DataEntryRenamer(Map nameMap,
- DataEntryReader renamedDataEntryReader)
+ public RenamedDataEntryReader(Map nameMap,
+ DataEntryReader dataEntryReader)
{
- this(nameMap, renamedDataEntryReader, null);
+ this(nameMap, dataEntryReader, null);
}
/**
- * Creates a new DataEntryRenamer.
+ * Creates a new RenamedDataEntryReader.
* @param nameMap the map from old names to new names.
- * @param renamedDataEntryReader the DataEntryReader to which renamed data
+ * @param dataEntryReader the DataEntryReader to which renamed data
* entries will be passed.
* @param missingDataEntryReader the optional DataEntryReader to which data
* entries that can't be renamed will be
* passed.
*/
- public DataEntryRenamer(Map nameMap,
- DataEntryReader renamedDataEntryReader,
- DataEntryReader missingDataEntryReader)
+ public RenamedDataEntryReader(Map nameMap,
+ DataEntryReader dataEntryReader,
+ DataEntryReader missingDataEntryReader)
{
this.nameMap = nameMap;
- this.renamedDataEntryReader = renamedDataEntryReader;
+ this.dataEntryReader = dataEntryReader;
this.missingDataEntryReader = missingDataEntryReader;
}
@@ -94,7 +94,7 @@ public void read(DataEntry dataEntry) throws IOException
newName = newName.substring(0, newName.length() - 1);
}
- renamedDataEntryReader.read(new RenamedDataEntry(dataEntry, newName));
+ dataEntryReader.read(new RenamedDataEntry(dataEntry, newName));
}
else if (missingDataEntryReader != null)
{
diff --git a/src/proguard/io/DataEntryObfuscator.java b/core/src/proguard/io/RenamedDataEntryWriter.java
similarity index 76%
rename from src/proguard/io/DataEntryObfuscator.java
rename to core/src/proguard/io/RenamedDataEntryWriter.java
index 05a0215..cbd2dbc 100644
--- a/src/proguard/io/DataEntryObfuscator.java
+++ b/core/src/proguard/io/RenamedDataEntryWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,50 +23,75 @@
import proguard.classfile.*;
import proguard.classfile.util.ClassUtil;
-import java.io.IOException;
+import java.io.*;
import java.util.Map;
/**
- * This DataEntryReader delegates to another DataEntryReader, renaming the
+ * This DataEntryWriter delegates to another DataEntryWriter, renaming the
* data entries based on the renamed classes in the given ClassPool.
*
* @author Eric Lafortune
*/
-public class DataEntryObfuscator implements DataEntryReader
+public class RenamedDataEntryWriter implements DataEntryWriter
{
private final ClassPool classPool;
private final Map packagePrefixMap;
- private final DataEntryReader dataEntryReader;
+ private final DataEntryWriter dataEntryWriter;
/**
- * Creates a new DataEntryObfuscator.
+ * Creates a new RenamedDataEntryWriter.
* @param classPool the class pool that maps from old names to new
* names.
* @param packagePrefixMap the map from old package prefixes to new package
* prefixes.
- * @param dataEntryReader the DataEntryReader to which calls will be
+ * @param dataEntryWriter the DataEntryWriter to which calls will be
* delegated.
*/
- public DataEntryObfuscator(ClassPool classPool,
- Map packagePrefixMap,
- DataEntryReader dataEntryReader)
+ public RenamedDataEntryWriter(ClassPool classPool,
+ Map packagePrefixMap,
+ DataEntryWriter dataEntryWriter)
{
this.classPool = classPool;
this.packagePrefixMap = packagePrefixMap;
- this.dataEntryReader = dataEntryReader;
+ this.dataEntryWriter = dataEntryWriter;
}
- // Implementations for DataEntryReader.
+ // Implementations for DataEntryWriter.
- public void read(DataEntry dataEntry) throws IOException
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
{
- // Delegate to the actual data entry reader.
- dataEntryReader.read(renamedDataEntry(dataEntry));
+ return dataEntryWriter.createDirectory(renamedDataEntry(dataEntry));
}
+ public boolean sameOutputStream(DataEntry dataEntry1, DataEntry dataEntry2) throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(dataEntry1, dataEntry2);
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createOutputStream(renamedDataEntry(dataEntry));
+ }
+
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ dataEntryWriter.println(pw, prefix);
+ }
+
+
+ // Small utility methods.
+
/**
* Create a renamed data entry, if possible.
*/
diff --git a/core/src/proguard/io/RenamedParentDataEntryWriter.java b/core/src/proguard/io/RenamedParentDataEntryWriter.java
new file mode 100644
index 0000000..b4e7256
--- /dev/null
+++ b/core/src/proguard/io/RenamedParentDataEntryWriter.java
@@ -0,0 +1,116 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.util.StringMatcher;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter delegates to another DataEntryWriter, renaming
+ * parent data entries based on the given matcher.
+ *
+ * @author Thomas Neidhart
+ */
+public class RenamedParentDataEntryWriter implements DataEntryWriter
+{
+ private final StringMatcher matcher;
+ private final String newParentName;
+ private final DataEntryWriter dataEntryWriter;
+
+
+ /**
+ * Creates a new RenamedParentDataEntryWriter.
+ *
+ * @param matcher the string matcher to match parent entries.
+ * @param newParentName the new parent name to use.
+ * @param dataEntryWriter the DataEntryWriter to which the writing will
+ * be delegated.
+ */
+ public RenamedParentDataEntryWriter(StringMatcher matcher,
+ String newParentName,
+ DataEntryWriter dataEntryWriter)
+ {
+ this.matcher = matcher;
+ this.newParentName = newParentName;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public boolean createDirectory(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createDirectory(getRedirectedEntry(dataEntry));
+ }
+
+
+ public boolean sameOutputStream(DataEntry dataEntry1, DataEntry dataEntry2)
+ throws IOException
+ {
+ return dataEntryWriter.sameOutputStream(getRedirectedEntry(dataEntry1),
+ getRedirectedEntry(dataEntry2));
+ }
+
+
+ public OutputStream createOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return dataEntryWriter.createOutputStream(getRedirectedEntry(dataEntry));
+ }
+
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+
+
+ public void println(PrintWriter pw, String prefix)
+ {
+ dataEntryWriter.println(pw, prefix);
+ }
+
+ private DataEntry getRedirectedEntry(DataEntry dataEntry)
+ {
+ if (dataEntry == null)
+ {
+ return null;
+ }
+
+ final DataEntry parentEntry = dataEntry.getParent();
+ if (parentEntry != null &&
+ matcher.matches(parentEntry.getName()))
+ {
+ final DataEntry renamedParentEntry =
+ new RenamedDataEntry(parentEntry, newParentName);
+
+ return new WrappedDataEntry(dataEntry) {
+ public DataEntry getParent()
+ {
+ return renamedParentEntry;
+ }
+ };
+ }
+
+ return dataEntry;
+ }
+
+}
diff --git a/core/src/proguard/io/WrappedDataEntry.java b/core/src/proguard/io/WrappedDataEntry.java
new file mode 100644
index 0000000..d084c10
--- /dev/null
+++ b/core/src/proguard/io/WrappedDataEntry.java
@@ -0,0 +1,87 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import java.io.*;
+
+/**
+ * This DataEntry wraps another data entry.
+ *
+ * @author Thomas Neidhart
+ */
+public class WrappedDataEntry implements DataEntry
+{
+ protected final DataEntry wrappedEntry;
+
+
+ public WrappedDataEntry(DataEntry wrappedEntry)
+ {
+ this.wrappedEntry = wrappedEntry;
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ wrappedEntry.closeInputStream();
+ }
+
+ public String getName()
+ {
+ return wrappedEntry.getName();
+ }
+
+
+ public String getOriginalName()
+ {
+ return wrappedEntry.getOriginalName();
+ }
+
+
+ public long getSize()
+ {
+ return wrappedEntry.getSize();
+ }
+
+
+ public boolean isDirectory()
+ {
+ return wrappedEntry.isDirectory();
+ }
+
+
+ public InputStream getInputStream() throws IOException
+ {
+ return wrappedEntry.getInputStream();
+ }
+
+
+ public DataEntry getParent()
+ {
+ return wrappedEntry.getParent();
+ }
+
+
+ public String toString()
+ {
+ return getName();
+ }
+
+}
diff --git a/src/proguard/io/ZipDataEntry.java b/core/src/proguard/io/ZipDataEntry.java
similarity index 93%
rename from src/proguard/io/ZipDataEntry.java
rename to core/src/proguard/io/ZipDataEntry.java
index 7425745..a1dcba3 100644
--- a/src/proguard/io/ZipDataEntry.java
+++ b/core/src/proguard/io/ZipDataEntry.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -65,6 +65,18 @@ public String getName()
}
+ public String getOriginalName()
+ {
+ return getName();
+ }
+
+
+ public long getSize()
+ {
+ return zipEntry.getSize();
+ }
+
+
public boolean isDirectory()
{
return zipEntry.isDirectory();
diff --git a/core/src/proguard/io/ZipFileDataEntry.java b/core/src/proguard/io/ZipFileDataEntry.java
new file mode 100644
index 0000000..6ad4d53
--- /dev/null
+++ b/core/src/proguard/io/ZipFileDataEntry.java
@@ -0,0 +1,123 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.classfile.ClassConstants;
+
+import java.io.*;
+import java.util.zip.*;
+
+/**
+ * This DataEntry represents a ZIP entry.
+ *
+ * @author Eric Lafortune
+ */
+public class ZipFileDataEntry implements DataEntry
+{
+ private final DataEntry parent;
+ private final ZipEntry zipEntry;
+ private ZipFile zipFile;
+ private InputStream zipInputStream;
+ private InputStream bufferedInputStream;
+
+
+ public ZipFileDataEntry(DataEntry parent,
+ ZipEntry zipEntry,
+ ZipFile zipFile)
+ {
+ this.parent = parent;
+ this.zipEntry = zipEntry;
+ this.zipFile = zipFile;
+ }
+
+
+ // Implementations for DataEntry.
+
+ public String getName()
+ {
+ // Get the right separators.
+ String name = zipEntry.getName()
+ .replace(File.separatorChar, ClassConstants.PACKAGE_SEPARATOR);
+
+ // Chop the trailing directory slash, if any.
+ int length = name.length();
+ return length > 0 &&
+ name.charAt(length-1) == ClassConstants.PACKAGE_SEPARATOR ?
+ name.substring(0, length -1) :
+ name;
+ }
+
+
+ public String getOriginalName()
+ {
+ return getName();
+ }
+
+
+ public long getSize()
+ {
+ return zipEntry.getSize();
+ }
+
+
+ public boolean isDirectory()
+ {
+ return zipEntry.isDirectory();
+ }
+
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (zipInputStream == null)
+ {
+ zipInputStream = zipFile.getInputStream(zipEntry);
+ }
+
+ if (bufferedInputStream == null)
+ {
+ bufferedInputStream = new BufferedInputStream(zipInputStream);
+ }
+
+ return bufferedInputStream;
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ zipInputStream.close();
+ zipFile = null;
+ bufferedInputStream = null;
+ }
+
+
+ public DataEntry getParent()
+ {
+ return parent;
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return parent.toString() + ':' + getName();
+ }
+}
diff --git a/core/src/proguard/io/ZipOutput.java b/core/src/proguard/io/ZipOutput.java
new file mode 100644
index 0000000..d8bb94f
--- /dev/null
+++ b/core/src/proguard/io/ZipOutput.java
@@ -0,0 +1,577 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.io;
+
+import proguard.util.StringUtil;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * This class writes zip data to a given output stream. It returns a new
+ * output stream for each zip entry that is opened. An entry can be compressed
+ * or uncompressed. Uncompressed entries can be aligned to a multiple of a
+ * given number of bytes.
+ *
+ * Multiple entries and output streams can be open at the same time. The entries
+ * are added to the central directory in the order in which they are opened, but
+ * the corresponding data are only written when their output streams are closed.
+ *
+ * The code automatically computes the CRC and lengths of the data, for
+ * compressed and uncompressed data.
+ *
+ * @author Eric Lafortune
+ */
+public class ZipOutput
+{
+ private static final int MAGIC_LOCAL_FILE_HEADER = 0x04034b50;
+ private static final int MAGIC_CENTRAL_DIRECTORY_FILE_HEADER = 0x02014b50;
+ private static final int MAGIC_END_OF_CENTRAL_DIRECTORY = 0x06054b50;
+
+ private static final int VERSION = 10;
+ private static final int GENERAL_PURPOSE_FLAG = 0;
+ private static final int METHOD_UNCOMPRESSED = 0;
+ private static final int METHOD_COMPRESSED = 8;
+
+ private static final boolean DEBUG = false;
+
+
+ private DataOutputStream outputStream;
+ private final int uncompressedAlignment;
+ private final String comment;
+
+ private List zipEntries = new ArrayList();
+ private Set zipEntryNames = new HashSet();
+
+ private long centralDirectoryOffset;
+
+
+ /**
+ * Creates a new ZipOutput.
+ * @param outputStream the output stream to which the zip data will be
+ * written.
+ */
+ public ZipOutput(OutputStream outputStream)
+ throws IOException
+ {
+ this(outputStream, null, null, 1);
+ }
+
+
+ /**
+ * Creates a new ZipOutput that aligns uncompressed entries.
+ * @param outputStream the output stream to which the zip data will
+ * be written.
+ * @param header an optional header for the jar file.
+ * @param comment optional comment for the entire zip file.
+ * @param uncompressedAlignment the requested alignment of uncompressed data.
+ */
+ public ZipOutput(OutputStream outputStream,
+ byte[] header,
+ String comment,
+ int uncompressedAlignment)
+ throws IOException
+ {
+ this.outputStream = new DataOutputStream(outputStream);
+ this.comment = comment;
+ this.uncompressedAlignment = uncompressedAlignment;
+
+ if (header != null)
+ {
+ outputStream.write(header);
+ }
+ }
+
+
+ /**
+ * Creates a new zip entry, returning an output stream to write its data.
+ * It is the caller's responsibility to close the output stream.
+ * @param name the name of the zip entry.
+ * @param compress specifies whether the entry should be compressed.
+ * @param modificationTime the modification date and time of the zip entry,
+ * in DOS format.
+ * @return an output stream for writing the data of the
+ * zip entry.
+ */
+ public OutputStream createOutputStream(String name,
+ boolean compress,
+ int modificationTime)
+ throws IOException
+ {
+ return createOutputStream(name,
+ compress,
+ modificationTime,
+ null,
+ null);
+ }
+
+
+ /**
+ * Creates a new zip entry, returning an output stream to write its data.
+ * It is the caller's responsibility to close the output stream.
+ * @param name the name of the zip entry.
+ * @param compress specifies whether the entry should be compressed.
+ * @param modificationTime the modification date and time of the zip entry,
+ * in DOS format.
+ * @param extraField optional extra field data. These should contain
+ * chunks, each with a short ID, a short length
+ * (little endian), and their corresponding data.
+ * The IDs 0-31 are reserved for Pkware.
+ * Java's jar tool just specifies an ID 0xcafe on
+ * its first entry.
+ * @param comment optional comment.
+ * @return an output stream for writing the data of the
+ * zip entry.
+ */
+ public OutputStream createOutputStream(String name,
+ boolean compress,
+ int modificationTime,
+ byte[] extraField,
+ String comment)
+ throws IOException
+ {
+ // Check if the name hasn't been used yet.
+ if (!zipEntryNames.add(name))
+ {
+ throw new IOException("Duplicate jar entry ["+name+"]");
+ }
+
+ ZipEntry entry = new ZipEntry(name,
+ compress,
+ modificationTime,
+ extraField,
+ comment);
+
+ // Add the entry to the list that will be put in the central directory.
+ zipEntries.add(entry);
+
+ return entry.createOutputStream();
+ }
+
+
+ /**
+ * Closes the zip archive, also closing the underlying output stream.
+ */
+ public void close() throws IOException
+ {
+ // Write the central directory.
+ writeStartOfCentralDirectory();
+
+ for (int index = 0; index < zipEntries.size(); index++)
+ {
+ ZipEntry entry = (ZipEntry)zipEntries.get(index);
+
+ entry.writeCentralDirectoryFileHeader();
+ }
+
+ writeEndOfCentralDirectory();
+
+ // Close the underlying output stream.
+ outputStream.close();
+
+ // Make sure the archive can't be used any further.
+ outputStream = null;
+ zipEntries = null;
+ zipEntryNames = null;
+ }
+
+
+ /**
+ * Starts the central directory.
+ */
+ private void writeStartOfCentralDirectory()
+ {
+ // The central directory as such doesn't have a header.
+ centralDirectoryOffset = outputStream.size();
+ }
+
+
+ /**
+ * Ends the central directory.
+ */
+ private void writeEndOfCentralDirectory() throws IOException
+ {
+ if (DEBUG)
+ {
+ System.out.println("ZipOutput.writeEndOfCentralDirectory ("+zipEntries.size()+" entries)");
+ }
+
+ // The size of the central directory, not counting this trailer.
+ long centralDirectorySize = outputStream.size() - centralDirectoryOffset;
+
+ writeInt(MAGIC_END_OF_CENTRAL_DIRECTORY);
+ writeShort(0); // Number of this disk.
+ writeShort(0); // Number of disk with central directory.
+ writeShort(zipEntries.size()); // Number of records on this disk.
+ writeShort(zipEntries.size()); // Total number of records.
+ writeInt(centralDirectorySize); // Size of central directory, in bytes.
+ writeInt(centralDirectoryOffset); // Offset of central directory.
+
+ if (comment == null)
+ {
+ // No comment.
+ writeShort(0);
+ }
+ else
+ {
+ // Comment length and comment.
+ byte[] commentBytes = StringUtil.getUtf8Bytes(comment);
+ writeShort(commentBytes.length);
+ outputStream.write(commentBytes);
+ }
+ }
+
+
+ /**
+ * This class represents a zip entry in its enclosing zip file. It can
+ * provide an output stream and write its headers and its data to the main
+ * zip output stream. In fact, it automatically writes its local header and
+ * data when the output stream is closed.
+ */
+ private class ZipEntry
+ {
+ private boolean compressed;
+ private int modificationTime;
+ private int crc;
+ private long compressedSize;
+ private long uncompressedSize;
+ private long offset;
+ private String name;
+ private byte[] extraField;
+ private String comment;
+
+
+ /**
+ * Creates a new zip entry, returning output stream to write its data.
+ * It is the caller's responsibility to close the output stream.
+ * @param name the name of the zip entry.
+ * @param compressed specifies whether the entry should be
+ * compressed.
+ * @param modificationTime the modification date and time of the zip
+ * entry, in DOS format.
+ * @param extraField optional extra field data. These should
+ * contain chunks, each with a short ID, a short
+ * length (little endian), and their
+ * corresponding data. The IDs 0-31 are reserved
+ * for Pkware. Java's jar tool just specifies an
+ * ID 0xcafe on its first entry.
+ * @param comment optional comment.
+ * @return an output stream for writing the zip data.
+ */
+ private ZipEntry(String name,
+ boolean compressed,
+ int modificationTime,
+ byte[] extraField,
+ String comment)
+ {
+ this.name = name;
+ this.compressed = compressed;
+ this.modificationTime = modificationTime;
+ this.extraField = extraField;
+ this.comment = comment;
+ }
+
+
+ public OutputStream createOutputStream() throws IOException
+ {
+ return compressed ?
+ (OutputStream)new CompressedZipEntryOutputStream() :
+ (OutputStream)new UncompressedZipEntryOutputStream();
+ }
+
+
+ /**
+ * Writes the local file header, which precedes the data, to the main
+ * zip output stream.
+ */
+ private void writeLocalFileHeader() throws IOException
+ {
+ if (DEBUG)
+ {
+ System.out.println("ZipOutput.writeLocalFileHeader ["+name+"] (compressed = "+compressed+", offset = "+offset+", "+compressedSize+"/"+uncompressedSize+" bytes)");
+ }
+
+ writeInt(MAGIC_LOCAL_FILE_HEADER);
+ writeShort(VERSION);
+ writeShort(GENERAL_PURPOSE_FLAG);
+ writeShort(compressed ? METHOD_COMPRESSED : METHOD_UNCOMPRESSED);
+ writeInt(modificationTime);
+ writeInt(crc);
+ writeInt(compressedSize);
+ writeInt(uncompressedSize);
+
+ byte[] nameBytes = StringUtil.getUtf8Bytes(name);
+ int nameLength = nameBytes.length;
+ int extraFieldLength = extraField == null ? 0 : extraField.length;
+
+ writeShort(nameLength);
+ writeShort(extraFieldLength);
+
+ outputStream.write(nameBytes);
+
+ if (extraField != null)
+ {
+ outputStream.write(extraField);
+ }
+ }
+
+
+ /**
+ * Writes the file header for the central directory to the main zip
+ * output stream.
+ */
+ public void writeCentralDirectoryFileHeader() throws IOException
+ {
+ if (DEBUG)
+ {
+ System.out.println("ZipOutput.writeCentralDirectoryFileHeader ["+name+"] (compressed = "+compressed+", offset = "+offset+", "+compressedSize+"/"+uncompressedSize+" bytes)");
+ }
+
+ writeInt(MAGIC_CENTRAL_DIRECTORY_FILE_HEADER);
+ writeShort(VERSION); // Creation version.
+ writeShort(VERSION); // Extraction Version.
+ writeShort(GENERAL_PURPOSE_FLAG);
+ writeShort(compressed ? METHOD_COMPRESSED : METHOD_UNCOMPRESSED);
+ writeInt(modificationTime);
+ writeInt(crc);
+ writeInt(compressedSize);
+ writeInt(uncompressedSize);
+
+ byte[] nameBytes = StringUtil.getUtf8Bytes(name);
+ byte[] commentBytes = comment == null ? null :
+ StringUtil.getUtf8Bytes(comment);
+
+ writeShort(nameBytes.length);
+ writeShort(extraField == null ? 0 : extraField.length);
+ writeShort(commentBytes == null ? 0 : commentBytes.length);
+ writeShort(0); // Disk number of file start.
+ writeShort(0); // Internal file attributes.
+ writeInt(0); // External file attributes.
+ writeInt(offset);
+ outputStream.write(nameBytes);
+ if (extraField != null)
+ {
+ outputStream.write(extraField);
+ }
+
+ if (commentBytes != null)
+ {
+ outputStream.write(commentBytes);
+ }
+ }
+
+
+ /**
+ * This OutputStream writes its uncompressed zip entry out to its zip
+ * output stream when it is closed.
+ */
+ private class UncompressedZipEntryOutputStream extends ByteArrayOutputStream
+ {
+ private CRC32 crc32 = new CRC32();
+
+
+ private UncompressedZipEntryOutputStream()
+ {
+ super(16 * 1024);
+ }
+
+
+ // Overridden methods for OutputStream.
+
+ public void write(int b)
+ {
+ super.write(b);
+
+ crc32.update(b);
+ }
+
+
+ //public void write(byte[] b) throws IOException
+ //{
+ // // The super implementation delegates to the method below.
+ // super.write(b);
+ //}
+
+
+ public void write(byte[] b, int off, int len)
+ {
+ super.write(b, off, len);
+
+ crc32.update(b, off, len);
+ }
+
+
+ public void close() throws IOException
+ {
+ super.close();
+
+ byte[] bytes = super.toByteArray();
+
+ offset = outputStream.size();
+ crc = (int)crc32.getValue();
+ compressedSize = bytes.length;
+ uncompressedSize = bytes.length;
+
+ writeLocalFileHeader();
+ outputStream.write(bytes);
+ }
+ }
+
+
+ /**
+ * This OutputStream writes its compressed zip entry out to its zip
+ * output stream when it is closed.
+ */
+ private class CompressedZipEntryOutputStream extends DeflaterOutputStream
+ {
+ private CRC32 crc32 = new CRC32();
+
+
+ private CompressedZipEntryOutputStream()
+ {
+ super(new ByteArrayOutputStream(16 * 1024),
+ new Deflater(Deflater.BEST_COMPRESSION, true),
+ 1024);
+ }
+
+
+ // Overridden methods for OutputStream.
+
+ //public void write(int b) throws IOException
+ //{
+ // // The super implementation delegates to the method below.
+ // super.write(b);
+ //}
+ //
+ //
+ //public void write(byte[] b) throws IOException
+ //{
+ // // The super implementation delegates to the method below.
+ // super.write(b);
+ //}
+
+
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ super.write(b, off, len);
+
+ crc32.update(b, off, len);
+ uncompressedSize += len;
+ }
+
+
+ public void close() throws IOException
+ {
+ // Make sure the memory is freed. [JDK-4797189]
+ super.finish();
+ super.def.end();
+ super.close();
+
+ ByteArrayOutputStream byteArrayOutputStream =
+ (ByteArrayOutputStream)super.out;
+
+ byte[] compressedBytes = byteArrayOutputStream.toByteArray();
+
+ offset = outputStream.size();
+ crc = (int)crc32.getValue();
+ compressedSize = compressedBytes.length;
+
+ writeLocalFileHeader();
+ outputStream.write(compressedBytes);
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Writes out a little-endian short value to the zip output stream.
+ */
+ private void writeShort(int value) throws IOException
+ {
+ outputStream.write(value);
+ outputStream.write(value >>> 8);
+ }
+
+
+ /**
+ * Writes out a little-endian int value to the zip output stream.
+ */
+ private void writeInt(int value) throws IOException
+ {
+ outputStream.write(value);
+ outputStream.write(value >>> 8);
+ outputStream.write(value >>> 16);
+ outputStream.write(value >>> 24);
+ }
+
+
+ /**
+ * Writes out a little-endian int value to the zip output stream.
+ */
+ private void writeInt(long value) throws IOException
+ {
+ outputStream.write((int)value);
+ outputStream.write((int)(value >>> 8));
+ outputStream.write((int)(value >>> 16));
+ outputStream.write((int)(value >>> 24));
+ }
+
+
+ /**
+ * Provides a simple test for this class, creating a zip file with the
+ * given name and a few aligned/compressed/uncompressed zip entries.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ ZipOutput output =
+ new ZipOutput(new FileOutputStream(args[0]), null, "Main file comment", 4);
+
+ PrintWriter printWriter1 =
+ new PrintWriter(output.createOutputStream("file1.txt", false, 0, new byte[] { 0x34, 0x12, 4, 0, 0x48, 0x65, 0x6c, 0x6c, 0x6f }, "Comment"));
+ printWriter1.println("This is file 1.");
+ printWriter1.println("Hello, world!");
+ printWriter1.close();
+
+ PrintWriter printWriter2 =
+ new PrintWriter(output.createOutputStream("file2.txt", true, 0, null, "Another comment"));
+ printWriter2.println("This is file 2.");
+ printWriter2.println("Hello, world!");
+ printWriter2.close();
+
+ PrintWriter printWriter3 =
+ new PrintWriter(output.createOutputStream("file3.txt", false, 0, null, "Last comment"));
+ printWriter3.println("This is file 3.");
+ printWriter3.println("Hello, world!");
+ printWriter3.close();
+
+ output.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/io/package.html b/core/src/proguard/io/package.html
similarity index 100%
rename from src/proguard/io/package.html
rename to core/src/proguard/io/package.html
diff --git a/src/proguard/obfuscate/AttributeShrinker.java b/core/src/proguard/obfuscate/AttributeShrinker.java
similarity index 98%
rename from src/proguard/obfuscate/AttributeShrinker.java
rename to core/src/proguard/obfuscate/AttributeShrinker.java
index 1916797..fdc3d92 100644
--- a/src/proguard/obfuscate/AttributeShrinker.java
+++ b/core/src/proguard/obfuscate/AttributeShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/AttributeUsageMarker.java b/core/src/proguard/obfuscate/AttributeUsageMarker.java
similarity index 97%
rename from src/proguard/obfuscate/AttributeUsageMarker.java
rename to core/src/proguard/obfuscate/AttributeUsageMarker.java
index 45b7fab..71179f0 100644
--- a/src/proguard/obfuscate/AttributeUsageMarker.java
+++ b/core/src/proguard/obfuscate/AttributeUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/ClassObfuscator.java b/core/src/proguard/obfuscate/ClassObfuscator.java
similarity index 99%
rename from src/proguard/obfuscate/ClassObfuscator.java
rename to core/src/proguard/obfuscate/ClassObfuscator.java
index bafe1ff..accee73 100644
--- a/src/proguard/obfuscate/ClassObfuscator.java
+++ b/core/src/proguard/obfuscate/ClassObfuscator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/ClassRenamer.java b/core/src/proguard/obfuscate/ClassRenamer.java
similarity index 98%
rename from src/proguard/obfuscate/ClassRenamer.java
rename to core/src/proguard/obfuscate/ClassRenamer.java
index 47a6568..e91b074 100644
--- a/src/proguard/obfuscate/ClassRenamer.java
+++ b/core/src/proguard/obfuscate/ClassRenamer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/DictionaryNameFactory.java b/core/src/proguard/obfuscate/DictionaryNameFactory.java
similarity index 54%
rename from src/proguard/obfuscate/DictionaryNameFactory.java
rename to core/src/proguard/obfuscate/DictionaryNameFactory.java
index 59fa69b..4625d6c 100644
--- a/src/proguard/obfuscate/DictionaryNameFactory.java
+++ b/core/src/proguard/obfuscate/DictionaryNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
package proguard.obfuscate;
import java.io.*;
+import java.net.URL;
import java.util.*;
/**
@@ -41,6 +42,40 @@ public class DictionaryNameFactory implements NameFactory
private int index = 0;
+ /**
+ * Creates a new DictionaryNameFactory.
+ * @param url the URL from which the names can be read.
+ * @param nameFactory the name factory from which names will be retrieved
+ * if the list of read names has been exhausted.
+ */
+ public DictionaryNameFactory(URL url,
+ NameFactory nameFactory) throws IOException
+ {
+ this(url, true, nameFactory);
+ }
+
+
+ /**
+ * Creates a new DictionaryNameFactory.
+ * @param url the URL from which the names can be read.
+ * @param validJavaIdentifiers specifies whether the produced names should
+ * be valid Java identifiers.
+ * @param nameFactory the name factory from which names will be
+ * retrieved if the list of read names has been
+ * exhausted.
+ */
+ public DictionaryNameFactory(URL url,
+ boolean validJavaIdentifiers,
+ NameFactory nameFactory) throws IOException
+ {
+ this (new BufferedReader(
+ new InputStreamReader(
+ url.openStream(), "UTF-8")),
+ validJavaIdentifiers,
+ nameFactory);
+ }
+
+
/**
* Creates a new DictionaryNameFactory.
* @param file the file from which the names can be read.
@@ -49,12 +84,63 @@ public class DictionaryNameFactory implements NameFactory
*/
public DictionaryNameFactory(File file,
NameFactory nameFactory) throws IOException
+ {
+ this(file, true, nameFactory);
+ }
+
+
+ /**
+ * Creates a new DictionaryNameFactory.
+ * @param file the file from which the names can be read.
+ * @param validJavaIdentifiers specifies whether the produced names should
+ * be valid Java identifiers.
+ * @param nameFactory the name factory from which names will be
+ * retrieved if the list of read names has been
+ * exhausted.
+ */
+ public DictionaryNameFactory(File file,
+ boolean validJavaIdentifiers,
+ NameFactory nameFactory) throws IOException
+ {
+ this (new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(file), "UTF-8")),
+ validJavaIdentifiers,
+ nameFactory);
+ }
+
+
+ /**
+ * Creates a new DictionaryNameFactory.
+ * @param reader the reader from which the names can be read. The
+ * reader is closed at the end.
+ * @param nameFactory the name factory from which names will be retrieved
+ * if the list of read names has been exhausted.
+ */
+ public DictionaryNameFactory(Reader reader,
+ NameFactory nameFactory) throws IOException
+ {
+ this(reader, true, nameFactory);
+ }
+
+
+ /**
+ * Creates a new DictionaryNameFactory.
+ * @param reader the reader from which the names can be read.
+ * The reader is closed at the end.
+ * @param validJavaIdentifiers specifies whether the produced names should
+ * be valid Java identifiers.
+ * @param nameFactory the name factory from which names will be
+ * retrieved if the list of read names has been
+ * exhausted.
+ */
+ public DictionaryNameFactory(Reader reader,
+ boolean validJavaIdentifiers,
+ NameFactory nameFactory) throws IOException
{
this.names = new ArrayList();
this.nameFactory = nameFactory;
- Reader reader = new FileReader(file);
-
try
{
StringBuffer buffer = new StringBuffer();
@@ -66,9 +152,13 @@ public DictionaryNameFactory(File file,
// Is it a valid identifier character?
if (c != -1 &&
- (buffer.length() == 0 ?
- Character.isJavaIdentifierStart((char)c) :
- Character.isJavaIdentifierPart((char)c)))
+ (validJavaIdentifiers ?
+ (buffer.length() == 0 ?
+ Character.isJavaIdentifierStart((char)c) :
+ Character.isJavaIdentifierPart((char)c)) :
+ (c != '\n' &&
+ c != '\r' &&
+ c != COMMENT_CHARACTER)))
{
// Append it to the current identifier.
buffer.append((char)c);
@@ -98,7 +188,7 @@ public DictionaryNameFactory(File file,
{
c = reader.read();
}
- while (c != -1 &&
+ while (c != -1 &&
c != '\n' &&
c != '\r');
}
@@ -176,10 +266,17 @@ public static void main(String[] args)
DictionaryNameFactory factory =
new DictionaryNameFactory(new File(args[0]), new SimpleNameFactory());
+ // For debugging, we're always using UTF-8 instead of the default
+ // character encoding, even for writing to the standard output.
+ PrintWriter out =
+ new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"));
+
for (int counter = 0; counter < 50; counter++)
{
- System.out.println("["+factory.nextName()+"]");
+ out.println("[" + factory.nextName() + "]");
}
+
+ out.flush();
}
catch (IOException ex)
{
diff --git a/src/proguard/obfuscate/MapCleaner.java b/core/src/proguard/obfuscate/MapCleaner.java
similarity index 96%
rename from src/proguard/obfuscate/MapCleaner.java
rename to core/src/proguard/obfuscate/MapCleaner.java
index 70bc4c3..df333ba 100644
--- a/src/proguard/obfuscate/MapCleaner.java
+++ b/core/src/proguard/obfuscate/MapCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MappingKeeper.java b/core/src/proguard/obfuscate/MappingKeeper.java
similarity index 99%
rename from src/proguard/obfuscate/MappingKeeper.java
rename to core/src/proguard/obfuscate/MappingKeeper.java
index 4025c1a..3933906 100644
--- a/src/proguard/obfuscate/MappingKeeper.java
+++ b/core/src/proguard/obfuscate/MappingKeeper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MappingPrinter.java b/core/src/proguard/obfuscate/MappingPrinter.java
similarity index 99%
rename from src/proguard/obfuscate/MappingPrinter.java
rename to core/src/proguard/obfuscate/MappingPrinter.java
index 50f6e49..f056ce6 100644
--- a/src/proguard/obfuscate/MappingPrinter.java
+++ b/core/src/proguard/obfuscate/MappingPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MappingProcessor.java b/core/src/proguard/obfuscate/MappingProcessor.java
similarity index 98%
rename from src/proguard/obfuscate/MappingProcessor.java
rename to core/src/proguard/obfuscate/MappingProcessor.java
index d7494ca..8658ff1 100644
--- a/src/proguard/obfuscate/MappingProcessor.java
+++ b/core/src/proguard/obfuscate/MappingProcessor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MappingReader.java b/core/src/proguard/obfuscate/MappingReader.java
similarity index 99%
rename from src/proguard/obfuscate/MappingReader.java
rename to core/src/proguard/obfuscate/MappingReader.java
index bb672bf..802532f 100644
--- a/src/proguard/obfuscate/MappingReader.java
+++ b/core/src/proguard/obfuscate/MappingReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberNameCleaner.java b/core/src/proguard/obfuscate/MemberNameCleaner.java
similarity index 97%
rename from src/proguard/obfuscate/MemberNameCleaner.java
rename to core/src/proguard/obfuscate/MemberNameCleaner.java
index f069100..35e48b4 100644
--- a/src/proguard/obfuscate/MemberNameCleaner.java
+++ b/core/src/proguard/obfuscate/MemberNameCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberNameCollector.java b/core/src/proguard/obfuscate/MemberNameCollector.java
similarity index 98%
rename from src/proguard/obfuscate/MemberNameCollector.java
rename to core/src/proguard/obfuscate/MemberNameCollector.java
index fcb6277..90c6115 100644
--- a/src/proguard/obfuscate/MemberNameCollector.java
+++ b/core/src/proguard/obfuscate/MemberNameCollector.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberNameConflictFixer.java b/core/src/proguard/obfuscate/MemberNameConflictFixer.java
similarity index 99%
rename from src/proguard/obfuscate/MemberNameConflictFixer.java
rename to core/src/proguard/obfuscate/MemberNameConflictFixer.java
index 44a43cb..a624959 100644
--- a/src/proguard/obfuscate/MemberNameConflictFixer.java
+++ b/core/src/proguard/obfuscate/MemberNameConflictFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberNameFilter.java b/core/src/proguard/obfuscate/MemberNameFilter.java
similarity index 98%
rename from src/proguard/obfuscate/MemberNameFilter.java
rename to core/src/proguard/obfuscate/MemberNameFilter.java
index a7791b9..0e381a8 100644
--- a/src/proguard/obfuscate/MemberNameFilter.java
+++ b/core/src/proguard/obfuscate/MemberNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberObfuscator.java b/core/src/proguard/obfuscate/MemberObfuscator.java
similarity index 99%
rename from src/proguard/obfuscate/MemberObfuscator.java
rename to core/src/proguard/obfuscate/MemberObfuscator.java
index 792e794..02093da 100644
--- a/src/proguard/obfuscate/MemberObfuscator.java
+++ b/core/src/proguard/obfuscate/MemberObfuscator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MemberSpecialNameFilter.java b/core/src/proguard/obfuscate/MemberSpecialNameFilter.java
similarity index 98%
rename from src/proguard/obfuscate/MemberSpecialNameFilter.java
rename to core/src/proguard/obfuscate/MemberSpecialNameFilter.java
index 99949e6..7af71b7 100644
--- a/src/proguard/obfuscate/MemberSpecialNameFilter.java
+++ b/core/src/proguard/obfuscate/MemberSpecialNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/MultiMappingProcessor.java b/core/src/proguard/obfuscate/MultiMappingProcessor.java
similarity index 98%
rename from src/proguard/obfuscate/MultiMappingProcessor.java
rename to core/src/proguard/obfuscate/MultiMappingProcessor.java
index 0c18ade..5e4f6ea 100644
--- a/src/proguard/obfuscate/MultiMappingProcessor.java
+++ b/core/src/proguard/obfuscate/MultiMappingProcessor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/NameFactory.java b/core/src/proguard/obfuscate/NameFactory.java
similarity index 95%
rename from src/proguard/obfuscate/NameFactory.java
rename to core/src/proguard/obfuscate/NameFactory.java
index dd5e459..dd307c1 100644
--- a/src/proguard/obfuscate/NameFactory.java
+++ b/core/src/proguard/obfuscate/NameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/NameFactoryResetter.java b/core/src/proguard/obfuscate/NameFactoryResetter.java
similarity index 96%
rename from src/proguard/obfuscate/NameFactoryResetter.java
rename to core/src/proguard/obfuscate/NameFactoryResetter.java
index 96a92bf..e2b982a 100644
--- a/src/proguard/obfuscate/NameFactoryResetter.java
+++ b/core/src/proguard/obfuscate/NameFactoryResetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/NameMarker.java b/core/src/proguard/obfuscate/NameMarker.java
similarity index 98%
rename from src/proguard/obfuscate/NameMarker.java
rename to core/src/proguard/obfuscate/NameMarker.java
index 6afe300..a690299 100644
--- a/src/proguard/obfuscate/NameMarker.java
+++ b/core/src/proguard/obfuscate/NameMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/NumericNameFactory.java b/core/src/proguard/obfuscate/NumericNameFactory.java
similarity index 95%
rename from src/proguard/obfuscate/NumericNameFactory.java
rename to core/src/proguard/obfuscate/NumericNameFactory.java
index d6609d3..62e663f 100644
--- a/src/proguard/obfuscate/NumericNameFactory.java
+++ b/core/src/proguard/obfuscate/NumericNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/Obfuscator.java b/core/src/proguard/obfuscate/Obfuscator.java
similarity index 85%
rename from src/proguard/obfuscate/Obfuscator.java
rename to core/src/proguard/obfuscate/Obfuscator.java
index 4b1f561..26fc28e 100644
--- a/src/proguard/obfuscate/Obfuscator.java
+++ b/core/src/proguard/obfuscate/Obfuscator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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 @@
import proguard.*;
import proguard.classfile.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.visitor.AllConstantVisitor;
+import proguard.classfile.constant.visitor.*;
import proguard.classfile.editor.*;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
@@ -84,12 +84,12 @@ public void execute(ClassPool programClassPool,
// Create a visitor for marking the seeds.
NameMarker nameMarker = new NameMarker();
ClassPoolVisitor classPoolvisitor =
- ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
- nameMarker,
- nameMarker,
- false,
- false,
- true);
+ new KeepClassSpecificationVisitorFactory(false, false, true)
+ .createClassPoolVisitor(configuration.keep,
+ nameMarker,
+ nameMarker,
+ nameMarker,
+ null);
// Mark the seeds.
programClassPool.accept(classPoolvisitor);
libraryClassPool.accept(classPoolvisitor);
@@ -98,15 +98,38 @@ public void execute(ClassPool programClassPool,
libraryClassPool.classesAccept(nameMarker);
libraryClassPool.classesAccept(new AllMemberVisitor(nameMarker));
- // We also keep the names of all methods of classes that are returned
- // by dynamic method invocations. They may return dynamic
- // implementations of interfaces. The method names then have to match
- // with the invoke dynamic names.
+ // We also keep the names of the abstract methods of functional
+ // interfaces referenced from bootstrap method arguments (additional
+ // interfaces with LambdaMetafactory.altMetafactory).
+ // The functional method names have to match the names in the
+ // dynamic method invocations with LambdaMetafactory.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllAttributeVisitor(
+ new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
+ new AllBootstrapMethodInfoVisitor(
+ new AllBootstrapMethodArgumentVisitor(
+ new ConstantTagFilter(ClassConstants.CONSTANT_Class,
+ new ReferencedClassVisitor(
+ new FunctionalInterfaceFilter(
+ new ClassHierarchyTraveler(true, false, true, false,
+ new AllMethodVisitor(
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ nameMarker))))))))))));
+
+ // We also keep the names of the abstract methods of functional
+ // interfaces that are returned by dynamic method invocations.
+ // The functional method names have to match the names in the
+ // dynamic method invocations with LambdaMetafactory.
programClassPool.classesAccept(
new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
new AllConstantVisitor(
new DynamicReturnedClassVisitor(
- new AllMemberVisitor(nameMarker)))));
+ new FunctionalInterfaceFilter(
+ new ClassHierarchyTraveler(true, false, true, false,
+ new AllMethodVisitor(
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ nameMarker))))))));
// Mark attributes that have to be kept.
AttributeVisitor attributeUsageMarker =
@@ -200,11 +223,11 @@ public void execute(ClassPool programClassPool,
// Come up with new names for all class members.
NameFactory nameFactory = new SimpleNameFactory();
-
if (configuration.obfuscationDictionary != null)
{
- nameFactory = new DictionaryNameFactory(configuration.obfuscationDictionary,
- nameFactory);
+ nameFactory =
+ new DictionaryNameFactory(configuration.obfuscationDictionary,
+ nameFactory);
}
WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn);
@@ -232,8 +255,7 @@ public void execute(ClassPool programClassPool,
{
// Come up with new names for all non-private class members.
programClassPool.classesAccept(
- new MultiClassVisitor(new ClassVisitor[]
- {
+ new MultiClassVisitor(
// Collect all private member names in this class and down
// the hierarchy.
new ClassHierarchyTraveler(true, false, false, true,
@@ -242,7 +264,8 @@ public void execute(ClassPool programClassPool,
new MemberNameCollector(configuration.overloadAggressively,
descriptorMap)))),
- // Collect all non-private member names anywhere in the hierarchy.
+ // Collect all non-private member names anywhere in the
+ // hierarchy.
new ClassHierarchyTraveler(true, true, true, true,
new AllMemberVisitor(
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
@@ -258,12 +281,11 @@ public void execute(ClassPool programClassPool,
// Clear the collected names.
new MapCleaner(descriptorMap)
- }));
+ ));
// Come up with new names for all private class members.
programClassPool.classesAccept(
- new MultiClassVisitor(new ClassVisitor[]
- {
+ new MultiClassVisitor(
// Collect all member names in this class.
new AllMemberVisitor(
new MemberNameCollector(configuration.overloadAggressively,
@@ -289,6 +311,18 @@ public void execute(ClassPool programClassPool,
new MemberNameCollector(configuration.overloadAggressively,
descriptorMap))))),
+ // Collect all default method names from interfaces of
+ // any classes down the hierarchy.
+ // This is an extended version of the above problem
+ // (Sun/Oracle bug #802464, ProGuard bug #662, and
+ // ProGuard test #2060).
+ new ClassHierarchyTraveler(false, false, false, true,
+ new ClassHierarchyTraveler(false, false, true, false,
+ new AllMethodVisitor(
+ new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT | ClassConstants.ACC_STATIC,
+ new MemberNameCollector(configuration.overloadAggressively,
+ descriptorMap))))),
+
// Assign new names to all private members in this class.
new AllMemberVisitor(
new MemberAccessFilter(ClassConstants.ACC_PRIVATE, 0,
@@ -298,7 +332,7 @@ public void execute(ClassPool programClassPool,
// Clear the collected names.
new MapCleaner(descriptorMap)
- }));
+ ));
}
// Some class members may have ended up with conflicting names.
@@ -324,8 +358,7 @@ public void execute(ClassPool programClassPool,
// Replace conflicting non-private member names with special names.
programClassPool.classesAccept(
- new MultiClassVisitor(new ClassVisitor[]
- {
+ new MultiClassVisitor(
// Collect all private member names in this class and down
// the hierarchy.
new ClassHierarchyTraveler(true, false, false, true,
@@ -356,13 +389,12 @@ public void execute(ClassPool programClassPool,
// Clear the collected names.
new MapCleaner(descriptorMap)
- }));
+ ));
// Replace conflicting private member names with special names.
// This is only possible if those names were kept or mapped.
programClassPool.classesAccept(
- new MultiClassVisitor(new ClassVisitor[]
- {
+ new MultiClassVisitor(
// Collect all member names in this class.
new AllMemberVisitor(
new MemberNameCollector(configuration.overloadAggressively,
@@ -388,7 +420,7 @@ public void execute(ClassPool programClassPool,
// Clear the collected names.
new MapCleaner(descriptorMap)
- }));
+ ));
// Print out any warnings about member name conflicts.
int warningCount = warningPrinter.getWarningCount();
@@ -434,6 +466,11 @@ public void execute(ClassPool programClassPool,
}
}
+ if (configuration.addConfigurationDebugging)
+ {
+ programClassPool.classesAccept(new RenamedFlagSetter());
+ }
+
// Actually apply the new names.
programClassPool.classesAccept(new ClassRenamer());
libraryClassPool.classesAccept(new ClassRenamer());
diff --git a/src/proguard/obfuscate/ParameterNameMarker.java b/core/src/proguard/obfuscate/ParameterNameMarker.java
similarity index 98%
rename from src/proguard/obfuscate/ParameterNameMarker.java
rename to core/src/proguard/obfuscate/ParameterNameMarker.java
index 6070715..49b2017 100644
--- a/src/proguard/obfuscate/ParameterNameMarker.java
+++ b/core/src/proguard/obfuscate/ParameterNameMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/obfuscate/PrefixingNameFactory.java b/core/src/proguard/obfuscate/PrefixingNameFactory.java
new file mode 100644
index 0000000..b135a94
--- /dev/null
+++ b/core/src/proguard/obfuscate/PrefixingNameFactory.java
@@ -0,0 +1,60 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.obfuscate;
+
+
+/**
+ * NameFactory that prepends the names of the wrapped NameFactory with
+ * a fixed prefix.
+ *
+ * @author Johan Leys
+ */
+public class PrefixingNameFactory implements NameFactory
+{
+ private final NameFactory delegateNameFactory;
+ private final String prefix;
+
+
+ /**
+ * Creates a new PrefixingNameFactory.
+ * @param delegateNameFactory the wrapped NameFactory.
+ * @param prefix the prefix to add to all generated names.
+ */
+ public PrefixingNameFactory(NameFactory delegateNameFactory,
+ String prefix)
+ {
+ this.delegateNameFactory = delegateNameFactory;
+ this.prefix = prefix;
+ }
+
+
+ // Implementations for NameFactory.
+
+ public String nextName()
+ {
+ return prefix + delegateNameFactory.nextName();
+ }
+
+ public void reset()
+ {
+ delegateNameFactory.reset();
+ }
+}
diff --git a/core/src/proguard/obfuscate/RenamedFlagSetter.java b/core/src/proguard/obfuscate/RenamedFlagSetter.java
new file mode 100644
index 0000000..dc77cde
--- /dev/null
+++ b/core/src/proguard/obfuscate/RenamedFlagSetter.java
@@ -0,0 +1,73 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassVisitor sets the ACC_RENAMED flag for classes or class members
+ * that have been renamed.
+ *
+ * @author Johan Leys
+ */
+public class RenamedFlagSetter
+extends SimplifiedVisitor
+implements ClassVisitor,
+
+ // Implementation interfaces.
+ MemberVisitor,
+ AttributeVisitor
+{
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ String oldName = programClass.getName();
+ String newName = ClassObfuscator.newClassName(programClass);
+
+ if (newName != null && !oldName.equals(newName))
+ {
+ programClass.u2accessFlags |= ClassConstants.ACC_RENAMED;
+ }
+
+ // Print out the class members.
+ programClass.fieldsAccept(this);
+ programClass.methodsAccept(this);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
+ {
+ String oldName = programMember.getName(programClass);
+ String newName = MemberObfuscator.newMemberName(programMember);
+
+ if (newName != null && !newName.equals(oldName))
+ {
+ programMember.u2accessFlags |= ClassConstants.ACC_RENAMED;
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/SimpleNameFactory.java b/core/src/proguard/obfuscate/SimpleNameFactory.java
similarity index 98%
rename from src/proguard/obfuscate/SimpleNameFactory.java
rename to core/src/proguard/obfuscate/SimpleNameFactory.java
index 1dc9d62..b0b5af7 100644
--- a/src/proguard/obfuscate/SimpleNameFactory.java
+++ b/core/src/proguard/obfuscate/SimpleNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/SourceFileRenamer.java b/core/src/proguard/obfuscate/SourceFileRenamer.java
similarity index 98%
rename from src/proguard/obfuscate/SourceFileRenamer.java
rename to core/src/proguard/obfuscate/SourceFileRenamer.java
index 7e2d8d7..c9a4572 100644
--- a/src/proguard/obfuscate/SourceFileRenamer.java
+++ b/core/src/proguard/obfuscate/SourceFileRenamer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/obfuscate/SpecialNameFactory.java b/core/src/proguard/obfuscate/SpecialNameFactory.java
similarity index 97%
rename from src/proguard/obfuscate/SpecialNameFactory.java
rename to core/src/proguard/obfuscate/SpecialNameFactory.java
index 0e7f56b..c421a2b 100644
--- a/src/proguard/obfuscate/SpecialNameFactory.java
+++ b/core/src/proguard/obfuscate/SpecialNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/obfuscate/UniqueMemberNameFactory.java b/core/src/proguard/obfuscate/UniqueMemberNameFactory.java
new file mode 100644
index 0000000..01a0361
--- /dev/null
+++ b/core/src/proguard/obfuscate/UniqueMemberNameFactory.java
@@ -0,0 +1,93 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.obfuscate;
+
+import proguard.classfile.Clazz;
+
+/**
+ * NameFactory which only generates names that don't exist yet as members
+ * on the class for which it is created.
+ *
+ * @author Johan Leys
+ */
+public class UniqueMemberNameFactory implements NameFactory
+{
+ private static final String INJECTED_MEMBER_PREFIX = "$$";
+
+ private final NameFactory delegateNameFactory;
+ private final Clazz clazz;
+
+
+ /**
+ * Utility for creating a new NameFactory that can generate names for injected
+ * members: the generated names are unique within the given class, and don't
+ * clash with non-injected members of its super classes.
+ *
+ * @param clazz the class for which to generate a NameFactory.
+ * @return the new NameFactory instance.
+ */
+ public static UniqueMemberNameFactory newInjectedMemberNameFactory(Clazz clazz)
+ {
+ return new UniqueMemberNameFactory(
+ new PrefixingNameFactory(
+ new SimpleNameFactory(), INJECTED_MEMBER_PREFIX), clazz);
+ }
+
+
+ /**
+ * Creates a new UniqueMemberNameFactory.
+ * @param delegateNameFactory the delegate NameFactory, used for generating
+ * new candidate names.
+ * @param clazz the class in which to check for existing
+ * member names.
+ */
+ public UniqueMemberNameFactory(NameFactory delegateNameFactory,
+ Clazz clazz)
+ {
+ this.delegateNameFactory = delegateNameFactory;
+ this.clazz = clazz;
+ }
+
+
+ // Implementations for NameFactory.
+
+ public String nextName()
+ {
+ String name;
+
+ // Check if the name doesn't exist yet. We don't have additional
+ // descriptor information, so we can only search on the name.
+ do
+ {
+ name = delegateNameFactory.nextName();
+ }
+ while (clazz.findField(name, null) != null ||
+ clazz.findMethod(name, null) != null);
+
+ return name;
+ }
+
+
+ public void reset()
+ {
+ delegateNameFactory.reset();
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/obfuscate/package.html b/core/src/proguard/obfuscate/package.html
similarity index 100%
rename from src/proguard/obfuscate/package.html
rename to core/src/proguard/obfuscate/package.html
diff --git a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java b/core/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
similarity index 98%
rename from src/proguard/optimize/BootstrapMethodArgumentShrinker.java
rename to core/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
index 5507ed9..cd094db 100644
--- a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
+++ b/core/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/ChangedCodePrinter.java b/core/src/proguard/optimize/ChangedCodePrinter.java
similarity index 95%
rename from src/proguard/optimize/ChangedCodePrinter.java
rename to core/src/proguard/optimize/ChangedCodePrinter.java
index 71efd02..c3fe243 100644
--- a/src/proguard/optimize/ChangedCodePrinter.java
+++ b/core/src/proguard/optimize/ChangedCodePrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +23,7 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.module.*;
import proguard.classfile.attribute.preverification.*;
import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.util.ClassUtil;
@@ -83,6 +84,24 @@ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute
}
+ public void visitModuleAttribute(Clazz clazz, ModuleAttribute moduleAttribute)
+ {
+ attributeVisitor.visitModuleAttribute(clazz, moduleAttribute);
+ }
+
+
+ public void visitModuleMainClassAttribute(Clazz clazz, ModuleMainClassAttribute moduleMainClassAttribute)
+ {
+ attributeVisitor.visitModuleMainClassAttribute(clazz, moduleMainClassAttribute);
+ }
+
+
+ public void visitModulePackagesAttribute(Clazz clazz, ModulePackagesAttribute modulePackagesAttribute)
+ {
+ attributeVisitor.visitModulePackagesAttribute(clazz, modulePackagesAttribute);
+ }
+
+
public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
{
attributeVisitor.visitDeprecatedAttribute(clazz, deprecatedAttribute);
diff --git a/src/proguard/optimize/ConstantMemberFilter.java b/core/src/proguard/optimize/ConstantMemberFilter.java
similarity index 97%
rename from src/proguard/optimize/ConstantMemberFilter.java
rename to core/src/proguard/optimize/ConstantMemberFilter.java
index 640ddc0..ebe3246 100644
--- a/src/proguard/optimize/ConstantMemberFilter.java
+++ b/core/src/proguard/optimize/ConstantMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/ConstantParameterFilter.java
similarity index 97%
rename from src/proguard/optimize/ConstantParameterFilter.java
rename to core/src/proguard/optimize/ConstantParameterFilter.java
index af16d9a..6009cfc 100644
--- a/src/proguard/optimize/ConstantParameterFilter.java
+++ b/core/src/proguard/optimize/ConstantParameterFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/DuplicateInitializerFixer.java b/core/src/proguard/optimize/DuplicateInitializerFixer.java
similarity index 84%
rename from src/proguard/optimize/DuplicateInitializerFixer.java
rename to core/src/proguard/optimize/DuplicateInitializerFixer.java
index a255343..8215355 100644
--- a/src/proguard/optimize/DuplicateInitializerFixer.java
+++ b/core/src/proguard/optimize/DuplicateInitializerFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,6 +27,7 @@
import proguard.classfile.editor.ConstantPoolEditor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
+import proguard.optimize.info.*;
/**
* This MemberVisitor adds an additional parameter to the duplicate
@@ -37,7 +38,11 @@ public class DuplicateInitializerFixer
implements MemberVisitor,
AttributeVisitor
{
+ //*
private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("dif") != null;
+ //*/
private static final char[] TYPES = new char[]
{
@@ -89,6 +94,8 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
if (KeepMarker.isKept(programMethod))
{
// Fix the other initializer.
+ // We'll just proceed if it is being kept as well;
+ // apparently the descriptor types didn't matter so much.
programMethod = (ProgramMethod)similarMethod;
}
@@ -132,6 +139,25 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
programMethod.attributesAccept(programClass,
this);
+ // Update the optimization info.
+ MethodOptimizationInfo methodOptimizationInfo =
+ ProgramMethodOptimizationInfo.getMethodOptimizationInfo(programMethod);
+ if (methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ProgramMethodOptimizationInfo programMethodOptimizationInfo =
+ (ProgramMethodOptimizationInfo)methodOptimizationInfo;
+
+ int parameterCount =
+ ClassUtil.internalMethodParameterCount(newDescriptor,
+ programMethod.getAccessFlags());
+ programMethodOptimizationInfo.insertParameter(parameterCount - 1);
+
+ int parameterSize =
+ programMethodOptimizationInfo.getParameterSize();
+ programMethodOptimizationInfo.setParameterSize(parameterSize + 1);
+ programMethodOptimizationInfo.setParameterUsed(parameterSize);
+ }
+
// Visit the initializer, if required.
if (extraFixedInitializerVisitor != null)
{
@@ -212,4 +238,4 @@ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, Pa
parameterAnnotationsAttribute.parameterAnnotations = annotations;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java b/core/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
similarity index 99%
rename from src/proguard/optimize/DuplicateInitializerInvocationFixer.java
rename to core/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
index a080208..c4acbe2 100644
--- a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
+++ b/core/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/KeepMarker.java b/core/src/proguard/optimize/KeepMarker.java
new file mode 100644
index 0000000..af5ab7c
--- /dev/null
+++ b/core/src/proguard/optimize/KeepMarker.java
@@ -0,0 +1,134 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.optimize.info.*;
+
+/**
+ * This ClassVisitor, MemberVisitor and
+ * AttributeVisitor marks classes, class members and
+ * code attributes it visits. The marked elements will remain
+ * unchanged as necessary in the optimization step.
+ *
+ * @see NoSideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class KeepMarker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor,
+ AttributeVisitor
+{
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ ClassOptimizationInfo.setClassOptimizationInfo(programClass);
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ ClassOptimizationInfo.setClassOptimizationInfo(libraryClass);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ FieldOptimizationInfo.setFieldOptimizationInfo(programClass, programField);
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ MethodOptimizationInfo.setMethodOptimizationInfo(programClass, programMethod);
+ }
+
+
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
+ {
+ FieldOptimizationInfo.setFieldOptimizationInfo(libraryClass, libraryField);
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ MethodOptimizationInfo.setMethodOptimizationInfo(libraryClass, libraryMethod);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ CodeAttributeOptimizationInfo.setCodeAttributeOptimizationInfo(codeAttribute);
+ }
+
+
+ // Small utility methods.
+
+ public static boolean isKept(Clazz clazz)
+ {
+ ClassOptimizationInfo info =
+ ClassOptimizationInfo.getClassOptimizationInfo(clazz);
+
+ return info != null &&
+ info.isKept();
+ }
+
+ public static boolean isKept(Field field)
+ {
+ FieldOptimizationInfo info =
+ FieldOptimizationInfo.getFieldOptimizationInfo(field);
+
+ return info != null &&
+ info.isKept();
+ }
+
+ public static boolean isKept(Method method)
+ {
+ MethodOptimizationInfo info =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ return info != null &&
+ info.isKept();
+ }
+
+ public static boolean isKept(CodeAttribute codeAttribute)
+ {
+ CodeAttributeOptimizationInfo info =
+ CodeAttributeOptimizationInfo.getCodeAttributeOptimizationInfo(codeAttribute);
+
+ return info != null &&
+ info.isKept();
+ }
+
+}
diff --git a/core/src/proguard/optimize/KeptClassFilter.java b/core/src/proguard/optimize/KeptClassFilter.java
new file mode 100644
index 0000000..93e8799
--- /dev/null
+++ b/core/src/proguard/optimize/KeptClassFilter.java
@@ -0,0 +1,94 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This ClassVisitor delegates its visits to one of two ClassVisitor's,
+ * depending on whether the visited class is kept or not.
+ *
+ * @see KeepMarker
+ *
+ * @author Eric Lafortune
+ */
+public class KeptClassFilter
+implements ClassVisitor
+{
+ private final ClassVisitor acceptedVisitor;
+ private final ClassVisitor rejectedVisitor;
+
+
+ /**
+ * Creates a new KeptClassFilter.
+ *
+ * @param acceptedVisitor the class visitor to which accepted (kept)
+ * classes will be delegated.
+ */
+ public KeptClassFilter(ClassVisitor acceptedVisitor)
+ {
+ this(acceptedVisitor, null);
+ }
+
+ /**
+ * Creates a new KeptClassFilter.
+ *
+ * @param acceptedVisitor the class visitor to which accepted (kept)
+ * classes will be delegated.
+ * @param rejectedVisitor the class visitor to which rejected (unkept)
+ * classes will be delegated.
+ */
+ public KeptClassFilter(ClassVisitor acceptedVisitor,
+ ClassVisitor rejectedVisitor)
+ {
+ this.acceptedVisitor = acceptedVisitor;
+ this.rejectedVisitor = rejectedVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ ClassVisitor delegateVisitor = selectVisitor(programClass);
+ if (delegateVisitor != null) {
+ delegateVisitor.visitProgramClass(programClass);
+ }
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ ClassVisitor delegateVisitor = selectVisitor(libraryClass);
+ if (delegateVisitor != null) {
+ delegateVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private ClassVisitor selectVisitor(Clazz clazz)
+ {
+ return KeepMarker.isKept(clazz) ? acceptedVisitor : rejectedVisitor;
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/KeptMemberFilter.java b/core/src/proguard/optimize/KeptMemberFilter.java
similarity index 97%
rename from src/proguard/optimize/KeptMemberFilter.java
rename to core/src/proguard/optimize/KeptMemberFilter.java
index 7c8eb7c..7ce7311 100644
--- a/src/proguard/optimize/KeptMemberFilter.java
+++ b/core/src/proguard/optimize/KeptMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/MemberDescriptorSpecializer.java
similarity index 98%
rename from src/proguard/optimize/MemberDescriptorSpecializer.java
rename to core/src/proguard/optimize/MemberDescriptorSpecializer.java
index ed3a6ec..6438d9c 100644
--- a/src/proguard/optimize/MemberDescriptorSpecializer.java
+++ b/core/src/proguard/optimize/MemberDescriptorSpecializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/MethodDescriptorShrinker.java b/core/src/proguard/optimize/MethodDescriptorShrinker.java
similarity index 97%
rename from src/proguard/optimize/MethodDescriptorShrinker.java
rename to core/src/proguard/optimize/MethodDescriptorShrinker.java
index b68877f..99de95a 100644
--- a/src/proguard/optimize/MethodDescriptorShrinker.java
+++ b/core/src/proguard/optimize/MethodDescriptorShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,9 +28,6 @@
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
@@ -47,7 +44,11 @@ public class MethodDescriptorShrinker
implements MemberVisitor,
AttributeVisitor
{
+ //*
private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("mds") != null;
+ //*/
private final MemberVisitor extraMemberVisitor;
@@ -201,7 +202,7 @@ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, Pa
annotationIndex++;
- parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+ parameterIndex += ClassUtil.internalTypeSize(type);
}
// Update the number of parameters.
@@ -252,7 +253,7 @@ else if (DEBUG)
System.out.println(" Deleting parameter #"+parameterIndex+" ["+type+"]");
}
- parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+ parameterIndex += ClassUtil.internalTypeSize(type);
}
// Copy the return type.
@@ -317,7 +318,7 @@ private Clazz[] shrinkReferencedClasses(Method method,
referencedClassIndex += count;
}
- parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+ parameterIndex += ClassUtil.internalTypeSize(type);
}
// Copy the return type.
diff --git a/src/proguard/optimize/MethodStaticizer.java b/core/src/proguard/optimize/MethodStaticizer.java
similarity index 93%
rename from src/proguard/optimize/MethodStaticizer.java
rename to core/src/proguard/optimize/MethodStaticizer.java
index 0d87e62..b92e04c 100644
--- a/src/proguard/optimize/MethodStaticizer.java
+++ b/core/src/proguard/optimize/MethodStaticizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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;
import proguard.classfile.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.editor.MethodInvocationFixer;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
@@ -39,8 +38,7 @@
*/
public class MethodStaticizer
extends SimplifiedVisitor
-implements MemberVisitor,
- AttributeVisitor
+implements MemberVisitor
{
private final MemberVisitor extraStaticMemberVisitor;
diff --git a/src/proguard/optimize/OptimizationInfoClassFilter.java b/core/src/proguard/optimize/OptimizationInfoClassFilter.java
similarity index 83%
rename from src/proguard/optimize/OptimizationInfoClassFilter.java
rename to core/src/proguard/optimize/OptimizationInfoClassFilter.java
index 93bf62e..83dad93 100644
--- a/src/proguard/optimize/OptimizationInfoClassFilter.java
+++ b/core/src/proguard/optimize/OptimizationInfoClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,15 +21,16 @@
package proguard.optimize;
import proguard.classfile.*;
-import proguard.classfile.visitor.*;
-import proguard.optimize.info.ClassOptimizationInfo;
+import proguard.classfile.visitor.ClassVisitor;
+import proguard.optimize.info.*;
/**
* This ClassVisitor delegates its visits to another given
- * ClassVisitor, but only when the visited class has optimization
- * info.
+ * ClassVisitor, but only when the visited class has editable
+ * optimization info.
*
* @see ClassOptimizationInfo
+ * @see ProgramClassOptimizationInfo
* @author Eric Lafortune
*/
public class OptimizationInfoClassFilter
@@ -40,8 +41,8 @@ public class OptimizationInfoClassFilter
/**
* Creates a new OptimizationInfoClassFilter.
- * @param classVisitor the ClassVisitor to which visits
- * will be delegated.
+ * @param classVisitor the ClassVisitor to which visits will
+ * be delegated.
*/
public OptimizationInfoClassFilter(ClassVisitor classVisitor)
{
@@ -51,10 +52,11 @@ public OptimizationInfoClassFilter(ClassVisitor classVisitor)
// Implementations for ClassVisitor.
+
public void visitProgramClass(ProgramClass programClass)
{
- // Does the class have optimization info?
- if (ClassOptimizationInfo.getClassOptimizationInfo(programClass) != null)
+ // Does the field have optimization info?
+ if (ClassOptimizationInfo.getClassOptimizationInfo(programClass) instanceof ProgramClassOptimizationInfo)
{
classVisitor.visitProgramClass(programClass);
}
@@ -64,7 +66,7 @@ public void visitProgramClass(ProgramClass programClass)
public void visitLibraryClass(LibraryClass libraryClass)
{
// Does the class have optimization info?
- if (ClassOptimizationInfo.getClassOptimizationInfo(libraryClass) != null)
+ if (ClassOptimizationInfo.getClassOptimizationInfo(libraryClass) instanceof ProgramClassOptimizationInfo)
{
classVisitor.visitLibraryClass(libraryClass);
}
diff --git a/src/proguard/optimize/OptimizationInfoMemberFilter.java b/core/src/proguard/optimize/OptimizationInfoMemberFilter.java
similarity index 55%
rename from src/proguard/optimize/OptimizationInfoMemberFilter.java
rename to core/src/proguard/optimize/OptimizationInfoMemberFilter.java
index 950fcfa..1f90763 100644
--- a/src/proguard/optimize/OptimizationInfoMemberFilter.java
+++ b/core/src/proguard/optimize/OptimizationInfoMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +26,20 @@
/**
* This MemberVisitor delegates its visits to another given
- * MemberVisitor, but only when the visited member has optimization
- * info.
+ * MemberVisitor, but only when the visited member has editable
+ * optimization info.
*
* @see FieldOptimizationInfo
+ * @see ProgramFieldOptimizationInfo
* @see MethodOptimizationInfo
+ * @see ProgramMethodOptimizationInfo
* @author Eric Lafortune
*/
public class OptimizationInfoMemberFilter
implements MemberVisitor
{
private final MemberVisitor memberVisitor;
+ private final MemberVisitor otherMemberVisitor;
/**
@@ -46,48 +49,54 @@ public class OptimizationInfoMemberFilter
*/
public OptimizationInfoMemberFilter(MemberVisitor memberVisitor)
{
- this.memberVisitor = memberVisitor;
+ this(memberVisitor, null);
}
- // Implementations for MemberVisitor.
-
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ /**
+ * Creates a new OptimizationInfoMemberFilter.
+ * @param memberVisitor the MemberVisitor to which visits will
+ * be delegated if the member has editable optimization
+ * info.
+ * @param otherMemberVisitor the MemberVisitor to which visits will
+ * be delegated if the member does not have editable
+ * optimization info.
+ */
+ public OptimizationInfoMemberFilter(MemberVisitor memberVisitor,
+ MemberVisitor otherMemberVisitor)
{
- // Does the field have optimization info?
- if (FieldOptimizationInfo.getFieldOptimizationInfo(programField) != null)
- {
- memberVisitor.visitProgramField(programClass, programField);
- }
+ this.memberVisitor = memberVisitor;
+ this.otherMemberVisitor = otherMemberVisitor;
}
- public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
- {
- // Does the field have optimization info?
- if (FieldOptimizationInfo.getFieldOptimizationInfo(libraryField) != null)
- {
- memberVisitor.visitLibraryField(libraryClass, libraryField);
- }
- }
+ // Implementations for MemberVisitor.
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {}
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- // Does the method have optimization info?
- if (MethodOptimizationInfo.getMethodOptimizationInfo(programMethod) != null)
+ MemberVisitor visitor =
+ FieldOptimizationInfo.getFieldOptimizationInfo(programField) instanceof ProgramFieldOptimizationInfo ?
+ memberVisitor : otherMemberVisitor;
+
+ if (visitor != null)
{
- memberVisitor.visitProgramMethod(programClass, programMethod);
+ visitor.visitProgramField(programClass, programField);
}
}
- public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- // Does the method have optimization info?
- if (MethodOptimizationInfo.getMethodOptimizationInfo(libraryMethod) != null)
+ MemberVisitor visitor =
+ MethodOptimizationInfo.getMethodOptimizationInfo(programMethod) instanceof ProgramMethodOptimizationInfo ?
+ memberVisitor : otherMemberVisitor;
+
+ if (visitor != null)
{
- memberVisitor.visitLibraryMethod(libraryClass, libraryMethod);
+ visitor.visitProgramMethod(programClass, programMethod);
}
}
}
diff --git a/core/src/proguard/optimize/Optimizer.java b/core/src/proguard/optimize/Optimizer.java
new file mode 100644
index 0000000..9ff4957
--- /dev/null
+++ b/core/src/proguard/optimize/Optimizer.java
@@ -0,0 +1,1706 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.*;
+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.value.*;
+import proguard.optimize.evaluation.*;
+import proguard.optimize.info.*;
+import proguard.optimize.peephole.*;
+import proguard.util.*;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * This class optimizes class pools according to a given configuration.
+ *
+ * @author Eric Lafortune
+ */
+public class Optimizer
+{
+ public static final boolean DETAILS = System.getProperty("optd") != null;
+
+ 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 CLASS_MERGING_WRAPPER = "class/merging/wrapper";
+ private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly";
+ private static final String FIELD_MARKING_PRIVATE = "field/marking/private";
+ private static final String FIELD_PROPAGATION_VALUE = "field/propagation/value";
+ private static final String METHOD_MARKING_PRIVATE = "method/marking/private";
+ private static final String METHOD_MARKING_STATIC = "method/marking/static";
+ private static final String METHOD_MARKING_FINAL = "method/marking/final";
+ private static final String METHOD_MARKING_SYNCHRONIZED = "method/marking/synchronized";
+ private static final String METHOD_REMOVAL_PARAMETER = "method/removal/parameter";
+ private static final String METHOD_PROPAGATION_PARAMETER = "method/propagation/parameter";
+ private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue";
+ private static final String METHOD_INLINING_SHORT = "method/inlining/short";
+ private static final String METHOD_INLINING_UNIQUE = "method/inlining/unique";
+ private static final String METHOD_INLINING_TAILRECURSION = "method/inlining/tailrecursion";
+ private static final String CODE_MERGING = "code/merging";
+ private static final String CODE_SIMPLIFICATION_VARIABLE = "code/simplification/variable";
+ private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic";
+ private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast";
+ private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field";
+ private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch";
+ private static final String CODE_SIMPLIFICATION_OBJECT = "code/simplification/object";
+ private static final String CODE_SIMPLIFICATION_STRING = "code/simplification/string";
+ private static final String CODE_SIMPLIFICATION_MATH = "code/simplification/math";
+ private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced";
+ private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced";
+ private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple";
+ private static final String CODE_REMOVAL_VARIABLE = "code/removal/variable";
+ private static final String CODE_REMOVAL_EXCEPTION = "code/removal/exception";
+ private static final String CODE_ALLOCATION_VARIABLE = "code/allocation/variable";
+
+
+ public static final String[] OPTIMIZATION_NAMES = new String[]
+ {
+ CLASS_MARKING_FINAL,
+ CLASS_MERGING_VERTICAL,
+ CLASS_MERGING_HORIZONTAL,
+ FIELD_REMOVAL_WRITEONLY,
+ FIELD_MARKING_PRIVATE,
+ FIELD_PROPAGATION_VALUE,
+ METHOD_MARKING_PRIVATE,
+ METHOD_MARKING_STATIC,
+ METHOD_MARKING_FINAL,
+ METHOD_MARKING_SYNCHRONIZED,
+ METHOD_REMOVAL_PARAMETER,
+ METHOD_PROPAGATION_PARAMETER,
+ METHOD_PROPAGATION_RETURNVALUE,
+ METHOD_INLINING_SHORT,
+ METHOD_INLINING_UNIQUE,
+ METHOD_INLINING_TAILRECURSION,
+ CODE_MERGING,
+ CODE_SIMPLIFICATION_VARIABLE,
+ CODE_SIMPLIFICATION_ARITHMETIC,
+ CODE_SIMPLIFICATION_CAST,
+ CODE_SIMPLIFICATION_FIELD,
+ CODE_SIMPLIFICATION_BRANCH,
+ CODE_SIMPLIFICATION_STRING,
+ CODE_SIMPLIFICATION_MATH,
+ CODE_SIMPLIFICATION_ADVANCED,
+ CODE_REMOVAL_ADVANCED,
+ CODE_REMOVAL_SIMPLE,
+ CODE_REMOVAL_VARIABLE,
+ CODE_REMOVAL_EXCEPTION,
+ CODE_ALLOCATION_VARIABLE,
+ };
+
+
+ private final Configuration configuration;
+
+ private final boolean classMarkingFinal;
+ private final boolean classUnboxingEnum;
+ private final boolean classMergingVertical;
+ private final boolean classMergingHorizontal;
+ private final boolean classMergingWrapper;
+ private final boolean fieldRemovalWriteonly;
+ private final boolean fieldMarkingPrivate;
+ private final boolean fieldPropagationValue;
+ private final boolean methodMarkingPrivate;
+ private final boolean methodMarkingStatic;
+ private final boolean methodMarkingFinal;
+ private final boolean methodMarkingSynchronized;
+ private final boolean methodRemovalParameter;
+ private final boolean methodPropagationParameter;
+ private final boolean methodPropagationReturnvalue;
+ private final boolean methodInliningShort;
+ private final boolean methodInliningUnique;
+ private final boolean methodInliningTailrecursion;
+ private final boolean codeMerging;
+ private final boolean codeSimplificationVariable;
+ private final boolean codeSimplificationArithmetic;
+ private final boolean codeSimplificationCast;
+ private final boolean codeSimplificationField;
+ private final boolean codeSimplificationBranch;
+ private final boolean codeSimplificationObject;
+ private final boolean codeSimplificationString;
+ private final boolean codeSimplificationMath;
+ private final boolean codeSimplificationPeephole;
+ private boolean codeSimplificationAdvanced;
+ private boolean codeRemovalAdvanced;
+ private boolean codeRemovalSimple;
+ private final boolean codeRemovalVariable;
+ private boolean codeRemovalException;
+ private final boolean codeAllocationVariable;
+
+
+ /**
+ * Creates a new Optimizer.
+ */
+ public Optimizer(Configuration configuration)
+ {
+ this.configuration = configuration;
+
+ // Create a matcher for filtering optimizations.
+ StringMatcher filter = configuration.optimizations != null ?
+ new ListParser(new NameParser()).parse(configuration.optimizations) :
+ new ConstantMatcher(true);
+
+ classMarkingFinal = filter.matches(CLASS_MARKING_FINAL);
+ classUnboxingEnum = filter.matches(CLASS_UNBOXING_ENUM);
+ classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL);
+ classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL);
+ classMergingWrapper = filter.matches(CLASS_MERGING_WRAPPER);
+ fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY);
+ fieldMarkingPrivate = filter.matches(FIELD_MARKING_PRIVATE);
+ fieldPropagationValue = filter.matches(FIELD_PROPAGATION_VALUE);
+ methodMarkingPrivate = filter.matches(METHOD_MARKING_PRIVATE);
+ methodMarkingStatic = filter.matches(METHOD_MARKING_STATIC);
+ methodMarkingFinal = filter.matches(METHOD_MARKING_FINAL);
+ methodMarkingSynchronized = filter.matches(METHOD_MARKING_SYNCHRONIZED);
+ methodRemovalParameter = filter.matches(METHOD_REMOVAL_PARAMETER);
+ methodPropagationParameter = filter.matches(METHOD_PROPAGATION_PARAMETER);
+ methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE);
+ methodInliningShort = filter.matches(METHOD_INLINING_SHORT);
+ methodInliningUnique = filter.matches(METHOD_INLINING_UNIQUE);
+ methodInliningTailrecursion = filter.matches(METHOD_INLINING_TAILRECURSION);
+ codeMerging = filter.matches(CODE_MERGING);
+ codeSimplificationVariable = filter.matches(CODE_SIMPLIFICATION_VARIABLE);
+ codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC);
+ codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST);
+ codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD);
+ codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH);
+ codeSimplificationObject = filter.matches(CODE_SIMPLIFICATION_OBJECT);
+ codeSimplificationString = filter.matches(CODE_SIMPLIFICATION_STRING);
+ codeSimplificationMath = filter.matches(CODE_SIMPLIFICATION_MATH);
+ codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED);
+ codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED);
+ codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE);
+ codeRemovalVariable = filter.matches(CODE_REMOVAL_VARIABLE);
+ codeRemovalException = filter.matches(CODE_REMOVAL_EXCEPTION);
+ codeAllocationVariable = filter.matches(CODE_ALLOCATION_VARIABLE);
+
+ // Some optimizations are required by other optimizations.
+ codeSimplificationAdvanced =
+ codeSimplificationAdvanced ||
+ fieldPropagationValue ||
+ methodPropagationParameter ||
+ methodPropagationReturnvalue;
+
+ codeRemovalAdvanced =
+ codeRemovalAdvanced ||
+ fieldRemovalWriteonly ||
+ methodMarkingStatic ||
+ methodRemovalParameter;
+
+ codeRemovalSimple =
+ codeRemovalSimple ||
+ codeSimplificationBranch;
+
+ codeRemovalException =
+ codeRemovalException ||
+ codeRemovalAdvanced ||
+ codeRemovalSimple;
+
+ codeSimplificationPeephole =
+ codeSimplificationVariable ||
+ codeSimplificationArithmetic ||
+ codeSimplificationCast ||
+ codeSimplificationField ||
+ codeSimplificationBranch ||
+ codeSimplificationObject ||
+ codeSimplificationString ||
+ codeSimplificationMath;
+ }
+
+
+ /**
+ * Performs optimization of the given program class pool.
+ */
+ public boolean execute(final ClassPool programClassPool,
+ final ClassPool libraryClassPool,
+ final MultiValueMap injectedClassNameMap) throws IOException
+ {
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null &&
+ configuration.applyMapping == null &&
+ configuration.printMapping == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the optimization step.");
+ }
+
+ // Create counters to count the numbers of optimizations.
+ final ClassCounter classMarkingFinalCounter = new ClassCounter();
+ final ClassCounter classUnboxingEnumCounter = new ClassCounter();
+ final ClassCounter classMergingVerticalCounter = new ClassCounter();
+ final ClassCounter classMergingHorizontalCounter = new ClassCounter();
+ final ClassCounter classMergingWrapperCounter = new ClassCounter();
+ final MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter();
+ final MemberCounter fieldMarkingPrivateCounter = new MemberCounter();
+ final MemberCounter fieldPropagationValueCounter = new MemberCounter();
+ final MemberCounter methodMarkingPrivateCounter = new MemberCounter();
+ final MemberCounter methodMarkingStaticCounter = new MemberCounter();
+ final MemberCounter methodMarkingFinalCounter = new MemberCounter();
+ final MemberCounter methodMarkingSynchronizedCounter = new MemberCounter();
+ final MemberCounter methodRemovalParameterCounter1 = new MemberCounter();
+ final MemberCounter methodRemovalParameterCounter2 = new MemberCounter();
+ final MemberCounter methodPropagationParameterCounter = new MemberCounter();
+ final MemberCounter methodPropagationReturnvalueCounter = new MemberCounter();
+ final InstructionCounter methodInliningShortCounter = new InstructionCounter();
+ final InstructionCounter methodInliningUniqueCounter = new InstructionCounter();
+ final InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter();
+ final InstructionCounter codeMergingCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationVariableCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationCastCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationFieldCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationBranchCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationObjectCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationStringCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationMathCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationAndroidMathCounter = new InstructionCounter();
+ final InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter();
+ final InstructionCounter deletedCounter = new InstructionCounter();
+ final InstructionCounter addedCounter = new InstructionCounter();
+ final MemberCounter codeRemovalVariableCounter = new MemberCounter();
+ final ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter();
+ final MemberCounter codeAllocationVariableCounter = new MemberCounter();
+ final MemberCounter initializerFixCounter1 = new MemberCounter();
+ final MemberCounter initializerFixCounter2 = new MemberCounter();
+
+ // Clean up any old visitor info.
+ programClassPool.classesAccept(new ClassCleaner());
+ libraryClassPool.classesAccept(new ClassCleaner());
+
+ // Link all methods that should get the same optimization info.
+ programClassPool.classesAccept(new BottomClassFilter(
+ new MethodLinker()));
+ libraryClassPool.classesAccept(new BottomClassFilter(
+ new MethodLinker()));
+
+ // Create a visitor for marking the seeds.
+ final KeepMarker keepMarker = new KeepMarker();
+ ClassPoolVisitor classPoolvisitor =
+ new KeepClassSpecificationVisitorFactory(false, true, false)
+ .createClassPoolVisitor(configuration.keep,
+ keepMarker,
+ keepMarker,
+ keepMarker,
+ keepMarker);
+ // Mark the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ // All library classes and library class members remain unchanged.
+ libraryClassPool.classesAccept(keepMarker);
+ 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))))));
+
+ // We also keep all classes that are accessed dynamically.
+ programClassPool.classesAccept(
+ new AllConstantVisitor(
+ new ConstantTagFilter(ClassConstants.CONSTANT_String,
+ new ReferencedClassVisitor(keepMarker))));
+
+ // We also keep all class members that are accessed dynamically.
+ programClassPool.classesAccept(
+ new AllConstantVisitor(
+ new ConstantTagFilter(ClassConstants.CONSTANT_String,
+ new ReferencedMemberVisitor(keepMarker))));
+
+ // We also keep all bootstrap method signatures.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllAttributeVisitor(
+ new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
+ new AllBootstrapMethodInfoVisitor(
+ new BootstrapMethodHandleTraveler(
+ new MethodrefTraveler(
+ new ReferencedMemberVisitor(keepMarker))))))));
+
+ // We also keep classes and methods referenced from bootstrap
+ // method arguments.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllAttributeVisitor(
+ new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
+ new AllBootstrapMethodInfoVisitor(
+ new AllBootstrapMethodArgumentVisitor(
+ new MultiConstantVisitor(
+ // Class constants refer to additional functional
+ // interfaces (with LambdaMetafactory.altMetafactory).
+ new ConstantTagFilter(ClassConstants.CONSTANT_Class,
+ new ReferencedClassVisitor(
+ new FunctionalInterfaceFilter(
+ new ClassHierarchyTraveler(true, false, true, false,
+ new MultiClassVisitor(
+ keepMarker,
+ new AllMethodVisitor(
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ keepMarker))
+ ))))),
+
+ // Method handle constants refer to synthetic lambda
+ // methods (with LambdaMetafactory.metafactory and
+ // altMetafactory).
+ new MethodrefTraveler(
+ new ReferencedMemberVisitor(keepMarker)))))))));
+
+ // We also keep the classes and abstract methods of functional
+ // interfaces that are returned by dynamic method invocations.
+ // These functional interfaces have to remain suitable for the
+ // dynamic method invocations with LambdaMetafactory.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
+ new AllConstantVisitor(
+ new DynamicReturnedClassVisitor(
+ new FunctionalInterfaceFilter(
+ new ClassHierarchyTraveler(true, false, true, false,
+ new MultiClassVisitor(
+ keepMarker,
+ new AllMethodVisitor(
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ keepMarker))
+ )))))));
+
+ // Attach some optimization info to all classes and class members, so
+ // it can be filled out later.
+ programClassPool.classesAccept(new ProgramClassOptimizationInfoSetter());
+
+ programClassPool.classesAccept(new AllMemberVisitor(
+ new ProgramMemberOptimizationInfoSetter()));
+
+ if (configuration.assumeNoSideEffects != null)
+ {
+ // Create a visitor for marking classes and methods that don't have
+ // any side effects.
+ NoSideEffectClassMarker noSideEffectClassMarker = new NoSideEffectClassMarker();
+ NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
+ ClassPoolVisitor classPoolVisitor =
+ new ClassSpecificationVisitorFactory()
+ .createClassPoolVisitor(configuration.assumeNoSideEffects,
+ noSideEffectClassMarker,
+ noSideEffectMethodMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolVisitor);
+ libraryClassPool.accept(classPoolVisitor);
+ }
+
+ if (configuration.assumeNoExternalSideEffects != null)
+ {
+ // Create a visitor for marking classes and methods that don't have
+ // any external side effects.
+ NoSideEffectClassMarker noSideEffectClassMarker = new NoSideEffectClassMarker();
+ NoExternalSideEffectMethodMarker noSideEffectMethodMarker = new NoExternalSideEffectMethodMarker();
+ ClassPoolVisitor classPoolVisitor =
+ new ClassSpecificationVisitorFactory()
+ .createClassPoolVisitor(configuration.assumeNoExternalSideEffects,
+ noSideEffectClassMarker,
+ noSideEffectMethodMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolVisitor);
+ libraryClassPool.accept(classPoolVisitor);
+ }
+
+ if (configuration.assumeNoEscapingParameters != null)
+ {
+ // Create a visitor for marking methods that don't let any
+ // reference parameters escape.
+ NoEscapingParametersMethodMarker noEscapingParametersMethodMarker = new NoEscapingParametersMethodMarker();
+ ClassPoolVisitor classPoolVisitor =
+ new ClassSpecificationVisitorFactory()
+ .createClassPoolVisitor(configuration.assumeNoEscapingParameters,
+ null,
+ noEscapingParametersMethodMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolVisitor);
+ libraryClassPool.accept(classPoolVisitor);
+ }
+
+ if (configuration.assumeNoExternalReturnValues != null)
+ {
+ // Create a visitor for marking methods that don't let any
+ // reference parameters escape.
+ NoExternalReturnValuesMethodMarker noExternalReturnValuesMethodMarker = new NoExternalReturnValuesMethodMarker();
+ ClassPoolVisitor classPoolVisitor =
+ new ClassSpecificationVisitorFactory()
+ .createClassPoolVisitor(configuration.assumeNoExternalReturnValues,
+ null,
+ noExternalReturnValuesMethodMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolVisitor);
+ libraryClassPool.accept(classPoolVisitor);
+ }
+
+ if (classMarkingFinal)
+ {
+ // Make classes final, whereever possible.
+ programClassPool.classesAccept(
+ new ClassFinalizer(classMarkingFinalCounter));
+ }
+
+ if (methodMarkingFinal)
+ {
+ // Make methods final, whereever possible.
+ programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
+ new AllMethodVisitor(
+ new MethodFinalizer(methodMarkingFinalCounter))));
+ }
+
+ // We'll repeatedly loop over all classes to mark read/write fields.
+ // side-effect methods, and escaping parameters.
+ final MutableBoolean repeatTrigger = new MutableBoolean();
+
+ // Create the various markers.
+ ReadWriteFieldMarker readWriteFieldMarker =
+ new ReadWriteFieldMarker(repeatTrigger);
+
+ if (!fieldRemovalWriteonly)
+ {
+ // Mark all fields as read/write.
+ programClassPool.classesAccept(
+ new AllFieldVisitor(
+ readWriteFieldMarker));
+ }
+
+ SideEffectMethodMarker sideEffectMethodMarker =
+ new SideEffectMethodMarker(repeatTrigger);
+
+ ParameterEscapeMarker parameterEscapeMarker =
+ new ParameterEscapeMarker(repeatTrigger);
+
+ // Mark methods based on their headers.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new MultiMemberVisitor(
+ sideEffectMethodMarker,
+ parameterEscapeMarker
+ ))));
+
+ {
+ // Mark fields based on the method instructions in methods
+ // without editable optimization info.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Marking field usage in kept methods",
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ null,
+
+ // member has no editable optimization info
+ new AllAttributeVisitor(
+ new AllInstructionVisitor(
+ readWriteFieldMarker))))));
+
+ ParallelAllClassVisitor.ClassVisitorFactory markingClassVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ ReferenceTracingValueFactory referenceTracingValueFactory1 =
+ new ReferenceTracingValueFactory(new TypedReferenceValueFactory());
+
+ PartialEvaluator partialEvaluator =
+ new PartialEvaluator(referenceTracingValueFactory1,
+ new ParameterTracingInvocationUnit(new BasicInvocationUnit(referenceTracingValueFactory1)),
+ false,
+ referenceTracingValueFactory1);
+
+ InstructionUsageMarker instructionUsageMarker =
+ new InstructionUsageMarker(partialEvaluator, false);
+
+ // Create the various markers.
+ ReadWriteFieldMarker readWriteFieldMarker =
+ new ReadWriteFieldMarker(repeatTrigger);
+
+ SideEffectMethodMarker sideEffectMethodMarker =
+ new SideEffectMethodMarker(repeatTrigger);
+
+ ParameterEscapeMarker parameterEscapeMarker =
+ new ParameterEscapeMarker(repeatTrigger, partialEvaluator, false);
+
+ return
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Marking fields, methods, and parameters",
+ new MultiAttributeVisitor(
+ partialEvaluator,
+ parameterEscapeMarker,
+ instructionUsageMarker,
+ new AllInstructionVisitor(
+ instructionUsageMarker.necessaryInstructionFilter(
+ new MultiInstructionVisitor(
+ readWriteFieldMarker,
+ sideEffectMethodMarker,
+ parameterEscapeMarker
+ )))
+ )))));
+ }
+ };
+
+ // Mark fields, methods and parameters based on the method instructions
+ // for methods that have editable optimization info.
+ programClassPool.accept(
+ new RepeatedClassPoolVisitor(repeatTrigger,
+ new TimedClassPoolVisitor("Marking fields, methods and parameters",
+ new ParallelAllClassVisitor(
+ markingClassVisitor))));
+ }
+
+ if (methodMarkingSynchronized)
+ {
+ // Mark all superclasses of escaping (kept) classes.
+ programClassPool.classesAccept(
+ new EscapingClassFilter(
+ new ClassHierarchyTraveler(false, true, true, false,
+ new EscapingClassMarker())));
+
+ ParallelAllClassVisitor.ClassVisitorFactory markingEscapingClassVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ return
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new EscapingClassMarker()));
+ }
+ };
+
+ // Mark classes that escape to the heap.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Marking escaping classes",
+ new ParallelAllClassVisitor(
+ markingEscapingClassVisitor)));
+
+ // Desynchronize all non-static methods whose classes don't escape.
+ programClassPool.classesAccept(
+ new EscapingClassFilter(null,
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new MemberAccessFilter(ClassConstants.ACC_SYNCHRONIZED, ClassConstants.ACC_STATIC,
+ new MultiMemberVisitor(
+ new MemberAccessFlagCleaner(ClassConstants.ACC_SYNCHRONIZED),
+ methodMarkingSynchronizedCounter
+ ))))));
+ }
+
+ if (fieldRemovalWriteonly)
+ {
+ // Count the write-only fields.
+ programClassPool.classesAccept(
+ new AllFieldVisitor(
+ new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter)));
+ }
+
+ 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 OptimizationInfoClassFilter(
+ 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());
+
+ // Unmark all simple enums that are used in descriptors of
+ // kept class members. Changing their names could upset
+ // the name parameters of invokedynamic instructions.
+ programClassPool.classesAccept(
+ new SimpleEnumFilter(null,
+ new AllMemberVisitor(
+ new KeptMemberFilter(
+ new MemberDescriptorReferencedClassVisitor(
+ new OptimizationInfoClassFilter(
+ new SimpleEnumMarker(false)))))));
+
+ // 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.accept(
+ new TimedClassPoolVisitor("Simplify use of simple enums",
+ 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.
+ ParallelAllClassVisitor.ClassVisitorFactory markingUsedParametersClassVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ return
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new ParameterUsageMarker(!methodMarkingStatic,
+ !methodRemovalParameter)));
+ }
+ };
+
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Marking used parameters",
+ new ParallelAllClassVisitor(
+ markingUsedParametersClassVisitor)));
+
+ // Mark all parameters of referenced methods in methods whose code must
+ // be kept. This prevents shrinking of method descriptors which may not
+ // be propagated correctly otherwise.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Marking used parameters in kept code attributes",
+ new AllClassVisitor(
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ null,
+
+ // visit all methods that are kept
+ new AllAttributeVisitor(
+ new OptimizationCodeAttributeFilter(
+ null,
+
+ // visit all code attributes that are kept
+ new AllInstructionVisitor(
+ new InstructionConstantVisitor(
+ new ConstantTagFilter(new int[] { ClassConstants.CONSTANT_Methodref,
+ ClassConstants.CONSTANT_InterfaceMethodref },
+ new ReferencedMemberVisitor(
+ new OptimizationInfoMemberFilter(
+ // Mark all parameters including "this" of referenced methods
+ new ParameterUsageMarker(true, true, false))))))))
+ )))));
+
+// System.out.println("Optimizer.execute: before evaluation simplification");
+// programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter()));
+
+ // Perform partial evaluation for filling out fields, method parameters,
+ // and method return values, so they can be propagated.
+ if (fieldPropagationValue ||
+ methodPropagationParameter ||
+ methodPropagationReturnvalue ||
+ classMergingWrapper)
+ {
+ // We'll create values to be stored with fields, method parameters,
+ // and return values.
+ ValueFactory valueFactory = new ParticularValueFactory();
+ ValueFactory detailedValueFactory = new DetailedArrayValueFactory();
+
+ InvocationUnit storingInvocationUnit =
+ new StoringInvocationUnit(valueFactory,
+ fieldPropagationValue,
+ methodPropagationParameter || classMergingWrapper,
+ 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 DebugAttributeVisitor("Filling out fields, method parameters, and return values in synthetic classes",
+ new PartialEvaluator(detailedValueFactory, storingInvocationUnit, false))))));
+
+ // Evaluate non-synthetic classes. We may need to evaluate all
+ // casts, to account for downcasts when specializing descriptors.
+
+ ParallelAllClassVisitor.ClassVisitorFactory fillingOutValuesClassVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ ValueFactory valueFactory = new ParticularValueFactory();
+
+ InvocationUnit storingInvocationUnit =
+ new StoringInvocationUnit(valueFactory,
+ fieldPropagationValue,
+ methodPropagationParameter || classMergingWrapper,
+ methodPropagationReturnvalue);
+
+ return
+ new ClassAccessFilter(0, ClassConstants.ACC_SYNTHETIC,
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Filling out fields, method parameters, and return values",
+ new PartialEvaluator(valueFactory, storingInvocationUnit,
+ false)))));
+ }
+ };
+
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Filling out values in non-synthetic classes",
+ new ParallelAllClassVisitor(
+ fillingOutValuesClassVisitor)));
+
+ if (fieldPropagationValue)
+ {
+ // Count the constant fields.
+ programClassPool.classesAccept(
+ new AllFieldVisitor(
+ new ConstantMemberFilter(fieldPropagationValueCounter)));
+ }
+
+ if (methodPropagationParameter)
+ {
+ // Count the constant method parameters.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new ConstantParameterFilter(methodPropagationParameterCounter)));
+ }
+
+ if (methodPropagationReturnvalue)
+ {
+ // Count the constant method return values.
+ programClassPool.classesAccept(
+ 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)))));
+ }
+ }
+
+ if (codeSimplificationAdvanced)
+ {
+ ParallelAllClassVisitor.ClassVisitorFactory simplifyingCodeVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ // Perform partial evaluation again, now loading any previously stored
+ // values for fields, method parameters, and method return values.
+ ValueFactory valueFactory = new IdentifiedValueFactory();
+
+ SimplifiedInvocationUnit loadingInvocationUnit =
+ new LoadingInvocationUnit(valueFactory,
+ fieldPropagationValue,
+ methodPropagationParameter,
+ methodPropagationReturnvalue);
+
+ return
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Simplifying code",
+ new OptimizationCodeAttributeFilter(
+ new EvaluationSimplifier(
+ new PartialEvaluator(valueFactory, loadingInvocationUnit, false),
+ codeSimplificationAdvancedCounter)))));
+ }
+ };
+
+ // Simplify based on partial evaluation, propagating constant
+ // field values, method parameter values, and return values.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Simplifying code",
+ new ParallelAllClassVisitor(
+ simplifyingCodeVisitor)));
+ }
+
+ if (codeRemovalAdvanced)
+ {
+ ParallelAllClassVisitor.ClassVisitorFactory shrinkingCodeVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ // Perform partial evaluation again, now loading any previously stored
+ // values for fields, method parameters, and method return values.
+ ValueFactory valueFactory = new IdentifiedValueFactory();
+
+ SimplifiedInvocationUnit loadingInvocationUnit =
+ new LoadingInvocationUnit(valueFactory,
+ fieldPropagationValue,
+ methodPropagationParameter,
+ methodPropagationReturnvalue);
+
+ // Trace the construction of reference values.
+ ReferenceTracingValueFactory referenceTracingValueFactory =
+ new ReferenceTracingValueFactory(valueFactory);
+
+ return
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Shrinking code",
+ new OptimizationCodeAttributeFilter(
+ new EvaluationShrinker(
+ new InstructionUsageMarker(
+ new PartialEvaluator(referenceTracingValueFactory,
+ new ParameterTracingInvocationUnit(loadingInvocationUnit),
+ !codeSimplificationAdvanced,
+ referenceTracingValueFactory),
+ true), true, deletedCounter, addedCounter)))));
+ }
+ };
+
+ // Remove code based on partial evaluation, also removing unused
+ // parameters from method invocations, and making methods static
+ // if possible.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Shrinking code",
+ new ParallelAllClassVisitor(
+ shrinkingCodeVisitor)));
+ }
+
+ if (methodRemovalParameter)
+ {
+ // Shrink the parameters in the method descriptors.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new UnusedParameterMethodFilter(
+ new OptimizationInfoMemberFilter(
+ new MethodDescriptorShrinker(methodRemovalParameterCounter1)))));
+ }
+
+ if (methodMarkingStatic)
+ {
+ // Make all non-static methods that don't require the 'this'
+ // parameter static.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new MemberAccessFilter(0, ClassConstants.ACC_STATIC,
+ new MethodStaticizer(methodMarkingStaticCounter)))));
+ }
+
+ if (methodRemovalParameterCounter1.getCount() > 0)
+ {
+ // Fix all references to class members.
+ // This operation also updates the stack sizes.
+ programClassPool.classesAccept(new MemberReferenceFixer());
+
+ // Remove unused bootstrap method arguments.
+ programClassPool.classesAccept(
+ new AllAttributeVisitor(
+ new AllBootstrapMethodInfoVisitor(
+ new BootstrapMethodArgumentShrinker())));
+ }
+
+ if (methodRemovalParameterCounter1.getCount() > 0 ||
+ methodMarkingPrivate ||
+ // Methods are only marked private later on.
+ //methodMarkingPrivateCounter .getCount() > 0 ||
+ methodMarkingStaticCounter .getCount() > 0)
+ {
+ // Remove all unused parameters from the corresponding byte code,
+ // shifting all remaining variables.
+ // This operation also updates the local variable frame sizes.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new UnusedParameterMethodFilter(
+ new AllAttributeVisitor(
+ new ParameterShrinker(methodRemovalParameterCounter2)))));
+
+ // Remove all unused parameters in the optimization info.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new UnusedParameterMethodFilter(
+ new AllAttributeVisitor(
+ new UnusedParameterOptimizationInfoUpdater()))));
+ }
+ else if (codeRemovalAdvanced)
+ {
+ // Just update the local variable frame sizes.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new OptimizationCodeAttributeFilter(
+ new StackSizeUpdater()))));
+ }
+
+ if (methodRemovalParameter &&
+ methodRemovalParameterCounter2.getCount() > 0)
+ {
+ // Tweak the descriptors of duplicate initializers, due to removed
+ // method parameters.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new DuplicateInitializerFixer(initializerFixCounter1)));
+
+ if (initializerFixCounter1.getCount() > 0)
+ {
+ // Fix all invocations of tweaked initializers.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DuplicateInitializerInvocationFixer(addedCounter))));
+
+ // Fix all references to tweaked initializers.
+ programClassPool.classesAccept(new MemberReferenceFixer());
+ }
+ }
+
+ // Mark all classes with package visible members.
+ // Mark all exception catches of methods.
+ // Count all method invocations.
+ // Mark super invocations and other access of methods.
+ StackSizeComputer stackSizeComputer = new StackSizeComputer();
+
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Marking method and referenced class properties",
+ new MultiClassVisitor(
+ // Mark classes.
+ new OptimizationInfoClassFilter(
+ new MultiClassVisitor(
+ new PackageVisibleMemberContainingClassMarker(),
+ new WrapperClassMarker(),
+
+ new AllConstantVisitor(
+ new PackageVisibleMemberInvokingClassMarker())
+ )),
+
+ // Mark methods.
+ new AllMethodVisitor(
+ new OptimizationInfoMemberFilter(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Marking method properties",
+ new MultiAttributeVisitor(
+ stackSizeComputer,
+ new CatchExceptionMarker(),
+
+ new AllInstructionVisitor(
+ new MultiInstructionVisitor(
+ new SuperInvocationMarker(),
+ new DynamicInvocationMarker(),
+ new BackwardBranchMarker(),
+ new AccessMethodMarker(),
+ new SynchronizedBlockMethodMarker(),
+ new NonEmptyStackReturnMarker(stackSizeComputer)
+ ))
+ ))))),
+
+ // Mark referenced classes and methods.
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Marking referenced class properties",
+ new MultiAttributeVisitor(
+ new AllExceptionInfoVisitor(
+ new ExceptionHandlerConstantVisitor(
+ new ReferencedClassVisitor(
+ new OptimizationInfoClassFilter(
+ new CaughtClassMarker())))),
+
+ new AllInstructionVisitor(
+ new MultiInstructionVisitor(
+ new InstantiationClassMarker(),
+ new InstanceofClassMarker(),
+ new DotClassMarker(),
+ new MethodInvocationMarker()
+ ))
+ ))))
+ )));
+
+ if (classMergingWrapper)
+ {
+ // Merge wrapper classes into their wrapped classes.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Merging wrapper classes",
+ // Exclude injected classes - they might not end up in the output.
+ new WrapperClassMerger(configuration.allowAccessModification,
+ classMergingWrapperCounter)));
+
+ if (classMergingWrapperCounter.getCount() > 0)
+ {
+ // Fix all uses of wrapper classes.
+ programClassPool.classesAccept(
+ new RetargetedClassFilter(null,
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new WrapperClassUseSimplifier()))));
+ }
+ }
+
+ if (classMergingVertical)
+ {
+ // Merge subclasses up into their superclasses or
+ // merge interfaces down into their implementing classes.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Merging classes vertically",
+ // Exclude injected classes - they might not end up in the output.
+ new VerticalClassMerger(configuration.allowAccessModification,
+ configuration.mergeInterfacesAggressively,
+ classMergingVerticalCounter)));
+ }
+
+ if (classMergingHorizontal)
+ {
+ // Merge classes into their sibling classes.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Merging classes horizontally",
+ // Exclude injected classes - they might not end up in the output.
+ new ClassNameFilter(
+ new NotMatcher(
+ new CollectionMatcher(injectedClassNameMap.getValues())),
+ new HorizontalClassMerger(configuration.allowAccessModification,
+ configuration.mergeInterfacesAggressively,
+ classMergingHorizontalCounter))));
+ }
+
+ if (classMergingVerticalCounter .getCount() > 0 ||
+ classMergingHorizontalCounter.getCount() > 0 ||
+ classMergingWrapperCounter .getCount() > 0)
+ {
+ // Clean up inner class attributes to avoid loops.
+ programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover());
+
+ // Update references to merged classes: first the referenced
+ // classes, then the various actual descriptors.
+ // Leave retargeted classes themselves unchanged and valid,
+ // in case they aren't shrunk later on.
+ programClassPool.classesAccept(new RetargetedClassFilter(null, new TargetClassChanger()));
+ programClassPool.classesAccept(new RetargetedClassFilter(null, new ClassReferenceFixer(true)));
+ programClassPool.classesAccept(new RetargetedClassFilter(null, new MemberReferenceFixer()));
+
+ if (configuration.allowAccessModification)
+ {
+ // Fix the access flags of referenced merged classes and their
+ // class members.
+ programClassPool.classesAccept(new AccessFixer());
+ }
+
+ // Fix the access flags of the inner classes information.
+ // DGD-63: don't change the access flags of inner classes
+ // that have not been renamed (Guice).
+ programClassPool.classesAccept(
+ new KeptClassFilter(null,
+ new AllAttributeVisitor(
+ new AllInnerClassesInfoVisitor(
+ new InnerClassesAccessFixer()))));
+
+ // Tweak the descriptors of duplicate initializers, due to merged
+ // parameter classes.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new DuplicateInitializerFixer(initializerFixCounter2)));
+
+ if (initializerFixCounter2.getCount() > 0)
+ {
+ // Fix all invocations of tweaked initializers.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DuplicateInitializerInvocationFixer(addedCounter))));
+
+ // Fix all references to tweaked initializers.
+ programClassPool.classesAccept(new MemberReferenceFixer());
+ }
+ }
+
+ if (methodInliningUnique)
+ {
+ // Inline methods that are only invoked once.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Inlining single methods",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Inlining single methods",
+ new OptimizationCodeAttributeFilter(
+ new MethodInliner(configuration.microEdition,
+ configuration.android,
+ configuration.allowAccessModification,
+ true,
+ methodInliningUniqueCounter)))))));
+ }
+
+ if (methodInliningShort)
+ {
+ // Inline short methods.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Inlining short methods",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Inlining short methods",
+ new OptimizationCodeAttributeFilter(
+ new MethodInliner(configuration.microEdition,
+ configuration.android,
+ configuration.allowAccessModification,
+ false,
+ methodInliningShortCounter)))))));
+ }
+
+ if (methodInliningTailrecursion)
+ {
+ // Simplify tail recursion calls.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Simplifying tail recursion",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Simplifying tail recursion",
+ new OptimizationCodeAttributeFilter(
+ new TailRecursionSimplifier(methodInliningTailrecursionCounter)))))));
+ }
+
+ if (fieldMarkingPrivate ||
+ methodMarkingPrivate)
+ {
+ // Mark all class members that can not be made private.
+ programClassPool.classesAccept(new NonPrivateMemberMarker());
+ }
+
+ if (fieldMarkingPrivate)
+ {
+ // Make all non-private fields private, whereever possible.
+ programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
+ new AllFieldVisitor(
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
+ new MemberPrivatizer(fieldMarkingPrivateCounter)))));
+ }
+
+ if (methodMarkingPrivate)
+ {
+ // Make all non-private methods private, whereever possible.
+ programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
+ new AllMethodVisitor(
+ new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
+ new MemberPrivatizer(methodMarkingPrivateCounter)))));
+ }
+
+ if ((methodInliningUniqueCounter .getCount() > 0 ||
+ methodInliningShortCounter .getCount() > 0 ||
+ methodInliningTailrecursionCounter.getCount() > 0) &&
+ configuration.allowAccessModification)
+ {
+ // Fix the access flags of referenced classes and class members,
+ // for MethodInliner.
+ programClassPool.classesAccept(new AccessFixer());
+ }
+
+ if (methodRemovalParameterCounter2.getCount() > 0 ||
+ classMergingVerticalCounter .getCount() > 0 ||
+ classMergingHorizontalCounter .getCount() > 0 ||
+ classMergingWrapperCounter .getCount() > 0 ||
+ methodMarkingPrivateCounter .getCount() > 0 ||
+ ((methodInliningUniqueCounter .getCount() > 0 ||
+ methodInliningShortCounter .getCount() > 0 ||
+ methodInliningTailrecursionCounter.getCount() > 0) &&
+ configuration.allowAccessModification))
+ {
+ // Fix invocations of interface methods, or methods that have become
+ // non-abstract or private, and of methods that have moved to a
+ // different package.
+ programClassPool.classesAccept(
+ new AllMemberVisitor(
+ new AllAttributeVisitor(
+ new MethodInvocationFixer())));
+ }
+
+ if (codeMerging)
+ {
+ // Share common blocks of code at branches.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Sharing common code",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Sharing common code",
+ new OptimizationCodeAttributeFilter(
+ new GotoCommonCodeReplacer(codeMergingCounter)))))));
+ }
+
+ if (codeSimplificationPeephole)
+ {
+ ParallelAllClassVisitor.ClassVisitorFactory peepHoleOptimizer =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ // Create a branch target marker and a code attribute editor that can
+ // be reused for all code attributes.
+ BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
+ CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+
+ InstructionSequenceConstants sequences =
+ new InstructionSequenceConstants(programClassPool,
+ libraryClassPool);
+
+ List peepholeOptimizations = createPeepholeOptimizations(sequences,
+ branchTargetFinder,
+ codeAttributeEditor,
+ codeSimplificationVariableCounter,
+ codeSimplificationArithmeticCounter,
+ codeSimplificationCastCounter,
+ codeSimplificationFieldCounter,
+ codeSimplificationBranchCounter,
+ codeSimplificationObjectCounter,
+ codeSimplificationStringCounter,
+ codeSimplificationMathCounter,
+ codeSimplificationAndroidMathCounter);
+
+ // Convert the list into an array.
+ InstructionVisitor[] peepholeOptimizationsArray =
+ new InstructionVisitor[peepholeOptimizations.size()];
+ peepholeOptimizations.toArray(peepholeOptimizationsArray);
+
+ return
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Peephole optimizations",
+ new OptimizationCodeAttributeFilter(
+ new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor,
+ new MultiInstructionVisitor(
+ peepholeOptimizationsArray))))));
+ }
+ };
+
+ // Perform the peephole optimisations.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Peephole optimizations",
+ new ParallelAllClassVisitor(
+ peepHoleOptimizer)));
+ }
+
+ if (codeRemovalException)
+ {
+ // Remove unnecessary exception handlers.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Unreachable exception removal",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Unreachable exception removal",
+ new OptimizationCodeAttributeFilter(
+ new UnreachableExceptionRemover(codeRemovalExceptionCounter)))))));
+ }
+
+ if (codeRemovalSimple)
+ {
+ // Remove unreachable code.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Unreachable code removal",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Unreachable code removal",
+ new OptimizationCodeAttributeFilter(
+ new UnreachableCodeRemover(deletedCounter)))))));
+ }
+
+ if (codeRemovalVariable)
+ {
+ // Remove all unused local variables.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Variable shrinking",
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Variable shrinking",
+ new OptimizationCodeAttributeFilter(
+ new VariableShrinker(codeRemovalVariableCounter)))))));
+ }
+
+ if (codeAllocationVariable)
+ {
+ ParallelAllClassVisitor.ClassVisitorFactory optimizingVariablesVisitor =
+ new ParallelAllClassVisitor.ClassVisitorFactory()
+ {
+ public ClassVisitor createClassVisitor()
+ {
+ return
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DebugAttributeVisitor("Variable optimizations",
+ new OptimizationCodeAttributeFilter(
+ new VariableOptimizer(false, codeAllocationVariableCounter)))));
+ }
+ };
+
+ // Optimize the variables.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Variable optimizations",
+ new ParallelAllClassVisitor(
+ optimizingVariablesVisitor)));
+ }
+
+ // Remove unused constants.
+ programClassPool.accept(
+ new TimedClassPoolVisitor("Shrinking constant pool",
+ new ConstantPoolShrinker()));
+
+ int classMarkingFinalCount = classMarkingFinalCounter .getCount();
+ int classUnboxingEnumCount = classUnboxingEnumCounter .getCount();
+ int classMergingVerticalCount = classMergingVerticalCounter .getCount();
+ int classMergingHorizontalCount = classMergingHorizontalCounter .getCount();
+ int classMergingWrapperCount = classMergingWrapperCounter .getCount();
+ int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount();
+ int fieldMarkingPrivateCount = fieldMarkingPrivateCounter .getCount();
+ int fieldPropagationValueCount = fieldPropagationValueCounter .getCount();
+ int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount();
+ int methodMarkingStaticCount = methodMarkingStaticCounter .getCount();
+ int methodMarkingFinalCount = methodMarkingFinalCounter .getCount();
+ int methodMarkingSynchronizedCount = methodMarkingSynchronizedCounter .getCount();
+ int methodRemovalParameterCount1 = methodRemovalParameterCounter1 .getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount();
+ int methodRemovalParameterCount2 = methodRemovalParameterCounter2 .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount();
+ int methodPropagationParameterCount = methodPropagationParameterCounter .getCount();
+ int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter .getCount();
+ int methodInliningShortCount = methodInliningShortCounter .getCount();
+ int methodInliningUniqueCount = methodInliningUniqueCounter .getCount();
+ int methodInliningTailrecursionCount = methodInliningTailrecursionCounter .getCount();
+ int codeMergingCount = codeMergingCounter .getCount();
+ int codeSimplificationVariableCount = codeSimplificationVariableCounter .getCount();
+ int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter .getCount();
+ int codeSimplificationCastCount = codeSimplificationCastCounter .getCount();
+ int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount();
+ int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount();
+ int codeSimplificationObjectCount = codeSimplificationObjectCounter .getCount();
+ int codeSimplificationStringCount = codeSimplificationStringCounter .getCount();
+ int codeSimplificationMathCount = codeSimplificationMathCounter .getCount();
+ int codeSimplificationAndroidMathCount = codeSimplificationAndroidMathCounter .getCount();
+ int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount();
+ int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount();
+ int codeRemovalVariableCount = codeRemovalVariableCounter .getCount();
+ int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount();
+ int codeAllocationVariableCount = codeAllocationVariableCounter .getCount();
+
+ // Forget about constant fields, parameters, and return values, if they
+ // didn't lead to any useful optimizations. We want to avoid fruitless
+ // additional optimization passes.
+ if (codeSimplificationAdvancedCount == 0)
+ {
+ fieldPropagationValueCount = 0;
+ methodPropagationParameterCount = 0;
+ methodPropagationReturnvalueCount = 0;
+ }
+
+ if (configuration.verbose)
+ {
+ System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal));
+ 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 merged wrapper classes: " + classMergingWrapperCount + disabled(classMergingWrapper));
+ System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly));
+ System.out.println(" Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate));
+ System.out.println(" Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue));
+ System.out.println(" Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate));
+ System.out.println(" Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic));
+ System.out.println(" Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal));
+ System.out.println(" Number of desynchronized methods: " + methodMarkingSynchronizedCount + disabled(methodMarkingSynchronized));
+ System.out.println(" Number of simplified method signatures: " + methodRemovalParameterCount1 + disabled(methodRemovalParameter));
+ System.out.println(" Number of removed method parameters: " + methodRemovalParameterCount2 + disabled(methodRemovalParameter));
+ System.out.println(" Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter));
+ System.out.println(" Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue));
+ System.out.println(" Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort));
+ System.out.println(" Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique));
+ System.out.println(" Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion));
+ System.out.println(" Number of merged code blocks: " + codeMergingCount + disabled(codeMerging));
+ System.out.println(" Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable));
+ System.out.println(" Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic));
+ System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast));
+ System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField));
+ System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch));
+ System.out.println(" Number of object peephole optimizations: " + codeSimplificationObjectCount + disabled(codeSimplificationObject));
+ System.out.println(" Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString));
+ System.out.println(" Number of math peephole optimizations: " + codeSimplificationMathCount + disabled(codeSimplificationMath));
+ if (configuration.android)
+ System.out.println(" Number of Android math peephole optimizations: " + codeSimplificationAndroidMathCount + disabled(codeSimplificationMath));
+ System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced));
+ System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced));
+ System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable));
+ System.out.println(" Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException));
+ System.out.println(" Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable));
+ }
+
+ return classMarkingFinalCount > 0 ||
+ classUnboxingEnumCount > 0 ||
+ classMergingVerticalCount > 0 ||
+ classMergingHorizontalCount > 0 ||
+ classMergingWrapperCount > 0 ||
+ fieldRemovalWriteonlyCount > 0 || // TODO: The write-only field counter may be optimistic about removal.
+ fieldMarkingPrivateCount > 0 ||
+ methodMarkingPrivateCount > 0 ||
+ methodMarkingStaticCount > 0 ||
+ methodMarkingFinalCount > 0 ||
+ fieldPropagationValueCount > 0 ||
+ methodRemovalParameterCount1 > 0 ||
+ methodRemovalParameterCount2 > 0 ||
+ methodPropagationParameterCount > 0 ||
+ methodPropagationReturnvalueCount > 0 ||
+ methodInliningShortCount > 0 ||
+ methodInliningUniqueCount > 0 ||
+ methodInliningTailrecursionCount > 0 ||
+ codeMergingCount > 0 ||
+ codeSimplificationVariableCount > 0 ||
+ codeSimplificationArithmeticCount > 0 ||
+ codeSimplificationCastCount > 0 ||
+ codeSimplificationFieldCount > 0 ||
+ codeSimplificationBranchCount > 0 ||
+ codeSimplificationObjectCount > 0 ||
+ codeSimplificationStringCount > 0 ||
+ codeSimplificationMathCount > 0 ||
+ codeSimplificationAndroidMathCount > 0 ||
+ codeSimplificationAdvancedCount > 0 ||
+ codeRemovalCount > 0 ||
+ codeRemovalVariableCount > 0 ||
+ codeRemovalExceptionCount > 0 ||
+ codeAllocationVariableCount > 0;
+ }
+
+
+ private List createPeepholeOptimizations(InstructionSequenceConstants sequences,
+ BranchTargetFinder branchTargetFinder,
+ CodeAttributeEditor codeAttributeEditor,
+ InstructionCounter codeSimplificationVariableCounter,
+ InstructionCounter codeSimplificationArithmeticCounter,
+ InstructionCounter codeSimplificationCastCounter,
+ InstructionCounter codeSimplificationFieldCounter,
+ InstructionCounter codeSimplificationBranchCounter,
+ InstructionCounter codeSimplificationObjectCounter,
+ InstructionCounter codeSimplificationStringCounter,
+ InstructionCounter codeSimplificationMathCounter,
+ InstructionCounter codeSimplificationAndroidMathCounter)
+ {
+ List peepholeOptimizations = new ArrayList();
+
+ if (codeSimplificationVariable)
+ {
+ // Peephole optimizations involving local variables.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.VARIABLE_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter));
+ }
+
+ if (codeSimplificationArithmetic)
+ {
+ // Peephole optimizations involving arithmetic operations.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.ARITHMETIC_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter));
+ }
+
+ if (codeSimplificationCast)
+ {
+ // Peephole optimizations involving cast operations.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.CAST_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter));
+ }
+
+ if (codeSimplificationField)
+ {
+ // Peephole optimizations involving fields.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.FIELD_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter));
+ }
+
+ if (codeSimplificationBranch)
+ {
+ // Peephole optimizations involving branches.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.BRANCH_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter));
+
+ // Include optimization of branches to branches and returns.
+ peepholeOptimizations.add(
+ new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
+ peepholeOptimizations.add(
+ new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
+ }
+
+ if (codeSimplificationObject)
+ {
+ // Peephole optimizations involving branches.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.OBJECT_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationObjectCounter));
+ }
+
+ if (codeSimplificationString)
+ {
+ // Peephole optimizations involving branches.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.STRING_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter));
+ }
+
+ if (codeSimplificationMath)
+ {
+ // Peephole optimizations involving math.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.MATH_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationMathCounter));
+
+ if (configuration.android)
+ {
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(sequences.CONSTANTS,
+ sequences.MATH_ANDROID_SEQUENCES,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationAndroidMathCounter));
+ }
+ }
+
+ return peepholeOptimizations;
+ }
+
+
+ /**
+ * Returns a String indicating whether the given flag is enabled or
+ * disabled.
+ */
+ private String disabled(boolean flag)
+ {
+ return flag ? "" : " (disabled)";
+ }
+
+
+ /**
+ * Returns a String indicating whether the given flags are enabled or
+ * disabled.
+ */
+ private String disabled(boolean flag1, boolean flag2)
+ {
+ return flag1 && flag2 ? "" :
+ flag1 || flag2 ? " (partially disabled)" :
+ " (disabled)";
+ }
+
+
+ /**
+ * A simple class pool visitor that will output timing information.
+ */
+ private class TimedClassPoolVisitor
+ implements ClassPoolVisitor
+ {
+ private final String message;
+ private final ClassPoolVisitor classPoolVisitor;
+
+ public TimedClassPoolVisitor(String message, ClassVisitor classVisitor)
+ {
+ this(message, new AllClassVisitor(classVisitor));
+ }
+
+ public TimedClassPoolVisitor(String message, ClassPoolVisitor classPoolVisitor)
+ {
+ this.message = message;
+ this.classPoolVisitor = classPoolVisitor;
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ long start = 0;
+
+ if (DETAILS)
+ {
+ System.out.print(message);
+ System.out.print(getPadding(message.length(), 48));
+ start = System.currentTimeMillis();
+ }
+
+ classPool.accept(classPoolVisitor);
+
+ if (DETAILS)
+ {
+ long end = System.currentTimeMillis();
+ System.out.println(String.format(" took: %6d ms", (end - start)));
+ }
+ }
+
+
+ // Private helper methods
+
+ private String getPadding(int pos, int size)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = pos; i < size; i++)
+ {
+ sb.append('.');
+ }
+ return sb.toString();
+ }
+ }
+}
diff --git a/src/proguard/optimize/ParameterShrinker.java b/core/src/proguard/optimize/ParameterShrinker.java
similarity index 88%
rename from src/proguard/optimize/ParameterShrinker.java
rename to core/src/proguard/optimize/ParameterShrinker.java
index 8d6ff62..0f54029 100644
--- a/src/proguard/optimize/ParameterShrinker.java
+++ b/core/src/proguard/optimize/ParameterShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -25,8 +25,8 @@
import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.editor.VariableRemapper;
import proguard.classfile.util.*;
-import proguard.classfile.visitor.MemberVisitor;
-import proguard.optimize.info.ParameterUsageMarker;
+import proguard.classfile.visitor.*;
+import proguard.optimize.info.*;
/**
* This AttributeVisitor removes unused parameters from the code of the methods
@@ -48,7 +48,7 @@ public class ParameterShrinker
//*/
- private final MemberVisitor extraVariableMemberVisitor;
+ private final MemberVisitor extraUnusedParameterMethodVisitor;
private final VariableRemapper variableRemapper = new VariableRemapper();
@@ -64,12 +64,12 @@ public ParameterShrinker()
/**
* Creates a new ParameterShrinker with an extra visitor.
- * @param extraVariableMemberVisitor an optional extra visitor for all
- * removed parameters.
+ * @param extraUnusedParameterMethodVisitor an optional extra visitor for
+ * all removed parameters.
*/
- public ParameterShrinker(MemberVisitor extraVariableMemberVisitor)
+ public ParameterShrinker(MemberVisitor extraUnusedParameterMethodVisitor)
{
- this.extraVariableMemberVisitor = extraVariableMemberVisitor;
+ this.extraUnusedParameterMethodVisitor = extraUnusedParameterMethodVisitor;
}
@@ -127,9 +127,9 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
variableMap[parameterIndex] = unusedParameterIndex++;
// Visit the method, if required.
- if (extraVariableMemberVisitor != null)
+ if (extraUnusedParameterMethodVisitor != null)
{
- method.accept(clazz, extraVariableMemberVisitor);
+ method.accept(clazz, extraUnusedParameterMethodVisitor);
}
}
}
diff --git a/src/proguard/optimize/TailRecursionSimplifier.java b/core/src/proguard/optimize/TailRecursionSimplifier.java
similarity index 85%
rename from src/proguard/optimize/TailRecursionSimplifier.java
rename to core/src/proguard/optimize/TailRecursionSimplifier.java
index 3e664b3..c92c1ec 100644
--- a/src/proguard/optimize/TailRecursionSimplifier.java
+++ b/core/src/proguard/optimize/TailRecursionSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -55,6 +55,7 @@ public class TailRecursionSimplifier
private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
private final MyRecursionChecker recursionChecker = new MyRecursionChecker();
+ private final StackSizeComputer stackSizeComputer = new StackSizeComputer();
private Method targetMethod;
private boolean inlinedAny;
@@ -118,12 +119,12 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
// Update the code attribute if any code has been inlined.
if (inlinedAny)
{
- // Copy the exceptions.
- codeAttribute.exceptionsAccept(clazz, method, this);
-
// Append a label just after the code.
codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
+ // Copy the exceptions.
+ codeAttribute.exceptionsAccept(clazz, method, this);
+
codeAttributeComposer.endCodeFragment();
codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute);
@@ -176,35 +177,40 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
if (recursionChecker.isRecursive())
{
- if (DEBUG)
+ // Is the stack empty after the return?
+ stackSizeComputer.visitCodeAttribute(clazz, method, codeAttribute);
+
+ if (stackSizeComputer.getStackSizeAfter(nextOffset) == 0)
{
- System.out.println("TailRecursionSimplifier: ["+
- clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"], inlining "+constantInstruction.toString(offset));
- }
+ if (DEBUG)
+ {
+ System.out.println("TailRecursionSimplifier: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"], inlining "+constantInstruction.toString(offset));
+ }
- // Append a label.
- codeAttributeComposer.appendLabel(offset);
+ // Append a label.
+ codeAttributeComposer.appendLabel(offset);
- storeParameters(clazz, method);
+ storeParameters(clazz, method);
- // Branch back to the start of the method.
- int gotoOffset = offset + 1;
- codeAttributeComposer.appendInstruction(gotoOffset,
- new BranchInstruction(InstructionConstants.OP_GOTO, -gotoOffset));
+ // Branch back to the start of the method.
+ int gotoOffset = offset + 1;
+ codeAttributeComposer.appendInstruction(gotoOffset,
+ new BranchInstruction(InstructionConstants.OP_GOTO, -gotoOffset));
- // The original return instruction will be
- // removed elsewhere, if possible.
+ // The original return instruction will be
+ // removed elsewhere, if possible.
- // Remember that the code has changed.
- inlinedAny = true;
+ // Remember that the code has changed.
+ inlinedAny = true;
- if (extraTailRecursionVisitor != null)
- {
- extraTailRecursionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction);
- }
+ if (extraTailRecursionVisitor != null)
+ {
+ extraTailRecursionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ }
- // The invocation itself is no longer necessary.
- return;
+ // The invocation itself is no longer necessary.
+ return;
+ }
}
}
}
diff --git a/src/proguard/optimize/WriteOnlyFieldFilter.java b/core/src/proguard/optimize/WriteOnlyFieldFilter.java
similarity index 97%
rename from src/proguard/optimize/WriteOnlyFieldFilter.java
rename to core/src/proguard/optimize/WriteOnlyFieldFilter.java
index b6c00b9..fc36a15 100644
--- a/src/proguard/optimize/WriteOnlyFieldFilter.java
+++ b/core/src/proguard/optimize/WriteOnlyFieldFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/evaluation/EvaluationShrinker.java b/core/src/proguard/optimize/evaluation/EvaluationShrinker.java
new file mode 100644
index 0000000..15591ce
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/EvaluationShrinker.java
@@ -0,0 +1,1548 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.RefConstant;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.CodeAttributeEditor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.TracedStack;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.ParameterUsageMarker;
+
+/**
+ * This AttributeVisitor shrinks the code attributes that it visits, based
+ * on partial evaluation.
+ *
+ * @author Eric Lafortune
+ */
+public class EvaluationShrinker
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ ExceptionInfoVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_RESULTS = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("es") != null;
+ private static boolean DEBUG_RESULTS = DEBUG;
+ //*/
+
+ private static final int UNSUPPORTED = -1;
+ private static final int NOP = InstructionConstants.OP_NOP & 0xff;
+ private static final int POP = InstructionConstants.OP_POP & 0xff;
+ private static final int POP2 = InstructionConstants.OP_POP2 & 0xff;
+ private static final int DUP = InstructionConstants.OP_DUP & 0xff;
+ private static final int DUP_X1 = InstructionConstants.OP_DUP_X1 & 0xff;
+ private static final int DUP_X2 = InstructionConstants.OP_DUP_X2 & 0xff;
+ private static final int DUP2 = InstructionConstants.OP_DUP2 & 0xff;
+ private static final int DUP2_X1 = InstructionConstants.OP_DUP2_X1 & 0xff;
+ private static final int DUP2_X2 = InstructionConstants.OP_DUP2_X2 & 0xff;
+ private static final int SWAP = InstructionConstants.OP_SWAP & 0xff;
+ private static final int MOV_X2 = DUP_X2 | (POP << 8);
+ private static final int MOV2_X1 = DUP2_X1 | (POP2 << 8);
+ private static final int MOV2_X2 = DUP2_X2 | (POP2 << 8);
+ private static final int POP_X1 = SWAP | (POP << 8);
+ private static final int POP_X2 = DUP2_X1 | (POP2 << 8) | (POP << 16);
+ private static final int POP_X3 = UNSUPPORTED;
+ private static final int POP2_X1 = DUP_X2 | (POP << 8) | (POP2 << 16);
+ private static final int POP2_X2 = DUP2_X2 | (POP2 << 8) | (POP2 << 16);
+ private static final int POP3 = POP2 | (POP << 8);
+ private static final int POP4 = POP2 | (POP2 << 8);
+ private static final int POP_DUP = POP | (DUP << 8);
+ private static final int POP_SWAP_POP = POP | (SWAP << 8) | (POP << 16);
+ private static final int POP2_SWAP_POP = POP2 | (SWAP << 8) | (POP << 16);
+ private static final int SWAP_DUP_X1 = SWAP | (DUP_X1 << 8);
+ private static final int SWAP_DUP_X1_SWAP = SWAP | (DUP_X1 << 8) | (SWAP << 16);
+ private static final int SWAP_POP_DUP = SWAP | (POP << 8) | (DUP << 16);
+ private static final int SWAP_POP_DUP_X1 = SWAP | (POP << 8) | (DUP_X1 << 16);
+ private static final int DUP_X2_POP2 = DUP_X2 | (POP2 << 8);
+ private static final int DUP2_X1_POP3 = DUP2_X1 | (POP2 << 8) | (POP << 16);
+ private static final int DUP2_X2_POP3 = DUP2_X2 | (POP2 << 8) | (POP << 16);
+ private static final int DUP2_X2_SWAP_POP = DUP2_X2 | (SWAP << 8) | (POP << 16);
+
+
+ private final InstructionUsageMarker instructionUsageMarker;
+ private final boolean runInstructionUsageMarker;
+ private final InstructionVisitor extraDeletedInstructionVisitor;
+ private final InstructionVisitor extraAddedInstructionVisitor;
+
+ private final MyStaticInvocationFixer staticInvocationFixer = new MyStaticInvocationFixer();
+ private final MyBackwardBranchFixer backwardBranchFixer = new MyBackwardBranchFixer();
+ private final MyNonReturningSubroutineFixer nonReturningSubroutineFixer = new MyNonReturningSubroutineFixer();
+ private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer();
+ private final MyInstructionDeleter instructionDeleter = new MyInstructionDeleter();
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, true);
+
+
+ /**
+ * Creates a new EvaluationShrinker.
+ */
+ public EvaluationShrinker()
+ {
+ this(new PartialEvaluator(), true, null, null);
+ }
+
+
+ /**
+ * Creates a new EvaluationShrinker.
+ * @param partialEvaluator the partial evaluator that will
+ * analyze the code.
+ * @param runPartialEvaluator specifies whether the partial
+ * evaluator should be run for each
+ * method, or if some other class is
+ * already doing this.
+ * @param extraDeletedInstructionVisitor an optional extra visitor for all
+ * deleted instructions.
+ * @param extraAddedInstructionVisitor an optional extra visitor for all
+ * added instructions.
+ */
+ public EvaluationShrinker(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator,
+ InstructionVisitor extraDeletedInstructionVisitor,
+ InstructionVisitor extraAddedInstructionVisitor)
+ {
+ this(new InstructionUsageMarker(partialEvaluator, runPartialEvaluator),
+ true,
+ extraDeletedInstructionVisitor,
+ extraAddedInstructionVisitor);
+ }
+
+
+ /**
+ * Creates a new EvaluationShrinker.
+ * @param instructionUsageMarker the instruction usage marker that
+ * will analyze the code.
+ * @param runInstructionUsageMarker specifies whether the usage
+ * marker should be run for each
+ * method, or if some other class is
+ * already doing this.
+ * @param extraDeletedInstructionVisitor an optional extra visitor for all
+ * deleted instructions.
+ * @param extraAddedInstructionVisitor an optional extra visitor for all
+ * added instructions.
+ */
+ public EvaluationShrinker(InstructionUsageMarker instructionUsageMarker,
+ boolean runInstructionUsageMarker,
+ InstructionVisitor extraDeletedInstructionVisitor,
+ InstructionVisitor extraAddedInstructionVisitor)
+ {
+ this.instructionUsageMarker = instructionUsageMarker;
+ this.runInstructionUsageMarker = runInstructionUsageMarker;
+ this.extraDeletedInstructionVisitor = extraDeletedInstructionVisitor;
+ this.extraAddedInstructionVisitor = extraAddedInstructionVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+// DEBUG = DEBUG_RESULTS =
+// clazz.getName().equals("abc/Def") &&
+// method.getName(clazz).equals("abc");
+
+ // TODO: Remove this when the evaluation shrinker has stabilized.
+ // Catch any unexpected exceptions from the actual visiting method.
+ try
+ {
+ // Process the code.
+ visitCodeAttribute0(clazz, method, codeAttribute);
+ }
+ catch (RuntimeException ex)
+ {
+ System.err.println("Unexpected error while shrinking instructions after partial evaluation:");
+ System.err.println(" Class = ["+clazz.getName()+"]");
+ System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+ System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
+
+ ex.printStackTrace();
+ System.err.println("Not optimizing this method");
+
+ if (DEBUG)
+ {
+ method.accept(clazz, new ClassPrinter());
+
+ throw ex;
+ }
+ }
+ }
+
+
+ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ if (DEBUG_RESULTS)
+ {
+ System.out.println("EvaluationShrinker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+ }
+
+ // Analyze the method.
+ if (runInstructionUsageMarker)
+ {
+ instructionUsageMarker.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ if (DEBUG) System.out.println();
+
+
+ // Reset the code changes.
+ codeAttributeEditor.reset(codeLength);
+
+ // Replace virtual invocations by static invocations, where neceesary.
+ if (DEBUG) System.out.println("Static invocation fixing:");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ instructionUsageMarker.necessaryInstructionFilter(true,
+ staticInvocationFixer));
+
+ if (DEBUG) System.out.println();
+
+
+ // Replace traced but unnecessary backward branches by infinite loops.
+ // The virtual machine's verification step is not smart enough to see
+ // the code isn't reachable, and may complain otherwise.
+ // Any clearly unreachable code will still be removed elsewhere.
+ if (DEBUG) System.out.println("Backward branch fixing:");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ instructionUsageMarker.tracedInstructionFilter(true,
+ instructionUsageMarker.necessaryInstructionFilter(false,
+ backwardBranchFixer)));
+
+ if (DEBUG) System.out.println();
+
+
+ // Insert infinite loops after jumps to subroutines that don't return.
+ // The virtual machine's verification step is not smart enough to see
+ // the code isn't reachable, and may complain otherwise.
+ if (DEBUG) System.out.println("Non-returning subroutine fixing:");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ instructionUsageMarker.necessaryInstructionFilter(true,
+ nonReturningSubroutineFixer));
+
+ if (DEBUG) System.out.println();
+
+
+ // Locally fix instructions, in order to keep the stack consistent.
+ if (DEBUG) System.out.println("Stack consistency fixing:");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ instructionUsageMarker.tracedInstructionFilter(true,
+ stackConsistencyFixer));
+
+ if (DEBUG) System.out.println();
+
+
+ // Delete all instructions that are not used.
+ if (DEBUG) System.out.println("Deleting unused instructions");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ instructionUsageMarker.necessaryInstructionFilter(false,
+ instructionDeleter));
+
+ if (DEBUG) System.out.println();
+
+
+ if (DEBUG_RESULTS)
+ {
+ System.out.println("Simplification results:");
+
+ int offset = 0;
+ do
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+ System.out.println((instructionUsageMarker.isInstructionNecessary(offset) ? " + " :
+ instructionUsageMarker.isExtraPushPopInstructionNecessary(offset) ? " ~ " :
+ " - ") +
+ instruction.toString(offset));
+
+ if (instructionUsageMarker.isTraced(offset))
+ {
+ InstructionOffsetValue branchTargets = instructionUsageMarker.branchTargets(offset);
+ if (branchTargets != null)
+ {
+ System.out.println(" has overall been branching to "+branchTargets);
+ }
+
+ boolean deleted = codeAttributeEditor.deleted[offset];
+ if (instructionUsageMarker.isInstructionNecessary(offset) && deleted)
+ {
+ System.out.println(" is deleted");
+ }
+
+ Instruction preInsertion = codeAttributeEditor.preInsertions[offset];
+ if (preInsertion != null)
+ {
+ System.out.println(" is preceded by: "+preInsertion);
+ }
+
+ Instruction replacement = codeAttributeEditor.replacements[offset];
+ if (replacement != null)
+ {
+ System.out.println(" is replaced by: "+replacement);
+ }
+
+ Instruction postInsertion = codeAttributeEditor.postInsertions[offset];
+ if (postInsertion != null)
+ {
+ System.out.println(" is followed by: "+postInsertion);
+ }
+ }
+
+ offset += instruction.length(offset);
+ }
+ while (offset < codeLength);
+ }
+
+ // Clear exception handlers that are not necessary.
+ codeAttribute.exceptionsAccept(clazz, method, this);
+
+ // Apply all accumulated changes to the code.
+ codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+
+ /**
+ * This MemberVisitor converts virtual method invocations into static
+ * method invocations if the 'this' parameter isn't used.
+ */
+ private class MyStaticInvocationFixer
+ extends SimplifiedVisitor
+ implements InstructionVisitor,
+ ConstantVisitor,
+ MemberVisitor
+ {
+ private int invocationOffset;
+ private ConstantInstruction invocationInstruction;
+
+
+ // 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)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ this.invocationOffset = offset;
+ this.invocationInstruction = constantInstruction;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ refConstant.referencedMemberAccept(this);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member) {}
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Make the method invocation static, if possible.
+ if ((programMethod.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 &&
+ !ParameterUsageMarker.isParameterUsed(programMethod, 0))
+ {
+ replaceByStaticInvocation(programClass,
+ invocationOffset,
+ invocationInstruction);
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor replaces all backward branches by
+ * infinite loops.
+ */
+ private class MyBackwardBranchFixer
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Is it a traced but unmarked backward branch, without an unmarked
+ // straddling forward branch? Note that this is still a heuristic.
+ if (isAllSmallerThanOrEqual(instructionUsageMarker.branchTargets(offset),
+ offset) &&
+ !isAnyUnnecessaryInstructionBranchingOver(lastNecessaryInstructionOffset(offset),
+ offset))
+ {
+ replaceByInfiniteLoop(clazz, offset);
+
+ if (DEBUG) System.out.println(" Setting infinite loop instead of "+instruction.toString(offset));
+ }
+ }
+
+
+ /**
+ * Returns whether all of the given instruction offsets (at least one)
+ * are smaller than or equal to the given offset.
+ */
+ private boolean isAllSmallerThanOrEqual(InstructionOffsetValue instructionOffsets,
+ int instructionOffset)
+ {
+ if (instructionOffsets != null)
+ {
+ // Loop over all instruction offsets.
+ int branchCount = instructionOffsets.instructionOffsetCount();
+ if (branchCount > 0)
+ {
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the offset larger than the reference offset?
+ if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns the highest offset of an instruction that has been marked as
+ * necessary, before the given offset.
+ */
+ private int lastNecessaryInstructionOffset(int instructionOffset)
+ {
+ for (int offset = instructionOffset-1; offset >= 0; offset--)
+ {
+ if (instructionUsageMarker.isInstructionNecessary(instructionOffset))
+ {
+ return offset;
+ }
+ }
+
+ return 0;
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor appends infinite loops after all visited
+ * non-returning subroutine invocations.
+ */
+ private class MyNonReturningSubroutineFixer
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ // Is it a necessary subroutine invocation?
+ if (branchInstruction.canonicalOpcode() == InstructionConstants.OP_JSR)
+ {
+ int nextOffset = offset + branchInstruction.length(offset);
+ if (!instructionUsageMarker.isInstructionNecessary(nextOffset))
+ {
+ replaceByInfiniteLoop(clazz, nextOffset);
+
+ if (DEBUG) System.out.println(" Adding infinite loop at ["+nextOffset+"] after "+branchInstruction.toString(offset));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor fixes instructions locally, popping any unused
+ * produced stack entries after marked instructions, and popping produced
+ * stack entries and pushing missing stack entries instead of unmarked
+ * instructions.
+ */
+ private class MyStackConsistencyFixer
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Has the instruction been marked?
+ if (instructionUsageMarker.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);
+ if (popCount > 0)
+ {
+ TracedStack tracedStack =
+ instructionUsageMarker.getStackBefore(offset);
+
+ int stackSize = tracedStack.size();
+
+ int requiredPopCount = 0;
+ int requiredPushCount = 0;
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
+ {
+ boolean stackEntryUnwantedBefore =
+ instructionUsageMarker.isStackEntryUnwantedBefore( offset, stackIndex);
+ boolean stackEntryPresentBefore =
+ instructionUsageMarker.isStackEntryPresentBefore( offset, stackIndex);
+
+ if (stackEntryUnwantedBefore)
+ {
+ if (stackEntryPresentBefore)
+ {
+ // Remember to pop it.
+ requiredPopCount++;
+ }
+ }
+ else
+ {
+ if (!stackEntryPresentBefore)
+ {
+ // Remember to push some value.
+ requiredPushCount++;
+ }
+ }
+ }
+
+ // 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)
+ {
+ Value value = tracedStack.getTop(0);
+
+ if (DEBUG) System.out.println(" Inserting before marked consumer "+instruction.toString(offset));
+
+ if (requiredPushCount > (value.isCategory2() ? 2 : 1))
+ {
+ throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]");
+ }
+
+ insertPushInstructions(offset, false, true, value.computationalType());
+ }
+ }
+
+ // Check all stack entries that are pushed.
+ // Typical case: a return value that wasn't really required and
+ // that should be popped.
+ int pushCount = instruction.stackPushCount(clazz);
+ if (pushCount > 0)
+ {
+ TracedStack tracedStack =
+ instructionUsageMarker.getStackAfter(offset);
+
+ int stackSize = tracedStack.size();
+
+ int requiredPopCount = 0;
+ for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
+ {
+ // Is the stack entry required by consumers?
+ if (!instructionUsageMarker.isStackEntryNecessaryAfter(offset, stackIndex))
+ {
+ // Remember to pop it.
+ requiredPopCount++;
+ }
+ }
+
+ // Pop the unnecessary stack entries.
+ if (requiredPopCount > 0)
+ {
+ if (DEBUG) System.out.println(" Inserting after marked producer "+instruction.toString(offset));
+
+ insertPopInstructions(offset, false, false, requiredPopCount);
+ }
+ }
+ }
+ else if (instructionUsageMarker.isExtraPushPopInstructionNecessary(offset))
+ {
+ // Check all stack entries that would be popped.
+ // Typical case: a stack value that is required elsewhere and
+ // that still has to be popped.
+ int popCount = instruction.stackPopCount(clazz);
+ if (popCount > 0)
+ {
+ TracedStack tracedStack =
+ instructionUsageMarker.getStackBefore(offset);
+
+ int stackSize = tracedStack.size();
+
+ int expectedPopCount = 0;
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (instructionUsageMarker.isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Remember to pop it.
+ expectedPopCount++;
+ }
+ }
+
+ // Pop the unnecessary stack entries.
+ if (expectedPopCount > 0)
+ {
+ if (DEBUG) System.out.println(" Replacing unmarked consumer "+instruction.toString(offset));
+
+ insertPopInstructions(offset, true, false, expectedPopCount);
+ }
+ }
+
+ // Check all stack entries that would be pushed.
+ // Typical case: a corresponding stack entry is pushed
+ // elsewhere so it still has to be pushed here.
+ int pushCount = instruction.stackPushCount(clazz);
+ if (pushCount > 0)
+ {
+ TracedStack tracedStack =
+ instructionUsageMarker.getStackAfter(offset);
+
+ int stackSize = tracedStack.size();
+
+ int expectedPushCount = 0;
+ for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
+ {
+ // Is the stack entry required by consumers?
+ if (instructionUsageMarker.isStackEntryNecessaryAfter(offset, stackIndex))
+ {
+ // Remember to push it.
+ expectedPushCount++;
+ }
+ }
+
+ // Push some necessary stack entries.
+ if (expectedPushCount > 0)
+ {
+ if (DEBUG) System.out.println(" Replacing unmarked producer "+instruction.toString(offset));
+
+ insertPushInstructions(offset, true, false, tracedStack.getTop(0).computationalType());
+ }
+ }
+ }
+ }
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (instructionUsageMarker.isInstructionNecessary(offset) &&
+ isDupOrSwap(simpleInstruction))
+ {
+ int topBefore = instructionUsageMarker.getStackBefore(offset).size() - 1;
+ int topAfter = instructionUsageMarker.getStackAfter(offset).size() - 1;
+
+ byte oldOpcode = simpleInstruction.opcode;
+
+ // Simplify the dup/swap instruction if possible.
+ int newOpcodes = fixDupSwap(offset, oldOpcode, topBefore, topAfter);
+
+ // Did we find a suitable (extended) opcode?
+ if (newOpcodes == UNSUPPORTED)
+ {
+ // We can't easily emulate some constructs.
+ throw new UnsupportedOperationException("Can't handle "+simpleInstruction.toString()+" instruction at ["+offset +"]");
+ }
+
+ // Is there a single replacement opcode?
+ if ((newOpcodes & ~0xff) == 0)
+ {
+ byte newOpcode = (byte)newOpcodes;
+
+ if (newOpcode == InstructionConstants.OP_NOP)
+ {
+ // Delete the instruction.
+ codeAttributeEditor.deleteInstruction(offset);
+
+ if (extraDeletedInstructionVisitor != null)
+ {
+ extraDeletedInstructionVisitor.visitSimpleInstruction(null, null, null, offset, null);
+ }
+
+ if (DEBUG) System.out.println(" Deleting marked instruction "+simpleInstruction.toString(offset));
+ }
+ else if (newOpcode == oldOpcode)
+ {
+ // Leave the instruction unchanged.
+ codeAttributeEditor.undeleteInstruction(offset);
+
+ if (DEBUG) System.out.println(" Marking unchanged instruction "+simpleInstruction.toString(offset));
+ }
+ else
+ {
+ // Replace the instruction.
+ Instruction replacementInstruction = new SimpleInstruction(newOpcode);
+ codeAttributeEditor.replaceInstruction(offset,
+ replacementInstruction);
+
+ if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by "+replacementInstruction.toString());
+ }
+ }
+ else
+ {
+ // Collect the replacement instructions.
+ Instruction[] replacementInstructions = new Instruction[4];
+
+ if (DEBUG) System.out.println(" Replacing instruction "+simpleInstruction.toString(offset)+" by");
+ int count = 0;
+ while (newOpcodes != 0)
+ {
+ SimpleInstruction replacementInstruction = new SimpleInstruction((byte)newOpcodes);
+ replacementInstructions[count++] = replacementInstruction;
+
+ if (DEBUG) System.out.println(" "+replacementInstruction.toString());
+ newOpcodes >>>= 8;
+ }
+
+ // Create a properly sized array.
+ if (count < 4)
+ {
+ Instruction[] newInstructions = new Instruction[count];
+ System.arraycopy(replacementInstructions, 0, newInstructions, 0, count);
+ replacementInstructions = newInstructions;
+ }
+
+ codeAttributeEditor.replaceInstruction(offset,
+ replacementInstructions);
+ }
+ }
+ else
+ {
+ visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ if (instructionUsageMarker.isInstructionNecessary(offset))
+ {
+ if (branchInstruction.stackPopCount(clazz) > 0 &&
+ !instructionUsageMarker.isStackEntryPresentBefore(offset, instructionUsageMarker.getStackBefore(offset).size() - 1))
+ {
+ // Replace the branch instruction by a simple goto.
+ Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO,
+ branchInstruction.branchOffset);
+ codeAttributeEditor.replaceInstruction(offset,
+ replacementInstruction);
+
+ if (DEBUG) System.out.println(" Replacing branch instruction "+branchInstruction.toString(offset)+" by "+replacementInstruction.toString());
+ }
+ }
+ else
+ {
+ visitAnyInstruction(clazz, method, codeAttribute, offset, branchInstruction);
+ }
+ }
+
+
+ public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
+ {
+ if (instructionUsageMarker.isInstructionNecessary(offset))
+ {
+ if (switchInstruction.stackPopCount(clazz) > 0 &&
+ !instructionUsageMarker.isStackEntryPresentBefore(offset, instructionUsageMarker.getStackBefore(offset).size() - 1))
+ {
+ // Replace the switch instruction by a simple goto.
+ Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO,
+ switchInstruction.defaultOffset);
+ codeAttributeEditor.replaceInstruction(offset,
+ replacementInstruction);
+
+ if (DEBUG) System.out.println(" Replacing switch instruction "+switchInstruction.toString(offset)+" by "+replacementInstruction.toString());
+ }
+ }
+ else
+ {
+ visitAnyInstruction(clazz, method, codeAttribute, offset, switchInstruction);
+ }
+ }
+
+
+ /**
+ * Returns whether the given instruction is a dup or swap instruction
+ * (dup, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2, swap).
+ */
+ private boolean isDupOrSwap(Instruction instruction)
+ {
+ return instruction.opcode >= InstructionConstants.OP_DUP &&
+ instruction.opcode <= InstructionConstants.OP_SWAP;
+ }
+
+
+ /**
+ * Returns a dup/swap opcode that is corrected for the stack entries
+ * that are present before the instruction and necessary after the
+ * instruction. The returned integer opcode may contain multiple byte
+ * opcodes (least significant byte first).
+ * @param instructionOffset the offset of the dup/swap instruction.
+ * @param dupSwapOpcode the original dup/swap opcode.
+ * @param topBefore the index of the top stack entry before
+ * the instruction (counting from the bottom).
+ * @param topAfter the index of the top stack entry after
+ * the instruction (counting from the bottom).
+ * @return the corrected opcode.
+ */
+ private int fixDupSwap(int instructionOffset,
+ byte dupSwapOpcode,
+ int topBefore,
+ int topAfter)
+ {
+ switch (dupSwapOpcode)
+ {
+ case InstructionConstants.OP_DUP: return fixedDup (instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_DUP_X1: return fixedDup_x1 (instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_DUP_X2: return fixedDup_x2 (instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_DUP2: return fixedDup2 (instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_DUP2_X1: return fixedDup2_x1(instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_DUP2_X2: return fixedDup2_x2(instructionOffset, topBefore, topAfter);
+ case InstructionConstants.OP_SWAP: return fixedSwap (instructionOffset, topBefore, topAfter);
+ default: throw new IllegalArgumentException("Not a dup/swap opcode ["+dupSwapOpcode+"]");
+ }
+ }
+
+
+ private int fixedDup(int instructionOffset, int topBefore, int topAfter)
+ {
+ boolean stackEntryPresent0 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore);
+
+ boolean stackEntryNecessary0 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter);
+ boolean stackEntryNecessary1 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+
+ // Figure out which stack entries should be moved,
+ // copied, or removed.
+ return
+ stackEntryNecessary0 ?
+ stackEntryNecessary1 ? DUP : // ...O -> ...OO
+ NOP : // ...O -> ...O
+ stackEntryNecessary1 ? NOP : // ...O -> ...O
+ stackEntryPresent0 ? POP : // ...O -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedDup_x1(int instructionOffset, int topBefore, int topAfter)
+ {
+ boolean stackEntryPresent0 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore);
+ boolean stackEntryPresent1 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+
+ boolean stackEntryNecessary0 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter);
+ boolean stackEntryNecessary1 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
+
+ // Figure out which stack entries should be moved,
+ // copied, or removed.
+ return
+ stackEntryNecessary1 ?
+ stackEntryNecessary2 ?
+ stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO
+ SWAP : // ...XO -> ...OX
+ // !stackEntryNecessary2
+ stackEntryNecessary0 ? NOP : // ...XO -> ...XO
+ stackEntryPresent0 ? POP : // ...XO -> ...X
+ NOP : // ...X -> ...X
+ stackEntryPresent1 ?
+ stackEntryNecessary2 ?
+ stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO
+ POP_X1 : // ...XO -> ...O
+ // !stackEntryNecessary2
+ stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O
+ stackEntryPresent0 ? POP2 : // ...XO -> ...
+ POP : // ...X -> ...
+ // !stackEntryPresent1
+ stackEntryNecessary2 ?
+ stackEntryNecessary0 ? DUP : // ...O -> ...OO
+ NOP : // ...O -> ...O
+ // !stackEntryNecessary2
+ stackEntryNecessary0 ? NOP : // ...O -> ...O
+ stackEntryPresent0 ? POP : // ...O -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedDup_x2(int instructionOffset, int topBefore, int topAfter)
+ {
+ boolean stackEntryPresent0 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore);
+ boolean stackEntryPresent1 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+ boolean stackEntryPresent2 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore - 2);
+
+ boolean stackEntryNecessary0 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter);
+ boolean stackEntryNecessary1 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 3);
+
+ // Figure out which stack entries should be moved,
+ // copied, or removed.
+ return
+ stackEntryNecessary1 ?
+ stackEntryNecessary2 ?
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? DUP_X2 : // ...XYO -> ...OXYO
+ MOV_X2 : // ...XYO -> ...OXY
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? NOP : // ...XYO -> ...XYO
+ stackEntryPresent0 ? POP : // ...XYO -> ...XY
+ NOP : // ...XY -> ...XY
+ stackEntryPresent2 ?
+ stackEntryNecessary3 ?
+ // stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OYO
+ UNSUPPORTED : // ...XYO -> ...OY
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? POP_X2 : // ...XYO -> ...YO
+ stackEntryPresent0 ? POP_SWAP_POP : // ...XYO -> ...Y
+ POP_X1 : // ...XY -> ...Y
+ // !stackEntryPresent2
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? DUP_X1 : // ...YO -> ...OYO
+ SWAP : // ...YO -> ...OY
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? NOP : // ...YO -> ...YO
+ stackEntryPresent0 ? POP : // ...YO -> ...Y
+ NOP : // ...Y -> ...Y
+ stackEntryPresent1 ?
+ stackEntryNecessary2 ?
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? SWAP_POP_DUP_X1 : // ...XYO -> ...OXO
+ DUP_X2_POP2 : // ...XYO -> ...OX
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? POP_X1 : // ...XYO -> ...XO
+ stackEntryPresent0 ? POP2 : // ...XYO -> ...X
+ POP : // ...XY -> ...X
+ stackEntryPresent2 ?
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? UNSUPPORTED : // ...XYO -> ...OO
+ POP2_X1 : // ...XYO -> ...O
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? POP2_X1 : // ...XYO -> ...O
+ stackEntryPresent0 ? POP3 : // ...XYO -> ...
+ POP2 : // ...XY -> ...
+ // !stackEntryPresent2
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? SWAP_POP_DUP : // ...YO -> ...OO
+ POP_X1 : // ...YO -> ...O
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? POP_X1 : // ...YO -> ...O
+ stackEntryPresent0 ? POP2 : // ...YO -> ...
+ POP : // ...Y -> ...
+ // !stackEntryPresent1
+ stackEntryNecessary2 ?
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? DUP_X1 : // ...XO -> ...OXO
+ SWAP : // ...XO -> ...OX
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? NOP : // ...XO -> ...XO
+ stackEntryPresent0 ? POP : // ...XO -> ...X
+ NOP : // ...X -> ...X
+ stackEntryPresent2 ?
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? SWAP_POP_DUP : // ...XO -> ...OO
+ POP_X1 : // ...XO -> ...O
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? POP_X1 : // ...XO -> ...O
+ stackEntryPresent0 ? POP2 : // ...XO -> ...
+ POP : // ...X -> ...
+ // !stackEntryPresent2
+ stackEntryNecessary3 ?
+ stackEntryNecessary0 ? DUP : // ...O -> ...OO
+ NOP : // ...O -> ...O
+ // !stackEntryNecessary3
+ stackEntryNecessary0 ? NOP : // ...O -> ...O
+ stackEntryPresent0 ? POP : // ...O -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedDup2(int instructionOffset, int topBefore, int topAfter)
+ {
+ boolean stackEntryPresent0 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore);
+ boolean stackEntryPresent1 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset,
+ topBefore -
+ 1);
+
+ boolean stackEntryNecessary0 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter);
+ boolean stackEntryNecessary1 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 3);
+
+ return
+ stackEntryNecessary3 ?
+ stackEntryNecessary2 ?
+ stackEntryNecessary1 ?
+ stackEntryNecessary0 ? DUP2 : // ...AB -> ...ABAB
+ SWAP_DUP_X1 : // ...AB -> ...ABA
+ // !stackEntryNecessary1
+ stackEntryNecessary0 ? DUP : // ...AB -> ...ABB
+ NOP : // ...AB -> ...AB
+ // !stackEntryNecessary2
+ stackEntryNecessary1 ?
+ stackEntryNecessary0 ? SWAP_DUP_X1_SWAP : // ...AB -> ...AAB
+ stackEntryPresent0 ? POP_DUP : // ...AB -> ...AA
+ DUP : // ...A -> ...AA
+ // !stackEntryNecessary1
+ stackEntryNecessary0 ? NOP : // ...AB -> ...AB
+ stackEntryPresent0 ? POP : // ...AB -> ...A
+ NOP : // ...A -> ...A
+ // !stackEntryNecessary3
+ stackEntryNecessary2 ?
+ stackEntryNecessary1 ?
+ stackEntryNecessary0 ? DUP_X1 : // ...AB -> ...BAB
+ SWAP : // ...AB -> ...BA
+ stackEntryPresent1 ?
+ stackEntryNecessary0 ? SWAP_POP_DUP : // ...AB -> ...BB
+ POP_X1 : // ...AB -> ...B
+ // !stackEntryPresent1
+ stackEntryNecessary0 ? POP : // ...B -> ...BB
+ NOP : // ...B -> ...B
+ // !stackEntryNecessary2
+ stackEntryNecessary1 ?
+ stackEntryNecessary0 ? NOP : // ...AB -> ...AB
+ stackEntryPresent0 ? POP : // ...AB -> ...A
+ NOP : // ...A -> ...A
+ stackEntryPresent1 ?
+ stackEntryNecessary0 ? POP_X1 : // ...AB -> ...B
+ stackEntryPresent0 ? POP2 : // ...AB -> ...
+ POP : // ...A -> ...
+ // !stackEntryPresent1
+ stackEntryNecessary0 ? NOP : // ...B -> ...B
+ stackEntryPresent0 ? POP : // ...B -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedDup2_x1(int instructionOffset, int topBefore, int topAfter)
+ {
+ // We're currently assuming the value to be duplicated
+ // is a long or a double, taking up two slots, or at
+ // least consistent.
+ boolean stackEntriesPresent01 = instructionUsageMarker.isStackEntriesPresentBefore(instructionOffset, topBefore, topBefore - 1);
+ boolean stackEntryPresent2 = instructionUsageMarker.isStackEntryPresentBefore( instructionOffset, topBefore - 2);
+
+ boolean stackEntriesNecessary01 = instructionUsageMarker.isStackEntriesNecessaryAfter(instructionOffset, topAfter, topAfter - 1);
+ boolean stackEntryNecessary2 = instructionUsageMarker.isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
+ boolean stackEntriesNecessary34 = instructionUsageMarker.isStackEntriesNecessaryAfter(instructionOffset, topAfter - 3, topAfter - 4);
+
+ // Figure out which stack entries should be moved,
+ // copied, or removed.
+ return
+ stackEntryNecessary2 ?
+ stackEntriesNecessary34 ?
+ stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB
+ MOV2_X1 : // ...XAB -> ...ABX
+ // !stackEntriesNecessary34
+ stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB
+ stackEntriesPresent01 ? POP2 : // ...XAB -> ...X
+ NOP : // ...X -> ...X
+ stackEntryPresent2 ?
+ stackEntriesNecessary34 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB
+ POP_X2 : // ...XAB -> ...AB
+ // !stackEntriesNecessary34
+ stackEntriesNecessary01 ? DUP2_X1_POP3 : // ...XAB -> ...AB
+ stackEntriesPresent01 ? POP3 : // ...XAB -> ...
+ POP : // ...X -> ...
+ // !stackEntryPresent2
+ stackEntriesNecessary34 ?
+ stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB
+ NOP : // ...AB -> ...AB
+ // !stackEntriesNecessary34
+ stackEntriesNecessary01 ? NOP : // ...AB -> ...AB
+ stackEntriesPresent01 ? POP2 : // ...AB -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedDup2_x2(int instructionOffset, int topBefore, int topAfter)
+ {
+ // We're currently assuming the value to be duplicated
+ // is a long or a double, taking up two slots, or at
+ // least consistent.
+ boolean stackEntriesPresent01 = instructionUsageMarker.isStackEntriesPresentBefore(instructionOffset, topBefore, topBefore - 1);
+ boolean stackEntryPresent2 = instructionUsageMarker.isStackEntryPresentBefore( instructionOffset, topBefore - 2);
+ boolean stackEntryPresent3 = instructionUsageMarker.isStackEntryPresentBefore( instructionOffset, topBefore - 3);
+
+ boolean stackEntriesNecessary01 = instructionUsageMarker.isStackEntriesNecessaryAfter(instructionOffset, topAfter, topAfter - 1);
+ boolean stackEntryNecessary2 = instructionUsageMarker.isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = instructionUsageMarker.isStackEntryNecessaryAfter( instructionOffset, topAfter - 3);
+ boolean stackEntriesNecessary45 = instructionUsageMarker.isStackEntriesNecessaryAfter(instructionOffset, topAfter - 4, topAfter - 5);
+
+ // Figure out which stack entries should be moved,
+ // copied, or removed.
+ return
+ stackEntryNecessary2 ?
+ stackEntryNecessary3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? DUP2_X2 : // ...XYAB -> ...ABXYAB
+ MOV2_X2 : // ...XYAB -> ...ABXY
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? NOP : // ...XYAB -> ...XYAB
+ stackEntriesPresent01 ? POP2 : // ...XYAB -> ...XY
+ NOP : // ...XY -> ...XY
+ stackEntryPresent3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABYAB
+ DUP2_X2_SWAP_POP : // ...XYAB -> ...ABY
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? POP_X3 : // ...XYAB -> ...YAB
+ stackEntriesPresent01 ? POP2_SWAP_POP : // ...XYAB -> ...Y
+ POP_X1 : // ...XY -> ...Y
+ // !stackEntryPresent3
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? DUP2_X1 : // ...YAB -> ...ABYAB
+ MOV2_X1 : // ...YAB -> ...ABY
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? NOP : // ...YAB -> ...YAB
+ stackEntriesPresent01 ? POP2 : // ...YAB -> ...Y
+ NOP : // ...Y -> ...Y
+ stackEntryPresent2 ?
+ stackEntryNecessary3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABXAB
+ DUP2_X2_POP3 : // ...XYAB -> ...ABX
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? POP_X2 : // ...XYAB -> ...XAB
+ stackEntriesPresent01 ? POP3 : // ...XYAB -> ...X
+ POP : // ...XY -> ...X
+ stackEntryPresent3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...XYAB -> ...ABAB
+ POP2_X2 : // ...XYAB -> ...AB
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? POP2_X2 : // ...XYAB -> ...AB
+ stackEntriesPresent01 ? POP4 : // ...XYAB -> ...
+ POP2 : // ...XY -> ...
+ // !stackEntryPresent3
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...YAB -> ...ABAB
+ POP_X2 : // ...YAB -> ...AB
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? POP_X2 : // ...YAB -> ...AB
+ stackEntriesPresent01 ? POP3 : // ...YAB -> ...
+ POP : // ...Y -> ...
+ // !stackEntryPresent2
+ stackEntryNecessary3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? DUP2_X1 : // ...XAB -> ...ABXAB
+ MOV2_X1 : // ...XAB -> ...ABX
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? NOP : // ...XAB -> ...XAB
+ stackEntriesPresent01 ? POP2 : // ...XAB -> ...X
+ NOP : // ...X -> ...X
+ stackEntryPresent3 ?
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? UNSUPPORTED : // ...XAB -> ...ABAB
+ POP_X2 : // ...XAB -> ...AB
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? POP_X2 : // ...XAB -> ...AB
+ stackEntriesPresent01 ? POP3 : // ...XAB -> ...
+ POP : // ...X -> ...
+ // !stackEntryPresent3
+ stackEntriesNecessary45 ?
+ stackEntriesNecessary01 ? DUP2 : // ...AB -> ...ABAB
+ NOP : // ...AB -> ...AB
+ // !stackEntriesNecessary45
+ stackEntriesNecessary01 ? NOP : // ...AB -> ...AB
+ stackEntriesPresent01 ? POP2 : // ...AB -> ...
+ NOP; // ... -> ...
+ }
+
+
+ private int fixedSwap(int instructionOffset, int topBefore, int topAfter)
+ {
+ boolean stackEntryPresent0 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore);
+ boolean stackEntryPresent1 = instructionUsageMarker.isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+
+ boolean stackEntryNecessary0 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter);
+ boolean stackEntryNecessary1 = instructionUsageMarker.isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+
+ // Figure out which stack entries should be moved
+ // or removed.
+ return
+ stackEntryNecessary0 ?
+ stackEntryNecessary1 ? SWAP : // ...AB -> ...BA
+ stackEntryPresent0 ? POP : // ...AB -> ...A
+ NOP : // ...A -> ...A
+ stackEntryPresent1 ? POP_X1 : // ...AB -> ...B
+ NOP; // ...B -> ...B
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor deletes all visited instructions.
+ */
+ private class MyInstructionDeleter
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ codeAttributeEditor.deleteInstruction(offset);
+
+ // We're allowing edits on deleted instructions.
+ //codeAttributeEditor.insertBeforeInstruction(offset, (Instruction)null);
+ //codeAttributeEditor.replaceInstruction(offset, (Instruction)null);
+ //codeAttributeEditor.insertAfterInstruction(offset, (Instruction)null);
+
+ // Visit the instruction, if required.
+ if (extraDeletedInstructionVisitor != null)
+ {
+ instruction.accept(clazz, method, codeAttribute, offset, extraDeletedInstructionVisitor);
+ }
+ }
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
+ {
+ // Is the catch handler necessary?
+ if (!instructionUsageMarker.isTraced(exceptionInfo.u2handlerPC))
+ {
+ // Make the code block empty, so the code editor can remove it.
+ exceptionInfo.u2endPC = exceptionInfo.u2startPC;
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether any traced but unnecessary instruction between the two
+ * given offsets is branching over the second given offset.
+ */
+ private boolean isAnyUnnecessaryInstructionBranchingOver(int instructionOffset1,
+ int instructionOffset2)
+ {
+ for (int offset = instructionOffset1; offset < instructionOffset2; offset++)
+ {
+ // Is it a traced but unmarked straddling branch?
+ if (instructionUsageMarker.isTraced(offset) &&
+ !instructionUsageMarker.isInstructionNecessary(offset) &&
+ isAnyLargerThan(instructionUsageMarker.branchTargets(offset),
+ instructionOffset2))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether any of the given instruction offsets (at least one)
+ * is larger than the given offset.
+ */
+ private boolean isAnyLargerThan(InstructionOffsetValue instructionOffsets,
+ int instructionOffset)
+ {
+ if (instructionOffsets != null)
+ {
+ // Loop over all instruction offsets.
+ int branchCount = instructionOffsets.instructionOffsetCount();
+ if (branchCount > 0)
+ {
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the offset larger than the reference offset?
+ if (instructionOffsets.instructionOffset(branchIndex) > instructionOffset)
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Pushes a specified type of stack entry before or at the given offset.
+ * The instruction is marked as necessary.
+ */
+ private void insertPushInstructions(int offset,
+ boolean replace,
+ boolean before,
+ int computationalType)
+ {
+ // We can edit an instruction without marking it.
+ //markInstruction(offset);
+
+ // Create a simple push instrucion.
+ Instruction replacementInstruction =
+ new SimpleInstruction(pushOpcode(computationalType));
+
+ if (DEBUG) System.out.println(": "+replacementInstruction.toString(offset));
+
+ // Replace or insert the push instruction.
+ insertInstruction(offset, replace, before, replacementInstruction);
+ }
+
+
+ /**
+ * Returns the opcode of a push instruction corresponding to the given
+ * computational type.
+ * @param computationalType the computational type to be pushed on the stack.
+ */
+ private byte pushOpcode(int computationalType)
+ {
+ switch (computationalType)
+ {
+ case Value.TYPE_INTEGER: return InstructionConstants.OP_ICONST_0;
+ case Value.TYPE_LONG: return InstructionConstants.OP_LCONST_0;
+ case Value.TYPE_FLOAT: return InstructionConstants.OP_FCONST_0;
+ case Value.TYPE_DOUBLE: return InstructionConstants.OP_DCONST_0;
+ case Value.TYPE_REFERENCE:
+ case Value.TYPE_INSTRUCTION_OFFSET: return InstructionConstants.OP_ACONST_NULL;
+ }
+
+ throw new IllegalArgumentException("No push opcode for computational type ["+computationalType+"]");
+ }
+
+
+ /**
+ * 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,
+ boolean before,
+ int popCount)
+ {
+ // We can edit an instruction without marking it.
+ //markInstruction(offset);
+
+ switch (popCount)
+ {
+ case 1:
+ {
+ // Replace or insert a single pop instruction.
+ Instruction popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP);
+
+ insertInstruction(offset, replace, before, popInstruction);
+ break;
+ }
+ case 2:
+ {
+ // Replace or insert a single pop2 instruction.
+ Instruction popInstruction =
+ new SimpleInstruction(InstructionConstants.OP_POP2);
+
+ insertInstruction(offset, replace, before, popInstruction);
+ break;
+ }
+ default:
+ {
+ // Replace or 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;
+ }
+
+ insertInstructions(offset,
+ replace,
+ before,
+ popInstruction,
+ popInstructions);
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * 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);
+
+ if (extraAddedInstructionVisitor != null &&
+ !instructionUsageMarker.isInstructionNecessary(offset))
+ {
+ instruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
+ }
+ }
+ 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)
+ {
+ if (!instructionUsageMarker.isInstructionNecessary(offset))
+ {
+ instruction.accept(null, null, null, offset, extraAddedInstructionVisitor);
+ }
+
+ for (int index = 1; index < instructions.length; index++)
+ {
+ 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 < instructions.length; index++)
+ {
+ if (extraAddedInstructionVisitor != null)
+ {
+ instructions[index].accept(null, null, null, offset, extraAddedInstructionVisitor);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the instruction at a given offset by a static invocation.
+ */
+ private void replaceByStaticInvocation(Clazz clazz,
+ int offset,
+ ConstantInstruction constantInstruction)
+ {
+ // Remember the replacement instruction.
+ Instruction replacementInstruction =
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
+ constantInstruction.constantIndex);
+
+ if (DEBUG) System.out.println(" Replacing by static invocation "+constantInstruction.toString(offset)+" -> "+replacementInstruction.toString());
+
+ codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
+ }
+
+
+ /**
+ * Replaces the given instruction by an infinite loop.
+ */
+ private void replaceByInfiniteLoop(Clazz clazz,
+ int offset)
+ {
+ if (DEBUG) System.out.println(" Inserting infinite loop at ["+offset+"]");
+
+ // We can edit an instruction without marking it.
+ //markInstruction(offset);
+
+ // Replace the instruction by an infinite loop.
+ Instruction replacementInstruction =
+ new BranchInstruction(InstructionConstants.OP_GOTO, 0);
+
+ codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/core/src/proguard/optimize/evaluation/EvaluationSimplifier.java
similarity index 80%
rename from src/proguard/optimize/evaluation/EvaluationSimplifier.java
rename to core/src/proguard/optimize/evaluation/EvaluationSimplifier.java
index 2beb43b..14ca598 100644
--- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java
+++ b/core/src/proguard/optimize/evaluation/EvaluationSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.ClassPrinter;
-import proguard.evaluation.TracedVariables;
+import proguard.evaluation.*;
import proguard.evaluation.value.*;
import proguard.optimize.info.SideEffectInstructionChecker;
@@ -51,14 +51,14 @@ public class EvaluationSimplifier
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = System.getProperty("es") != null;
+ private static boolean DEBUG = System.getProperty("es") != null;
//*/
private final InstructionVisitor extraInstructionVisitor;
private final PartialEvaluator partialEvaluator;
private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, true);
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, true);
/**
@@ -78,7 +78,7 @@ public EvaluationSimplifier()
* @param extraInstructionVisitor an optional extra visitor for all
* simplified instructions.
*/
- public EvaluationSimplifier(PartialEvaluator partialEvaluator,
+ public EvaluationSimplifier(PartialEvaluator partialEvaluator,
InstructionVisitor extraInstructionVisitor)
{
this.partialEvaluator = partialEvaluator;
@@ -88,6 +88,7 @@ public EvaluationSimplifier(PartialEvaluator partialEvaluator,
// Implementations for AttributeVisitor.
+
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
@@ -161,15 +162,102 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
{
switch (simpleInstruction.opcode)
{
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_IREM:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceIntegerPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isDivisionByZero(offset, Value.TYPE_INTEGER))
+ {
+ // In case we detected a certain division by zero, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/ArithmeticException");
+ }
+ break;
+
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_LREM:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceLongPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isDivisionByZero(offset, Value.TYPE_LONG))
+ {
+ // In case we detected a certain division by zero, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/ArithmeticException");
+ }
+ break;
+
+ case InstructionConstants.OP_FDIV:
+ case InstructionConstants.OP_FREM:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceFloatPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isDivisionByZero(offset, Value.TYPE_FLOAT))
+ {
+ // In case we detected a certain division by zero, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/ArithmeticException");
+ }
+ break;
+
+ case InstructionConstants.OP_DDIV:
+ case InstructionConstants.OP_DREM:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceDoublePushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isDivisionByZero(offset, Value.TYPE_DOUBLE))
+ {
+ // In case we detected a certain division by zero, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/ArithmeticException");
+ }
+ break;
+
case InstructionConstants.OP_IALOAD:
case InstructionConstants.OP_BALOAD:
case InstructionConstants.OP_CALOAD:
case InstructionConstants.OP_SALOAD:
+ case InstructionConstants.OP_ARRAYLENGTH:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceIntegerPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
+ break;
+
case InstructionConstants.OP_IADD:
case InstructionConstants.OP_ISUB:
case InstructionConstants.OP_IMUL:
- case InstructionConstants.OP_IDIV:
- case InstructionConstants.OP_IREM:
case InstructionConstants.OP_INEG:
case InstructionConstants.OP_ISHL:
case InstructionConstants.OP_ISHR:
@@ -183,7 +271,6 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
case InstructionConstants.OP_I2B:
case InstructionConstants.OP_I2C:
case InstructionConstants.OP_I2S:
- case InstructionConstants.OP_ARRAYLENGTH:
if (!sideEffectInstructionChecker.hasSideEffects(clazz,
method,
codeAttribute,
@@ -195,11 +282,25 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
break;
case InstructionConstants.OP_LALOAD:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceLongPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
+ break;
+
case InstructionConstants.OP_LADD:
case InstructionConstants.OP_LSUB:
case InstructionConstants.OP_LMUL:
- case InstructionConstants.OP_LDIV:
- case InstructionConstants.OP_LREM:
case InstructionConstants.OP_LNEG:
case InstructionConstants.OP_LSHL:
case InstructionConstants.OP_LSHR:
@@ -221,11 +322,25 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
break;
case InstructionConstants.OP_FALOAD:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceFloatPushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
+ break;
+
case InstructionConstants.OP_FADD:
case InstructionConstants.OP_FSUB:
case InstructionConstants.OP_FMUL:
- case InstructionConstants.OP_FDIV:
- case InstructionConstants.OP_FREM:
case InstructionConstants.OP_FNEG:
case InstructionConstants.OP_I2F:
case InstructionConstants.OP_L2F:
@@ -241,11 +356,25 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
break;
case InstructionConstants.OP_DALOAD:
+ if (!sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ simpleInstruction))
+ {
+ replaceDoublePushInstruction(clazz, offset, simpleInstruction);
+ }
+ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
+ break;
+
case InstructionConstants.OP_DADD:
case InstructionConstants.OP_DSUB:
case InstructionConstants.OP_DMUL:
- case InstructionConstants.OP_DDIV:
- case InstructionConstants.OP_DREM:
case InstructionConstants.OP_DNEG:
case InstructionConstants.OP_I2D:
case InstructionConstants.OP_L2D:
@@ -269,6 +398,29 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
{
replaceReferencePushInstruction(clazz, offset, simpleInstruction);
}
+ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
+ break;
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
+ isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
+ // is enabled, replace the instruction by the explicit exception.
+ replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
+ }
break;
}
}
@@ -339,12 +491,27 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
{
switch (constantInstruction.opcode)
{
- case InstructionConstants.OP_GETSTATIC:
- case InstructionConstants.OP_GETFIELD:
case InstructionConstants.OP_INVOKEVIRTUAL:
case InstructionConstants.OP_INVOKESPECIAL:
- case InstructionConstants.OP_INVOKESTATIC:
case InstructionConstants.OP_INVOKEINTERFACE:
+ if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
+ isNullReference(offset, constantInstruction.stackPopCount(clazz) - 1))
+ {
+ // In case a method is invoked on a null reference
+ // replace the instruction with an explicit NullPointerException.
+ // This is mainly needed to counter obfuscated code that might
+ // use exceptions to change the control flow. This is especially
+ // problematic if it happens with methods that are explicitly marked
+ // as having no side-effect (e.g. String#length()) as they might get
+ // removed otherwise.
+ replaceByException(clazz, offset, constantInstruction, "java/lang/NullPointerException");
+ break;
+ }
+ // intended fallthrough
+
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_INVOKESTATIC:
if (constantInstruction.stackPushCount(clazz) > 0 &&
!sideEffectInstructionChecker.hasSideEffects(clazz,
method,
@@ -761,8 +928,8 @@ private void replaceReferencePushInstruction(Clazz clazz,
int offset,
Instruction instruction)
{
- Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
- if (pushedValue.isParticular())
+ ReferenceValue pushedValue = partialEvaluator.getStackAfter(offset).getTop(0).referenceValue();
+ if (pushedValue.isNull() == Value.ALWAYS)
{
// A reference value can only be specific if it is null.
replaceConstantPushInstruction(clazz,
@@ -948,8 +1115,7 @@ private void replaceSimpleEnumSwitchInstruction(Clazz clazz,
for (int index = 0; index < newJumpOffsets.length; index++)
{
int switchCase =
- mappingValue.integerArrayLoad(valueFactory.createIntegerValue(
- index),
+ mappingValue.integerArrayLoad(valueFactory.createIntegerValue(index),
valueFactory).value();
newJumpOffsets[index] =
@@ -1236,6 +1402,96 @@ private void trimSwitchInstruction(Clazz clazz,
}
+ /**
+ * Checks whether if the current top value on the stack is a divisor
+ * leading to a certain division by zero for the given computation type.
+ */
+ private boolean isDivisionByZero(int offset, int computationType)
+ {
+ TracedStack tracedStack = partialEvaluator.getStackBefore(offset);
+ Value divisor = tracedStack.getTop(0);
+ switch (computationType)
+ {
+ case Value.TYPE_INTEGER:
+ return divisor.computationalType() == Value.TYPE_INTEGER &&
+ divisor.isParticular() &&
+ divisor.integerValue().value() == 0;
+
+ case Value.TYPE_LONG:
+ return divisor.computationalType() == Value.TYPE_LONG &&
+ divisor.isParticular() &&
+ divisor.longValue().value() == 0L;
+
+ case Value.TYPE_FLOAT:
+ return divisor.computationalType() == Value.TYPE_FLOAT &&
+ divisor.isParticular() &&
+ divisor.floatValue().value() == 0f;
+
+ case Value.TYPE_DOUBLE:
+ return divisor.computationalType() == Value.TYPE_DOUBLE &&
+ divisor.isParticular() &&
+ divisor.doubleValue().value() == 0d;
+
+ default:
+ return false;
+ }
+ }
+
+
+ /**
+ * Checks whether the value at the given stack entry index is always a null reference.
+ */
+ private boolean isNullReference(int offset, int popStackEntryIndex)
+ {
+ TracedStack tracedStack = partialEvaluator.getStackBefore(offset);
+ Value objectRef = tracedStack.getTop(popStackEntryIndex);
+
+ return objectRef.computationalType() == Value.TYPE_REFERENCE &&
+ objectRef.isParticular() &&
+ objectRef.referenceValue().isNull() == Value.ALWAYS;
+ }
+
+
+ /**
+ * Replaces the given instruction by an explicit exception.
+ */
+ private void replaceByException(Clazz clazz,
+ int offset,
+ Instruction instruction,
+ String exceptionClass)
+ {
+ ConstantPoolEditor constantPoolEditor =
+ new ConstantPoolEditor((ProgramClass)clazz);
+
+ // Replace the instruction by an infinite loop.
+ Instruction[] replacementInstructions = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW,
+ constantPoolEditor.addClassConstant(exceptionClass, null)),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL,
+ constantPoolEditor.addMethodrefConstant(exceptionClass, "", "()V", null, null)),
+ new SimpleInstruction(InstructionConstants.OP_ATHROW)
+ };
+
+ if (DEBUG) System.out.println(" Replacing instruction by explicit exception "+exceptionClass);
+
+ 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 given instruction by an infinite loop.
*/
diff --git a/core/src/proguard/optimize/evaluation/InitializationFinder.java b/core/src/proguard/optimize/evaluation/InitializationFinder.java
new file mode 100644
index 0000000..f206994
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/InitializationFinder.java
@@ -0,0 +1,349 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.instruction.InstructionFactory;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.BasicInvocationUnit;
+import proguard.evaluation.value.*;
+import proguard.util.ArrayUtil;
+
+/**
+ * This AttributeVisitor links 'new' instructions and their corresponding
+ * initializers in the CodeAttribute objects that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class InitializationFinder
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ InstructionVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("if") != null;
+ //*/
+
+ public static final int NONE = -1;
+
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+
+ private int superInitializationOffset;
+ private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
+ private InstructionOffsetValue[] uninitializedOffsets = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
+
+
+ /**
+ * Creates a new InitializationFinder.
+ */
+ public InitializationFinder()
+ {
+ this(new ReferenceTracingValueFactory(new BasicValueFactory()));
+ }
+
+
+ /**
+ * Creates a new InitializationFinder. This private constructor gets around
+ * the constraint that it's not allowed to add statements before calling
+ * 'this'.
+ */
+ private InitializationFinder(ReferenceTracingValueFactory referenceTracingValueFactory)
+ {
+ this(new PartialEvaluator(referenceTracingValueFactory,
+ new ReferenceTracingInvocationUnit(new BasicInvocationUnit(referenceTracingValueFactory)),
+ true,
+ referenceTracingValueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new InitializationFinder that will use the given partial
+ * evaluator.
+ * @param partialEvaluator the evaluator to be used for the analysis.
+ * @param runPartialEvaluator specifies whether to run this evaluator on
+ * every code attribute that is visited.
+ */
+ public InitializationFinder(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ }
+
+
+ /**
+ * Returns whether the method is an instance initializer, in the
+ * CodeAttribute that was visited most recently.
+ */
+ public boolean isInitializer()
+ {
+ return superInitializationOffset != NONE;
+ }
+
+
+ /**
+ * Returns the instruction offset at which this initializer is calling
+ * the "super" or "this" initializer method, or NONE if it is
+ * not an initializer.
+ */
+ public int superInitializationOffset()
+ {
+ return superInitializationOffset;
+ }
+
+
+// /**
+// * Returns whether the instruction at the given offset is a 'new'
+// * instruction.
+// */
+// public boolean isNew(int offset)
+// {
+// return initializationOffsets[offset] != NONE;
+// }
+//
+//
+// /**
+// * Returns the instruction offset at which the object instance that is
+// * created at the given 'new' instruction offset is initialized, or
+// * NONE if it is not being created.
+// */
+// public int initializationOffset(int creationOffset)
+// {
+// return initializationOffsets[creationOffset];
+// }
+
+
+ /**
+ * Returns the 'new' instruction offset at which the object instance is
+ * created that is initialized at the given offset.
+ */
+ public int creationOffset(int initializationOffset)
+ {
+ return creationOffsetValue(initializationOffset).instructionOffset(0);
+ }
+
+
+ /**
+ * Returns whether the specified stack entry is initialized.
+ */
+ public boolean isInitializedBefore(int offset, int stackEntryIndexBottom)
+ {
+ InstructionOffsetValue creationOffsetValue =
+ creationOffsetValue(offset, stackEntryIndexBottom);
+
+ return isInitializedBefore(offset, creationOffsetValue);
+ }
+
+
+ /**
+ * Returns whether the given creation offset is initialized before the given
+ * offset.
+ */
+ public boolean isInitializedBefore(int offset,
+ InstructionOffsetValue creationOffsetValue)
+ {
+ return !uninitializedOffsets[offset].contains(creationOffsetValue.instructionOffset(0));
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is the special
+ * invocation of an instance initializer.
+ */
+ public boolean isInitializer(int offset)
+ {
+ return partialEvaluator.isInitializer(offset);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+// DEBUG =
+// clazz.getName().equals("abc/Def") &&
+// method.getName(clazz).equals("abc");
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ superInitializationOffset = NONE;
+
+ // Make sure the global arrays are sufficiently large.
+ initializationOffsets = ArrayUtil.ensureArraySize(initializationOffsets, codeLength, NONE);
+ uninitializedOffsets = ArrayUtil.ensureArraySize(uninitializedOffsets,codeLength, null);
+
+ // Evaluate the method.
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ // Loop over all instructions. This is sufficient, because the JVM
+ // specifications don't allow uninitialized instances on the stack or
+ // in variables when branching backward. JVMs without preverification
+ // and the Dalvik VM do allow it in practice.
+ InstructionOffsetValue currentUninitializedOffsets = method.getName(clazz).equals(ClassConstants.METHOD_NAME_INIT) ?
+ new InstructionOffsetValue(InstructionOffsetValue.METHOD_PARAMETER) :
+ InstructionOffsetValue.EMPTY_VALUE;
+
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (partialEvaluator.isTraced(offset))
+ {
+ // Exception handlers start without uninitialized instances
+ // (on the stack or in variables).
+ if (partialEvaluator.isExceptionHandler(offset))
+ {
+ currentUninitializedOffsets = InstructionOffsetValue.EMPTY_VALUE;
+ }
+
+ // Check if the uninitialized creation offsets have been set
+ // before (because of a forward branch).
+ if (uninitializedOffsets[offset] != null)
+ {
+ // Continue using them.
+ currentUninitializedOffsets = uninitializedOffsets[offset];
+ }
+ else
+ {
+ uninitializedOffsets[offset] = currentUninitializedOffsets;
+ }
+
+ // Is it a 'new' instruction?
+ if (partialEvaluator.isCreation(offset))
+ {
+ // Add its offset to the current list.
+ currentUninitializedOffsets =
+ currentUninitializedOffsets.add(offset);
+ }
+ // Is it an instance initialization?
+ else if (partialEvaluator.isInitializer(offset))
+ {
+ // Remove its creation offset from the current list.
+ InstructionOffsetValue creationOffsetValue =
+ creationOffsetValue(offset);
+
+ int creationOffset =
+ creationOffsetValue.instructionOffset(0);
+
+ if (creationOffsetValue.isMethodParameter(0))
+ {
+ // Remember the super initialization offset of the
+ // initializer method.
+ superInitializationOffset = offset;
+ }
+ else
+ {
+ // Remember the instance initialization for the 'new'
+ // instruction.
+ initializationOffsets[creationOffset] = offset;
+ }
+
+ currentUninitializedOffsets =
+ currentUninitializedOffsets.remove(creationOffset);
+ }
+
+ // Propagate the uninitialized creation offsets to the forward
+ // branch targets, if any.
+ InstructionOffsetValue branchTargets =
+ partialEvaluator.branchTargets(offset);
+
+ if (branchTargets != null)
+ {
+ for (int branchIndex = 0; branchIndex < branchTargets.instructionOffsetCount(); branchIndex++)
+ {
+ int branchOffset = branchTargets.instructionOffset(branchIndex);
+ if (branchOffset > offset)
+ {
+ uninitializedOffsets[branchOffset] = currentUninitializedOffsets;
+ }
+ }
+
+ currentUninitializedOffsets = InstructionOffsetValue.EMPTY_VALUE;
+ }
+ }
+ }
+
+ if (DEBUG)
+ {
+ System.out.println();
+ System.out.println("InitializationFinder: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (partialEvaluator.isInstruction(offset))
+ {
+ System.out.println((initializationOffsets[offset] >= 0 ? "i"+initializationOffsets[offset] : " ") +
+ (uninitializedOffsets[offset] != null &&
+ uninitializedOffsets[offset].instructionOffsetCount() > 0 ? " u"+uninitializedOffsets[offset] : " ") +
+ (isInitializer(offset) ? " "+creationOffsetValue(offset) : " ") + " " +
+ InstructionFactory.create(codeAttribute.code, offset).toString(offset));
+ }
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the 'new' instruction offset value (or method parameter) at
+ * which the object instance is created that is initialized at the given
+ * offset.
+ */
+ private InstructionOffsetValue creationOffsetValue(int initializationOffset)
+ {
+ int stackEntryIndexBottom =
+ partialEvaluator.getStackAfter(initializationOffset).size();
+
+ return creationOffsetValue(initializationOffset, stackEntryIndexBottom);
+ }
+
+
+ /**
+ * Returns the 'new' instruction offset value (or method parameter) of
+ * the specified stack entry.
+ */
+ private InstructionOffsetValue creationOffsetValue(int instructionOffset,
+ int stackEntryIndexBottom)
+ {
+ // Get the reference value of the new instance.
+ ReferenceValue newReferenceValue =
+ partialEvaluator.getStackBefore(instructionOffset).getBottom(stackEntryIndexBottom).referenceValue();
+
+ // It's a traced reference.
+ TracedReferenceValue tracedReferenceValue =
+ (TracedReferenceValue)newReferenceValue;
+
+ // Get the trace value.
+ return tracedReferenceValue.getTraceValue().instructionOffsetValue();
+ }
+}
diff --git a/core/src/proguard/optimize/evaluation/InstructionUsageMarker.java b/core/src/proguard/optimize/evaluation/InstructionUsageMarker.java
new file mode 100644
index 0000000..cb0fb1d
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/InstructionUsageMarker.java
@@ -0,0 +1,1777 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.TracedStack;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.*;
+import proguard.util.ArrayUtil;
+
+import java.util.*;
+
+/**
+ * This AttributeVisitor marks necessary instructions in the code attributes
+ * that it visits, based on partial evaluation.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionUsageMarker
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_RESULTS = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("ium") != null;
+ private static boolean DEBUG_RESULTS = DEBUG;
+ //*/
+
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+ private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator(new TypedReferenceValueFactory());
+ private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
+ private final MyParameterUsageMarker parameterUsageMarker = new MyParameterUsageMarker();
+ private final MyInitialUsageMarker initialUsageMarker = new MyInitialUsageMarker();
+ private final MyProducerMarker producerMarker = new MyProducerMarker();
+ private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker();
+ private final MyStackConsistencyMarker stackConsistencyMarker = new MyStackConsistencyMarker();
+ private final MyExtraPopInstructionMarker extraPopInstructionMarker = new MyExtraPopInstructionMarker();
+
+ private InstructionOffsetValue[] reverseDependencies = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
+
+ private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
+ private boolean[][] stacksUnwantedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
+ private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[] extraPushPopInstructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+
+ private int maxMarkedOffset;
+
+
+ /**
+ * Creates a new InstructionUsageMarker.
+ */
+ public InstructionUsageMarker()
+ {
+ this(new PartialEvaluator(), true);
+ }
+
+
+ /**
+ * Creates a new InstructionUsageMarker.
+ * @param partialEvaluator the evaluator to be used for the analysis.
+ * @param runPartialEvaluator specifies whether to run this evaluator on
+ * every code attribute that is visited.
+ */
+ public InstructionUsageMarker(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ }
+
+
+ /**
+ * Returns whether the specified instruction was traced in the most
+ * recently analyzed code attribute.
+ */
+ public boolean isTraced(int instructionOffset)
+ {
+ return partialEvaluator.isTraced(instructionOffset);
+ }
+
+
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits traced instructions.
+ */
+ public InstructionVisitor tracedInstructionFilter(InstructionVisitor instructionVisitor)
+ {
+ return partialEvaluator.tracedInstructionFilter(instructionVisitor);
+ }
+
+
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits traced or untraced instructions.
+ */
+ public InstructionVisitor tracedInstructionFilter(boolean traced,
+ InstructionVisitor instructionVisitor)
+ {
+ return partialEvaluator.tracedInstructionFilter(traced, instructionVisitor);
+ }
+
+
+ /**
+ * Returns whether the specified instruction is necessary in the most
+ * recently analyzed code attribute.
+ */
+ public boolean isInstructionNecessary(int instructionOffset)
+ {
+ return instructionsNecessary[instructionOffset];
+ }
+
+
+ /**
+ * Returns whether an extra push/pop instruction is required at the given
+ * offset in the most recently analyzed code attribute.
+ */
+ public boolean isExtraPushPopInstructionNecessary(int instructionOffset)
+ {
+ return extraPushPopInstructionsNecessary[instructionOffset];
+ }
+
+
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits necessary instructions.
+ */
+ public InstructionVisitor necessaryInstructionFilter(InstructionVisitor instructionVisitor)
+ {
+ return necessaryInstructionFilter(true, instructionVisitor);
+ }
+
+
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits necessary or unnecessary instructions.
+ */
+ public InstructionVisitor necessaryInstructionFilter(boolean necessary,
+ InstructionVisitor instructionVisitor)
+ {
+ return new MyNecessaryInstructionFilter(necessary, instructionVisitor);
+ }
+
+
+ /**
+ * Returns the stack before execution of the instruction at the given
+ * offset.
+ */
+ public TracedStack getStackBefore(int instructionOffset)
+ {
+ return partialEvaluator.getStackBefore(instructionOffset);
+ }
+
+
+ /**
+ * Returns the stack after execution of the instruction at the given
+ * offset.
+ */
+ public TracedStack getStackAfter(int instructionOffset)
+ {
+ return partialEvaluator.getStackAfter(instructionOffset);
+ }
+
+
+ /**
+ * Returns whether the specified stack entry before the given offset is
+ * unwanted, e.g. because it was intended as a method parameter that has
+ * been removed.
+ */
+ public boolean isStackEntryUnwantedBefore(int instructionOffset,
+ int stackIndex)
+ {
+ return stacksUnwantedBefore[instructionOffset][stackIndex];
+ }
+
+
+ /**
+ * Returns whether the stack specified entries before the given offset are
+ * present.
+ */
+ public boolean isStackEntriesPresentBefore(int instructionOffset,
+ int stackIndex1,
+ int stackIndex2)
+ {
+ boolean present1 = isStackEntryPresentBefore(instructionOffset, stackIndex1);
+ boolean present2 = isStackEntryPresentBefore(instructionOffset, stackIndex2);
+
+ //if (present1 ^ present2)
+ //{
+ // throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
+ //}
+
+ return present1 || present2;
+ }
+
+
+ /**
+ * Returns whether the specified stack entry before the given offset is
+ * present.
+ * @param instructionOffset the offset of the stack entry to be checked.
+ * @param stackIndex the index of the stack entry to be checked
+ * (counting from the bottom).
+ */
+ public boolean isStackEntryPresentBefore(int instructionOffset,
+ int stackIndex)
+ {
+ TracedStack tracedStack =
+ partialEvaluator.getStackBefore(instructionOffset);
+
+ InstructionOffsetValue producerOffsets =
+ tracedStack.getBottomProducerValue(stackIndex).instructionOffsetValue();
+
+ return isAnyStackEntryNecessaryAfter(producerOffsets, stackIndex);
+ }
+
+
+ /**
+ * Returns whether the stack specified entries after the given offset are
+ * necessary.
+ */
+ public boolean isStackEntriesNecessaryAfter(int instructionOffset,
+ int stackIndex1,
+ int stackIndex2)
+ {
+ boolean present1 = isStackEntryNecessaryAfter(instructionOffset, stackIndex1);
+ boolean present2 = isStackEntryNecessaryAfter(instructionOffset, stackIndex2);
+
+ //if (present1 ^ present2)
+ //{
+ // throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
+ //}
+
+ return present1 || present2;
+ }
+
+
+ /**
+ * Returns whether any of the stack entries after the given offsets are
+ * necessary.
+ * @param instructionOffsets the offsets of the stack entries to be checked.
+ * @param stackIndex the index of the stack entries to be checked
+ * (counting from the bottom).
+ */
+ public boolean isAnyStackEntryNecessaryAfter(InstructionOffsetValue instructionOffsets,
+ int stackIndex)
+ {
+ int offsetCount = instructionOffsets.instructionOffsetCount();
+
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ if (instructionOffsets.isExceptionHandler(offsetIndex) ||
+ isStackEntryNecessaryAfter(instructionOffsets.instructionOffset(offsetIndex), stackIndex))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the specified stack entry after the given offset is
+ * necessary.
+ * @param instructionOffset the offset of the stack entry to be checked.
+ * @param stackIndex the index of the stack entry to be checked
+ * (counting from the bottom).
+ */
+ public boolean isStackEntryNecessaryAfter(int instructionOffset,
+ int stackIndex)
+ {
+ return
+ (instructionOffset & InstructionOffsetValue.EXCEPTION_HANDLER) != 0 ||
+ stacksNecessaryAfter[instructionOffset][stackIndex];
+ }
+
+
+ /**
+ * Returns the instruction offsets to which the given instruction offset
+ * branches in the most recently analyzed code attribute.
+ */
+ public InstructionOffsetValue branchTargets(int instructionOffset)
+ {
+ return partialEvaluator.branchTargets(instructionOffset);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+// DEBUG = DEBUG_RESULTS =
+// clazz.getName().equals("abc/Def") &&
+// method.getName(clazz).equals("abc");
+
+ // TODO: Remove this when the instruction usage marker has stabilized.
+ // Catch any unexpected exceptions from the actual visiting method.
+ try
+ {
+ // Process the code.
+ visitCodeAttribute0(clazz, method, codeAttribute);
+ }
+ catch (RuntimeException ex)
+ {
+ System.err.println("Unexpected error while marking instruction usage after partial evaluation:");
+ System.err.println(" Class = ["+clazz.getName()+"]");
+ System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+ System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
+
+ if (DEBUG)
+ {
+ method.accept(clazz, new ClassPrinter());
+ }
+
+ throw ex;
+ }
+ }
+
+
+ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ if (DEBUG_RESULTS)
+ {
+ System.out.println();
+ System.out.println("InstructionUsageMarker ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+ }
+
+ // Initialize the necessary arrays.
+ initializeNecessary(codeAttribute);
+
+ // Evaluate the method.
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ // Evaluate the method the way the JVM verifier would do it.
+ simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ maxMarkedOffset = -1;
+
+ // Mark any unused method parameters on the stack.
+ if (DEBUG) System.out.println("Invocation simplification:");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ partialEvaluator.tracedInstructionFilter(parameterUsageMarker));
+
+
+ // Mark all essential instructions that have been encountered as used.
+ // Also mark infinite loops and instructions that can have side effects.
+ if (DEBUG) System.out.println("Usage initialization: ");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ partialEvaluator.tracedInstructionFilter(initialUsageMarker));
+
+ if (DEBUG) System.out.println();
+
+
+ // Globally mark instructions and their produced variables and stack
+ // entries on which necessary instructions depend.
+ // Instead of doing this recursively, we loop across all instructions,
+ // starting at the highest previously unmarked instruction that has
+ // been been marked.
+ if (DEBUG) System.out.println("Usage marking:");
+
+ while (maxMarkedOffset >= 0)
+ {
+ int offset = maxMarkedOffset;
+
+ maxMarkedOffset = offset - 1;
+
+ if (partialEvaluator.isTraced(offset))
+ {
+ if (isInstructionNecessary(offset))
+ {
+ // Mark the stack/variable producers of this instruction/
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, producerMarker);
+
+ // Also mark any reverse dependencies.
+ markReverseDependencies(offset);
+ }
+
+ // Check if this instruction is a branch origin from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchTargets(offset),
+ true);
+
+ // Check if this instruction is a branch target from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchOrigins(offset),
+ false);
+ }
+
+ if (DEBUG)
+ {
+ if (maxMarkedOffset > offset)
+ {
+ System.out.println(" -> "+maxMarkedOffset);
+ }
+ }
+ }
+ if (DEBUG) System.out.println();
+
+
+ // Mark variable initializations, even if they aren't strictly necessary.
+ // The virtual machine's verification step is not smart enough to see
+ // this, and may complain otherwise.
+ if (DEBUG) System.out.println("Initialization marking: ");
+
+ codeAttribute.instructionsAccept(clazz, method,
+ necessaryInstructionFilter(
+ variableInitializationMarker));
+
+ if (DEBUG) System.out.println();
+
+
+ // Mark produced stack entries, in order to keep the stack consistent.
+ if (DEBUG) System.out.println("Stack consistency fixing:");
+
+ maxMarkedOffset = codeLength - 1;
+
+ while (maxMarkedOffset >= 0)
+ {
+ int offset = maxMarkedOffset;
+
+ maxMarkedOffset = offset - 1;
+
+ if (partialEvaluator.isTraced(offset))
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, stackConsistencyMarker);
+
+ // Check if this instruction is a branch origin from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchTargets(offset),
+ true);
+
+ // Check if this instruction is a branch target from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchOrigins(offset),
+ false);
+ }
+ }
+ if (DEBUG) System.out.println();
+
+
+ // Mark unnecessary popping instructions, in order to keep the stack
+ // consistent.
+ if (DEBUG) System.out.println("Extra pop marking:");
+
+ maxMarkedOffset = codeLength - 1;
+
+ while (maxMarkedOffset >= 0)
+ {
+ int offset = maxMarkedOffset;
+
+ maxMarkedOffset = offset - 1;
+
+ if (partialEvaluator.isTraced(offset) &&
+ !isInstructionNecessary(offset))
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, extraPopInstructionMarker);
+
+ // Check if this instruction is a branch origin from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchTargets(offset),
+ true);
+
+ // Check if this instruction is a branch target from a branch
+ // that straddles some marked code.
+ markStraddlingBranches(offset,
+ partialEvaluator.branchOrigins(offset),
+ false);
+ }
+ }
+ if (DEBUG) System.out.println();
+
+
+ if (DEBUG_RESULTS)
+ {
+ System.out.println("Instruction usage results:");
+
+ int offset = 0;
+ do
+ {
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+ System.out.println((isInstructionNecessary(offset) ? " + " :
+ isExtraPushPopInstructionNecessary(offset) ? " ~ " :
+ " - ") +
+ instruction.toString(offset));
+
+ offset += instruction.length(offset);
+ }
+ while (offset < codeLength);
+ }
+ }
+
+
+ /**
+ * This MemberVisitor marks stack entries that aren't necessary because
+ * parameters aren't used in the methods that are visited.
+ */
+ private class MyParameterUsageMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor,
+ ConstantVisitor,
+ MemberVisitor
+ {
+ private int parameterSize;
+ private long usedParameters;
+
+
+ // 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)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ {
+ parameterSize = 0;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+
+ // Mark unused parameters.
+ for (int index = 0; index < parameterSize; index++)
+ {
+ if (index < 64 &&
+ (usedParameters & (1L << index)) == 0L)
+ {
+ TracedStack stack =
+ partialEvaluator.getStackBefore(offset);
+
+ int stackIndex = stack.size() - parameterSize + index;
+
+ if (DEBUG)
+ {
+ System.out.println(" ["+offset+"] Ignoring parameter #"+index+" (stack entry #"+stackIndex+" ["+stack.getBottom(stackIndex)+"])");
+ System.out.println(" Full stack: "+stack);
+ }
+
+ markStackEntryUnwantedBefore(offset, stackIndex);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ refConstant.referencedMemberAccept(this);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member) {}
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Get the total size of the parameters and the mask of the used
+ // parameters.
+ parameterSize = ParameterUsageMarker.getParameterSize(programMethod);
+ usedParameters = ParameterUsageMarker.getUsedParameters(programMethod);
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor marks the instructions that are intrinsically
+ * necessary, because they have side effects.
+ */
+ private class MyInitialUsageMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor,
+ ConstantVisitor,
+ ParameterVisitor
+ {
+ private final MemberVisitor reverseDependencyCreator = new AllParameterVisitor(true, this);
+
+ // Parameters and values for visitor methods.
+ private int referencingOffset;
+ private int referencingPopCount;
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ if (sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction))
+ {
+ markInstruction(offset);
+ }
+ }
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ createReverseDependencies(clazz, offset, simpleInstruction);
+
+ // Also check for side-effects of the instruction itself.
+ visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ break;
+
+ default:
+ visitAnyInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ break;
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ // We may have to mark the instruction due to initializers.
+ referencingOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+
+ // Also check for side-effects of the instruction itself.
+ visitAnyInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ break;
+
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_GETSTATIC:
+ // We may have to mark the instruction due to initializers.
+ referencingOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ case InstructionConstants.OP_PUTFIELD:
+ createReverseDependencies(clazz, offset, constantInstruction);
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ referencingOffset = offset;
+ referencingPopCount = constantInstruction.stackPopCount(clazz);
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ default:
+ visitAnyInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ break;
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ if (branchInstruction.opcode == InstructionConstants.OP_GOTO &&
+ branchInstruction.branchOffset == 0)
+ {
+ if (DEBUG) System.out.print("(infinite loop)");
+ markInstruction(offset);
+ }
+ else
+ {
+ visitAnyInstruction(clazz, method, codeAttribute, offset, branchInstruction);
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ Clazz referencedClass = stringConstant.referencedClass;
+
+ // If a static initializer may have side effects, the instruction
+ // has to be marked.
+ if (referencedClass != null &&
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ referencedClass))
+ {
+ // Mark the invocation.
+ markInstruction(referencingOffset);
+ }
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ Clazz referencedClass = classConstant.referencedClass;
+
+ // If a static initializer may have side effects, the instruction
+ // has to be marked.
+ if (referencedClass == null ||
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ referencedClass))
+ {
+ // Mark the invocation.
+ markInstruction(referencingOffset);
+ }
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this);
+ }
+
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ Method referencedMethod = (Method)refConstant.referencedMember;
+
+// if (referencedMethod != null)
+// {
+// System.out.println("InstructionUsageMarker$MyInitialUsageMarker.visitAnyMethodrefConstant [" + refConstant.getClassName(clazz) + "." + refConstant.getName(clazz) +
+// "]: mark! esc = " + ParameterEscapeMarker.getEscapingParameters(referencedMethod) +
+// ", mod = " + ParameterEscapeMarker.modifiesAnything(referencedMethod) +
+// ", side = " + SideEffectClassChecker.mayHaveSideEffects(clazz,
+// refConstant.referencedClass,
+// referencedMethod));
+// }
+
+ // Is the method invocation really necessary?
+ if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
+ referencedMethod != null &&
+ SideEffectMethodMarker.hasSideEffects(referencedMethod) &&
+ // Skip if the method was explicitly marked as having no external side-effects.
+ !NoExternalSideEffectMethodMarker.hasNoExternalSideEffects(referencedMethod))
+ {
+ // In case we shall optimize conservatively, always mark the method
+ // call if the referenced method has side effects.
+ markInstruction(referencingOffset);
+ }
+ else if (referencedMethod == null ||
+ ParameterEscapeMarker.getEscapingParameters(referencedMethod) != 0L ||
+ ParameterEscapeMarker.modifiesAnything(referencedMethod) ||
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ refConstant.referencedClass,
+ referencedMethod))
+ {
+// System.out.println(" -> mark ["+referencingOffset+"]");
+ // Mark the invocation.
+ markInstruction(referencingOffset);
+ }
+ else
+ {
+ if (DEBUG)
+ {
+ System.out.println(" ["+referencingOffset+"] Checking parameters of ["+refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+refConstant.getType(clazz)+"] (pop count = "+referencingPopCount+")");
+ }
+
+ // Create reverse dependencies for reference parameters that
+ // are modified.
+ refConstant.referencedMemberAccept(reverseDependencyCreator);
+ }
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ Method method = (Method)member;
+
+ if (DEBUG)
+ {
+ System.out.println(" P"+parameterIndex+
+ ": escaping = "+ParameterEscapeMarker.isParameterEscaping(method, parameterIndex)+
+ ", modified = "+ParameterEscapeMarker.isParameterModified(method, parameterIndex)+
+ ", returned = "+ParameterEscapeMarker.isParameterReturned(method, parameterIndex));
+ }
+
+ // Create a reverse dependency if the reference parameter is
+ // modified.
+ if (ParameterEscapeMarker.isParameterModified(method, parameterIndex))
+ {
+ createReverseDependencies(referencingOffset,
+ parameterSize - parameterOffset - 1);
+ }
+ }
+
+
+ /**
+ * Marks the specified instruction offset or creates reverse
+ * dependencies to the producers of its bottom popped stack entry.
+ */
+ private void createReverseDependencies(Clazz clazz,
+ int offset,
+ Instruction instruction)
+ {
+ createReverseDependencies(offset,
+ instruction.stackPopCount(clazz) - 1);
+ }
+
+
+ /**
+ * Marks the specified instruction offset or creates reverse
+ * dependencies to the producers of the specified stack entry, if it
+ * is a reference value.
+ */
+ private void createReverseDependencies(int offset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+// System.out.println(" ["+offset+"] s"+stackEntryIndex+": ["+stackEntry+"]");
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+// System.out.println("EvaluationShrinker$MyInitialUsageMarker.createReverseDependencies: ["+offset+"] ["+referenceValue+"]?");
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ if (referenceValue instanceof TracedReferenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue =
+ (TracedReferenceValue)referenceValue;
+
+ createReverseDependencies(offset,
+ tracedReferenceValue.getTraceValue().instructionOffsetValue());
+ }
+ else
+ {
+// System.out.println("InstructionUsageMarker$MyInitialUsageMarker.createReverseDependencies: not a TracedReferenceValue");
+ markInstruction(offset);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Marks the specified instruction offset or creates reverse
+ * dependencies to the producers of the given reference value.
+ */
+ private void createReverseDependencies(int offset,
+ InstructionOffsetValue producerOffsets)
+ {
+ InstructionOffsetValue consumerOffset =
+ new InstructionOffsetValue(offset);
+
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ if (producerOffsets.isNewinstance(offsetIndex))
+ {
+ // Create a reverse dependency. If the creating instruction
+ // is necessary, then so is this one.
+ int producerOffset = producerOffsets.instructionOffset(offsetIndex);
+
+ // Avoid circular dependencies in code that loops with
+ // instances on the stack (like the string encryption code).
+ if (producerOffset != offset)
+ {
+ if (DEBUG) System.out.println(" Inserting reverse dependency from instance producers ["+producerOffset+"] to ["+offset+"]");
+
+ InstructionOffsetValue reverseDependency =
+ reverseDependencies[producerOffset];
+
+ reverseDependencies[producerOffset] =
+ reverseDependency == null ?
+ consumerOffset :
+ reverseDependency.generalize(consumerOffset);
+ }
+ }
+ else
+ {
+ // Just mark the instruction.
+ markInstruction(offset);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor marks the producing instructions and produced
+ * variables and stack entries of the instructions that it visits.
+ * Simplified method arguments are ignored.
+ */
+ private class MyProducerMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ markStackProducers(clazz, offset, instruction);
+ }
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_DUP:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 0);
+ break;
+ case InstructionConstants.OP_DUP_X1:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 1);
+ conditionallyMarkStackEntryProducers(offset, 2, 0);
+ break;
+ case InstructionConstants.OP_DUP_X2:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 1);
+ conditionallyMarkStackEntryProducers(offset, 2, 2);
+ conditionallyMarkStackEntryProducers(offset, 3, 0);
+ break;
+ case InstructionConstants.OP_DUP2:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 1);
+ conditionallyMarkStackEntryProducers(offset, 2, 0);
+ conditionallyMarkStackEntryProducers(offset, 3, 1);
+ break;
+ case InstructionConstants.OP_DUP2_X1:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 1);
+ conditionallyMarkStackEntryProducers(offset, 2, 2);
+ conditionallyMarkStackEntryProducers(offset, 3, 0);
+ conditionallyMarkStackEntryProducers(offset, 4, 1);
+ break;
+ case InstructionConstants.OP_DUP2_X2:
+ conditionallyMarkStackEntryProducers(offset, 0, 0);
+ conditionallyMarkStackEntryProducers(offset, 1, 1);
+ conditionallyMarkStackEntryProducers(offset, 2, 2);
+ conditionallyMarkStackEntryProducers(offset, 3, 3);
+ conditionallyMarkStackEntryProducers(offset, 4, 0);
+ conditionallyMarkStackEntryProducers(offset, 5, 1);
+ break;
+ case InstructionConstants.OP_SWAP:
+ conditionallyMarkStackEntryProducers(offset, 0, 1);
+ conditionallyMarkStackEntryProducers(offset, 1, 0);
+ break;
+ default:
+ markStackProducers(clazz, offset, simpleInstruction);
+ break;
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ // Is the variable being loaded or incremented?
+ if (variableInstruction.isLoad())
+ {
+ markVariableProducers(offset, variableInstruction.variableIndex);
+ }
+ else
+ {
+ markStackProducers(clazz, offset, variableInstruction);
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ markStackProducers(clazz, offset, constantInstruction);
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ // Explicitly mark the produced stack entry of a 'jsr' instruction,
+ // because the consuming 'astore' instruction of the subroutine is
+ // cleared every time it is traced.
+ if (branchInstruction.opcode == InstructionConstants.OP_JSR ||
+ branchInstruction.opcode == InstructionConstants.OP_JSR_W)
+ {
+ markStackEntryAfter(offset, 0);
+ }
+ else
+ {
+ markStackProducers(clazz, offset, branchInstruction);
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor marks variable initializations that are
+ * necessary to appease the JVM.
+ */
+ private class MyVariableInitializationMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ // Is the variable being loaded or incremented?
+ if (variableInstruction.isLoad())
+ {
+ // Mark any variable initializations for this variable load that
+ // are required according to the JVM.
+ markVariableInitializersBefore(offset, variableInstruction.variableIndex, null);
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor marks stack entries that should be pushed
+ * (and previously unnecessary pushing instructions) to keep the stack
+ * consistent at later points in the execution.
+ */
+ private class MyStackConsistencyMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // We check all entries to make sure the stack is also consistent
+ // at method exit points, where some stack entries might be
+ // discarded.
+ int stackSize = partialEvaluator.getStackBefore(offset).size();
+
+ for (int stackIndex = 0; stackIndex < stackSize; stackIndex++)
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (!isStackEntryUnwantedBefore(offset, stackIndex) &&
+ isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex, false);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This InstructionVisitor marks unnecessary popping instructions that
+ * should still pop some values to keep the stack consistent.
+ */
+ private class MyExtraPopInstructionMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Check all stack entries that are popped.
+ //
+ // Typical case: a stack value that is required elsewhere or a
+ // pushed exception type that still has to be popped.
+ int stackSize = partialEvaluator.getStackBefore(offset).size();
+
+ int firstStackIndex =
+ stackSize - instruction.stackPopCount(clazz);
+
+ for (int stackIndex = firstStackIndex; stackIndex < stackSize; stackIndex++)
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (!isStackEntryUnwantedBefore(offset, stackIndex) &&
+ isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Is it already a pop instruction?
+ if (isPop(instruction))
+ {
+ // Just mark it as necessary, along with the stack
+ // entries at the producer offsets. This might happen
+ // in Kotlin code [DGD-481], with getstatic/pop.
+ markInstruction(offset);
+ markStackEntryProducers(offset, stackIndex, false);
+ }
+ else
+ {
+ // Mark that we'll need an extra pop instruction.
+ markExtraPushPopInstruction(offset);
+ }
+ }
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the given instruction is a pop instruction.
+ */
+ private boolean isPop(Instruction instruction)
+ {
+ return instruction.opcode == InstructionConstants.OP_POP ||
+ instruction.opcode == InstructionConstants.OP_POP2;
+ }
+
+
+ /**
+ * Marks the producing 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.
+ */
+ private void markVariableProducers(int consumerOffset,
+ int variableIndex)
+ {
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
+
+ if (producerOffsets != null)
+ {
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ if (!producerOffsets.isMethodParameter(offsetIndex) &&
+ !producerOffsets.isExceptionHandler(offsetIndex))
+ {
+ // Make sure the variable and the instruction are marked
+ // at the producing offset.
+ int offset = producerOffsets.instructionOffset(offsetIndex);
+
+ markInstruction(offset);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 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.
+ * @param visitedOffsets the already visited consumer offsets, needed to
+ * prevent infinite loops.
+ */
+ private void markVariableInitializersBefore(int consumerOffset,
+ int variableIndex,
+ InstructionOffsetValue visitedOffsets)
+ {
+ // Avoid infinite loops by stopping recursion if we encounter
+ // an already visited offset.
+ if (visitedOffsets != null &&
+ visitedOffsets.contains(consumerOffset))
+ {
+ return;
+ }
+
+ visitedOffsets = visitedOffsets == null ?
+ new InstructionOffsetValue(consumerOffset) :
+ visitedOffsets.add(consumerOffset);
+
+ // 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();
+
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ if (!producerOffsets.isMethodParameter(offsetIndex) &&
+ !producerOffsets.isExceptionHandler(offsetIndex))
+ {
+ int producerOffset =
+ producerOffsets.instructionOffset(offsetIndex);
+ markVariableInitializersAfter(producerOffset, variableIndex, visitedOffsets);
+ }
+ }
+ }
+
+
+ /**
+ * 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.
+ * @param visitedOffsets the already visited consumer offsets, needed to
+ * prevent infinite loops.
+ */
+ private void markVariableInitializersAfter(int producerOffset,
+ int variableIndex,
+ InstructionOffsetValue visitedOffsets)
+ {
+ // 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 ");
+
+ 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, visitedOffsets);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the stack entries and their producing instructions of the
+ * consumer at the given offset.
+ * @param clazz the containing class.
+ * @param consumerOffset the offset of the consumer.
+ * @param consumer the consumer of the stack entries.
+ */
+ private void markStackProducers(Clazz clazz,
+ int consumerOffset,
+ Instruction consumer)
+ {
+ TracedStack tracedStack =
+ partialEvaluator.getStackBefore(consumerOffset);
+
+ int stackSize = tracedStack.size();
+
+ // Mark the producers of the popped values.
+ int popCount = consumer.stackPopCount(clazz);
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
+ {
+ markStackEntryProducers(consumerOffset, stackIndex, true);
+ }
+ }
+
+
+ /**
+ * Marks the stack entry and the corresponding producing instructions
+ * of the consumer at the given offset, if the stack entry of the
+ * consumer is marked.
+ * @param consumerOffset the offset of the consumer.
+ * @param consumerTopStackIndex the index of the stack entry to be checked
+ * (counting from the top).
+ * @param producerTopStackIndex the index of the stack entry to be marked
+ * (counting from the top).
+ */
+ private void conditionallyMarkStackEntryProducers(int consumerOffset,
+ int consumerTopStackIndex,
+ int producerTopStackIndex)
+ {
+ int consumerBottomStackIndex = partialEvaluator.getStackAfter(consumerOffset).size() - consumerTopStackIndex - 1;
+
+ if (isStackEntryNecessaryAfter(consumerOffset, consumerBottomStackIndex))
+ {
+ int producerBottomStackIndex = partialEvaluator.getStackBefore(consumerOffset).size() - producerTopStackIndex - 1;
+
+ markStackEntryProducers(consumerOffset, producerBottomStackIndex, true);
+ }
+ }
+
+
+ /**
+ * Marks the stack entry and optionally the corresponding producing
+ * instructions of the consumer at the given offset.
+ * @param consumerOffset the offset of the consumer.
+ * @param stackIndex the index of the stack entry to be marked
+ * (counting from the bottom).
+ * @param markInstructions specifies whether the producing instructions
+ * should be marked.
+ */
+ private void markStackEntryProducers(int consumerOffset,
+ int stackIndex,
+ boolean markInstructions)
+ {
+ if (!isStackEntryUnwantedBefore(consumerOffset, stackIndex))
+ {
+ markStackEntryProducers(partialEvaluator.getStackBefore(consumerOffset).getBottomProducerValue(stackIndex).instructionOffsetValue(),
+ stackIndex,
+ markInstructions);
+ }
+ }
+
+
+ /**
+ * Marks the stack entry and optionally its producing instructions at the
+ * given offsets.
+ * @param producerOffsets the offsets of the producers to be marked.
+ * @param stackIndex the index of the stack entry to be marked
+ * (counting from the bottom).
+ * @param markInstructions specifies whether the producing instructions
+ * should be marked.
+ */
+ private void markStackEntryProducers(InstructionOffsetValue producerOffsets,
+ int stackIndex,
+ boolean markInstructions)
+ {
+ if (producerOffsets != null)
+ {
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ if (!producerOffsets.isExceptionHandler(offsetIndex))
+ {
+ // Make sure the stack entry and the instruction are marked
+ // at the producing offset.
+ int offset = producerOffsets.instructionOffset(offsetIndex);
+
+ markStackEntryAfter(offset, stackIndex);
+
+ if (markInstructions)
+ {
+ // We can mark the producer.
+ markInstruction(offset);
+ }
+ else
+ {
+ // We'll need to push a stack entry at that point
+ // instead.
+ markExtraPushPopInstruction(offset);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Marks any modification instructions that are required by the specified
+ * creation instruction (new, newarray, method returning new
+ * instance,...), so this new instance is properly initialized.
+ * @param instructionOffset the offset of the creation instruction.
+ */
+ private void markReverseDependencies(int instructionOffset)
+ {
+ InstructionOffsetValue reverseDependency =
+ reverseDependencies[instructionOffset];
+
+ if (reverseDependency != null)
+ {
+ markInstructions(reverseDependency);
+ }
+ }
+
+
+ /**
+ * Marks the branch instructions of straddling branches, if they straddle
+ * some code that has been marked.
+ * @param instructionOffset the offset of the branch origin or branch target.
+ * @param branchOffsets the offsets of the straddling branch targets
+ * or branch origins.
+ * @param isPointingToTargets true if the above offsets are
+ * branch targets, false if they
+ * are branch origins.
+ */
+ private void markStraddlingBranches(int instructionOffset,
+ InstructionOffsetValue branchOffsets,
+ boolean isPointingToTargets)
+ {
+ if (branchOffsets != null)
+ {
+ // Loop over all branch offsets.
+ int branchCount = branchOffsets.instructionOffsetCount();
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the branch straddling forward any necessary instructions?
+ int branchOffset = branchOffsets.instructionOffset(branchIndex);
+
+ // Is the offset pointing to a branch origin or to a branch target?
+ if (isPointingToTargets)
+ {
+ markStraddlingBranch(instructionOffset,
+ branchOffset,
+ instructionOffset,
+ branchOffset);
+ }
+ else
+ {
+ markStraddlingBranch(instructionOffset,
+ branchOffset,
+ branchOffset,
+ instructionOffset);
+ }
+ }
+ }
+ }
+
+
+ private void markStraddlingBranch(int instructionOffsetStart,
+ int instructionOffsetEnd,
+ int branchOrigin,
+ int branchTarget)
+ {
+ if (!isInstructionNecessary(branchOrigin) &&
+ isAnyInstructionNecessary(instructionOffsetStart, instructionOffsetEnd))
+ {
+ if (DEBUG) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
+
+ // Mark the branch instruction.
+ markInstruction(branchOrigin);
+ }
+ }
+
+
+ /**
+ * Initializes the necessary data structure.
+ */
+ private void initializeNecessary(CodeAttribute codeAttribute)
+ {
+ int codeLength = codeAttribute.u4codeLength;
+ int maxLocals = codeAttribute.u2maxLocals;
+ int maxStack = codeAttribute.u2maxStack;
+
+ // Create new arrays for storing information at each instruction offset.
+ reverseDependencies =
+ ArrayUtil.ensureArraySize(reverseDependencies, codeLength, null);
+
+ if (stacksNecessaryAfter.length < codeLength ||
+ stacksNecessaryAfter[0].length < maxStack)
+ {
+ stacksNecessaryAfter = new boolean[codeLength][maxStack];
+ }
+ else
+ {
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false);
+ }
+ }
+
+ if (stacksUnwantedBefore.length < codeLength ||
+ stacksUnwantedBefore[0].length < maxStack)
+ {
+ stacksUnwantedBefore = new boolean[codeLength][maxStack];
+ }
+ else
+ {
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ Arrays.fill(stacksUnwantedBefore[offset], 0, maxStack, false);
+ }
+ }
+
+ instructionsNecessary =
+ ArrayUtil.ensureArraySize(instructionsNecessary,
+ codeLength,
+ false);
+
+ extraPushPopInstructionsNecessary =
+ ArrayUtil.ensureArraySize(extraPushPopInstructionsNecessary,
+ codeLength,
+ false);
+ }
+
+
+ /**
+ * Returns whether the specified variable is initialized at the specified
+ * offset.
+ */
+ private boolean isVariableInitialization(int instructionOffset,
+ int variableIndex)
+ {
+ // Wasn't the variable set yet?
+ Value valueBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex);
+ if (valueBefore == null)
+ {
+ return true;
+ }
+
+ // Is the computational type different now?
+ Value valueAfter = simplePartialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex);
+ if (valueAfter.computationalType() != valueBefore.computationalType())
+ {
+ return true;
+ }
+
+ // Is the reference type different now?
+ if (valueAfter.computationalType() == Value.TYPE_REFERENCE &&
+ (valueAfter.referenceValue().isNull() == Value.ALWAYS ||
+ !valueAfter.referenceValue().getType().equals(valueBefore.referenceValue().getType())))
+ {
+ return true;
+ }
+
+ // Was the producer an argument (which may be removed)?
+ InstructionOffsetValue producersBefore = simplePartialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex).instructionOffsetValue();
+ return producersBefore.instructionOffsetCount() == 1 &&
+ producersBefore.isMethodParameter(0);
+ }
+
+
+ /**
+ * Marks the stack entry after the given offset.
+ * @param instructionOffset the offset of the stack entry to be marked.
+ * @param stackIndex the index of the stack entry to be marked
+ * (counting from the bottom).
+ */
+ private void markStackEntryAfter(int instructionOffset,
+ int stackIndex)
+ {
+ if (!isStackEntryNecessaryAfter(instructionOffset, stackIndex))
+ {
+ if (DEBUG) System.out.print("["+instructionOffset+".s"+stackIndex+"],");
+
+ stacksNecessaryAfter[instructionOffset][stackIndex] = true;
+
+ if (maxMarkedOffset < instructionOffset)
+ {
+ maxMarkedOffset = instructionOffset;
+ }
+ }
+ }
+
+
+ /**
+ * Marks the specified stack entry as unwanted, typically because it is
+ * an unused parameter of a method invocation.
+ * @param instructionOffset the offset of the consumer.
+ * @param stackIndex the index of the stack entry to be marked
+ * (counting from the bottom).
+ */
+ private void markStackEntryUnwantedBefore(int instructionOffset,
+ int stackIndex)
+ {
+ stacksUnwantedBefore[instructionOffset][stackIndex] = true;
+ }
+
+
+ /**
+ * Marks the specified instructions as used.
+ * @param instructionOffsets the offsets of the instructions.
+ */
+ private void markInstructions(InstructionOffsetValue instructionOffsets)
+ {
+ int count = instructionOffsets.instructionOffsetCount();
+
+ for (int index = 0; index < count; index++)
+ {
+ markInstruction(instructionOffsets.instructionOffset(index));
+ }
+ }
+
+
+ /**
+ * Marks the specified instruction as used.
+ * @param instructionOffset the offset of the instruction.
+ */
+ private void markInstruction(int instructionOffset)
+ {
+ if (!isInstructionNecessary(instructionOffset))
+ {
+ if (DEBUG) System.out.print(instructionOffset+",");
+
+ instructionsNecessary[instructionOffset] = true;
+
+ if (maxMarkedOffset < instructionOffset)
+ {
+ maxMarkedOffset = instructionOffset;
+ }
+ }
+ }
+
+
+ /**
+ * Marks that an extra push/pop instruction is required at the given
+ * offset, if the current instruction at that offset is unused.
+ * @param instructionOffset the offset of the instruction.
+ */
+ private void markExtraPushPopInstruction(int instructionOffset)
+ {
+ if (!isInstructionNecessary(instructionOffset) &&
+ !isExtraPushPopInstructionNecessary(instructionOffset))
+ {
+ if (DEBUG) System.out.print(instructionOffset+",");
+
+ extraPushPopInstructionsNecessary[instructionOffset] = true;
+
+ if (maxMarkedOffset < instructionOffset)
+ {
+ maxMarkedOffset = instructionOffset;
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether any instruction in the specified sequence of
+ * instructions is necessary.
+ * @param startInstructionOffset the start offset of the instruction
+ * sequence (inclusive).
+ * @param endInstructionOffset the end offset of the instruction
+ * sequence (exclusive).
+ * @return whether any instruction is necessary.
+ */
+ private boolean isAnyInstructionNecessary(int startInstructionOffset,
+ int endInstructionOffset)
+ {
+ for (int instructionOffset = startInstructionOffset;
+ instructionOffset < endInstructionOffset;
+ instructionOffset++)
+ {
+ if (isInstructionNecessary(instructionOffset) ||
+ isExtraPushPopInstructionNecessary(instructionOffset))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * This InstructionVisitor delegates its visits to a given
+ * InstructionVisitor, but only if the instruction has been marked as
+ * necessary (or not).
+ */
+ private class MyNecessaryInstructionFilter implements InstructionVisitor
+ {
+ private final boolean necessary;
+ private final InstructionVisitor instructionVisitor;
+
+
+ public MyNecessaryInstructionFilter(boolean necessary,
+ InstructionVisitor instructionVisitor)
+ {
+ this.necessary = necessary;
+ this.instructionVisitor = instructionVisitor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitVariableInstruction(clazz, method, codeAttribute, offset, variableInstruction);
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction);
+ }
+ }
+
+
+ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitTableSwitchInstruction(clazz, method, codeAttribute, offset, tableSwitchInstruction);
+ }
+ }
+
+
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, lookUpSwitchInstruction);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the instruction at the given offset should be
+ * visited, depending on whether it is necessary or not.
+ */
+ private boolean shouldVisit(int offset)
+ {
+ return isInstructionNecessary(offset) == necessary;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/core/src/proguard/optimize/evaluation/LivenessAnalyzer.java
similarity index 76%
rename from src/proguard/optimize/evaluation/LivenessAnalyzer.java
rename to core/src/proguard/optimize/evaluation/LivenessAnalyzer.java
index bfcb629..5bb977e 100644
--- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java
+++ b/core/src/proguard/optimize/evaluation/LivenessAnalyzer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,9 @@
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.BasicInvocationUnit;
import proguard.evaluation.value.*;
+import proguard.util.ArrayUtil;
/**
* This AttributeVisitor analyzes the liveness of the variables in the code
@@ -48,7 +50,10 @@ public class LivenessAnalyzer
private static final int MAX_VARIABLES_SIZE = 64;
- private final PartialEvaluator partialEvaluator;
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+ private final InitializationFinder initializationFinder;
+ private final boolean runInitializationFinder;
private long[] isAliveBefore = new long[ClassConstants.TYPICAL_CODE_LENGTH];
private long[] isAliveAfter = new long[ClassConstants.TYPICAL_CODE_LENGTH];
@@ -64,17 +69,61 @@ public class LivenessAnalyzer
*/
public LivenessAnalyzer()
{
- this(new PartialEvaluator());
+ this(new ReferenceTracingValueFactory(new BasicValueFactory()));
}
/**
- * Creates a new LivenessAnalyzer that will use the given partial evaluator.
- * It will run this evaluator on every code attribute that it visits.
+ * Creates a new LivenessAnalyzer. This private constructor gets around
+ * the constraint that it's not allowed to add statements before calling
+ * 'this'.
*/
- public LivenessAnalyzer(PartialEvaluator partialEvaluator)
+ private LivenessAnalyzer(ReferenceTracingValueFactory referenceTracingValueFactory)
{
- this.partialEvaluator = partialEvaluator;
+ this(new PartialEvaluator(referenceTracingValueFactory,
+ new ReferenceTracingInvocationUnit(new BasicInvocationUnit(referenceTracingValueFactory)),
+ true,
+ referenceTracingValueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new LivenessAnalyzer. This private constructor gets around
+ * the constraint that it's not allowed to add statements before calling
+ * 'this'.
+ */
+ private LivenessAnalyzer(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this(partialEvaluator,
+ runPartialEvaluator,
+ new InitializationFinder(partialEvaluator, false),
+ true);
+ }
+
+
+ /**
+ * Creates a new LivenessAnalyzer that will use the given partial evaluator
+ * and initialization finder.
+ * @param partialEvaluator the evaluator to be used for the analysis.
+ * @param runPartialEvaluator specifies whether to run this evaluator on
+ * every code attribute that is visited.
+ * @param initializationFinder the initialization finder to be used for
+ * the analysis.
+ * @param runInitializationFinder specifies whether to run this
+ * initialization finder on every code
+ * attribute that is visited.
+ */
+ public LivenessAnalyzer(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator,
+ InitializationFinder initializationFinder,
+ boolean runInitializationFinder)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ this.initializationFinder = initializationFinder;
+ this.runInitializationFinder = runInitializationFinder;
}
@@ -94,8 +143,9 @@ public boolean isTraced(int instructionOffset)
*/
public boolean isAliveBefore(int instructionOffset, int variableIndex)
{
- return variableIndex >= MAX_VARIABLES_SIZE ||
- (isAliveBefore[instructionOffset] & (1L << variableIndex)) != 0;
+ return variableIndex >= MAX_VARIABLES_SIZE ?
+ partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex) != null :
+ (isAliveBefore[instructionOffset] & (1L << variableIndex)) != 0;
}
@@ -125,8 +175,9 @@ public void setAliveBefore(int instructionOffset, int variableIndex, boolean ali
*/
public boolean isAliveAfter(int instructionOffset, int variableIndex)
{
- return variableIndex >= MAX_VARIABLES_SIZE ||
- (isAliveAfter[instructionOffset] & (1L << variableIndex)) != 0;
+ return variableIndex >= MAX_VARIABLES_SIZE ?
+ partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex) != null :
+ (isAliveAfter[instructionOffset] & (1L << variableIndex)) != 0;
}
@@ -156,8 +207,10 @@ public void setAliveAfter(int instructionOffset, int variableIndex, boolean aliv
*/
public boolean isCategory2(int instructionOffset, int variableIndex)
{
- return variableIndex < MAX_VARIABLES_SIZE &&
- (isCategory2[instructionOffset] & (1L << variableIndex)) != 0;
+ return variableIndex >= MAX_VARIABLES_SIZE ?
+ partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex) != null &&
+ partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex).isCategory2() :
+ (isCategory2[instructionOffset] & (1L << variableIndex)) != 0;
}
@@ -198,14 +251,24 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
System.out.println("Liveness analysis: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
}
+ int codeLength = codeAttribute.u4codeLength;
+ int variablesSize = codeAttribute.u2maxLocals;
+
// Initialize the global arrays.
- initializeArrays(codeAttribute);
+ isAliveBefore = ArrayUtil.ensureArraySize(isAliveBefore, codeLength, 0L);
+ isAliveAfter = ArrayUtil.ensureArraySize(isAliveAfter, codeLength, 0L);
+ isCategory2 = ArrayUtil.ensureArraySize(isCategory2, codeLength, 0L);
// Evaluate the method.
- partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
- int codeLength = codeAttribute.u4codeLength;
- int variablesSize = codeAttribute.u2maxLocals;
+ if (runInitializationFinder)
+ {
+ initializationFinder.visitCodeAttribute(clazz, method, codeAttribute);
+ }
// We'll only really analyze the first 64 variables.
if (variablesSize > MAX_VARIABLES_SIZE)
@@ -250,7 +313,12 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
isAliveBefore[offset] = alive;
// Do we have to check again after this loop?
- checkAgain |= offset < maxOffset(partialEvaluator.branchOrigins(offset));
+ InstructionOffsetValue branchOrigins = partialEvaluator.branchOrigins(offset);
+ if (branchOrigins != null &&
+ offset < branchOrigins.maximumValue())
+ {
+ checkAgain = true;
+ }
}
}
}
@@ -374,7 +442,7 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
{
// Special case: variable 0 ('this') in an initializer has to be alive
// as long as it hasn't been initialized.
- if (offset == partialEvaluator.superInitializationOffset())
+ if (offset == initializationFinder.superInitializationOffset())
{
alive |= 1L;
}
@@ -413,32 +481,6 @@ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAtt
// Small utility methods.
- /**
- * Initializes the global arrays.
- */
- private void initializeArrays(CodeAttribute codeAttribute)
- {
- int codeLength = codeAttribute.u4codeLength;
-
- // Create new arrays for storing information at each instruction offset.
- if (isAliveBefore.length < codeLength)
- {
- isAliveBefore = new long[codeLength];
- isAliveAfter = new long[codeLength];
- isCategory2 = new long[codeLength];
- }
- else
- {
- for (int index = 0; index < codeLength; index++)
- {
- isAliveBefore[index] = 0L;
- isAliveAfter[index] = 0L;
- isCategory2[index] = 0L;
- }
- }
- }
-
-
/**
* Returns the combined liveness mask of the variables right before the
* specified instruction offsets.
@@ -455,72 +497,4 @@ private long combinedLiveness(InstructionOffsetValue instructionOffsetValue)
return alive;
}
-
-
- /**
- * Returns the minimum offset from the given instruction offsets.
- */
- private int minOffset(Value instructionOffsets)
- {
- return minOffset(instructionOffsets, Integer.MAX_VALUE);
- }
-
-
- /**
- * Returns the minimum offset from the given instruction offsets.
- */
- private int minOffset(Value instructionOffsets, int minOffset)
- {
- if (instructionOffsets != null)
- {
- InstructionOffsetValue instructionOffsetValue =
- instructionOffsets.instructionOffsetValue();
-
- int count = instructionOffsetValue.instructionOffsetCount();
- for (int index = 0; index < count; index++)
- {
- int offset = instructionOffsetValue.instructionOffset(index);
- if (minOffset > offset)
- {
- minOffset = offset;
- }
- }
- }
-
- return minOffset;
- }
-
-
- /**
- * Returns the maximum offset from the given instruction offsets.
- */
- private int maxOffset(Value instructionOffsets)
- {
- return maxOffset(instructionOffsets, Integer.MIN_VALUE);
- }
-
-
- /**
- * Returns the maximum offset from the given instruction offsets.
- */
- private int maxOffset(Value instructionOffsets, int maxOffset)
- {
- if (instructionOffsets != null)
- {
- InstructionOffsetValue instructionOffsetValue =
- instructionOffsets.instructionOffsetValue();
-
- int count = instructionOffsetValue.instructionOffsetCount();
- for (int index = 0; index < count; index++)
- {
- int offset = instructionOffsetValue.instructionOffset(index);
- if (maxOffset < offset)
- {
- maxOffset = offset;
- }
- }
- }
-
- return maxOffset;
- }
}
diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/core/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
similarity index 84%
rename from src/proguard/optimize/evaluation/LoadingInvocationUnit.java
rename to core/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
index 08a6e50..771064a 100644
--- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
+++ b/core/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -68,9 +68,9 @@ public LoadingInvocationUnit(ValueFactory valueFactory,
// Implementations for BasicInvocationUnit.
- protected Value getFieldClassValue(Clazz clazz,
- RefConstant refConstant,
- String type)
+ public Value getFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
{
if (loadFieldValues)
{
@@ -91,9 +91,9 @@ protected Value getFieldClassValue(Clazz clazz,
}
- protected Value getFieldValue(Clazz clazz,
- RefConstant refConstant,
- String type)
+ public Value getFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
{
if (loadFieldValues)
{
@@ -114,11 +114,11 @@ protected Value getFieldValue(Clazz clazz,
}
- protected Value getMethodParameterValue(Clazz clazz,
- Method method,
- int parameterIndex,
- String type,
- Clazz referencedClass)
+ public Value getMethodParameterValue(Clazz clazz,
+ Method method,
+ int parameterIndex,
+ String type,
+ Clazz referencedClass)
{
if (loadMethodParameterValues)
{
@@ -138,9 +138,9 @@ protected Value getMethodParameterValue(Clazz clazz,
}
- protected Value getMethodReturnValue(Clazz clazz,
- RefConstant refConstant,
- String type)
+ public Value getMethodReturnValue(Clazz clazz,
+ RefConstant refConstant,
+ String type)
{
if (loadMethodReturnValues)
{
diff --git a/core/src/proguard/optimize/evaluation/ParameterTracingInvocationUnit.java b/core/src/proguard/optimize/evaluation/ParameterTracingInvocationUnit.java
new file mode 100644
index 0000000..b5dea74
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/ParameterTracingInvocationUnit.java
@@ -0,0 +1,172 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.constant.RefConstant;
+import proguard.classfile.util.ClassUtil;
+import proguard.evaluation.SimplifiedInvocationUnit;
+import proguard.evaluation.value.*;
+import proguard.optimize.info.ParameterEscapeMarker;
+
+/**
+ * This InvocationUnit tags reference values like
+ * {@link ReferenceTracingInvocationUnit}, but adds detail to return values
+ * from invoked methods.
+ *
+ * @see ReferenceTracingInvocationUnit
+ * @see TracedReferenceValue
+ * @see InstructionOffsetValue
+ * @author Eric Lafortune
+ */
+public class ParameterTracingInvocationUnit
+extends ReferenceTracingInvocationUnit
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("ptiu") != null;
+ //*/
+
+
+ private Value[] parameters = new Value[256];
+
+
+ /**
+ * Creates a new ParameterTracingInvocationUnit that attaches trace
+ * values specifying the parameter index to each parameter.
+ * @param invocationUnit the invocation unit to which invocations will
+ * be delegated.
+ */
+ public ParameterTracingInvocationUnit(SimplifiedInvocationUnit invocationUnit)
+ {
+ super(invocationUnit);
+ }
+
+
+ // Implementations for SimplifiedInvocationUnit.
+
+ public void setMethodParameterValue(Clazz clazz, RefConstant refConstant, int parameterIndex, Value value)
+ {
+ super.setMethodParameterValue(clazz, refConstant, parameterIndex, value);
+
+ parameters[parameterIndex] = value;
+ }
+
+
+ public Value getMethodReturnValue(Clazz clazz, RefConstant refConstant, String type)
+ {
+ Value returnValue =
+ super.getMethodReturnValue(clazz, refConstant, type);
+
+ // We only need to worry about reference values.
+ if (returnValue.computationalType() != Value.TYPE_REFERENCE)
+ {
+ return returnValue;
+ }
+
+ Method referencedMethod = (Method)refConstant.referencedMember;
+ if (referencedMethod != null)
+ {
+ // Start figuring out which trace value to attach to the return value.
+ int offset =
+ ((TracedReferenceValue)returnValue).getTraceValue().instructionOffsetValue().instructionOffset(0);
+
+ // The trace value might be any external value or just a new instance.
+ InstructionOffsetValue traceValue =
+ ParameterEscapeMarker.returnsExternalValues(referencedMethod) ? new InstructionOffsetValue(offset | InstructionOffsetValue.FIELD_VALUE) :
+ ParameterEscapeMarker.returnsNewInstances(referencedMethod) ? new InstructionOffsetValue(offset | InstructionOffsetValue.NEW_INSTANCE) :
+ null;
+
+ long returnedParameters =
+ ParameterEscapeMarker.getReturnedParameters(referencedMethod);
+
+ int parameterCount =
+ ClassUtil.internalMethodParameterCount(refConstant.getType(clazz), isStatic);
+
+ for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
+ {
+ if ((returnedParameters & (1L << parameterIndex)) != 0L)
+ {
+ Value parameterValue = parameters[parameterIndex];
+ if (parameterValue instanceof TracedReferenceValue)
+ {
+ TracedReferenceValue tracedParameterValue =
+ (TracedReferenceValue)parameterValue;
+
+ if (mayReturnType(refConstant.referencedClass,
+ referencedMethod,
+ tracedParameterValue))
+ {
+ InstructionOffsetValue parameterTraceValue =
+ tracedParameterValue.getTraceValue().instructionOffsetValue();
+
+ traceValue = traceValue == null ?
+ parameterTraceValue :
+ traceValue.generalize(parameterTraceValue);
+ }
+ }
+ }
+ }
+
+ if (DEBUG)
+ {
+ System.out.println("ParameterTracingInvocationUnit.getMethodReturnValue: calling ["+refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+refConstant.getType(clazz)+"] returns ["+traceValue+" "+returnValue+"]");
+ }
+
+ // Did we find more detailed information on the return value?
+ // We should, unless the return value is always null.
+ if (traceValue != null)
+ {
+ return trace(returnValue, traceValue);
+ }
+ }
+
+ return returnValue;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the given method may return the given type of reference
+ * value
+ */
+ private boolean mayReturnType(Clazz clazz,
+ Method method,
+ ReferenceValue referenceValue)
+ {
+ String returnType =
+ ClassUtil.internalMethodReturnType(method.getDescriptor(clazz));
+
+ Clazz[] referencedClasses = method instanceof ProgramMethod ?
+ ((ProgramMethod)method).referencedClasses :
+ ((LibraryMethod)method).referencedClasses;
+
+ Clazz referencedClass =
+ referencedClasses == null ||
+ !ClassUtil.isInternalClassType(returnType) ? null :
+ referencedClasses[referencedClasses.length - 1];
+
+ return referenceValue.instanceOf(returnType,
+ referencedClass) != Value.NEVER;
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/core/src/proguard/optimize/evaluation/PartialEvaluator.java
similarity index 77%
rename from src/proguard/optimize/evaluation/PartialEvaluator.java
rename to core/src/proguard/optimize/evaluation/PartialEvaluator.java
index 96281d2..28e5826 100644
--- a/src/proguard/optimize/evaluation/PartialEvaluator.java
+++ b/core/src/proguard/optimize/evaluation/PartialEvaluator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,13 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.ClassConstant;
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.evaluation.BranchTargetFinder;
+import proguard.optimize.peephole.BranchTargetFinder;
import java.util.Arrays;
@@ -48,8 +48,8 @@ public class PartialEvaluator
private static final boolean DEBUG = false;
private static final boolean DEBUG_RESULTS = false;
/*/
- private static boolean DEBUG = System.getProperty("pe") != null;
- private static boolean DEBUG_RESULTS = DEBUG;
+ public static boolean DEBUG = System.getProperty("pe") != null;
+ public static boolean DEBUG_RESULTS = DEBUG;
//*/
private static final int MAXIMUM_EVALUATION_COUNT = 5;
@@ -58,18 +58,19 @@ public class PartialEvaluator
public static final int AT_METHOD_ENTRY = -1;
public static final int AT_CATCH_ENTRY = -1;
- private final ValueFactory valueFactory;
- private final InvocationUnit invocationUnit;
- private final boolean evaluateAllCode;
-
- private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
- private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedVariables[] variablesBefore = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedStack[] stacksBefore = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedVariables[] variablesAfter = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
- private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
- private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
- private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH];
+ private final ValueFactory valueFactory;
+ private final InvocationUnit invocationUnit;
+ private final boolean evaluateAllCode;
+ private final InstructionVisitor extraInstructionVisitor;
+
+ private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
+ private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[ClassConstants.TYPICAL_CODE_LENGTH];
+ private TracedVariables[] variablesBefore = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
+ private TracedStack[] stacksBefore = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
+ private TracedVariables[] variablesAfter = new TracedVariables[ClassConstants.TYPICAL_CODE_LENGTH];
+ private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private boolean evaluateExceptions;
private int codeLength;
@@ -85,9 +86,7 @@ public class PartialEvaluator
*/
public PartialEvaluator()
{
- this(new ValueFactory(),
- new BasicInvocationUnit(new ValueFactory()),
- true);
+ this(new BasicValueFactory());
}
@@ -95,6 +94,19 @@ public PartialEvaluator()
* Creates a new PartialEvaluator.
* @param valueFactory the value factory that will create all values
* during evaluation.
+ */
+ public PartialEvaluator(ValueFactory valueFactory)
+ {
+ this(valueFactory,
+ new BasicInvocationUnit(valueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new PartialEvaluator.
+ * @param valueFactory the value factory that will create all values
+ * during the 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
@@ -109,6 +121,33 @@ public PartialEvaluator(ValueFactory valueFactory,
this(valueFactory,
invocationUnit,
evaluateAllCode,
+ null);
+ }
+
+
+ /**
+ * Creates a new PartialEvaluator.
+ * @param valueFactory the value factory that will create all
+ * values during the 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 extraInstructionVisitor an optional extra visitor for all
+ * instructions right before they are
+ * executed.
+ */
+ public PartialEvaluator(ValueFactory valueFactory,
+ InvocationUnit invocationUnit,
+ boolean evaluateAllCode,
+ InstructionVisitor extraInstructionVisitor)
+ {
+ this(valueFactory,
+ invocationUnit,
+ evaluateAllCode,
+ extraInstructionVisitor,
evaluateAllCode ?
new BasicBranchUnit() :
new TracedBranchUnit(),
@@ -126,6 +165,7 @@ private PartialEvaluator(PartialEvaluator partialEvaluator)
this(partialEvaluator.valueFactory,
partialEvaluator.invocationUnit,
partialEvaluator.evaluateAllCode,
+ partialEvaluator.extraInstructionVisitor,
partialEvaluator.branchUnit,
partialEvaluator.branchTargetFinder,
partialEvaluator.instructionBlockStack);
@@ -154,15 +194,17 @@ private PartialEvaluator(PartialEvaluator partialEvaluator)
private PartialEvaluator(ValueFactory valueFactory,
InvocationUnit invocationUnit,
boolean evaluateAllCode,
+ InstructionVisitor extraInstructionVisitor,
BasicBranchUnit branchUnit,
BranchTargetFinder branchTargetFinder,
java.util.Stack callingInstructionBlockStack)
{
- this.valueFactory = valueFactory;
- this.invocationUnit = invocationUnit;
- this.evaluateAllCode = evaluateAllCode;
- this.branchUnit = branchUnit;
- this.branchTargetFinder = branchTargetFinder;
+ this.valueFactory = valueFactory;
+ this.invocationUnit = invocationUnit;
+ this.evaluateAllCode = evaluateAllCode;
+ this.extraInstructionVisitor = extraInstructionVisitor;
+ this.branchUnit = branchUnit;
+ this.branchTargetFinder = branchTargetFinder;
this.callingInstructionBlockStack = callingInstructionBlockStack == null ?
this.instructionBlockStack :
callingInstructionBlockStack;
@@ -219,11 +261,11 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
if (isTraced(offset))
{
- int initializationOffset = branchTargetFinder.initializationOffset(offset);
- if (initializationOffset != NONE)
- {
- System.out.println(" is to be initialized at ["+initializationOffset+"]");
- }
+// int initializationOffset = branchTargetFinder.initializationOffset(offset);
+// if (initializationOffset != NONE)
+// {
+// System.out.println(" is to be initialized at ["+initializationOffset+"]");
+// }
InstructionOffsetValue branchTargets = branchTargets(offset);
if (branchTargets != null)
@@ -264,6 +306,10 @@ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAt
initializeArrays(codeAttribute);
initializeParameters(clazz, method, codeAttribute, variables);
+ // Reset stacks.
+ instructionBlockStack.clear();
+ callingInstructionBlockStack.clear();
+
// Find all instruction offsets,...
codeAttribute.accept(clazz, method, branchTargetFinder);
@@ -299,11 +345,11 @@ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAt
if (isTraced(offset))
{
- int initializationOffset = branchTargetFinder.initializationOffset(offset);
- if (initializationOffset >= 0)
- {
- System.out.println(" is to be initialized at ["+initializationOffset+"]");
- }
+// int initializationOffset = branchTargetFinder.initializationOffset(offset);
+// if (initializationOffset != NONE)
+// {
+// System.out.println(" is to be initialized at ["+initializationOffset+"]");
+// }
InstructionOffsetValue branchTargets = branchTargets(offset);
if (branchTargets != null)
@@ -358,6 +404,36 @@ public boolean isInstruction(int instructionOffset)
}
+ /**
+ * Returns whether the instruction at the given offset is the target of
+ * any kind.
+ */
+ public boolean isTarget(int instructionOffset)
+ {
+ return branchTargetFinder.isTarget(instructionOffset);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is the origin of a
+ * branch instruction.
+ */
+ public boolean isBranchOrigin(int instructionOffset)
+ {
+ return branchTargetFinder.isBranchOrigin(instructionOffset);
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is the target of a
+ * branch instruction.
+ */
+ public boolean isBranchTarget(int instructionOffset)
+ {
+ return branchTargetFinder.isBranchTarget(instructionOffset);
+ }
+
+
/**
* Returns whether the instruction at the given offset is the target of a
* branch instruction or an exception.
@@ -369,6 +445,16 @@ public boolean isBranchOrExceptionTarget(int instructionOffset)
}
+ /**
+ * Returns whether the instruction at the given offset is the start of
+ * an exception handler.
+ */
+ public boolean isExceptionHandler(int instructionOffset)
+ {
+ return branchTargetFinder.isExceptionHandler(instructionOffset);
+ }
+
+
/**
* Returns whether the instruction at the given offset is the start of a
* subroutine.
@@ -419,47 +505,54 @@ public int subroutineEnd(int instructionOffset)
}
- /**
- * Returns the instruction offset at which the object instance that is
- * created at the given 'new' instruction offset is initialized, or
- * NONE if it is not being created.
- */
- public int initializationOffset(int instructionOffset)
- {
- return branchTargetFinder.initializationOffset(instructionOffset);
- }
+// /**
+// * Returns the instruction offset at which the object instance that is
+// * created at the given 'new' instruction offset is initialized, or
+// * NONE if it is not being created.
+// */
+// public int initializationOffset(int instructionOffset)
+// {
+// return branchTargetFinder.initializationOffset(instructionOffset);
+// }
- /**
- * Returns whether the method is an instance initializer.
- */
- public boolean isInitializer()
- {
- return branchTargetFinder.isInitializer();
- }
+// /**
+// * Returns whether the method is an instance initializer.
+// */
+// public boolean isInitializer()
+// {
+// return branchTargetFinder.isInitializer();
+// }
+
+
+// /**
+// * Returns the instruction offset at which this initializer is calling
+// * the "super" or "this" initializer method, or NONE if it is
+// * not an initializer.
+// */
+// public int superInitializationOffset()
+// {
+// return branchTargetFinder.superInitializationOffset();
+// }
/**
- * Returns the instruction offset at which this initializer is calling
- * the "super" or "this" initializer method, or NONE if it is
- * not an initializer.
+ * Returns whether the instruction at the given offset creates a new,
+ * uninitialized instance.
*/
- public int superInitializationOffset()
+ public boolean isCreation(int offset)
{
- return branchTargetFinder.superInitializationOffset();
+ return branchTargetFinder.isCreation(offset);
}
/**
- * Returns the offset of the 'new' instruction that corresponds to the
- * invocation of the instance initializer at the given offset, or
- * AT_METHOD_ENTRY if the invocation is calling the "super" or
- * "this" initializer method, , or NONE if it is not a 'new'
- * instruction.
+ * Returns whether the instruction at the given offset is the special
+ * invocation of an instance initializer.
*/
- public int creationOffset(int offset)
+ public boolean isInitializer(int offset)
{
- return branchTargetFinder.creationOffset(offset);
+ return branchTargetFinder.isInitializer(offset);
}
@@ -523,6 +616,27 @@ public InstructionOffsetValue branchTargets(int instructionOffset)
}
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits traced instructions.
+ */
+ public InstructionVisitor tracedInstructionFilter(InstructionVisitor instructionVisitor)
+ {
+ return tracedInstructionFilter(true, instructionVisitor);
+ }
+
+
+ /**
+ * Returns a filtering version of the given instruction visitor that only
+ * visits traced or untraced instructions.
+ */
+ public InstructionVisitor tracedInstructionFilter(boolean traced,
+ InstructionVisitor instructionVisitor)
+ {
+ return new MyTracedInstructionFilter(traced, instructionVisitor);
+ }
+
+
// Utility methods to evaluate instruction blocks.
/**
@@ -734,25 +848,27 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
variables.setProducerValue(storeValue);
stack.setProducerValue(storeValue);
- // Reset the trace value.
- InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE;
-
- // Note that the instruction is only volatile.
+ // Decode the instruction.
Instruction instruction = InstructionFactory.create(code, instructionOffset);
- // By default, the next instruction will be the one after this
- // instruction.
- int nextInstructionOffset = instructionOffset +
- instruction.length(instructionOffset);
- InstructionOffsetValue nextInstructionOffsetValue = new InstructionOffsetValue(nextInstructionOffset);
- branchUnit.resetCalled();
- branchUnit.setTraceBranchTargets(nextInstructionOffsetValue);
+ // Reset the branch unit.
+ branchUnit.reset();
if (DEBUG)
{
System.out.println(instruction.toString(instructionOffset));
}
+ if (extraInstructionVisitor != null)
+ {
+ // Visit the instruction with the optional visitor.
+ instruction.accept(clazz,
+ method,
+ codeAttribute,
+ instructionOffset,
+ extraInstructionVisitor);
+ }
+
try
{
// Process the instruction. The processor may modify the
@@ -779,9 +895,6 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
int branchTargetCount = branchTargets.instructionOffsetCount();
- // Stop tracing.
- branchUnit.setTraceBranchTargets(traceValue);
-
if (DEBUG)
{
if (branchUnit.wasCalled())
@@ -828,7 +941,7 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
// Accumulate the branch targets at this offset.
branchTargetValues[instructionOffset] = branchTargetValues[instructionOffset] == null ?
branchTargets :
- branchTargetValues[instructionOffset].generalize(branchTargets).instructionOffsetValue();
+ branchTargetValues[instructionOffset].generalize(branchTargets);
// Are there no branch targets at all?
if (branchTargetCount == 0)
@@ -844,7 +957,7 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
int branchTarget = branchTargets.instructionOffset(index);
branchOriginValues[branchTarget] = branchOriginValues[branchTarget] == null ?
instructionOffsetValue:
- branchOriginValues[branchTarget].generalize(instructionOffsetValue).instructionOffsetValue();
+ branchOriginValues[branchTarget].generalize(instructionOffsetValue);
}
// Are there multiple branch targets?
@@ -864,10 +977,15 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
}
if (DEBUG) System.out.println("Definite branch from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(0)+"]");
- }
- // Just continue with the next instruction.
- instructionOffset = branchTargets.instructionOffset(0);
+ // Continue at the definite branch target.
+ instructionOffset = branchTargets.instructionOffset(0);
+ }
+ else
+ {
+ // Just continue with the next instruction.
+ instructionOffset += instruction.length(instructionOffset);
+ }
// Is this a subroutine invocation?
if (instruction.opcode == InstructionConstants.OP_JSR ||
@@ -879,8 +997,7 @@ private void evaluateSingleInstructionBlock(Clazz clazz,
codeAttribute,
variables,
stack,
- instructionOffset,
- instructionBlockStack);
+ instructionOffset);
break;
}
@@ -908,8 +1025,7 @@ private void evaluateSubroutine(Clazz clazz,
CodeAttribute codeAttribute,
TracedVariables variables,
TracedStack stack,
- int subroutineStart,
- java.util.Stack instructionBlockStack)
+ int subroutineStart)
{
int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart);
@@ -956,7 +1072,7 @@ private void generalize(PartialEvaluator other,
{
branchOriginValues[offset] = branchOriginValues[offset] == null ?
other.branchOriginValues[offset] :
- branchOriginValues[offset].generalize(other.branchOriginValues[offset]).instructionOffsetValue();
+ branchOriginValues[offset].generalize(other.branchOriginValues[offset]);
}
if (other.isTraced(offset))
@@ -965,7 +1081,7 @@ private void generalize(PartialEvaluator other,
{
branchTargetValues[offset] = branchTargetValues[offset] == null ?
other.branchTargetValues[offset] :
- branchTargetValues[offset].generalize(other.branchTargetValues[offset]).instructionOffsetValue();
+ branchTargetValues[offset].generalize(other.branchTargetValues[offset]);
}
if (evaluationCounts[offset] == 0)
@@ -1034,7 +1150,7 @@ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAtt
int endPC = exceptionInfo.u2endPC;
// Do we have to evaluate this exception catch block?
- if (isTraced(startPC, endPC))
+ if (mayThrowExceptions(clazz, method, codeAttribute, startPC, endPC))
{
int handlerPC = exceptionInfo.u2handlerPC;
int catchType = exceptionInfo.u2catchType;
@@ -1047,7 +1163,7 @@ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAtt
TracedStack stack = new TracedStack(codeAttribute.u2maxStack);
// Initialize the trace values.
- Value storeValue = new InstructionOffsetValue(AT_CATCH_ENTRY);
+ Value storeValue = new InstructionOffsetValue(handlerPC | InstructionOffsetValue.EXCEPTION_HANDLER);
variables.setProducerValue(storeValue);
stack.setProducerValue(storeValue);
@@ -1059,19 +1175,13 @@ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAtt
evaluateAllCode,
variables);
- // Initialize the the stack.
- //stack.push(valueFactory.createReference((ClassConstant)((ProgramClass)clazz).getConstant(exceptionInfo.u2catchType), false));
- String catchClassName = catchType != 0 ?
- clazz.getClassName(catchType) :
- ClassConstants.NAME_JAVA_LANG_THROWABLE;
-
- Clazz catchClass = catchType != 0 ?
- ((ClassConstant)((ProgramClass)clazz).getConstant(catchType)).referencedClass :
- null;
-
- stack.push(valueFactory.createReferenceValue(catchClassName,
- catchClass,
- false));
+ // Initialize the stack.
+ invocationUnit.enterExceptionHandler(clazz,
+ method,
+ codeAttribute,
+ handlerPC,
+ catchType,
+ stack);
int evaluationCount = evaluationCounts[handlerPC];
@@ -1194,12 +1304,15 @@ private void initializeParameters(Clazz clazz,
CodeAttribute codeAttribute,
TracedVariables variables)
{
- // Create the method parameters.
- TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals);
+// // Create the method parameters.
+// TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals);
+//
+// // Remember this instruction's offset with any stored value.
+// Value storeValue = new InstructionOffsetValue(AT_METHOD_ENTRY);
+// parameters.setProducerValue(storeValue);
- // Remember this instruction's offset with any stored value.
- Value storeValue = new InstructionOffsetValue(AT_METHOD_ENTRY);
- parameters.setProducerValue(storeValue);
+ // Create the method parameters.
+ Variables parameters = new Variables(codeAttribute.u2maxLocals);
// Initialize the method parameters.
invocationUnit.enterMethod(clazz, method, parameters);
@@ -1212,13 +1325,39 @@ private void initializeParameters(Clazz clazz,
// Initialize the variables with the parameters.
variables.initialize(parameters);
- // Set the store value of each parameter variable.
- InstructionOffsetValue atMethodEntry = new InstructionOffsetValue(AT_METHOD_ENTRY);
-
+ // Set the store value of each parameter variable. We store the
+ // variable indices of the parameters. These parameter offsets take
+ // into account Category 2 types.
for (int index = 0; index < parameters.size(); index++)
{
- variables.setProducerValue(index, atMethodEntry);
+ InstructionOffsetValue producerValue =
+ new InstructionOffsetValue(index | InstructionOffsetValue.METHOD_PARAMETER);
+
+ variables.setProducerValue(index, producerValue);
+ }
+ }
+
+
+ /**
+ * Returns whether a block of instructions may ever throw an exception.
+ */
+ private boolean mayThrowExceptions(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int startOffset,
+ int endOffset)
+ {
+ for (int index = startOffset; index < endOffset; index++)
+ {
+ if (isTraced(index) &&
+ (evaluateAllCode ||
+ InstructionFactory.create(codeAttribute.code, index).mayThrowExceptions()))
+ {
+ return true;
+ }
}
+
+ return false;
}
@@ -1289,6 +1428,10 @@ private void generalizeVariables(int startOffset,
}
+ /**
+ * This class represents an instruction block that has to be executed,
+ * starting with a given state at a given instruction offset.
+ */
private static class MyInstructionBlock
{
private TracedVariables variables;
@@ -1305,4 +1448,85 @@ private MyInstructionBlock(TracedVariables variables,
this.startOffset = startOffset;
}
}
+
+
+ /**
+ * This InstructionVisitor delegates its visits to a given
+ * InstructionVisitor, but only if the instruction has been traced (or not).
+ */
+ private class MyTracedInstructionFilter implements InstructionVisitor
+ {
+ private final boolean traced;
+ private final InstructionVisitor instructionVisitor;
+
+
+ public MyTracedInstructionFilter(boolean traced,
+ InstructionVisitor instructionVisitor)
+ {
+ this.traced = traced;
+ this.instructionVisitor = instructionVisitor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitVariableInstruction(clazz, method, codeAttribute, offset, variableInstruction);
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction);
+ }
+ }
+
+
+ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitTableSwitchInstruction(clazz, method, codeAttribute, offset, tableSwitchInstruction);
+ }
+ }
+
+
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ if (shouldVisit(offset))
+ {
+ instructionVisitor.visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, lookUpSwitchInstruction);
+ }
+ }
+
+
+ private boolean shouldVisit(int offset)
+ {
+ return isTraced(offset) == traced;
+ }
+ }
}
diff --git a/core/src/proguard/optimize/evaluation/ReferenceTracingInvocationUnit.java b/core/src/proguard/optimize/evaluation/ReferenceTracingInvocationUnit.java
new file mode 100644
index 0000000..e3b6bf3
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/ReferenceTracingInvocationUnit.java
@@ -0,0 +1,211 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.CodeAttribute;
+import proguard.classfile.constant.*;
+import proguard.classfile.instruction.ConstantInstruction;
+import proguard.evaluation.*;
+import proguard.evaluation.value.*;
+
+/**
+ * This InvocationUnit tags reference values of retrieved fields, passed method
+ * parameters, method return values, and caught exceptions, so they can be
+ * traced throughout the execution of a method. The tags are instruction offsets
+ * or parameter indices (not parameter offsets).
+ *
+ * @see TracedReferenceValue
+ * @see InstructionOffsetValue
+ * @author Eric Lafortune
+ */
+public class ReferenceTracingInvocationUnit
+extends SimplifiedInvocationUnit
+{
+ private final SimplifiedInvocationUnit invocationUnit;
+
+ private int offset;
+
+
+ /**
+ * Creates a new ReferenceTracingInvocationUnit.
+ * @param invocationUnit the invocation unit to which invocations will
+ * be delegated.
+ */
+ public ReferenceTracingInvocationUnit(SimplifiedInvocationUnit invocationUnit)
+ {
+ this.invocationUnit = invocationUnit;
+ }
+
+
+ // Implementations for InvocationUnit.
+
+ public void enterExceptionHandler(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ int catchType,
+ Stack stack)
+ {
+ this.offset = offset;
+
+ super.enterExceptionHandler(clazz,
+ method,
+ codeAttribute,
+ offset,
+ catchType,
+ stack);
+ }
+
+
+ public void invokeMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction, Stack stack)
+ {
+ this.offset = offset;
+
+ super.invokeMember(clazz,
+ method,
+ codeAttribute,
+ offset,
+ constantInstruction,
+ stack);
+ }
+
+
+ // Implementations for SimplifiedInvocationUnit.
+
+ public Value getExceptionValue(Clazz clazz,
+ ClassConstant catchClassConstant)
+ {
+ return trace(invocationUnit.getExceptionValue(clazz, catchClassConstant),
+ offset | InstructionOffsetValue.EXCEPTION_HANDLER);
+ }
+
+
+ public void setFieldClassValue(Clazz clazz, RefConstant refConstant, ReferenceValue value)
+ {
+ invocationUnit.setFieldClassValue(clazz, refConstant, value);
+ }
+
+
+ public Value getFieldClassValue(Clazz clazz, RefConstant refConstant, String type)
+ {
+ return trace(invocationUnit.getFieldClassValue(clazz, refConstant, type),
+ offset | InstructionOffsetValue.FIELD_VALUE);
+ }
+
+
+ public void setFieldValue(Clazz clazz, RefConstant refConstant, Value value)
+ {
+ invocationUnit.setFieldValue(clazz, refConstant, value);
+ }
+
+
+ public Value getFieldValue(Clazz clazz, RefConstant refConstant, String type)
+ {
+ return trace(invocationUnit.getFieldValue(clazz, refConstant, type),
+ offset | InstructionOffsetValue.FIELD_VALUE);
+ }
+
+
+ public void setMethodParameterValue(Clazz clazz, RefConstant refConstant, int parameterIndex, Value value)
+ {
+ invocationUnit.setMethodParameterValue(clazz, refConstant, parameterIndex, value);
+ }
+
+
+ public Value getMethodParameterValue(Clazz clazz, Method method, int parameterIndex, String type, Clazz referencedClass)
+ {
+ Value parameterValue =
+ invocationUnit.getMethodParameterValue(clazz, method, parameterIndex, type, referencedClass);
+
+ // We're attaching the parameter index as a trace value. It doesn't
+ // take into account Category 2 values, so it is not compatible with
+ // variable indices.
+ return trace(parameterValue,
+ parameterIndex | InstructionOffsetValue.METHOD_PARAMETER);
+ }
+
+
+ public void setMethodReturnValue(Clazz clazz, Method method, Value value)
+ {
+ invocationUnit.setMethodReturnValue(clazz, method, value);
+ }
+
+
+ public Value getMethodReturnValue(Clazz clazz, RefConstant refConstant, String type)
+ {
+ Value returnValue =
+ invocationUnit.getMethodReturnValue(clazz, refConstant, type);
+
+ return trace(returnValue,
+ offset | InstructionOffsetValue.METHOD_RETURN_VALUE);
+ }
+
+
+ public Value getMethodReturnValue(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant, String type)
+ {
+ Value returnValue =
+ invocationUnit.getMethodReturnValue(clazz, invokeDynamicConstant, type);
+
+ return trace(returnValue,
+ offset | InstructionOffsetValue.METHOD_RETURN_VALUE);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Sets or replaces the trace value on a given value, if it's a
+ * reference value, returning the result.
+ */
+ protected Value trace(Value value, int trace)
+ {
+ if (value.computationalType() != Value.TYPE_REFERENCE)
+ {
+ return value;
+ }
+
+ return trace(value, new InstructionOffsetValue(trace));
+ }
+
+
+ /**
+ * Sets or replaces the trace value on a given value, returning the result.
+ */
+ protected Value trace(Value value, InstructionOffsetValue traceValue)
+ {
+ return new TracedReferenceValue(untrace(value).referenceValue(),
+ traceValue);
+ }
+
+
+ /**
+ * Removes the trace value from a given value, if present, returning the
+ * result.
+ */
+ private Value untrace(Value value)
+ {
+ return value instanceof TracedReferenceValue ?
+ ((TracedReferenceValue)value).getReferenceValue() :
+ value;
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/evaluation/ReferenceTracingValueFactory.java b/core/src/proguard/optimize/evaluation/ReferenceTracingValueFactory.java
new file mode 100644
index 0000000..ad1adb3
--- /dev/null
+++ b/core/src/proguard/optimize/evaluation/ReferenceTracingValueFactory.java
@@ -0,0 +1,301 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.CodeAttribute;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This ValueFactory tags newly created reference values so they can be traced
+ * throughout the execution of a method.
+ *
+ * @see TracedReferenceValue
+ * @see InstructionOffsetValue
+ * @author Eric Lafortune
+ */
+public class ReferenceTracingValueFactory
+extends SimplifiedVisitor
+implements InstructionVisitor,
+ ValueFactory
+{
+ private final ValueFactory valueFactory;
+ private final boolean preserveTraceValueOnCasts;
+
+ private Value traceValue;
+
+
+ /**
+ * Creates a new ReferenceTracingValueFactory that attaches instruction
+ * offset values based on being used as an instruction visitor. This
+ * instance preserves trace values in the {@link #cast} method.
+ * @param valueFactory the value factory that creates the actual values.
+ */
+ public ReferenceTracingValueFactory(ValueFactory valueFactory)
+ {
+ this(valueFactory, true);
+ }
+
+
+ /**
+ * Creates a new ReferenceTracingValueFactory that attaches instruction
+ * offset values based on being used as an instruction visitor.
+ * @param valueFactory the value factory that creates the
+ * actual values.
+ * @param preserveTraceValueOnCasts specifies whether to preserve the
+ * trace value for reference values that
+ * are passed to the {@link #cast} method.
+ */
+ public ReferenceTracingValueFactory(ValueFactory valueFactory,
+ boolean preserveTraceValueOnCasts)
+ {
+ this.valueFactory = valueFactory;
+ this.preserveTraceValueOnCasts = preserveTraceValueOnCasts;
+ }
+
+
+ public void setTraceValue(Value traceValue)
+ {
+ this.traceValue = traceValue;
+ }
+
+
+ /**
+ * Casts a given traced reference value to the given type, either keeping
+ * its trace value or setting a new one.
+ */
+ public TracedReferenceValue cast(TracedReferenceValue referenceValue,
+ String type,
+ Clazz referencedClass,
+ boolean alwaysCast)
+ {
+ // Cast the value.
+ ReferenceValue castValue =
+ referenceValue.getReferenceValue().cast(type,
+ referencedClass,
+ valueFactory,
+ alwaysCast);
+
+ // Trace it.
+ return new TracedReferenceValue(castValue,
+ preserveTraceValueOnCasts ?
+ referenceValue.getTraceValue() :
+ traceValue);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ traceValue = null;
+ }
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_ACONST_NULL:
+ case InstructionConstants.OP_NEWARRAY:
+ case InstructionConstants.OP_ATHROW:
+ traceValue = new InstructionOffsetValue(offset | InstructionOffsetValue.NEW_INSTANCE);
+ break;
+
+ case InstructionConstants.OP_AALOAD:
+ traceValue = new InstructionOffsetValue(offset);
+ break;
+
+ default:
+ traceValue = null;
+ break;
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ traceValue = new InstructionOffsetValue(offset | InstructionOffsetValue.NEW_INSTANCE);
+ break;
+
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ traceValue = new InstructionOffsetValue(offset | InstructionOffsetValue.FIELD_VALUE);
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ traceValue = new InstructionOffsetValue(offset | InstructionOffsetValue.METHOD_RETURN_VALUE);
+ break;
+
+ case InstructionConstants.OP_CHECKCAST:
+ traceValue = new InstructionOffsetValue(offset | InstructionOffsetValue.CAST);
+ break;
+
+ default:
+ traceValue = null;
+ break;
+ }
+ }
+
+
+ // Implementations for BasicValueFactory.
+
+ public Value createValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
+ {
+ return trace(valueFactory.createValue(type,
+ referencedClass,
+ mayBeExtension,
+ mayBeNull));
+ }
+
+
+ public IntegerValue createIntegerValue()
+ {
+ return valueFactory.createIntegerValue();
+ }
+
+
+ public IntegerValue createIntegerValue(int value)
+ {
+ return valueFactory.createIntegerValue(value);
+ }
+
+
+ public LongValue createLongValue()
+ {
+ return valueFactory.createLongValue();
+ }
+
+
+ public LongValue createLongValue(long value)
+ {
+ return valueFactory.createLongValue(value);
+ }
+
+
+ public FloatValue createFloatValue()
+ {
+ return valueFactory.createFloatValue();
+ }
+
+
+ public FloatValue createFloatValue(float value)
+ {
+ return valueFactory.createFloatValue(value);
+ }
+
+
+ public DoubleValue createDoubleValue()
+ {
+ return valueFactory.createDoubleValue();
+ }
+
+
+ public DoubleValue createDoubleValue(double value)
+ {
+ return valueFactory.createDoubleValue(value);
+ }
+
+
+ public ReferenceValue createReferenceValue()
+ {
+ return trace(valueFactory.createReferenceValue());
+ }
+
+
+ public ReferenceValue createReferenceValueNull()
+ {
+ return trace(valueFactory.createReferenceValueNull());
+ }
+
+
+ public ReferenceValue createReferenceValue(String type,
+ Clazz referencedClass,
+ boolean mayBeExtension,
+ boolean mayBeNull)
+ {
+ return trace(valueFactory.createReferenceValue(type,
+ referencedClass,
+ mayBeExtension,
+ mayBeNull));
+ }
+
+
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength)
+ {
+ return trace(valueFactory.createArrayReferenceValue(type, referencedClass, arrayLength));
+ }
+
+
+ /**
+ * Creates a new ReferenceValue that represents an array with elements of
+ * the given type, with the given length and initial element values.
+ */
+ public ReferenceValue createArrayReferenceValue(String type,
+ Clazz referencedClass,
+ IntegerValue arrayLength,
+ Value elementValue)
+ {
+ return trace(valueFactory.createArrayReferenceValue(type, referencedClass, arrayLength, elementValue));
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Attaches the current trace value to given value, if it is a reference
+ * value.
+ */
+ public Value trace(Value value)
+ {
+ return value.computationalType() == Value.TYPE_REFERENCE ?
+ trace(value.referenceValue()) :
+ value;
+ }
+
+ /**
+ * Attaches the current trace value to given reference value.
+ */
+ public ReferenceValue trace(ReferenceValue referenceValue)
+ {
+ return traceValue != null ?
+ new TracedReferenceValue(referenceValue, traceValue) :
+ referenceValue;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java b/core/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
similarity index 54%
rename from src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
index 73b8b8f..552bee9 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumArrayPropagator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
import proguard.evaluation.value.*;
+import proguard.optimize.OptimizationInfoMemberFilter;
import proguard.optimize.info.*;
/**
@@ -38,7 +39,17 @@ public class SimpleEnumArrayPropagator
implements ClassVisitor,
MemberVisitor
{
- private final ValueFactory valueFactory = new ParticularValueFactory();
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("enum") != null;
+ //*/
+
+
+ private final MemberVisitor fieldArrayFinder = new MemberDescriptorFilter("[I", this);
+ private final MemberVisitor methodArrayPropagator = new OptimizationInfoMemberFilter(
+ new MemberDescriptorFilter("()[I", this));
+ private final ValueFactory valueFactory = new ParticularValueFactory();
private Value array;
@@ -47,48 +58,49 @@ public class SimpleEnumArrayPropagator
public void visitProgramClass(ProgramClass programClass)
{
- // Update the return value of the "int[] values()" method.
- programClass.methodsAccept(new MemberDescriptorFilter("()[I", this));
- }
-
-
- // Implementations for MemberVisitor.
+ // Find the array of the "int[] $VALUES" field.
+ array = null;
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
- {
- // Find the array length of the "int[] $VALUES" field.
- programClass.fieldsAccept(new MemberDescriptorFilter("[I", this));
+ programClass.fieldsAccept(fieldArrayFinder);
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;
+ // Update the return value of the "int[] values()" method.
+ programClass.methodsAccept(methodArrayPropagator);
}
}
+
+ // Implementations for MemberVisitor.
+
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
array = StoringInvocationUnit.getFieldValue(programField);
}
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // 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));
+
+ if (DEBUG)
+ {
+ System.out.println("SimpleEnumArrayPropagator: ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]: propagating ["+propagatedArray+"] as return value");
+ }
+
+ setMethodReturnValue(programMethod, propagatedArray);
+ }
+
+
// Small utility methods.
private static void setMethodReturnValue(Method method, Value value)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setReturnValue(value);
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setReturnValue( value);
}
}
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java b/core/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
similarity index 79%
rename from src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
index 9208402..af6f291 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumClassChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +22,7 @@
import proguard.classfile.*;
import proguard.classfile.visitor.*;
+import proguard.optimize.OptimizationInfoClassFilter;
import proguard.optimize.info.SimpleEnumMarker;
/**
@@ -40,12 +41,13 @@ public class SimpleEnumClassChecker
//*/
- private final SimpleEnumMarker simpleEnumMarker = new SimpleEnumMarker(true);
- private final MemberVisitor virtualMemberChecker = new MemberAccessFilter(0,
- ClassConstants.ACC_PRIVATE |
- ClassConstants.ACC_STATIC,
- new MemberToClassVisitor(
- new SimpleEnumMarker(false)));
+ private final ClassVisitor simpleEnumMarker = new OptimizationInfoClassFilter(
+ new SimpleEnumMarker(true));
+ private final MemberVisitor virtualMemberChecker = new MemberAccessFilter(0,
+ ClassConstants.ACC_PRIVATE |
+ ClassConstants.ACC_STATIC,
+ new MemberToClassVisitor(
+ new SimpleEnumMarker(false)));
// Implementations for ClassVisitor.
@@ -72,4 +74,4 @@ public void visitProgramClass(ProgramClass programClass)
programClass.methodsAccept(virtualMemberChecker);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java b/core/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
similarity index 71%
rename from src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
index 07a1768..caea0fe 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumClassSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -88,30 +88,49 @@ public class SimpleEnumClassSimplifier
new Utf8Constant(ClassConstants.METHOD_TYPE_INIT_ENUM),
};
- private static final Instruction[] INSTRUCTIONS = new Instruction[]
+ private static final Instruction[][][] INSTRUCTION_SEQUENCES = 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),
+ {
+ // Replace new Enum("name", constant)
+ // by constant + 1.
+ {
+ 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),
+ },
+ {
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, ENUM_CONSTANT_ORDINAL),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ new SimpleInstruction(InstructionConstants.OP_IADD),
+ }
+ },
+ {
+ // The name constants may have been encrypted.
+ // Replace (..., constant)
+ // by (..., 0); pop; constant + 1.
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, ENUM_CONSTANT_ORDINAL),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_ENUM_INIT),
+ },
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_ENUM_INIT),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ 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,
+ private final InstructionSequencesReplacer instructionSequenceReplacer =
+ new InstructionSequencesReplacer(CONSTANTS,
+ INSTRUCTION_SEQUENCES,
null,
codeAttributeEditor);
diff --git a/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java b/core/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
similarity index 98%
rename from src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
index 1dcd80e..85ffd0b 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumDescriptorSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,9 +26,9 @@
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.KeepMarker;
import proguard.optimize.info.*;
/**
@@ -217,11 +217,9 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
programField.u2accessFlags &= ~ClassConstants.ACC_ENUM;
// Clear the field value.
- FieldOptimizationInfo fieldOptimizationInfo =
- FieldOptimizationInfo.getFieldOptimizationInfo(programField);
- if (fieldOptimizationInfo != null)
+ if (!KeepMarker.isKept(programField))
{
- fieldOptimizationInfo.resetValue(programClass, programField);
+ ProgramFieldOptimizationInfo.getProgramFieldOptimizationInfo(programField).resetValue(programClass, programField);
}
// Simplify the signature.
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java b/core/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
similarity index 97%
rename from src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
index 37c885a..bb06134 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumUseChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,7 @@
import proguard.classfile.visitor.*;
import proguard.evaluation.*;
import proguard.evaluation.value.*;
+import proguard.optimize.OptimizationInfoClassFilter;
import proguard.optimize.info.SimpleEnumMarker;
/**
@@ -58,8 +59,8 @@ public class SimpleEnumUseChecker
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 ConstantVisitor parameterChecker = new ReferencedMemberVisitor(new AllParameterVisitor(false, this));
+ private final ClassVisitor complexEnumMarker = new OptimizationInfoClassFilter(new SimpleEnumMarker(false));
private final ReferencedClassVisitor referencedComplexEnumMarker = new ReferencedClassVisitor(complexEnumMarker);
@@ -72,7 +73,7 @@ public class SimpleEnumUseChecker
*/
public SimpleEnumUseChecker()
{
- this(new PartialEvaluator());
+ this(new PartialEvaluator(new TypedReferenceValueFactory()));
}
@@ -91,7 +92,7 @@ public SimpleEnumUseChecker(PartialEvaluator partialEvaluator)
public void visitProgramClass(ProgramClass programClass)
{
- if ((programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) != 0)
+ if ((programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATION) != 0)
{
// Unmark the simple enum classes in annotations.
programClass.methodsAccept(referencedComplexEnumMarker);
@@ -475,11 +476,11 @@ private void checkMixedStackEntriesBefore(int offset)
// Check all producers.
for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
{
- int producerOffset =
- producerOffsets.instructionOffset(producerIndex);
-
- if (producerOffset >= 0)
+ if (!producerOffsets.isExceptionHandler(producerIndex))
{
+ int producerOffset =
+ producerOffsets.instructionOffset(producerIndex);
+
if (DEBUG)
{
ReferenceValue producedValue =
@@ -537,11 +538,11 @@ private void checkMixedVariablesBefore(int offset)
// Check all producers.
for (int producerIndex = 0; producerIndex < producerCount; producerIndex++)
{
- int producerOffset =
- producerOffsets.instructionOffset(producerIndex);
-
- if (producerOffset >= 0)
+ if (!producerOffsets.isMethodParameter(producerIndex))
{
+ int producerOffset =
+ producerOffsets.instructionOffset(producerIndex);
+
if (DEBUG)
{
ReferenceValue producedValue =
diff --git a/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java b/core/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
similarity index 96%
rename from src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
rename to core/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
index 295cdfb..340faf3 100644
--- a/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
+++ b/core/src/proguard/optimize/evaluation/SimpleEnumUseSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -54,11 +54,12 @@ public class SimpleEnumUseSimplifier
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));
+ private final ConstantVisitor nullParameterFixer = new ReferencedMemberVisitor(new AllParameterVisitor(false, this));
// Fields acting as parameters and return values for the visitor methods.
private Clazz invocationClazz;
@@ -73,7 +74,7 @@ public class SimpleEnumUseSimplifier
*/
public SimpleEnumUseSimplifier()
{
- this(new PartialEvaluator(), null);
+ this(new PartialEvaluator(new TypedReferenceValueFactory()), null);
}
@@ -799,19 +800,22 @@ private void replaceNullVariableProducers(Clazz clazz,
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)
+ if (!producerOffsets.isMethodParameter(index) &&
+ !producerOffsets.isExceptionHandler(index))
{
- // Replace loading null by loading 0.
- replaceInstruction(clazz,
- producerOffset,
- new VariableInstruction(InstructionConstants.OP_ASTORE, variableIndex),
- new VariableInstruction(InstructionConstants.OP_ISTORE, variableIndex));
+ int producerOffset = producerOffsets.instructionOffset(index);
- // Replace pushing null by pushing 0.
- replaceNullStackEntryProducers(clazz, method, codeAttribute, producerOffset);
+ if (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/core/src/proguard/optimize/evaluation/StoringInvocationUnit.java
similarity index 65%
rename from src/proguard/optimize/evaluation/StoringInvocationUnit.java
rename to core/src/proguard/optimize/evaluation/StoringInvocationUnit.java
index 27af58c..6de19c8 100644
--- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java
+++ b/core/src/proguard/optimize/evaluation/StoringInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
import proguard.classfile.constant.RefConstant;
import proguard.evaluation.BasicInvocationUnit;
import proguard.evaluation.value.*;
+import proguard.optimize.KeepMarker;
import proguard.optimize.info.*;
/**
@@ -69,9 +70,9 @@ public StoringInvocationUnit(ValueFactory valueFactory,
// Implementations for BasicInvocationUnit.
- protected void setFieldClassValue(Clazz clazz,
- RefConstant refConstant,
- ReferenceValue value)
+ public void setFieldClassValue(Clazz clazz,
+ RefConstant refConstant,
+ ReferenceValue value)
{
if (storeFieldValues)
{
@@ -84,9 +85,9 @@ protected void setFieldClassValue(Clazz clazz,
}
- protected void setFieldValue(Clazz clazz,
- RefConstant refConstant,
- Value value)
+ public void setFieldValue(Clazz clazz,
+ RefConstant refConstant,
+ Value value)
{
if (storeFieldValues)
{
@@ -99,10 +100,10 @@ protected void setFieldValue(Clazz clazz,
}
- protected void setMethodParameterValue(Clazz clazz,
- RefConstant refConstant,
- int parameterIndex,
- Value value)
+ public void setMethodParameterValue(Clazz clazz,
+ RefConstant refConstant,
+ int parameterIndex,
+ Value value)
{
if (storeMethodParameterValues)
{
@@ -117,9 +118,9 @@ protected void setMethodParameterValue(Clazz clazz,
}
- protected void setMethodReturnValue(Clazz clazz,
- Method method,
- Value value)
+ public void setMethodReturnValue(Clazz clazz,
+ Method method,
+ Value value)
{
if (storeMethodReturnValues)
{
@@ -132,76 +133,60 @@ protected void setMethodReturnValue(Clazz clazz,
private static void generalizeFieldClassValue(Field field, ReferenceValue value)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
+ if (!KeepMarker.isKept(field))
{
- info.generalizeReferencedClass(value);
+ ProgramFieldOptimizationInfo.getProgramFieldOptimizationInfo(field).generalizeReferencedClass(value);
}
}
public static ReferenceValue getFieldClassValue(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info != null ?
- info.getReferencedClass() :
- null;
+ return FieldOptimizationInfo.getFieldOptimizationInfo(field).getReferencedClass();
}
private static void generalizeFieldValue(Field field, Value value)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
+ if (!KeepMarker.isKept(field))
{
- info.generalizeValue(value);
+ ProgramFieldOptimizationInfo.getProgramFieldOptimizationInfo(field).generalizeValue(value);
}
}
public static Value getFieldValue(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info != null ?
- info.getValue() :
- null;
+ return FieldOptimizationInfo.getFieldOptimizationInfo(field).getValue();
}
private static void generalizeMethodParameterValue(Method method, int parameterIndex, Value value)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
+ if (!KeepMarker.isKept(method))
{
- info.generalizeParameter(parameterIndex, value);
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).generalizeParameterValue(parameterIndex, value);
}
}
public static Value getMethodParameterValue(Method method, int parameterIndex)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ?
- info.getParameter(parameterIndex) :
- null;
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getParameterValue(parameterIndex);
}
private static void generalizeMethodReturnValue(Method method, Value value)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
+ if (!KeepMarker.isKept(method))
{
- info.generalizeReturnValue(value);
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).generalizeReturnValue(value);
}
}
public static Value getMethodReturnValue(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ?
- info.getReturnValue() :
- null;
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getReturnValue();
}
}
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/core/src/proguard/optimize/evaluation/TracedBranchUnit.java
similarity index 69%
rename from src/proguard/optimize/evaluation/TracedBranchUnit.java
rename to core/src/proguard/optimize/evaluation/TracedBranchUnit.java
index 8d6e150..019897d 100644
--- a/src/proguard/optimize/evaluation/TracedBranchUnit.java
+++ b/core/src/proguard/optimize/evaluation/TracedBranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,8 +33,32 @@
class TracedBranchUnit
extends BasicBranchUnit
{
+ private boolean isFixed;
+
+
+ // Implementations for BasicBranchUnit.
+
+ public void reset()
+ {
+ super.reset();
+
+ isFixed = false;
+ }
+
+
// Implementations for BranchUnit.
+ public void branch(Clazz clazz,
+ CodeAttribute codeAttribute,
+ int offset,
+ int branchTarget)
+ {
+ super.branch(clazz, codeAttribute, offset, branchTarget);
+
+ isFixed = true;
+ }
+
+
public void branchConditionally(Clazz clazz,
CodeAttribute codeAttribute,
int offset,
@@ -45,15 +69,20 @@ public void branchConditionally(Clazz clazz,
{
// Always branch.
super.branch(clazz, codeAttribute, offset, branchTarget);
+
+ isFixed = true;
}
- else if (conditional != Value.NEVER)
+ else if (conditional == Value.MAYBE)
{
- // Maybe branch.
- super.branchConditionally(clazz, codeAttribute, offset, branchTarget, conditional);
+ if (!isFixed)
+ {
+ // Maybe branch.
+ super.branchConditionally(clazz, codeAttribute, offset, branchTarget, conditional);
+ }
}
else
{
- super.setCalled();
+ super.wasCalled = true;
}
}
}
diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/core/src/proguard/optimize/evaluation/VariableOptimizer.java
similarity index 98%
rename from src/proguard/optimize/evaluation/VariableOptimizer.java
rename to core/src/proguard/optimize/evaluation/VariableOptimizer.java
index 239ec2e..9b709f9 100644
--- a/src/proguard/optimize/evaluation/VariableOptimizer.java
+++ b/core/src/proguard/optimize/evaluation/VariableOptimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -42,7 +42,7 @@ public class VariableOptimizer
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = System.getProperty("vo") != null;
+ private static boolean DEBUG = true;
//*/
private static final int MAX_VARIABLES_SIZE = 64;
diff --git a/src/proguard/optimize/evaluation/package.html b/core/src/proguard/optimize/evaluation/package.html
similarity index 100%
rename from src/proguard/optimize/evaluation/package.html
rename to core/src/proguard/optimize/evaluation/package.html
diff --git a/src/proguard/optimize/info/AccessMethodMarker.java b/core/src/proguard/optimize/info/AccessMethodMarker.java
similarity index 81%
rename from src/proguard/optimize/info/AccessMethodMarker.java
rename to core/src/proguard/optimize/info/AccessMethodMarker.java
index b030c55..1b03afc 100644
--- a/src/proguard/optimize/info/AccessMethodMarker.java
+++ b/core/src/proguard/optimize/info/AccessMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -65,7 +65,7 @@ public void visitAnyConstant(Clazz clazz, Constant constant) {}
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
- // Check the referenced class or class member, if any.
+ // Check the referenced class or class member, if any.
stringConstant.referencedClassAccept(this);
stringConstant.referencedMemberAccept(this);
}
@@ -141,11 +141,7 @@ else if ((accessFlags & ClassConstants.ACC_PUBLIC) == 0)
private static void setAccessesPrivateCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setAccessesPrivateCode();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setAccessesPrivateCode();
}
@@ -154,18 +150,13 @@ private static void setAccessesPrivateCode(Method method)
*/
public static boolean accessesPrivateCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.accessesPrivateCode();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).accessesPrivateCode();
}
private static void setAccessesPackageCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setAccessesPackageCode();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setAccessesPackageCode();
}
@@ -175,18 +166,13 @@ private static void setAccessesPackageCode(Method method)
*/
public static boolean accessesPackageCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.accessesPackageCode();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).accessesPackageCode();
}
private static void setAccessesProtectedCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setAccessesProtectedCode();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setAccessesProtectedCode();
}
@@ -195,7 +181,6 @@ private static void setAccessesProtectedCode(Method method)
*/
public static boolean accessesProtectedCode(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.accessesProtectedCode();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).accessesProtectedCode();
}
}
diff --git a/src/proguard/optimize/info/BackwardBranchMarker.java b/core/src/proguard/optimize/info/BackwardBranchMarker.java
similarity index 86%
rename from src/proguard/optimize/info/BackwardBranchMarker.java
rename to core/src/proguard/optimize/info/BackwardBranchMarker.java
index af1862e..3da8806 100644
--- a/src/proguard/optimize/info/BackwardBranchMarker.java
+++ b/core/src/proguard/optimize/info/BackwardBranchMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +74,12 @@ private void markBackwardBranch(Method method, int branchOffset)
private static void setBranchesBackward(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setBranchesBackward();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setBranchesBackward();
}
public static boolean branchesBackward(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.branchesBackward();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).branchesBackward();
}
}
diff --git a/src/proguard/optimize/info/CatchExceptionMarker.java b/core/src/proguard/optimize/info/CatchExceptionMarker.java
similarity index 81%
rename from src/proguard/optimize/info/CatchExceptionMarker.java
rename to core/src/proguard/optimize/info/CatchExceptionMarker.java
index 9105142..213963f 100644
--- a/src/proguard/optimize/info/CatchExceptionMarker.java
+++ b/core/src/proguard/optimize/info/CatchExceptionMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -52,18 +52,12 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
private static void markCatchException(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setCatchesExceptions();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setCatchesExceptions();
}
public static boolean catchesExceptions(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null ||
- info.catchesExceptions();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).catchesExceptions();
}
}
diff --git a/src/proguard/optimize/info/CaughtClassFilter.java b/core/src/proguard/optimize/info/CaughtClassFilter.java
similarity index 97%
rename from src/proguard/optimize/info/CaughtClassFilter.java
rename to core/src/proguard/optimize/info/CaughtClassFilter.java
index 78f10cf..1a63c50 100644
--- a/src/proguard/optimize/info/CaughtClassFilter.java
+++ b/core/src/proguard/optimize/info/CaughtClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/info/CaughtClassMarker.java
similarity index 81%
rename from src/proguard/optimize/info/CaughtClassMarker.java
rename to core/src/proguard/optimize/info/CaughtClassMarker.java
index 9d4a1e9..a124aaf 100644
--- a/src/proguard/optimize/info/CaughtClassMarker.java
+++ b/core/src/proguard/optimize/info/CaughtClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +47,12 @@ public void visitProgramClass(ProgramClass programClass)
private static void setCaught(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setCaught();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setCaught();
}
public static boolean isCaught(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.isCaught();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isCaught();
}
}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/info/ClassOptimizationInfo.java b/core/src/proguard/optimize/info/ClassOptimizationInfo.java
new file mode 100644
index 0000000..4789bc6
--- /dev/null
+++ b/core/src/proguard/optimize/info/ClassOptimizationInfo.java
@@ -0,0 +1,144 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.Clazz;
+
+/**
+ * This class stores some optimization information that can be attached to
+ * a class.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassOptimizationInfo
+{
+ protected boolean hasNoSideEffects = false;
+
+
+ public void setNoSideEffects()
+ {
+ hasNoSideEffects = true;
+ }
+
+
+ public boolean hasNoSideEffects()
+ {
+ return hasNoSideEffects;
+ }
+
+
+ public boolean isKept()
+ {
+ return true;
+ }
+
+
+ public boolean isInstantiated()
+ {
+ return true;
+ }
+
+
+ public boolean isInstanceofed()
+ {
+ // We're relaxing the strict assumption of "true".
+ return !hasNoSideEffects;
+ }
+
+
+ public boolean isDotClassed()
+ {
+ // We're relaxing the strict assumption of "true".
+ return !hasNoSideEffects;
+ }
+
+
+ public boolean isCaught()
+ {
+ return true;
+ }
+
+
+ public boolean isSimpleEnum()
+ {
+ return false;
+ }
+
+
+ public boolean isWrapper()
+ {
+ return false;
+ }
+
+
+ public boolean isEscaping()
+ {
+ return true;
+ }
+
+
+ public boolean hasSideEffects()
+ {
+ return !hasNoSideEffects;
+ }
+
+
+ public boolean containsPackageVisibleMembers()
+ {
+ return true;
+ }
+
+
+ public boolean invokesPackageVisibleMembers()
+ {
+ return true;
+ }
+
+
+ public boolean mayBeMerged()
+ {
+ return false;
+ }
+
+
+ public Clazz getWrappedClass()
+ {
+ return null;
+ }
+
+
+ public Clazz getTargetClass()
+ {
+ return null;
+ }
+
+
+ public static void setClassOptimizationInfo(Clazz clazz)
+ {
+ clazz.setVisitorInfo(new ClassOptimizationInfo());
+ }
+
+
+ public static ClassOptimizationInfo getClassOptimizationInfo(Clazz clazz)
+ {
+ return (ClassOptimizationInfo)clazz.getVisitorInfo();
+ }
+}
diff --git a/core/src/proguard/optimize/info/CodeAttributeOptimizationInfo.java b/core/src/proguard/optimize/info/CodeAttributeOptimizationInfo.java
new file mode 100644
index 0000000..aa41d35
--- /dev/null
+++ b/core/src/proguard/optimize/info/CodeAttributeOptimizationInfo.java
@@ -0,0 +1,51 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.attribute.CodeAttribute;
+
+/**
+ * This class stores some optimization information that can be attached
+ * to a code attribute.
+ *
+ * @author Thomas Neidhart
+ */
+public class CodeAttributeOptimizationInfo
+{
+
+ public boolean isKept()
+ {
+ return true;
+ }
+
+
+ public static void setCodeAttributeOptimizationInfo(CodeAttribute codeAttribute)
+ {
+ codeAttribute.setVisitorInfo(new CodeAttributeOptimizationInfo());
+ }
+
+
+ public static CodeAttributeOptimizationInfo getCodeAttributeOptimizationInfo(CodeAttribute codeAttribute)
+ {
+ return (CodeAttributeOptimizationInfo)codeAttribute.getVisitorInfo();
+ }
+
+}
diff --git a/src/proguard/optimize/info/DotClassFilter.java b/core/src/proguard/optimize/info/DotClassFilter.java
similarity index 97%
rename from src/proguard/optimize/info/DotClassFilter.java
rename to core/src/proguard/optimize/info/DotClassFilter.java
index 9c85568..739ba57 100644
--- a/src/proguard/optimize/info/DotClassFilter.java
+++ b/core/src/proguard/optimize/info/DotClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/info/DotClassMarker.java
similarity index 81%
rename from src/proguard/optimize/info/DotClassMarker.java
rename to core/src/proguard/optimize/info/DotClassMarker.java
index d7f8fa3..0989a92 100644
--- a/src/proguard/optimize/info/DotClassMarker.java
+++ b/core/src/proguard/optimize/info/DotClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
+import proguard.optimize.OptimizationInfoClassFilter;
/**
* This InstructionVisitor marks all classes that are used in a .class
@@ -41,6 +42,9 @@ public class DotClassMarker
ConstantVisitor,
ClassVisitor
{
+ private final OptimizationInfoClassFilter filteredClassMarker = new OptimizationInfoClassFilter(this);
+
+
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
@@ -62,17 +66,15 @@ public void visitAnyConstant(Clazz clazz, Constant constant) {}
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
- classConstant.referencedClassAccept(this);
+ classConstant.referencedClassAccept(filteredClassMarker);
}
// Implementations for ClassVisitor.
- public void visitLibraryClass(LibraryClass libraryClass) {}
-
- public void visitProgramClass(ProgramClass programClass)
+ public void visitAnyClass(Clazz clazz)
{
- setDotClassed(programClass);
+ setDotClassed(clazz);
}
@@ -80,17 +82,12 @@ public void visitProgramClass(ProgramClass programClass)
private static void setDotClassed(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setDotClassed();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setDotClassed();
}
public static boolean isDotClassed(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.isDotClassed();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isDotClassed();
}
}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/DynamicInvocationMarker.java b/core/src/proguard/optimize/info/DynamicInvocationMarker.java
similarity index 84%
rename from src/proguard/optimize/info/DynamicInvocationMarker.java
rename to core/src/proguard/optimize/info/DynamicInvocationMarker.java
index f59244c..0b50a3b 100644
--- a/src/proguard/optimize/info/DynamicInvocationMarker.java
+++ b/core/src/proguard/optimize/info/DynamicInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 @@
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;
@@ -60,11 +59,7 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
private static void setInvokesDynamically(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setInvokesDynamically();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setInvokesDynamically();
}
@@ -73,7 +68,6 @@ private static void setInvokesDynamically(Method method)
*/
public static boolean invokesDynamically(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.invokesDynamically();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).invokesDynamically();
}
}
diff --git a/core/src/proguard/optimize/info/EscapingClassFilter.java b/core/src/proguard/optimize/info/EscapingClassFilter.java
new file mode 100644
index 0000000..0c51419
--- /dev/null
+++ b/core/src/proguard/optimize/info/EscapingClassFilter.java
@@ -0,0 +1,99 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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 its visits to one of two other given
+ * ClassVisitor instances, depending on whether the classes are marked to be
+ * escaping or not.
+ *
+ * @see EscapingClassMarker
+ *
+ * @author Eric Lafortune
+ */
+public class EscapingClassFilter
+implements ClassVisitor
+{
+ private final ClassVisitor escapingClassVisitor;
+ private final ClassVisitor otherClassVisitor;
+
+
+ /**
+ * Creates a new EscapingClassFilter.
+ * @param escapingClassVisitor the class visitor to which visits to
+ * classes that are marked to be escaping
+ * will be delegated.
+ */
+ public EscapingClassFilter(ClassVisitor escapingClassVisitor)
+ {
+ this(escapingClassVisitor, null);
+ }
+
+
+ /**
+ * Creates a new EscapingClassFilter.
+ * @param escapingClassVisitor the class visitor to which visits to
+ * classes that are marked to be escaping
+ * will be delegated.
+ * @param otherClassVisitor the class visitor to which visits to
+ * classes that are not marked to be escaping
+ * will be delegated.
+ */
+ public EscapingClassFilter(ClassVisitor escapingClassVisitor,
+ ClassVisitor otherClassVisitor)
+ {
+ this.escapingClassVisitor = escapingClassVisitor;
+ this.otherClassVisitor = otherClassVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ // Is the class marked to be escaping?
+ ClassVisitor classVisitor = EscapingClassMarker.isClassEscaping(libraryClass) ?
+ escapingClassVisitor :
+ otherClassVisitor;
+
+ if (classVisitor != null)
+ {
+ classVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Is the class marked to be escaping?
+ ClassVisitor classVisitor = EscapingClassMarker.isClassEscaping(programClass) ?
+ escapingClassVisitor :
+ otherClassVisitor;
+
+ if (classVisitor != null)
+ {
+ classVisitor.visitProgramClass(programClass);
+ }
+ }
+}
diff --git a/core/src/proguard/optimize/info/EscapingClassMarker.java b/core/src/proguard/optimize/info/EscapingClassMarker.java
new file mode 100644
index 0000000..a34c39a
--- /dev/null
+++ b/core/src/proguard/optimize/info/EscapingClassMarker.java
@@ -0,0 +1,222 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.ClassVisitor;
+import proguard.evaluation.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.evaluation.*;
+
+/**
+ * This AttributeVisitor marks the classes that are escaping from the visited
+ * code attributes.
+ *
+ * @see ReferenceEscapeChecker
+ * @author Eric Lafortune
+ */
+public class EscapingClassMarker
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ InstructionVisitor,
+ ClassVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("ecm") != null;
+ //*/
+
+
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+ private final ReferenceEscapeChecker referenceEscapeChecker;
+ private final boolean runReferenceEscapeChecker;
+
+
+ /**
+ * Creates a new EscapingClassMarker.
+ */
+ public EscapingClassMarker()
+ {
+ // We need typed references.
+ this(new TypedReferenceValueFactory());
+ }
+
+
+ /**
+ * Creates a new EscapingClassMarker.
+ */
+ public EscapingClassMarker(ValueFactory valueFactory)
+ {
+ this(valueFactory,
+ new ReferenceTracingValueFactory(valueFactory));
+ }
+
+
+ /**
+ * Creates a new EscapingClassMarker.
+ */
+ public EscapingClassMarker(ValueFactory valueFactory,
+ ReferenceTracingValueFactory tracingValueFactory)
+ {
+ this(new PartialEvaluator(tracingValueFactory,
+ new ReferenceTracingInvocationUnit(new BasicInvocationUnit(tracingValueFactory)),
+ true,
+ tracingValueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new EscapingClassMarker.
+ */
+ public EscapingClassMarker(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this(partialEvaluator,
+ runPartialEvaluator,
+ new ReferenceEscapeChecker(partialEvaluator, false),
+ true);
+ }
+
+
+ /**
+ * Creates a new EscapingClassMarker.
+ */
+ public EscapingClassMarker(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator,
+ ReferenceEscapeChecker referenceEscapeChecker,
+ boolean runReferenceEscapeChecker)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ this.referenceEscapeChecker = referenceEscapeChecker;
+ this.runReferenceEscapeChecker = runReferenceEscapeChecker;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Evaluate the code.
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ if (runReferenceEscapeChecker)
+ {
+ referenceEscapeChecker.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ // Mark all escaping classes.
+ codeAttribute.instructionsAccept(clazz,
+ method,
+ partialEvaluator.tracedInstructionFilter(this));
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Does the instruction push a value that escapes?
+ // We'll also count values that are returned, since they may be
+ // downcast and the downcast type may escape in some calling
+ // method.
+ // TODO: Refine check: is a value is downcast to an escaping class, while it is being returned?
+ if (instruction.stackPushCount(clazz) == 1 &&
+ (referenceEscapeChecker.isInstanceEscaping(offset) ||
+ referenceEscapeChecker.isInstanceReturned(offset)))
+ {
+ TracedStack stackAfter = partialEvaluator.getStackAfter(offset);
+ Value stackEntry = stackAfter.getTop(0);
+
+ // Is it really a reference type?
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ // Is it a plain class reference type?
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+ if (referenceValue.isNull() != Value.ALWAYS &&
+ !ClassUtil.isInternalArrayType(referenceValue.getType()))
+ {
+ // Do we know the class?
+ Clazz referencedClass = referenceValue.getReferencedClass();
+ if (referencedClass != null)
+ {
+ if (DEBUG)
+ {
+ System.out.println("EscapingClassMarker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+instruction.toString(offset)+" pushes escaping ["+referencedClass.getName()+"]");
+ }
+
+ // Mark it, along with its superclasses.
+ referencedClass.hierarchyAccept(true, true, true, false, this);
+ }
+ }
+ }
+ }
+ }
+
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ markClassEscaping(programClass);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given class as escaping.
+ */
+ private void markClassEscaping(Clazz clazz)
+ {
+ ClassOptimizationInfo info = ProgramClassOptimizationInfo.getClassOptimizationInfo(clazz);
+ if (info instanceof ProgramClassOptimizationInfo)
+ {
+ ((ProgramClassOptimizationInfo)info).setEscaping();
+ }
+ }
+
+
+ /**
+ * Returns whether the given class is escaping.
+ */
+ public static boolean isClassEscaping(Clazz clazz)
+ {
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isEscaping();
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/ExceptionInstructionChecker.java b/core/src/proguard/optimize/info/ExceptionInstructionChecker.java
similarity index 73%
rename from src/proguard/optimize/info/ExceptionInstructionChecker.java
rename to core/src/proguard/optimize/info/ExceptionInstructionChecker.java
index 7271391..5b945c3 100644
--- a/src/proguard/optimize/info/ExceptionInstructionChecker.java
+++ b/core/src/proguard/optimize/info/ExceptionInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -37,6 +37,13 @@ public class ExceptionInstructionChecker
// ConstantVisitor,
// MemberVisitor
{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ public static boolean DEBUG = System.getProperty("eic") != null;
+ //*/
+
+
// A return value for the visitor methods.
private boolean mayThrowExceptions;
@@ -65,6 +72,34 @@ public boolean mayThrowExceptions(Clazz clazz,
int startOffset,
int endOffset)
{
+ if (DEBUG)
+ {
+ System.out.println("ExceptionInstructionChecker.mayThrowExceptions ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+startOffset+" -> "+endOffset);
+ }
+
+ return firstExceptionThrowingInstructionOffset(clazz,
+ method,
+ codeAttribute,
+ startOffset,
+ endOffset) < endOffset;
+ }
+
+
+ /**
+ * Returns the offset of the first instruction in the specified block of
+ * code that may throw exceptions, or the end offset if there is none.
+ */
+ public int firstExceptionThrowingInstructionOffset(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int startOffset,
+ int endOffset)
+ {
+ if (DEBUG)
+ {
+ System.out.println("ExceptionInstructionChecker.firstExceptionThrowingInstructionOffset ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+startOffset+" -> "+endOffset);
+ }
+
byte[] code = codeAttribute.code;
// Go over all instructions.
@@ -81,14 +116,73 @@ public boolean mayThrowExceptions(Clazz clazz,
offset,
instruction))
{
- return true;
+ if (DEBUG)
+ {
+ System.out.println(" "+instruction.toString(offset));
+ }
+
+ return offset;
}
// Go to the next instruction.
offset += instruction.length(offset);
}
- return false;
+ return endOffset;
+ }
+
+
+ /**
+ * Returns the offset after the last instruction in the specified block of
+ * code that may throw exceptions, or the start offset if there is none.
+ */
+ public int lastExceptionThrowingInstructionOffset(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int startOffset,
+ int endOffset)
+ {
+ if (DEBUG)
+ {
+ System.out.println("ExceptionInstructionChecker.lastExceptionThrowingInstructionOffset ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+startOffset+" -> "+endOffset);
+ }
+
+ byte[] code = codeAttribute.code;
+
+ int lastOffset = startOffset;
+
+ // Go over all instructions.
+ int offset = startOffset;
+ while (offset < endOffset)
+ {
+ // Get the current instruction.
+ Instruction instruction = InstructionFactory.create(code, offset);
+
+ // Check if it may be throwing exceptions.
+ if (mayThrowExceptions(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction))
+ {
+ if (DEBUG)
+ {
+ System.out.println(" "+instruction.toString(offset));
+ }
+
+ // Go to the next instruction.
+ offset += instruction.length(offset);
+
+ lastOffset = offset;
+ }
+ else
+ {
+ // Go to the next instruction.
+ offset += instruction.length(offset);
+ }
+ }
+
+ return lastOffset;
}
diff --git a/core/src/proguard/optimize/info/FieldOptimizationInfo.java b/core/src/proguard/optimize/info/FieldOptimizationInfo.java
new file mode 100644
index 0000000..cf8a56e
--- /dev/null
+++ b/core/src/proguard/optimize/info/FieldOptimizationInfo.java
@@ -0,0 +1,82 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This class stores some optimization information that can be attached to
+ * a field.
+ *
+ * @author Eric Lafortune
+ */
+public class FieldOptimizationInfo
+extends SimplifiedVisitor
+{
+ public boolean isKept()
+ {
+ return true;
+ }
+
+
+ public boolean isWritten()
+ {
+ return true;
+ }
+
+
+ public boolean isRead()
+ {
+ return true;
+ }
+
+
+ public boolean canBeMadePrivate()
+ {
+ return false;
+ }
+
+
+ public ReferenceValue getReferencedClass()
+ {
+ return null;
+ }
+
+
+ public Value getValue()
+ {
+ return null;
+ }
+
+
+ public static void setFieldOptimizationInfo(Clazz clazz, Field field)
+ {
+ field.setVisitorInfo(new FieldOptimizationInfo());
+ }
+
+
+ public static FieldOptimizationInfo getFieldOptimizationInfo(Field field)
+ {
+ return (FieldOptimizationInfo)field.getVisitorInfo();
+ }
+}
diff --git a/src/proguard/optimize/info/InstanceofClassFilter.java b/core/src/proguard/optimize/info/InstanceofClassFilter.java
similarity index 97%
rename from src/proguard/optimize/info/InstanceofClassFilter.java
rename to core/src/proguard/optimize/info/InstanceofClassFilter.java
index 35d3b5d..0906914 100644
--- a/src/proguard/optimize/info/InstanceofClassFilter.java
+++ b/core/src/proguard/optimize/info/InstanceofClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/info/InstanceofClassMarker.java
similarity index 80%
rename from src/proguard/optimize/info/InstanceofClassMarker.java
rename to core/src/proguard/optimize/info/InstanceofClassMarker.java
index 26cc966..47ac03a 100644
--- a/src/proguard/optimize/info/InstanceofClassMarker.java
+++ b/core/src/proguard/optimize/info/InstanceofClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
+import proguard.optimize.OptimizationInfoClassFilter;
/**
* This InstructionVisitor marks all classes that are used in an 'instanceof'
@@ -41,6 +42,9 @@ public class InstanceofClassMarker
ConstantVisitor,
ClassVisitor
{
+ private final OptimizationInfoClassFilter filteredClassMarker = new OptimizationInfoClassFilter(this);
+
+
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
@@ -59,17 +63,15 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
- classConstant.referencedClassAccept(this);
+ classConstant.referencedClassAccept(filteredClassMarker);
}
// Implementations for ClassVisitor.
- public void visitLibraryClass(LibraryClass libraryClass) {}
-
- public void visitProgramClass(ProgramClass programClass)
+ public void visitAnyClass(Clazz clazz)
{
- setInstanceofed(programClass);
+ setInstanceofed(clazz);
}
@@ -77,17 +79,12 @@ public void visitProgramClass(ProgramClass programClass)
private static void setInstanceofed(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setInstanceofed();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setInstanceofed();
}
public static boolean isInstanceofed(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.isInstanceofed();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isInstanceofed();
}
}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/InstantiationClassFilter.java b/core/src/proguard/optimize/info/InstantiationClassFilter.java
similarity index 97%
rename from src/proguard/optimize/info/InstantiationClassFilter.java
rename to core/src/proguard/optimize/info/InstantiationClassFilter.java
index 804e9d0..cf9952a 100644
--- a/src/proguard/optimize/info/InstantiationClassFilter.java
+++ b/core/src/proguard/optimize/info/InstantiationClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/info/InstantiationClassMarker.java
similarity index 80%
rename from src/proguard/optimize/info/InstantiationClassMarker.java
rename to core/src/proguard/optimize/info/InstantiationClassMarker.java
index 610be97..577bfa5 100644
--- a/src/proguard/optimize/info/InstantiationClassMarker.java
+++ b/core/src/proguard/optimize/info/InstantiationClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
+import proguard.optimize.OptimizationInfoClassFilter;
/**
* This InstructionVisitor marks all classes that are instantiated by any of
@@ -41,6 +42,9 @@ public class InstantiationClassMarker
ConstantVisitor,
ClassVisitor
{
+ private final OptimizationInfoClassFilter filteredClassMarker = new OptimizationInfoClassFilter(this);
+
+
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
@@ -59,17 +63,15 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
- classConstant.referencedClassAccept(this);
+ classConstant.referencedClassAccept(filteredClassMarker);
}
// Implementations for ClassVisitor.
- public void visitLibraryClass(LibraryClass libraryClass) {}
-
- public void visitProgramClass(ProgramClass programClass)
+ public void visitAnyClass(Clazz clazz)
{
- setInstantiated(programClass);
+ setInstantiated(clazz);
}
@@ -77,17 +79,12 @@ public void visitProgramClass(ProgramClass programClass)
private static void setInstantiated(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setInstantiated();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setInstantiated();
}
public static boolean isInstantiated(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.isInstantiated();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isInstantiated();
}
}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/MethodInvocationMarker.java b/core/src/proguard/optimize/info/MethodInvocationMarker.java
similarity index 84%
rename from src/proguard/optimize/info/MethodInvocationMarker.java
rename to core/src/proguard/optimize/info/MethodInvocationMarker.java
index 2288669..bc5ec5b 100644
--- a/src/proguard/optimize/info/MethodInvocationMarker.java
+++ b/core/src/proguard/optimize/info/MethodInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
+import proguard.optimize.OptimizationInfoMemberFilter;
/**
* This InstructionVisitor counts the number of times methods are invoked from
@@ -41,6 +42,9 @@ public class MethodInvocationMarker
ConstantVisitor,
MemberVisitor
{
+ private final OptimizationInfoMemberFilter filteredMethodMarker = new OptimizationInfoMemberFilter(this);
+
+
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
@@ -60,14 +64,14 @@ public void visitAnyConstant(Clazz clazz, Constant constant) {}
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
// Mark the referenced method, if any.
- stringConstant.referencedMemberAccept(this);
+ stringConstant.referencedMemberAccept(filteredMethodMarker);
}
public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
{
// Mark the referenced method.
- refConstant.referencedMemberAccept(this);
+ refConstant.referencedMemberAccept(filteredMethodMarker);
}
@@ -86,11 +90,7 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
private static void incrementInvocationCount(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.incrementInvocationCount();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).incrementInvocationCount();
}
@@ -100,8 +100,6 @@ private static void incrementInvocationCount(Method method)
*/
public static int getInvocationCount(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ? info.getInvocationCount() :
- Integer.MAX_VALUE;
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getInvocationCount();
}
}
diff --git a/core/src/proguard/optimize/info/MethodOptimizationInfo.java b/core/src/proguard/optimize/info/MethodOptimizationInfo.java
new file mode 100644
index 0000000..50299a2
--- /dev/null
+++ b/core/src/proguard/optimize/info/MethodOptimizationInfo.java
@@ -0,0 +1,291 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.MethodLinker;
+import proguard.evaluation.value.Value;
+
+/**
+ * This class stores some optimization information that can be attached to
+ * a method.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodOptimizationInfo
+{
+ protected boolean hasNoSideEffects = false;
+ protected boolean hasNoExternalSideEffects = false;
+ protected boolean hasNoEscapingParameters = false;
+ protected boolean hasNoExternalReturnValues = false;
+
+
+ public boolean isKept()
+ {
+ return true;
+ }
+
+
+ public void setNoSideEffects()
+ {
+ hasNoSideEffects = true;
+ hasNoExternalSideEffects = true;
+ hasNoEscapingParameters = true;
+ }
+
+
+ public boolean hasNoSideEffects()
+ {
+ return hasNoSideEffects;
+ }
+
+
+ public void setNoExternalSideEffects()
+ {
+ hasNoExternalSideEffects = true;
+ hasNoEscapingParameters = true;
+ }
+
+
+ public boolean hasNoExternalSideEffects()
+ {
+ return hasNoExternalSideEffects;
+ }
+
+
+ public void setNoEscapingParameters()
+ {
+ hasNoEscapingParameters = true;
+ }
+
+
+ public boolean hasNoEscapingParameters()
+ {
+ return hasNoEscapingParameters;
+ }
+
+
+ public void setNoExternalReturnValues()
+ {
+ hasNoExternalReturnValues = true;
+ }
+
+
+ public boolean hasNoExternalReturnValues()
+ {
+ return hasNoExternalReturnValues;
+ }
+
+
+ // Methods that may be specialized.
+
+ public boolean hasSideEffects()
+ {
+ return !hasNoSideEffects;
+ }
+
+
+ public boolean canBeMadePrivate()
+ {
+ return false;
+ }
+
+
+ public boolean catchesExceptions()
+ {
+ return true;
+ }
+
+
+ public boolean branchesBackward()
+ {
+ return true;
+ }
+
+
+ public boolean invokesSuperMethods()
+ {
+ return true;
+ }
+
+
+ public boolean invokesDynamically()
+ {
+ return true;
+ }
+
+
+ public boolean accessesPrivateCode()
+ {
+ return true;
+ }
+
+
+ public boolean accessesPackageCode()
+ {
+ return true;
+ }
+
+
+ public boolean accessesProtectedCode()
+ {
+ return true;
+ }
+
+
+ public boolean hasSynchronizedBlock()
+ {
+ return true;
+ }
+
+
+ public boolean returnsWithNonEmptyStack()
+ {
+ return false;
+ }
+
+
+ public int getInvocationCount()
+ {
+ return Integer.MAX_VALUE;
+ }
+
+
+ public int getParameterSize()
+ {
+ return 0;
+ }
+
+
+ public boolean hasUnusedParameters()
+ {
+ return false;
+ }
+
+
+ public boolean isParameterUsed(int variableIndex)
+ {
+ return true;
+ }
+
+
+ public long getUsedParameters()
+ {
+ return -1L;
+ }
+
+
+ public boolean hasParameterEscaped(int parameterIndex)
+ {
+ return true;
+ }
+
+
+ public long getEscapedParameters()
+ {
+ return -1L;
+ }
+
+
+ public boolean isParameterEscaping(int parameterIndex)
+ {
+ return !hasNoEscapingParameters;
+ }
+
+
+ public long getEscapingParameters()
+ {
+ return hasNoEscapingParameters ? 0L : -1L;
+ }
+
+
+ public boolean isParameterModified(int parameterIndex)
+ {
+ // TODO: Refine for static methods.
+ return
+ !hasNoSideEffects &&
+ (!hasNoExternalSideEffects || parameterIndex == 0);
+ }
+
+
+ public long getModifiedParameters()
+ {
+ // TODO: Refine for static methods.
+ return
+ hasNoSideEffects ? 0L :
+ hasNoExternalSideEffects ? 1L :
+ -1L;
+ }
+
+
+ public boolean modifiesAnything()
+ {
+ return !hasNoExternalSideEffects;
+ }
+
+
+ public Value getParameterValue(int parameterIndex)
+ {
+ return null;
+ }
+
+
+ public boolean returnsParameter(int parameterIndex)
+ {
+ return true;
+ }
+
+
+ public long getReturnedParameters()
+ {
+ return -1L;
+ }
+
+
+ public boolean returnsNewInstances()
+ {
+ return true;
+ }
+
+
+ public boolean returnsExternalValues()
+ {
+ return !hasNoExternalReturnValues;
+ }
+
+
+ public Value getReturnValue()
+ {
+ return null;
+ }
+
+
+ public static void setMethodOptimizationInfo(Clazz clazz, Method method)
+ {
+ MethodLinker.lastMember(method).setVisitorInfo(new MethodOptimizationInfo());
+ }
+
+
+ public static MethodOptimizationInfo getMethodOptimizationInfo(Method method)
+ {
+ return (MethodOptimizationInfo)MethodLinker.lastMember(method).getVisitorInfo();
+ }
+}
diff --git a/core/src/proguard/optimize/info/MutableBoolean.java b/core/src/proguard/optimize/info/MutableBoolean.java
new file mode 100644
index 0000000..a4f56cc
--- /dev/null
+++ b/core/src/proguard/optimize/info/MutableBoolean.java
@@ -0,0 +1,66 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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;
+
+/**
+ * This class provides a mutable boolean flag.
+ */
+public class MutableBoolean
+{
+ private boolean flag;
+ /*
+ private int resetCounter;
+ private int setCounter;
+ private int totalCounter;
+ //*/
+
+
+ public void set()
+ {
+ flag = true;
+
+ /*
+ System.out.println("MutableBoolean.set: "+resetCounter+", "+setCounter++ +", "+totalCounter++);
+ if (totalCounter > 5000)
+ {
+ Thread.dumpStack();
+ }
+ //*/
+ }
+
+
+ public void reset()
+ {
+ flag = false;
+
+ /*
+ resetCounter++;
+ setCounter = 0;
+ //*/
+ }
+
+
+ public boolean isSet()
+ {
+ return flag;
+ }
+}
diff --git a/core/src/proguard/optimize/info/NoEscapingParametersMethodMarker.java b/core/src/proguard/optimize/info/NoEscapingParametersMethodMarker.java
new file mode 100644
index 0000000..18e9dd0
--- /dev/null
+++ b/core/src/proguard/optimize/info/NoEscapingParametersMethodMarker.java
@@ -0,0 +1,72 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor marks all methods that it visits as not having any
+ * escaping parameters (including 'this'). It will make the
+ * ParameterEscapeMarker consider them as such without further analysis.
+ *
+ * @see ParameterEscapeMarker
+ * @author Eric Lafortune
+ */
+public class NoEscapingParametersMethodMarker
+extends SimplifiedVisitor
+implements MemberVisitor
+{
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz Clazz, Member member)
+ {
+ // Ignore any attempts to mark fields.
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ markNoParameterEscaping(programMethod);
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ markNoParameterEscaping(libraryMethod);
+ }
+
+
+ // Small utility methods.
+
+ private static void markNoParameterEscaping(Method method)
+ {
+ MethodOptimizationInfo.getMethodOptimizationInfo(method).setNoEscapingParameters();
+ }
+
+
+ public static boolean hasNoParameterEscaping(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasNoEscapingParameters();
+ }
+}
diff --git a/core/src/proguard/optimize/info/NoExternalReturnValuesMethodMarker.java b/core/src/proguard/optimize/info/NoExternalReturnValuesMethodMarker.java
new file mode 100644
index 0000000..07419e3
--- /dev/null
+++ b/core/src/proguard/optimize/info/NoExternalReturnValuesMethodMarker.java
@@ -0,0 +1,73 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor marks all methods that it visits as not having any
+ * return values that are external reference values (only parameters or new
+ * instances). It will make the ParameterEscapeMarker consider them as
+ * such without further analysis.
+ *
+ * @see ParameterEscapeMarker
+ * @author Eric Lafortune
+ */
+public class NoExternalReturnValuesMethodMarker
+extends SimplifiedVisitor
+implements MemberVisitor
+{
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz Clazz, Member member)
+ {
+ // Ignore any attempts to mark fields.
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ markNoExternalReturnValues(programMethod);
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ markNoExternalReturnValues(libraryMethod);
+ }
+
+
+ // Small utility methods.
+
+ private static void markNoExternalReturnValues(Method method)
+ {
+ MethodOptimizationInfo.getMethodOptimizationInfo(method).setNoExternalReturnValues();
+ }
+
+
+ public static boolean hasNoExternalReturnValues(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasNoExternalReturnValues();
+ }
+}
diff --git a/core/src/proguard/optimize/info/NoExternalSideEffectMethodMarker.java b/core/src/proguard/optimize/info/NoExternalSideEffectMethodMarker.java
new file mode 100644
index 0000000..f8b507f
--- /dev/null
+++ b/core/src/proguard/optimize/info/NoExternalSideEffectMethodMarker.java
@@ -0,0 +1,72 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor marks all methods that it visits as not having any
+ * external side effects. It will make the SideEffectMethodMarker consider them
+ * as such without further analysis.
+ *
+ * @see SideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class NoExternalSideEffectMethodMarker
+extends SimplifiedVisitor
+implements MemberVisitor
+{
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz Clazz, Member member)
+ {
+ // Ignore any attempts to mark fields.
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ markNoExternalSideEffects(programMethod);
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ markNoExternalSideEffects(libraryMethod);
+ }
+
+
+ // Small utility methods.
+
+ private static void markNoExternalSideEffects(Method method)
+ {
+ MethodOptimizationInfo.getMethodOptimizationInfo(method).setNoExternalSideEffects();
+ }
+
+
+ public static boolean hasNoExternalSideEffects(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasNoExternalSideEffects();
+ }
+}
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java b/core/src/proguard/optimize/info/NoSideEffectClassMarker.java
similarity index 56%
rename from src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
rename to core/src/proguard/optimize/info/NoSideEffectClassMarker.java
index 49fb543..ea4c0ed 100644
--- a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
+++ b/core/src/proguard/optimize/info/NoSideEffectClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -18,48 +18,43 @@
* 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.Clazz;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
/**
- * This ClassVisitor marks all classes that contain static initializers.
+ * This ClassVisitor marks all classes that it visits as not having any side
+ * effects. It will make the SideEffectClassMarker consider them as such
+ * without further analysis.
*
+ * @see SideEffectMethodMarker
* @author Eric Lafortune
*/
-public class StaticInitializerContainingClassMarker
+public class NoSideEffectClassMarker
extends SimplifiedVisitor
implements ClassVisitor
{
- // Implementations for ClassVisitor.
+ // Implementations for MemberVisitor.
public void visitAnyClass(Clazz clazz)
{
- if (clazz.findMethod(ClassConstants.METHOD_NAME_CLINIT,
- ClassConstants.METHOD_TYPE_CLINIT) != null)
- {
- setStaticInitializer(clazz);
- }
+ markNoSideEffects(clazz);
}
// Small utility methods.
- private static void setStaticInitializer(Clazz clazz)
+ private static void markNoSideEffects(Clazz Clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setContainsStaticInitializer();
- }
+ ClassOptimizationInfo.getClassOptimizationInfo(Clazz).setNoSideEffects();
}
- public static boolean containsStaticInitializer(Clazz clazz)
+ public static boolean hasNoSideEffects(Clazz Clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.containsStaticInitializer();
+ return ClassOptimizationInfo.getClassOptimizationInfo(Clazz).hasNoSideEffects();
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/optimize/info/NoSideEffectMethodMarker.java b/core/src/proguard/optimize/info/NoSideEffectMethodMarker.java
similarity index 68%
rename from src/proguard/optimize/info/NoSideEffectMethodMarker.java
rename to core/src/proguard/optimize/info/NoSideEffectMethodMarker.java
index 624b22a..e51faf9 100644
--- a/src/proguard/optimize/info/NoSideEffectMethodMarker.java
+++ b/core/src/proguard/optimize/info/NoSideEffectMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.util.*;
+import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
/**
@@ -36,11 +36,6 @@ public class NoSideEffectMethodMarker
extends SimplifiedVisitor
implements MemberVisitor
{
- // A visitor info flag to indicate the visitor accepter is being kept,
- // but that it doesn't have any side effects.
- public static final Object KEPT_BUT_NO_SIDE_EFFECTS = new Object();
-
-
// Implementations for MemberVisitor.
public void visitAnyMember(Clazz Clazz, Member member)
@@ -65,27 +60,12 @@ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryM
private static void markNoSideEffects(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setNoSideEffects();
- }
- else
- {
- MethodLinker.lastMember(method).setVisitorInfo(KEPT_BUT_NO_SIDE_EFFECTS);
- }
+ MethodOptimizationInfo.getMethodOptimizationInfo(method).setNoSideEffects();
}
public static boolean hasNoSideEffects(Method method)
{
- if (MethodLinker.lastVisitorAccepter(method).getVisitorInfo() == KEPT_BUT_NO_SIDE_EFFECTS)
- {
- return true;
- }
-
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null &&
- info.hasNoSideEffects();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasNoSideEffects();
}
}
diff --git a/src/proguard/optimize/info/NonEmptyStackReturnMarker.java b/core/src/proguard/optimize/info/NonEmptyStackReturnMarker.java
similarity index 89%
rename from src/proguard/optimize/info/NonEmptyStackReturnMarker.java
rename to core/src/proguard/optimize/info/NonEmptyStackReturnMarker.java
index 1212412..9e2194a 100644
--- a/src/proguard/optimize/info/NonEmptyStackReturnMarker.java
+++ b/core/src/proguard/optimize/info/NonEmptyStackReturnMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +99,12 @@ private void markReturnWithNonEmptyStack(Method method,
private static void setReturnsWithNonEmptyStack(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setReturnsWithNonEmptyStack();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setReturnsWithNonEmptyStack();
}
public static boolean returnsWithNonEmptyStack(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.returnsWithNonEmptyStack();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).returnsWithNonEmptyStack();
}
}
diff --git a/src/proguard/optimize/info/NonPrivateMemberMarker.java b/core/src/proguard/optimize/info/NonPrivateMemberMarker.java
similarity index 71%
rename from src/proguard/optimize/info/NonPrivateMemberMarker.java
rename to core/src/proguard/optimize/info/NonPrivateMemberMarker.java
index 9905608..9218c8f 100644
--- a/src/proguard/optimize/info/NonPrivateMemberMarker.java
+++ b/core/src/proguard/optimize/info/NonPrivateMemberMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 +25,7 @@
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
+import proguard.optimize.OptimizationInfoMemberFilter;
/**
* This ClassVisitor marks all class members that can not be made private in the
@@ -38,7 +39,9 @@ public class NonPrivateMemberMarker
ConstantVisitor,
MemberVisitor
{
- private final MethodImplementationFilter filteredMethodMarker = new MethodImplementationFilter(this);
+ private final MemberVisitor filteredMemberMarker = new OptimizationInfoMemberFilter(this);
+ private final MemberVisitor implementedMethodMarker = new OptimizationInfoMemberFilter(
+ new MethodImplementationFilter(this));
// Implementations for ClassVisitor.
@@ -51,22 +54,15 @@ public void visitProgramClass(ProgramClass programClass)
// Explicitly mark the method.
programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
ClassConstants.METHOD_TYPE_CLINIT,
- this);
+ filteredMemberMarker);
// Explicitly mark the parameterless method.
programClass.methodAccept(ClassConstants.METHOD_NAME_INIT,
ClassConstants.METHOD_TYPE_INIT,
- this);
+ filteredMemberMarker);
// Mark all methods that may have implementations.
- programClass.methodsAccept(filteredMethodMarker);
- }
-
-
- public void visitLibraryClass(LibraryClass libraryClass)
- {
- // Go over all methods.
- libraryClass.methodsAccept(this);
+ programClass.methodsAccept(implementedMethodMarker);
}
@@ -79,7 +75,7 @@ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
// The referenced class member, if any, can never be made private,
// even if it's in the same class.
- stringConstant.referencedMemberAccept(this);
+ stringConstant.referencedMemberAccept(filteredMemberMarker);
}
@@ -95,7 +91,7 @@ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
!refConstant.getClassName(clazz).equals(clazz.getName()))
{
// The referenced class member can never be made private.
- refConstant.referencedMemberAccept(this);
+ refConstant.referencedMemberAccept(filteredMemberMarker);
}
}
@@ -108,33 +104,17 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
}
- public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
- {
- markCanNotBeMadePrivate(libraryField);
- }
-
-
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
markCanNotBeMadePrivate(programMethod);
}
- public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
- {
- markCanNotBeMadePrivate(libraryMethod);
- }
-
-
// Small utility methods.
private static void markCanNotBeMadePrivate(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
- {
- info.setCanNotBeMadePrivate();
- }
+ ProgramFieldOptimizationInfo.getProgramFieldOptimizationInfo(field).setCanNotBeMadePrivate();
}
@@ -143,19 +123,13 @@ private static void markCanNotBeMadePrivate(Field field)
*/
public static boolean canBeMadePrivate(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info != null &&
- info.canBeMadePrivate();
+ return FieldOptimizationInfo.getFieldOptimizationInfo(field).canBeMadePrivate();
}
private static void markCanNotBeMadePrivate(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setCanNotBeMadePrivate();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setCanNotBeMadePrivate();
}
@@ -164,8 +138,6 @@ private static void markCanNotBeMadePrivate(Method method)
*/
public static boolean canBeMadePrivate(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null &&
- info.canBeMadePrivate();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).canBeMadePrivate();
}
}
diff --git a/core/src/proguard/optimize/info/OptimizationCodeAttributeFilter.java b/core/src/proguard/optimize/info/OptimizationCodeAttributeFilter.java
new file mode 100644
index 0000000..81c1e6d
--- /dev/null
+++ b/core/src/proguard/optimize/info/OptimizationCodeAttributeFilter.java
@@ -0,0 +1,88 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.optimize.KeepMarker;
+
+/**
+ * This AttributeVisitor delegates calls for code attributes to another
+ * AttributeVisitor, but only if they can be optimized.
+ *
+ * Note: any other attribute will not be delegated.
+ *
+ *
+ * @author Thomas Neidhart
+ */
+public class OptimizationCodeAttributeFilter
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final AttributeVisitor attributeVisitor;
+ private final AttributeVisitor otherAttributeVisitor;
+
+
+ /**
+ * Creates a new OptimizationCodeAttributeFilter.
+ * @param attributeVisitor the AttributeVisitor to which visits will
+ * be delegated.
+ */
+ public OptimizationCodeAttributeFilter(AttributeVisitor attributeVisitor)
+ {
+ this(attributeVisitor, null);
+ }
+
+
+ /**
+ * Creates a new OptimizationCodeAttributeFilter.
+ * @param attributeVisitor the AttributeVisitor to which visits will
+ * be delegated if the code attribute can be optimized.
+ * @param otherAttributeVisitor the AttributeVisitor to which visits will
+ * be delegated if the code attribute must be kept.
+ */
+ public OptimizationCodeAttributeFilter(AttributeVisitor attributeVisitor,
+ AttributeVisitor otherAttributeVisitor)
+ {
+ this.attributeVisitor = attributeVisitor;
+ this.otherAttributeVisitor = otherAttributeVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ AttributeVisitor visitor = !KeepMarker.isKept(codeAttribute) ?
+ attributeVisitor : otherAttributeVisitor;
+
+ if (visitor != null)
+ {
+ visitor.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java b/core/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
similarity index 84%
rename from src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
rename to core/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
index 6ac7b60..1693970 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
+++ b/core/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +69,12 @@ public void visitAnyMember(Clazz clazz, Member member)
private static void setPackageVisibleMembers(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setContainsPackageVisibleMembers();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setContainsPackageVisibleMembers();
}
public static boolean containsPackageVisibleMembers(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.containsPackageVisibleMembers();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).containsPackageVisibleMembers();
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java b/core/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
similarity index 89%
rename from src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
rename to core/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
index 86ba808..4a98b8f 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
+++ b/core/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -113,17 +113,12 @@ public void visitAnyMember(Clazz clazz, Member member)
private static void setInvokesPackageVisibleMembers(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setInvokesPackageVisibleMembers();
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setInvokesPackageVisibleMembers();
}
public static boolean invokesPackageVisibleMembers(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info == null || info.invokesPackageVisibleMembers();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).invokesPackageVisibleMembers();
}
-}
\ No newline at end of file
+}
diff --git a/core/src/proguard/optimize/info/ParameterEscapeMarker.java b/core/src/proguard/optimize/info/ParameterEscapeMarker.java
new file mode 100644
index 0000000..710e204
--- /dev/null
+++ b/core/src/proguard/optimize/info/ParameterEscapeMarker.java
@@ -0,0 +1,924 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+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.evaluation.*;
+
+/**
+ * This MemberVisitor, AttributeVisitor, and InstructionVisitor marks the
+ * reference parameters that are escaping, that are modified, or that are
+ * returned.
+ *
+ * It also marks methods that may modify anything on the heap.
+ *
+ * The class must be called as a MemberVisitor on all members (to mark the
+ * parameters of native methods, without code attributes), then as an
+ * AttributeVisitor on their code attributes (so it can run its PartialEvaluator
+ * and ReferenceEscapeChecker), and finally as an InstructionVisitor on its
+ * instructions (to actually mark the parameters).
+ *
+ * @see SideEffectClassChecker
+ * @see SideEffectClassMarker
+ * @author Eric Lafortune
+ */
+public class ParameterEscapeMarker
+extends SimplifiedVisitor
+implements MemberVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor,
+ ParameterVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("pem") != null;
+ //*/
+
+
+ private final MutableBoolean repeatTrigger;
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+ private final ReferenceEscapeChecker referenceEscapeChecker;
+ private final boolean runReferenceEscapeChecker;
+
+ private final MemberVisitor parameterMarker = new AllParameterVisitor(true, this);
+
+ // Parameters and values for visitor methods.
+ private Method referencingMethod;
+ private int referencingOffset;
+ private int referencingPopCount;
+ private boolean isReturnValueEscaping;
+ private boolean isReturnValueModified;
+
+
+ /**
+ * Creates a new ParameterEscapeMarker.
+ */
+ public ParameterEscapeMarker(MutableBoolean repeatTrigger)
+ {
+ this(repeatTrigger,
+ new BasicValueFactory());
+ }
+
+
+ /**
+ * Creates a new ParameterEscapeMarker.
+ */
+ public ParameterEscapeMarker(MutableBoolean repeatTrigger,
+ ValueFactory valueFactory)
+ {
+ this(repeatTrigger,
+ valueFactory,
+ new ReferenceTracingValueFactory(valueFactory));
+ }
+
+
+ /**
+ * Creates a new ParameterEscapeMarker.
+ */
+ public ParameterEscapeMarker(MutableBoolean repeatTrigger,
+ ValueFactory valueFactory,
+ ReferenceTracingValueFactory tracingValueFactory)
+ {
+ this(repeatTrigger,
+ new PartialEvaluator(tracingValueFactory,
+ new ParameterTracingInvocationUnit(new BasicInvocationUnit(tracingValueFactory)),
+ true,
+ tracingValueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new ParameterEscapeMarker.
+ */
+ public ParameterEscapeMarker(MutableBoolean repeatTrigger,
+ PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this(repeatTrigger,
+ partialEvaluator,
+ runPartialEvaluator,
+ new ReferenceEscapeChecker(partialEvaluator, false),
+ true);
+ }
+
+
+ /**
+ * Creates a new ParameterEscapeMarker.
+ */
+ public ParameterEscapeMarker(MutableBoolean repeatTrigger,
+ PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator,
+ ReferenceEscapeChecker referenceEscapeChecker,
+ boolean runReferenceEscapeChecker)
+ {
+ this.repeatTrigger = repeatTrigger;
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ this.referenceEscapeChecker = referenceEscapeChecker;
+ this.runReferenceEscapeChecker = runReferenceEscapeChecker;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ int accessFlags = programMethod.getAccessFlags();
+
+ // Is it a native method?
+ if ((accessFlags & ClassConstants.ACC_NATIVE) != 0)
+ {
+ // Mark all parameters.
+ markModifiedParameters(programMethod, -1L);
+ markEscapingParameters(programMethod, -1L);
+ markReturnedParameters(programMethod, -1L);
+ markAnythingModified(programMethod);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Evaluate the code.
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ if (runReferenceEscapeChecker)
+ {
+ referenceEscapeChecker.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ if (DEBUG)
+ {
+ // These results are not complete yet, since this class must still
+ // be called as an InstructionVisitor.
+ System.out.println("ParameterEscapeMarker: [" + clazz.getName() + "." + method.getName(clazz) + method.getDescriptor(clazz) + "]");
+
+ int parameterCount =
+ ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz),
+ method.getAccessFlags());
+
+ for (int index = 0; index < parameterCount; index++)
+ {
+ System.out.println(" " +
+// (hasParameterEscaped(method, index) ? 'e' : '.') +
+ (isParameterEscaping(method, index) ? 'E' : '.') +
+ (isParameterReturned(method, index) ? 'R' : '.') +
+ (isParameterModified(method, index) ? 'M' : '.') +
+ " P" + index);
+ }
+
+ System.out.println(" " +
+ (returnsExternalValues(method) ? 'X' : '.') +
+ " Return value");
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_AASTORE:
+ // Mark array parameters whose element is modified.
+ markModifiedParameters(method,
+ offset,
+ simpleInstruction.stackPopCount(clazz) - 1);
+
+ // Mark reference values that are put in the array.
+ markEscapingParameters(method, offset, 0);
+ break;
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ // Mark array parameters whose element is modified.
+ markModifiedParameters(method,
+ offset,
+ simpleInstruction.stackPopCount(clazz) - 1);
+ break;
+
+ case InstructionConstants.OP_ARETURN:
+ // Mark returned reference values.
+ markReturnedParameters(clazz, method, offset, 0);
+ break;
+
+ case InstructionConstants.OP_ATHROW:
+ // Mark the escaping reference values.
+ markEscapingParameters(method, offset, 0);
+ break;
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ case InstructionConstants.OP_GETSTATIC:
+ // Mark possible modifications due to initializers.
+ referencingMethod = method;
+ referencingOffset = offset;
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ // Mark some global modification.
+ markAnythingModified(method);
+
+ // Mark reference values that are put in the field.
+ markEscapingParameters(method, offset, 0);
+ break;
+
+ case InstructionConstants.OP_PUTFIELD:
+ // Mark reference parameters whose field is modified.
+ markModifiedParameters(method,
+ offset,
+ constantInstruction.stackPopCount(clazz) - 1);
+
+ // Mark reference values that are put in the field.
+ markEscapingParameters(method, offset, 0);
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
+ // Mark reference parameters that are modified as parameters
+ // of the invoked method.
+ // Mark reference values that are escaping as parameters
+ // of the invoked method.
+ // Mark escaped reference parameters in the invoked method.
+ referencingMethod = method;
+ referencingOffset = offset;
+ referencingPopCount = constantInstruction.stackPopCount(clazz);
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ Clazz referencedClass = stringConstant.referencedClass;
+
+ // If a static initializer may modify anything, so does the referencing
+ // method.
+ if (referencedClass == null ||
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ referencedClass))
+ {
+ markAnythingModified(referencingMethod);
+ }
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ Clazz referencedClass = classConstant.referencedClass;
+
+ // If a static initializer may modify anything, so does the referencing
+ // method.
+ if (referencedClass == null ||
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ referencedClass))
+ {
+ markAnythingModified(referencingMethod);
+ }
+ }
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ markAnythingModified(referencingMethod);
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this);
+ }
+
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ Method referencedMethod = (Method)refConstant.referencedMember;
+
+ // If the referenced method or a static initializer may modify anything,
+ // so does the referencing method.
+ if (referencedMethod == null ||
+ modifiesAnything(referencedMethod) ||
+ SideEffectClassChecker.mayHaveSideEffects(clazz,
+ refConstant.referencedClass,
+ referencedMethod))
+ {
+ markAnythingModified(referencingMethod);
+ }
+
+ // Do we know the invoked method?
+ if (referencedMethod == null)
+ {
+ // Mark all parameters of the invoking method that are passed to
+ // the invoked method, since they may escape or or be modified
+ // there.
+ for (int parameterOffset = 0; parameterOffset < referencingPopCount; parameterOffset++)
+ {
+ int stackEntryIndex = referencingPopCount - parameterOffset - 1;
+
+ markEscapingParameters(referencingMethod,
+ referencingOffset,
+ stackEntryIndex);
+
+ markModifiedParameters(referencingMethod,
+ referencingOffset,
+ stackEntryIndex);
+ }
+ }
+ else
+ {
+ // Remember whether the return value of the method is escaping or
+ // modified later on.
+ isReturnValueEscaping =
+ referenceEscapeChecker.isInstanceEscaping(referencingOffset);
+
+ isReturnValueModified =
+ referenceEscapeChecker.isInstanceModified(referencingOffset);
+
+ // Mark parameters of the invoking method that are passed to the
+ // invoked method and escaping or modified there.
+ refConstant.referencedMemberAccept(parameterMarker);
+ }
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ if (!ClassUtil.isInternalPrimitiveType(parameterType.charAt(0)))
+ {
+ Method method = (Method)member;
+
+ // Is the parameter escaping from the method,
+ // or is it returned and then escaping?
+ if (isParameterEscaping(method, parameterIndex) ||
+ (isParameterReturned(method, parameterIndex) &&
+ isReturnValueEscaping))
+ {
+ markEscapingParameters(referencingMethod,
+ referencingOffset,
+ parameterSize - parameterOffset - 1);
+ }
+
+ // Is the parameter being modified in the method.
+ // or is it returned and then modified?
+ if (isParameterModified(method, parameterIndex) ||
+ (isParameterReturned(method, parameterIndex) &&
+ isReturnValueModified))
+ {
+ markModifiedParameters(referencingMethod,
+ referencingOffset,
+ parameterSize - parameterOffset - 1);
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the producing reference parameters (and the classes) of the
+ * specified stack entry at the given instruction offset.
+ */
+ private void markEscapingParameters(Method method,
+ int consumerOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(consumerOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ markEscapingParameters(method, referenceValue);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing parameters (and the classes) of the given
+ * reference value.
+ */
+ private void markEscapingParameters(Method method,
+ ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue producers = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int producerCount = producers.instructionOffsetCount();
+ for (int index = 0; index < producerCount; index++)
+ {
+ if (producers.isMethodParameter(index))
+ {
+ // We know exactly which parameter is escaping.
+ markParameterEscaping(method, producers.methodParameter(index));
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameter as escaping from the given method.
+ */
+ private void markParameterEscaping(Method method, int parameterIndex)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.isParameterEscaping(parameterIndex) &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setParameterEscaping(parameterIndex);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.isParameterEscaping(parameterIndex))
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameters as escaping from the given method.
+ */
+ private void markEscapingParameters(Method method, long escapingParameters)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ long oldEscapingParameters =
+ methodOptimizationInfo.getEscapingParameters();
+
+ if ((~oldEscapingParameters & escapingParameters) != 0 &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).updateEscapingParameters(escapingParameters);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.getEscapingParameters() != oldEscapingParameters)
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the given parameter is escaping from the given method.
+ */
+ public static boolean isParameterEscaping(Method method, int parameterIndex)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).isParameterEscaping(parameterIndex);
+ }
+
+
+ /**
+ * Returns which parameters are escaping from the given method.
+ */
+ public static long getEscapingParameters(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getEscapingParameters();
+ }
+
+
+ /**
+ * Marks the method and the returned reference parameters of the specified
+ * stack entry at the given instruction offset.
+ */
+ private void markReturnedParameters(Clazz clazz,
+ Method method,
+ int returnOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(returnOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS &&
+ mayReturnType(clazz, method, referenceValue))
+ {
+ markReturnedParameters(method, referenceValue);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the method and the producing parameters of the given reference
+ * value.
+ */
+ private void markReturnedParameters(Method method,
+ ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue producers = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int producerCount = producers.instructionOffsetCount();
+ for (int index = 0; index < producerCount; index++)
+ {
+ if (producers.isMethodParameter(index))
+ {
+ // We know exactly which parameter is returned.
+ markParameterReturned(method, producers.methodParameter(index));
+ }
+ else if (producers.isFieldValue(index))
+ {
+ markReturnsExternalValues(method);
+ }
+ else if (producers.isNewinstance(index) ||
+ producers.isExceptionHandler(index))
+ {
+ markReturnsNewInstances(method);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameter as returned from the given method.
+ */
+ private void markParameterReturned(Method method, int parameterIndex)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.returnsParameter(parameterIndex) &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setParameterReturned(parameterIndex);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.returnsParameter(parameterIndex))
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameters as returned from the given method.
+ */
+ private void markReturnedParameters(Method method, long returnedParameters)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ long oldReturnedParameters =
+ methodOptimizationInfo.getReturnedParameters();
+
+ if ((~oldReturnedParameters & returnedParameters) != 0 &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).updateReturnedParameters(returnedParameters);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.getReturnedParameters() != oldReturnedParameters)
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the given parameter is returned from the given method.
+ */
+ public static boolean isParameterReturned(Method method, int parameterIndex)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).returnsParameter(parameterIndex);
+ }
+
+
+ /**
+ * Returns which parameters are returned from the given method.
+ */
+ public static long getReturnedParameters(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getReturnedParameters();
+ }
+
+
+ /**
+ * Marks that the given method returns new instances (created inside the
+ * method).
+ */
+ private void markReturnsNewInstances(Method method)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.returnsNewInstances() &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setReturnsNewInstances();
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.returnsNewInstances())
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the given method returns new instances (created inside
+ * the method).
+ */
+ public static boolean returnsNewInstances(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).returnsNewInstances();
+ }
+
+
+ /**
+ * Marks that the given method returns external reference values (not
+ * parameter or new instance).
+ */
+ private void markReturnsExternalValues(Method method)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.returnsExternalValues() &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setReturnsExternalValues();
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.returnsExternalValues())
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the given method returns external reference values
+ * (not parameter or new instance).
+ */
+ public static boolean returnsExternalValues(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).returnsExternalValues();
+ }
+
+
+ /**
+ * Returns whether the given method may return the given type of reference
+ * value
+ */
+ private boolean mayReturnType(Clazz clazz,
+ Method method,
+ ReferenceValue referenceValue)
+ {
+ String returnType =
+ ClassUtil.internalMethodReturnType(method.getDescriptor(clazz));
+
+ Clazz[] referencedClasses = method instanceof ProgramMethod ?
+ ((ProgramMethod)method).referencedClasses :
+ ((LibraryMethod)method).referencedClasses;
+
+ Clazz referencedClass =
+ referencedClasses == null ||
+ !ClassUtil.isInternalClassType(returnType) ? null :
+ referencedClasses[referencedClasses.length - 1];
+
+ return referenceValue.instanceOf(returnType,
+ referencedClass) != Value.NEVER;
+ }
+
+
+ /**
+ * Marks the producing reference parameters of the specified stack entry at
+ * the given instruction offset.
+ */
+ private void markModifiedParameters(Method method,
+ int offset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(offset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ markModifiedParameters(method, referenceValue);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing parameters of the given reference value.
+ */
+ private void markModifiedParameters(Method method,
+ ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue producers = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int producerCount = producers.instructionOffsetCount();
+ for (int index = 0; index < producerCount; index++)
+ {
+ if (producers.isMethodParameter(index))
+ {
+ // We know exactly which parameter is being modified.
+ markParameterModified(method, producers.methodParameter(index));
+ }
+ else if (!producers.isNewinstance(index) &&
+ !producers.isExceptionHandler(index))
+ {
+ // If some unknown instance is modified, any escaping parameters
+ // may be modified.
+ markModifiedParameters(method, getEscapingParameters(method));
+ markAnythingModified(method);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameter as modified by the given method.
+ */
+ private void markParameterModified(Method method, int parameterIndex)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.isParameterModified(parameterIndex) &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setParameterModified(parameterIndex);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.isParameterModified(parameterIndex))
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Marks the given parameters as modified by the given method.
+ */
+ private void markModifiedParameters(Method method, long modifiedParameters)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ long oldModifiedParameters =
+ methodOptimizationInfo.getModifiedParameters();
+
+ if ((~oldModifiedParameters & modifiedParameters) != 0 &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).updateModifiedParameters(modifiedParameters);
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.getModifiedParameters() != oldModifiedParameters)
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether the given parameter is modified by the given method.
+ */
+ public static boolean isParameterModified(Method method, int parameterIndex)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).isParameterModified(parameterIndex);
+ }
+
+
+ /**
+ * Returns which parameters are modified by the given method.
+ */
+ public static long getModifiedParameters(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getModifiedParameters();
+ }
+
+
+ /**
+ * Marks that anything may be modified by the given method.
+ */
+ private void markAnythingModified(Method method)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.modifiesAnything() &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setModifiesAnything();
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.modifiesAnything())
+ {
+ repeatTrigger.set();
+ }
+ }
+ }
+
+
+ /**
+ * Returns whether anything may be modified by the given method. This takes
+ * into account the side effects of static initializers, except the static
+ * initializer of the invoked method (because it is better checked
+ * explicitly as a function of the referencing class).
+ *
+ * @see SideEffectClassChecker#mayHaveSideEffects(Clazz, Clazz, Member)
+ */
+ public static boolean modifiesAnything(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).modifiesAnything();
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/info/ParameterEscapedMarker.java b/core/src/proguard/optimize/info/ParameterEscapedMarker.java
new file mode 100644
index 0000000..04faf1f
--- /dev/null
+++ b/core/src/proguard/optimize/info/ParameterEscapedMarker.java
@@ -0,0 +1,307 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+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.evaluation.*;
+
+/**
+ * This ClassPoolVisitor marks the reference parameters that have escaped or
+ * that are escaping, outside or inside their methods.
+ *
+ * @see ReferenceEscapeChecker
+ * @see ParameterEscapeMarker
+ * @author Eric Lafortune
+ */
+public class ParameterEscapedMarker
+extends SimplifiedVisitor
+implements ClassPoolVisitor,
+ ClassVisitor,
+ MemberVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor
+{
+ /*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("pem") != null;
+ //*/
+
+
+ private final ClassVisitor parameterEscapedMarker =
+ new AllMethodVisitor(
+ new AllAttributeVisitor(this));
+ private final ValueFactory valueFactory = new BasicValueFactory();
+ private final ReferenceTracingValueFactory tracingValueFactory = new ReferenceTracingValueFactory(valueFactory);
+ private final PartialEvaluator partialEvaluator =
+ new PartialEvaluator(tracingValueFactory,
+ new ParameterTracingInvocationUnit(new BasicInvocationUnit(tracingValueFactory)),
+ true,
+ tracingValueFactory);
+ private final ReferenceEscapeChecker referenceEscapeChecker = new ReferenceEscapeChecker(partialEvaluator, false);
+
+ // Parameters and values for visitor methods.
+ private boolean newEscapes;
+ private Method referencingMethod;
+ private int referencingOffset;
+ private int referencingPopCount;
+
+
+ /**
+ * Creates a new ParameterModificationMarker.
+ */
+ public ParameterEscapedMarker()
+ {
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ // Go over all classes and their methods, marking if parameters are
+ // modified, until no new cases can be found.
+ do
+ {
+ newEscapes = false;
+
+ if (DEBUG)
+ {
+ System.out.println("ParameterEscapedMarker: new iteration");
+ }
+
+ // Go over all classes and their methods once.
+ classPool.classesAccept(parameterEscapedMarker);
+ }
+ while (newEscapes);
+
+ if (DEBUG)
+ {
+ classPool.classesAccept(new AllMethodVisitor(this));
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (DEBUG)
+ {
+ System.out.println("ParameterEscapedMarker: [" + programClass.getName() + "." + programMethod.getName(programClass) + programMethod.getDescriptor(programClass) + "]");
+
+ int parameterSize =
+ ClassUtil.internalMethodParameterSize(programMethod.getDescriptor(programClass),
+ programMethod.getAccessFlags());
+
+ for (int index = 0; index < parameterSize; index++)
+ {
+ System.out.println(" " +
+ (hasParameterEscaped(programMethod, index) ? 'e' : '.') +
+ " P" + index);
+ }
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Evaluate the code.
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ referenceEscapeChecker.visitCodeAttribute(clazz, method, codeAttribute);
+
+ // Mark the parameters that are modified from the code.
+ codeAttribute.instructionsAccept(clazz, method, partialEvaluator.tracedInstructionFilter(this));
+ }
+
+
+ // 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)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // Mark escaped reference parameters in the invoked method.
+ referencingMethod = method;
+ referencingOffset = offset;
+ referencingPopCount = constantInstruction.stackPopCount(clazz);
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ Method referencedMethod = (Method)refConstant.referencedMember;
+
+ if (referencedMethod != null &&
+ MethodOptimizationInfo.getMethodOptimizationInfo(referencedMethod) instanceof ProgramMethodOptimizationInfo)
+ {
+ // Mark reference parameters that are passed to the method.
+ for (int parameterIndex = 0; parameterIndex < referencingPopCount; parameterIndex++)
+ {
+ int stackEntryIndex = referencingPopCount - parameterIndex - 1;
+
+ TracedStack stackBefore = partialEvaluator.getStackBefore(referencingOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ // Has the parameter escaped outside or inside the referencing
+ // method?
+ if (hasEscapedBefore(referencingOffset, stackEntryIndex))
+ {
+ markParameterEscaped(referencedMethod, parameterIndex);
+ }
+ }
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether any of the producing reference values of the specified
+ * stack entry before the given instruction offset are escaping or have
+ * escaped.
+ */
+ private boolean hasEscapedBefore(int instructionOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(instructionOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS &&
+ hasEscaped(referenceValue))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the producing reference value is escaping or has escaped.
+ */
+ private boolean hasEscaped(ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue instructionOffsetValue = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int count = instructionOffsetValue.instructionOffsetCount();
+ for (int index = 0; index < count; index++)
+ {
+ if (instructionOffsetValue.isMethodParameter(index) ?
+ hasParameterEscaped(referencingMethod, instructionOffsetValue.methodParameter(index)) :
+ referenceEscapeChecker.isInstanceEscaping(instructionOffsetValue.instructionOffset(index)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Marks the given parameter as escaped from the given method.
+ */
+ private void markParameterEscaped(Method method, int parameterIndex)
+ {
+ ProgramMethodOptimizationInfo info = ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method);
+ if (!info.hasParameterEscaped(parameterIndex))
+ {
+ info.setParameterEscaped(parameterIndex);
+
+ newEscapes = true;
+ }
+ }
+
+
+ /**
+ * Marks the given parameters as escaped from the given method.
+ */
+ private void markEscapedParameters(Method method, long escapedParameters)
+ {
+ ProgramMethodOptimizationInfo info = ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method);
+ if ((~info.getEscapedParameters() & escapedParameters) != 0)
+ {
+ info.updateEscapedParameters(escapedParameters);
+
+ newEscapes = true;
+ }
+ }
+
+
+ /**
+ * Returns whether the given parameter is escaped from the given method.
+ */
+ public static boolean hasParameterEscaped(Method method, int parameterIndex)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasParameterEscaped(parameterIndex);
+ }
+
+
+ /**
+ * Returns which parameters are escaped from the given method.
+ */
+ public static long getEscapedParameters(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getEscapedParameters();
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/ParameterUsageMarker.java b/core/src/proguard/optimize/info/ParameterUsageMarker.java
similarity index 71%
rename from src/proguard/optimize/info/ParameterUsageMarker.java
rename to core/src/proguard/optimize/info/ParameterUsageMarker.java
index 85e348c..d7be40a 100644
--- a/src/proguard/optimize/info/ParameterUsageMarker.java
+++ b/core/src/proguard/optimize/info/ParameterUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
-import proguard.evaluation.value.Value;
+import proguard.evaluation.value.*;
import proguard.optimize.evaluation.PartialEvaluator;
/**
@@ -43,11 +43,16 @@ public class ParameterUsageMarker
AttributeVisitor,
InstructionVisitor
{
+ //*
private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("pum") != null;
+ //*/
private final boolean markThisParameter;
private final boolean markAllParameters;
+ private final boolean analyzeCode;
private final PartialEvaluator partialEvaluator = new PartialEvaluator();
@@ -69,9 +74,27 @@ public ParameterUsageMarker()
*/
public ParameterUsageMarker(boolean markThisParameter,
boolean markAllParameters)
+ {
+ this(markThisParameter, markAllParameters, true);
+ }
+
+
+ /**
+ * Creates a new ParameterUsageMarker that optionally marks all parameters.
+ * @param markThisParameter specifies whether all 'this' parameters should
+ * be marked as being used.
+ * @param markAllParameters specifies whether all other parameters should
+ * be marked as being used.
+ * @param analyzeCode specifies whether the code of visited methods
+ * should be analyzed for used parameters.
+ */
+ public ParameterUsageMarker(boolean markThisParameter,
+ boolean markAllParameters,
+ boolean analyzeCode)
{
this.markThisParameter = markThisParameter;
this.markAllParameters = markAllParameters;
+ this.analyzeCode = analyzeCode;
}
@@ -125,23 +148,26 @@ else if ((accessFlags & ClassConstants.ACC_ABSTRACT) != 0)
// other implementations, or is it a class instance initializer?
if ((accessFlags & ClassConstants.ACC_STATIC) == 0 &&
((accessFlags & ClassConstants.ACC_SYNCHRONIZED) != 0 ||
- programClass.mayHaveImplementations(programMethod) ||
+ programClass.mayHaveImplementations(programMethod) ||
programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT)))
{
// Mark the 'this' parameter.
markParameterUsed(programMethod, 0);
}
- // Mark the parameters that are used by the code.
- programMethod.attributesAccept(programClass, this);
+ if (analyzeCode)
+ {
+ // Mark the parameters that are used by the code.
+ programMethod.attributesAccept(programClass, this);
+ }
}
if (DEBUG)
{
System.out.print("ParameterUsageMarker: ["+programClass.getName() +"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]: ");
- for (int index = 0; index < parameterSize; index++)
+ for (int variableIndex = 0; variableIndex < parameterSize; variableIndex++)
{
- System.out.print(isParameterUsed(programMethod, index) ? '+' : '-');
+ System.out.print(isParameterUsed(programMethod, variableIndex) ? '+' : '-');
}
System.out.println();
}
@@ -190,21 +216,25 @@ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute c
if (partialEvaluator.isTraced(offset) &&
variableInstruction.isLoad())
{
- int parameterIndex = variableInstruction.variableIndex;
- if (parameterIndex < codeAttribute.u2maxLocals)
+ int variableIndex = variableInstruction.variableIndex;
+ if (variableIndex < codeAttribute.u2maxLocals)
{
+ // The parameter indices stored in the producer values are
+ // parameter offsets, taking into account Category 2 types,
+ // and therefore compatible with variable indices.
Value producer =
- partialEvaluator.getVariablesBefore(offset).getProducerValue(parameterIndex);
+ partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
if (producer != null &&
- producer.instructionOffsetValue().contains(PartialEvaluator.AT_METHOD_ENTRY))
+ producer.instructionOffsetValue().contains(variableIndex | InstructionOffsetValue.METHOD_PARAMETER))
{
// Mark the variable.
- markParameterUsed(method, parameterIndex);
+ markParameterUsed(method, variableIndex);
// Account for Category 2 instructions, which take up two entries.
- if (variableInstruction.isCategory2())
+ if (variableInstruction.stackPopCount(clazz) == 2 ||
+ variableInstruction.stackPushCount(clazz) == 2)
{
- markParameterUsed(method, parameterIndex + 1);
+ markParameterUsed(method, variableIndex + 1);
}
}
}
@@ -219,11 +249,7 @@ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute c
*/
private static void setParameterSize(Method method, int parameterSize)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setParameterSize(parameterSize);
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setParameterSize(parameterSize);
}
@@ -232,8 +258,7 @@ private static void setParameterSize(Method method, int parameterSize)
*/
public static int getParameterSize(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ? info.getParameterSize() : 0;
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getParameterSize();
}
@@ -242,24 +267,25 @@ public static int getParameterSize(Method method)
*/
public static void markParameterUsed(Method method, int variableIndex)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setParameterUsed(variableIndex);
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setParameterUsed(variableIndex);
}
/**
* Marks the given parameters as being used.
*/
- public static void markUsedParameters(Method method, long usedParameters)
+ private static void markUsedParameters(Method method, long usedParameters)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setUsedParameters(info.getUsedParameters() | usedParameters);
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).updateUsedParameters(usedParameters);
+ }
+
+
+ /**
+ * Returns whether the given method has any unused parameters.
+ */
+ public static boolean hasUnusedParameters(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasUnusedParameters();
}
@@ -268,9 +294,7 @@ public static void markUsedParameters(Method method, long usedParameters)
*/
public static boolean isParameterUsed(Method method, int variableIndex)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null ||
- info.isParameterUsed(variableIndex);
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).isParameterUsed(variableIndex);
}
@@ -279,7 +303,6 @@ public static boolean isParameterUsed(Method method, int variableIndex)
*/
public static long getUsedParameters(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info != null ? info.getUsedParameters() : -1L;
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).getUsedParameters();
}
}
diff --git a/src/proguard/optimize/info/ClassOptimizationInfo.java b/core/src/proguard/optimize/info/ProgramClassOptimizationInfo.java
similarity index 56%
rename from src/proguard/optimize/info/ClassOptimizationInfo.java
rename to core/src/proguard/optimize/info/ProgramClassOptimizationInfo.java
index 4bf1e9f..0851cd1 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfo.java
+++ b/core/src/proguard/optimize/info/ProgramClassOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,17 +28,27 @@
*
* @author Eric Lafortune
*/
-public class ClassOptimizationInfo
+public class ProgramClassOptimizationInfo
+extends ClassOptimizationInfo
{
- private boolean isInstantiated = false;
- 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;
- private Clazz targetClass;
+ private volatile boolean isInstantiated = false;
+ private volatile boolean isInstanceofed = false;
+ private volatile boolean isDotClassed = false;
+ private volatile boolean isCaught = false;
+ private volatile boolean isSimpleEnum = false;
+ private volatile boolean isEscaping = false;
+ private volatile boolean hasSideEffects = false;
+ private volatile boolean containsPackageVisibleMembers = false;
+ private volatile boolean invokesPackageVisibleMembers = false;
+ private volatile boolean mayBeMerged = true;
+ private volatile Clazz wrappedClass;
+ private volatile Clazz targetClass;
+
+
+ public boolean isKept()
+ {
+ return false;
+ }
public void setInstantiated()
@@ -101,15 +111,27 @@ public boolean isSimpleEnum()
}
- public void setContainsStaticInitializer()
+ public void setEscaping()
+ {
+ isEscaping = true;
+ }
+
+
+ public boolean isEscaping()
{
- containsStaticInitializer = true;
+ return isEscaping;
}
- public boolean containsStaticInitializer()
+ public void setSideEffects()
{
- return containsStaticInitializer;
+ hasSideEffects = true;
+ }
+
+
+ public boolean hasSideEffects()
+ {
+ return !hasNoSideEffects && hasSideEffects;
}
@@ -137,6 +159,30 @@ public boolean invokesPackageVisibleMembers()
}
+ public void setMayNotBeMerged()
+ {
+ mayBeMerged = false;
+ }
+
+
+ public boolean mayBeMerged()
+ {
+ return mayBeMerged;
+ }
+
+
+ public void setWrappedClass(Clazz wrappedClass)
+ {
+ this.wrappedClass = wrappedClass;
+ }
+
+
+ public Clazz getWrappedClass()
+ {
+ return wrappedClass;
+ }
+
+
public void setTargetClass(Clazz targetClass)
{
this.targetClass = targetClass;
@@ -151,27 +197,26 @@ public Clazz getTargetClass()
public void merge(ClassOptimizationInfo other)
{
- this.isInstantiated |= other.isInstantiated;
- this.isInstanceofed |= other.isInstanceofed;
- this.isDotClassed |= other.isDotClassed;
- this.isCaught |= other.isCaught;
- this.containsStaticInitializer |= other.containsStaticInitializer;
- this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers;
- this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers;
+ this.isInstantiated |= other.isInstantiated();
+ this.isInstanceofed |= other.isInstanceofed();
+ this.isDotClassed |= other.isDotClassed();
+ this.isCaught |= other.isCaught();
+ this.isSimpleEnum |= other.isSimpleEnum();
+ this.isEscaping |= other.isEscaping();
+ this.hasSideEffects |= other.hasSideEffects();
+ this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers();
+ this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers();
}
- public static void setClassOptimizationInfo(Clazz clazz)
+ public static void setProgramClassOptimizationInfo(Clazz clazz)
{
- clazz.setVisitorInfo(new ClassOptimizationInfo());
+ clazz.setVisitorInfo(new ProgramClassOptimizationInfo());
}
- public static ClassOptimizationInfo getClassOptimizationInfo(Clazz clazz)
+ public static ProgramClassOptimizationInfo getProgramClassOptimizationInfo(Clazz clazz)
{
- Object visitorInfo = clazz.getVisitorInfo();
- return visitorInfo instanceof ClassOptimizationInfo ?
- (ClassOptimizationInfo)visitorInfo :
- null;
+ return (ProgramClassOptimizationInfo)clazz.getVisitorInfo();
}
}
diff --git a/core/src/proguard/optimize/info/ProgramClassOptimizationInfoSetter.java b/core/src/proguard/optimize/info/ProgramClassOptimizationInfoSetter.java
new file mode 100644
index 0000000..5b6d37c
--- /dev/null
+++ b/core/src/proguard/optimize/info/ProgramClassOptimizationInfoSetter.java
@@ -0,0 +1,70 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.ProgramClass;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This ClassVisitor attaches a ProgramClassOptimizationInfo instance to every
+ * class that is not being kept that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class ProgramClassOptimizationInfoSetter
+extends SimplifiedVisitor
+implements ClassVisitor
+{
+ private final boolean overwrite;
+
+
+ /**
+ * Creates a new ProgramClassOptimizationInfoSetter.
+ * Existing visitor info is not overridden.
+ */
+ public ProgramClassOptimizationInfoSetter()
+ {
+ this(false);
+ }
+
+
+ /**
+ * Creates a new ProgramClassOptimizationInfoSetter.
+ *
+ * @param overwrite true if existing visitor info should be overridden,
+ * false otherwise.
+ */
+ public ProgramClassOptimizationInfoSetter(boolean overwrite)
+ {
+ this.overwrite = overwrite;
+ }
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (programClass.getVisitorInfo() == null || overwrite)
+ {
+ ProgramClassOptimizationInfo.setProgramClassOptimizationInfo(programClass);
+ }
+ }
+}
diff --git a/src/proguard/optimize/info/FieldOptimizationInfo.java b/core/src/proguard/optimize/info/ProgramFieldOptimizationInfo.java
similarity index 65%
rename from src/proguard/optimize/info/FieldOptimizationInfo.java
rename to core/src/proguard/optimize/info/ProgramFieldOptimizationInfo.java
index 5be9ce7..07d1bfc 100644
--- a/src/proguard/optimize/info/FieldOptimizationInfo.java
+++ b/core/src/proguard/optimize/info/ProgramFieldOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 @@
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.util.SimplifiedVisitor;
import proguard.evaluation.ConstantValueFactory;
import proguard.evaluation.value.*;
@@ -33,22 +32,23 @@
*
* @author Eric Lafortune
*/
-public class FieldOptimizationInfo
-extends SimplifiedVisitor
+public class ProgramFieldOptimizationInfo
+extends FieldOptimizationInfo
implements AttributeVisitor
{
- 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 static final ValueFactory 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;
- private boolean canBeMadePrivate = true;
- private ReferenceValue referencedClass;
- private Value value;
+ private volatile boolean isWritten;
+ private volatile boolean isRead;
+ private volatile boolean canBeMadePrivate = true;
+ private volatile ReferenceValue referencedClass;
+ private volatile Value value;
- public FieldOptimizationInfo(Clazz clazz, Field field)
+
+ public ProgramFieldOptimizationInfo(Clazz clazz, Field field)
{
int accessFlags = field.getAccessFlags();
@@ -59,13 +59,19 @@ public FieldOptimizationInfo(Clazz clazz, Field field)
}
- public FieldOptimizationInfo(FieldOptimizationInfo FieldOptimizationInfo)
+ public ProgramFieldOptimizationInfo(ProgramFieldOptimizationInfo programFieldOptimizationInfo)
+ {
+ this.isWritten = programFieldOptimizationInfo.isWritten;
+ this.isRead = programFieldOptimizationInfo.isRead;
+ this.canBeMadePrivate = programFieldOptimizationInfo.canBeMadePrivate;
+ this.referencedClass = programFieldOptimizationInfo.referencedClass;
+ this.value = programFieldOptimizationInfo.value;
+ }
+
+
+ public boolean isKept()
{
- this.isWritten = FieldOptimizationInfo.isWritten;
- this.isRead = FieldOptimizationInfo.isRead;
- this.canBeMadePrivate = FieldOptimizationInfo.canBeMadePrivate;
- this.referencedClass = FieldOptimizationInfo.referencedClass;
- this.value = FieldOptimizationInfo.value;
+ return false;
}
@@ -105,7 +111,7 @@ public boolean canBeMadePrivate()
}
- public void generalizeReferencedClass(ReferenceValue referencedClass)
+ public synchronized void generalizeReferencedClass(ReferenceValue referencedClass)
{
this.referencedClass = this.referencedClass != null ?
this.referencedClass.generalize(referencedClass) :
@@ -125,7 +131,7 @@ public void resetValue(Clazz clazz, Field field)
value = null;
- // See if we can initialize a static field with a constant value.
+ // See if we can initialize the static field with a constant value.
if ((accessFlags & ClassConstants.ACC_STATIC) != 0)
{
field.accept(clazz, new AllAttributeVisitor(this));
@@ -138,12 +144,13 @@ public void resetValue(Clazz clazz, Field field)
(SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY ||
(accessFlags & ClassConstants.ACC_FINAL) == 0))
{
+ // Otherwise initialize the non-final field with the default value.
value = INITIAL_VALUE_FACTORY.createValue(field.getDescriptor(clazz));
}
}
- public void generalizeValue(Value value)
+ public synchronized void generalizeValue(Value value)
{
this.value = this.value != null ?
this.value.generalize(value) :
@@ -171,18 +178,14 @@ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueA
// Small utility methods.
- public static void setFieldOptimizationInfo(Clazz clazz, Field field)
+ public static void setProgramFieldOptimizationInfo(Clazz clazz, Field field)
{
- field.setVisitorInfo(new FieldOptimizationInfo(clazz, field));
+ field.setVisitorInfo(new ProgramFieldOptimizationInfo(clazz, field));
}
- public static FieldOptimizationInfo getFieldOptimizationInfo(Field field)
+ public static ProgramFieldOptimizationInfo getProgramFieldOptimizationInfo(Field field)
{
- Object visitorInfo = field.getVisitorInfo();
-
- return visitorInfo instanceof FieldOptimizationInfo ?
- (FieldOptimizationInfo)visitorInfo :
- null;
+ return (ProgramFieldOptimizationInfo)field.getVisitorInfo();
}
}
diff --git a/core/src/proguard/optimize/info/ProgramMemberOptimizationInfoSetter.java b/core/src/proguard/optimize/info/ProgramMemberOptimizationInfoSetter.java
new file mode 100644
index 0000000..7c6f980
--- /dev/null
+++ b/core/src/proguard/optimize/info/ProgramMemberOptimizationInfoSetter.java
@@ -0,0 +1,83 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor attaches a ProgramFieldOptimizationInfo instance to every
+ * field and a ProgramMethodOptimizationInfo instance to every method that is
+ * not being kept that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class ProgramMemberOptimizationInfoSetter
+extends SimplifiedVisitor
+implements MemberVisitor
+{
+ private final boolean overwrite;
+
+
+ /**
+ * Creates a new ProgramMemberOptimizationInfoSetter that only attaches a
+ * ProgramFieldOptimizationInfo to a member if no other info is present
+ * on the member yet.
+ */
+ public ProgramMemberOptimizationInfoSetter()
+ {
+ this(false);
+ }
+
+
+ /**
+ * Creates a new ProgramMemberOptimizationInfoSetter.
+ *
+ * @param overwrite boolean indicating whether an existing visitor info on
+ * a visited member should be overwritten or not.
+ */
+ public ProgramMemberOptimizationInfoSetter(boolean overwrite)
+ {
+ this.overwrite = overwrite;
+ }
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ if (programField.getVisitorInfo() == null || overwrite)
+ {
+ ProgramFieldOptimizationInfo.setProgramFieldOptimizationInfo(programClass,
+ programField);
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (MethodLinker.lastMember(programMethod).getVisitorInfo() == null || overwrite)
+ {
+ ProgramMethodOptimizationInfo.setProgramMethodOptimizationInfo(programClass,
+ programMethod);
+ }
+ }
+}
diff --git a/core/src/proguard/optimize/info/ProgramMethodOptimizationInfo.java b/core/src/proguard/optimize/info/ProgramMethodOptimizationInfo.java
new file mode 100644
index 0000000..7b37a0e
--- /dev/null
+++ b/core/src/proguard/optimize/info/ProgramMethodOptimizationInfo.java
@@ -0,0 +1,588 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.evaluation.value.Value;
+import proguard.util.ArrayUtil;
+
+/**
+ * This class stores some optimization information that can be attached to
+ * a method.
+ *
+ * @author Eric Lafortune
+ */
+public class ProgramMethodOptimizationInfo
+extends MethodOptimizationInfo
+{
+ private static final Value[] EMPTY_PARAMETERS = new Value[0];
+
+
+ private volatile boolean hasSideEffects = false;
+ private volatile boolean canBeMadePrivate = true;
+ private volatile boolean catchesExceptions = false;
+ private volatile boolean branchesBackward = false;
+ private volatile boolean invokesSuperMethods = false;
+ private volatile boolean invokesDynamically = false;
+ private volatile boolean accessesPrivateCode = false;
+ private volatile boolean accessesPackageCode = false;
+ private volatile boolean accessesProtectedCode = false;
+ private volatile boolean hasSynchronizedBlock = false;
+ private volatile boolean returnsWithNonEmptyStack = false;
+ private volatile int invocationCount = 0;
+ private volatile int parameterSize = 0;
+ private volatile long usedParameters = 0L;
+ private volatile long escapedParameters = 0L;
+ private volatile long escapingParameters = 0L;
+ private volatile long modifiedParameters = 0L;
+ private volatile boolean modifiesAnything = false;
+ private volatile Value[] parameters;
+ private volatile long returnedParameters = 0L;
+ private volatile boolean returnsNewInstances = false;
+ private volatile boolean returnsExternalValues = false;
+ private volatile Value returnValue;
+
+
+ /**
+ * Creates a new MethodOptimizationInfo for the given method.
+ */
+ public ProgramMethodOptimizationInfo(Clazz clazz, Method method)
+ {
+ // Set up an array of the right size for storing information about the
+ // passed parameters.
+ int parameterCount =
+ ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz));
+
+ if ((method.getAccessFlags() & ClassConstants.ACC_STATIC) == 0)
+ {
+ parameterCount++;
+ }
+
+ parameters = parameterCount == 0 ?
+ EMPTY_PARAMETERS :
+ new Value[parameterCount];
+ }
+
+
+ public boolean isKept()
+ {
+ return false;
+ }
+
+
+ public void setSideEffects()
+ {
+ hasSideEffects = true;
+ }
+
+
+ public boolean hasSideEffects()
+ {
+ return !hasNoSideEffects && hasSideEffects;
+ }
+
+
+ public void setCanNotBeMadePrivate()
+ {
+ canBeMadePrivate = false;
+ }
+
+
+ public boolean canBeMadePrivate()
+ {
+ return canBeMadePrivate;
+ }
+
+
+ public void setCatchesExceptions()
+ {
+ catchesExceptions = true;
+ }
+
+
+ public boolean catchesExceptions()
+ {
+ return catchesExceptions;
+ }
+
+
+ public void setBranchesBackward()
+ {
+ branchesBackward = true;
+ }
+
+
+ public boolean branchesBackward()
+ {
+ return branchesBackward;
+ }
+
+
+ public void setInvokesSuperMethods()
+ {
+ invokesSuperMethods = true;
+ }
+
+
+ public boolean invokesSuperMethods()
+ {
+ return invokesSuperMethods;
+ }
+
+
+ public void setInvokesDynamically()
+ {
+ invokesDynamically = true;
+ }
+
+
+ public boolean invokesDynamically()
+ {
+ return invokesDynamically;
+ }
+
+
+ public void setAccessesPrivateCode()
+ {
+ accessesPrivateCode = true;
+ }
+
+
+ public boolean accessesPrivateCode()
+ {
+ return accessesPrivateCode;
+ }
+
+
+ public void setAccessesPackageCode()
+ {
+ accessesPackageCode = true;
+ }
+
+
+ public boolean accessesPackageCode()
+ {
+ return accessesPackageCode;
+ }
+
+
+ public void setAccessesProtectedCode()
+ {
+ accessesProtectedCode = true;
+ }
+
+
+ public boolean accessesProtectedCode()
+ {
+ return accessesProtectedCode;
+ }
+
+
+ public void setHasSynchronizedBlock()
+ {
+ hasSynchronizedBlock = true;
+ }
+
+
+ public boolean hasSynchronizedBlock()
+ {
+ return hasSynchronizedBlock;
+ }
+
+
+ public void setReturnsWithNonEmptyStack()
+ {
+ returnsWithNonEmptyStack = true;
+ }
+
+
+ public boolean returnsWithNonEmptyStack()
+ {
+ return returnsWithNonEmptyStack;
+ }
+
+
+ public void incrementInvocationCount()
+ {
+ invocationCount++;
+ }
+
+
+ public int getInvocationCount()
+ {
+ return invocationCount;
+ }
+
+
+ public synchronized void setParameterSize(int parameterSize)
+ {
+ this.parameterSize = parameterSize;
+ }
+
+
+ public int getParameterSize()
+ {
+ return parameterSize;
+ }
+
+
+ public synchronized void setParameterUsed(int variableIndex)
+ {
+ usedParameters = setBit(usedParameters, variableIndex);
+ }
+
+
+ public synchronized void updateUsedParameters(long usedParameters)
+ {
+ this.usedParameters |= usedParameters;
+ }
+
+
+ public boolean hasUnusedParameters()
+ {
+ return (usedParameters | -1L << parameterSize) != -1L;
+ }
+
+
+ public boolean isParameterUsed(int variableIndex)
+ {
+ return isBitSet(usedParameters, variableIndex);
+ }
+
+
+ public long getUsedParameters()
+ {
+ return usedParameters;
+ }
+
+
+ /**
+ * Notifies this object that a parameter is inserted at the given
+ * index.
+ * @param parameterIndex the parameter index,
+ * not taking into account the entry size,
+ * but taking into account the 'this' parameter,
+ * if any.
+ */
+ public synchronized void insertParameter(int parameterIndex)
+ {
+ // The used parameter bits are indexed with their variable indices
+ // (which take into account the sizes of the entries).
+ //usedParameters = insertBit(usedParameters, parameterIndex, 1L);
+ //parameterSize++;
+
+ escapedParameters = insertBit(escapedParameters, parameterIndex, 1L);
+ escapingParameters = insertBit(escapingParameters, parameterIndex, 1L);
+ modifiedParameters = insertBit(modifiedParameters, parameterIndex, 1L);
+ returnedParameters = insertBit(returnedParameters, parameterIndex, 1L);
+ parameters = ArrayUtil.insert(parameters, parameters.length, parameterIndex, null);
+ }
+
+
+ /**
+ * Notifies this object that the specified parameter is removed.
+ * @param parameterIndex the parameter index,
+ * not taking into account the entry size,
+ * but taking into account the 'this' parameter,
+ * if any.
+ */
+ public synchronized void removeParameter(int parameterIndex)
+ {
+ // The used parameter bits are indexed with their variable indices
+ // (which take into account the sizes of the entries).
+ //usedParameters = removeBit(usedParameters, parameterIndex, 1L);
+ //parameterSize--;
+
+ escapedParameters = removeBit(escapedParameters, parameterIndex, 1L);
+ escapingParameters = removeBit(escapingParameters, parameterIndex, 1L);
+ modifiedParameters = removeBit(modifiedParameters, parameterIndex, 1L);
+ returnedParameters = removeBit(returnedParameters, parameterIndex, 1L);
+ ArrayUtil.remove(parameters, parameters.length, parameterIndex);
+ }
+
+
+ public synchronized void setParameterEscaped(int parameterIndex)
+ {
+ escapedParameters = setBit(escapedParameters, parameterIndex);
+ }
+
+
+ public synchronized void updateEscapedParameters(long escapedParameters)
+ {
+ this.escapedParameters |= escapedParameters;
+ }
+
+
+ public boolean hasParameterEscaped(int parameterIndex)
+ {
+ return isBitSet(escapedParameters, parameterIndex);
+ }
+
+
+ public long getEscapedParameters()
+ {
+ return escapedParameters;
+ }
+
+
+ public synchronized void setParameterEscaping(int parameterIndex)
+ {
+ escapingParameters = setBit(escapingParameters, parameterIndex);
+ }
+
+
+ public synchronized void updateEscapingParameters(long escapingParameters)
+ {
+ this.escapingParameters |= escapingParameters;
+ }
+
+
+ public boolean isParameterEscaping(int parameterIndex)
+ {
+ return
+ !hasNoEscapingParameters &&
+ (isBitSet(escapingParameters, parameterIndex));
+ }
+
+
+ public long getEscapingParameters()
+ {
+ return hasNoEscapingParameters ? 0L : escapingParameters;
+ }
+
+
+ public synchronized void setParameterModified(int parameterIndex)
+ {
+ modifiedParameters = setBit(modifiedParameters, parameterIndex);
+ }
+
+
+ public synchronized void updateModifiedParameters(long modifiedParameters)
+ {
+ this.modifiedParameters |= modifiedParameters;
+ }
+
+
+ public boolean isParameterModified(int parameterIndex)
+ {
+ // TODO: Refine for static methods.
+ return
+ !hasNoSideEffects &&
+ (!hasNoExternalSideEffects || parameterIndex == 0) &&
+ (isBitSet((modifiesAnything ?
+ modifiedParameters | escapedParameters :
+ modifiedParameters), parameterIndex));
+ }
+
+
+ public long getModifiedParameters()
+ {
+ // TODO: Refine for static methods.
+ return
+ hasNoSideEffects ? 0L :
+ hasNoExternalSideEffects ? modifiedParameters & 1L :
+ modifiedParameters;
+ }
+
+
+ public void setModifiesAnything()
+ {
+ modifiesAnything = true;
+ }
+
+
+ public boolean modifiesAnything()
+ {
+ return !hasNoExternalSideEffects && modifiesAnything;
+ }
+
+
+ public synchronized void generalizeParameterValue(int parameterIndex, Value parameter)
+ {
+ parameters[parameterIndex] = parameters[parameterIndex] != null ?
+ parameters[parameterIndex].generalize(parameter) :
+ parameter;
+ }
+
+
+ public Value getParameterValue(int parameterIndex)
+ {
+ return parameters != null ?
+ parameters[parameterIndex] :
+ null;
+ }
+
+
+ public synchronized void setParameterReturned(int parameterIndex)
+ {
+ returnedParameters = setBit(returnedParameters, parameterIndex);
+ }
+
+
+ public synchronized void updateReturnedParameters(long returnedParameters)
+ {
+ this.returnedParameters |= returnedParameters;
+ }
+
+
+ public boolean returnsParameter(int parameterIndex)
+ {
+ return isBitSet(returnedParameters, parameterIndex);
+ }
+
+
+ public long getReturnedParameters()
+ {
+ return returnedParameters;
+ }
+
+
+ public void setReturnsNewInstances()
+ {
+ returnsNewInstances = true;
+ }
+
+
+ public boolean returnsNewInstances()
+ {
+ return returnsNewInstances;
+ }
+
+
+ public void setReturnsExternalValues()
+ {
+ returnsExternalValues = true;
+ }
+
+
+ public boolean returnsExternalValues()
+ {
+ return
+ !hasNoExternalReturnValues &&
+ returnsExternalValues;
+ }
+
+
+ public synchronized void generalizeReturnValue(Value returnValue)
+ {
+ this.returnValue = this.returnValue != null ?
+ this.returnValue.generalize(returnValue) :
+ returnValue;
+ }
+
+
+ public Value getReturnValue()
+ {
+ return returnValue;
+ }
+
+
+ // For setting enum return values.
+ public synchronized void setReturnValue(Value returnValue)
+ {
+ this.returnValue = returnValue;
+ }
+
+
+ public synchronized void merge(MethodOptimizationInfo other)
+ {
+ 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();
+ this.hasSynchronizedBlock |= other.hasSynchronizedBlock();
+
+ // Some of these should actually be recomputed, since these are
+ // relative to the method:
+ // this.invokesSuperMethods
+ // this.accessesPrivateCode
+ // this.accessesPackageCode
+ // this.accessesProtectedCode
+ }
+
+
+ public static void setProgramMethodOptimizationInfo(Clazz clazz, Method method)
+ {
+ MethodLinker.lastMember(method).setVisitorInfo(new ProgramMethodOptimizationInfo(clazz, method));
+ }
+
+
+ public static ProgramMethodOptimizationInfo getProgramMethodOptimizationInfo(Method method)
+ {
+ return (ProgramMethodOptimizationInfo)MethodLinker.lastMember(method).getVisitorInfo();
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the given value with the specified bit set.
+ */
+ private long setBit(long bits, int index)
+ {
+ return index < 64 ?
+ bits | (1L << index) :
+ bits;
+ }
+
+
+ /**
+ * Returns whether the specified bit is set in the given value
+ * (or if the index exceeds the size of the long).
+ */
+ private boolean isBitSet(long bits, int index)
+ {
+ return index >= 64 || (bits & (1L << index)) != 0;
+ }
+
+
+ /**
+ * Returns the given value with a given bit inserted at the given index.
+ */
+ private long insertBit(long value, int bitIndex, long bitValue)
+ {
+ long higherMask = -1L << bitIndex;
+ long lowerMask = ~higherMask;
+
+ return ((value & higherMask) << 1) |
+ ( value & lowerMask ) |
+ (bitValue << bitIndex);
+ }
+
+
+ /**
+ * Returns the given value with a bit removed at the given index.
+ * The given given bit value is shifted in as the new most significant bit.
+ */
+ private long removeBit(long value, int bitIndex, long highBitValue)
+ {
+ long higherMask = -1L << bitIndex;
+ long lowerMask = ~higherMask;
+
+ return ((value & (higherMask<<1)) >>> 1) |
+ ( value & lowerMask ) |
+ (highBitValue << 63);
+ }
+}
diff --git a/src/proguard/optimize/info/ReadWriteFieldMarker.java b/core/src/proguard/optimize/info/ReadWriteFieldMarker.java
similarity index 74%
rename from src/proguard/optimize/info/ReadWriteFieldMarker.java
rename to core/src/proguard/optimize/info/ReadWriteFieldMarker.java
index 472309d..15a3a9d 100644
--- a/src/proguard/optimize/info/ReadWriteFieldMarker.java
+++ b/core/src/proguard/optimize/info/ReadWriteFieldMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -40,11 +40,32 @@ public class ReadWriteFieldMarker
ConstantVisitor,
MemberVisitor
{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("rwfm") != null;
+ //*/
+
+
+ private final MutableBoolean repeatTrigger;
+
+
// Parameters for the visitor methods.
+ // We'll set them to true by default, in case this class is being used
+ // as a field visitor.
private boolean reading = true;
private boolean writing = true;
+ /**
+ * Creates a new ReadWriteFieldMarker.
+ */
+ public ReadWriteFieldMarker(MutableBoolean repeatTrigger)
+ {
+ this.repeatTrigger = repeatTrigger;
+ }
+
+
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
@@ -126,38 +147,44 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
// Small utility methods.
- private static void markAsRead(Field field)
+ private void markAsRead(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
+ FieldOptimizationInfo fieldOptimizationInfo =
+ FieldOptimizationInfo.getFieldOptimizationInfo(field);
+
+ if (!fieldOptimizationInfo.isRead() &&
+ fieldOptimizationInfo instanceof ProgramFieldOptimizationInfo)
{
- info.setRead();
+ ((ProgramFieldOptimizationInfo)fieldOptimizationInfo).setRead();
+
+ repeatTrigger.set();
}
}
public static boolean isRead(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info == null ||
- info.isRead();
+ return FieldOptimizationInfo.getFieldOptimizationInfo(field).isRead();
}
- private static void markAsWritten(Field field)
+ private void markAsWritten(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- if (info != null)
+ FieldOptimizationInfo fieldOptimizationInfo =
+ FieldOptimizationInfo.getFieldOptimizationInfo(field);
+
+ if (!fieldOptimizationInfo.isWritten() &&
+ fieldOptimizationInfo instanceof ProgramFieldOptimizationInfo)
{
- info.setWritten();
+ ((ProgramFieldOptimizationInfo)fieldOptimizationInfo).setWritten();
+
+ repeatTrigger.set();
}
}
public static boolean isWritten(Field field)
{
- FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
- return info == null ||
- info.isWritten();
+ return FieldOptimizationInfo.getFieldOptimizationInfo(field).isWritten();
}
}
diff --git a/core/src/proguard/optimize/info/ReferenceEscapeChecker.java b/core/src/proguard/optimize/info/ReferenceEscapeChecker.java
new file mode 100644
index 0000000..cd30c43
--- /dev/null
+++ b/core/src/proguard/optimize/info/ReferenceEscapeChecker.java
@@ -0,0 +1,466 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.evaluation.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.evaluation.*;
+import proguard.util.ArrayUtil;
+
+/**
+ * This AttributeVisitor can tell whether reference parameters and instances
+ * are escaping, are modified, or are returned.
+ *
+ * @see ParameterEscapeMarker
+ * @author Eric Lafortune
+ */
+public class ReferenceEscapeChecker
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("rec") != null;
+ //*/
+
+
+ private boolean[] instanceEscaping = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[] instanceReturned = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[] instanceModified = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[] externalInstance = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+// private boolean[] exceptionEscaping = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+// private boolean[] exceptionReturned = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+// private boolean[] exceptionModified = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+
+ private final PartialEvaluator partialEvaluator;
+ private final boolean runPartialEvaluator;
+
+ // Parameters and values for visitor methods.
+ private Method referencingMethod;
+ private int referencingOffset;
+ private int referencingPopCount;
+
+
+ /**
+ * Creates a new ReferenceEscapeChecker.
+ */
+ public ReferenceEscapeChecker()
+ {
+ this(new ReferenceTracingValueFactory(new BasicValueFactory()));
+ }
+
+
+ /**
+ * Creates a new ReferenceEscapeChecker. This private constructor gets around
+ * the constraint that it's not allowed to add statements before calling
+ * 'this'.
+ */
+ private ReferenceEscapeChecker(ReferenceTracingValueFactory referenceTracingValueFactory)
+ {
+ this(new PartialEvaluator(referenceTracingValueFactory,
+ new ParameterTracingInvocationUnit(new BasicInvocationUnit(referenceTracingValueFactory)),
+ true,
+ referenceTracingValueFactory),
+ true);
+ }
+
+
+ /**
+ * Creates a new ReferenceEscapeChecker.
+ * @param partialEvaluator the evaluator to be used for the analysis.
+ * @param runPartialEvaluator specifies whether to run this evaluator on
+ * every code attribute that is visited.
+ */
+ public ReferenceEscapeChecker(PartialEvaluator partialEvaluator,
+ boolean runPartialEvaluator)
+ {
+ this.partialEvaluator = partialEvaluator;
+ this.runPartialEvaluator = runPartialEvaluator;
+ }
+
+
+ /**
+ * Returns whether the instance created or retrieved at the specified
+ * instruction offset is escaping.
+ */
+ public boolean isInstanceEscaping(int instructionOffset)
+ {
+ return instanceEscaping[instructionOffset];
+ }
+
+
+ /**
+ * Returns whether the instance created or retrieved at the specified
+ * instruction offset is being returned.
+ */
+ public boolean isInstanceReturned(int instructionOffset)
+ {
+ return instanceReturned[instructionOffset];
+ }
+
+
+ /**
+ * Returns whether the instance created or retrieved at the specified
+ * instruction offset is being modified.
+ */
+ public boolean isInstanceModified(int instructionOffset)
+ {
+ return instanceModified[instructionOffset];
+ }
+
+
+ /**
+ * Returns whether the instance created or retrieved at the specified
+ * instruction offset is external to this method and its invoked methods.
+ */
+ public boolean isInstanceExternal(int instructionOffset)
+ {
+ return externalInstance[instructionOffset];
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Evaluate the method.
+ if (runPartialEvaluator)
+ {
+ partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ int codeLength = codeAttribute.u4codeLength;
+
+ // Initialize the global arrays.
+ instanceEscaping = ArrayUtil.ensureArraySize(instanceEscaping, codeLength, false);
+ instanceReturned = ArrayUtil.ensureArraySize(instanceReturned, codeLength, false);
+ instanceModified = ArrayUtil.ensureArraySize(instanceModified, codeLength, false);
+ externalInstance = ArrayUtil.ensureArraySize(externalInstance, codeLength, false);
+
+ // Mark the parameters and instances that are escaping from the code.
+ codeAttribute.instructionsAccept(clazz, method, partialEvaluator.tracedInstructionFilter(this));
+
+ if (DEBUG)
+ {
+ System.out.println();
+ System.out.println("ReferenceEscapeChecker: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+
+ for (int index = 0; index < codeLength; index++)
+ {
+ if (partialEvaluator.isInstruction(index))
+ {
+ System.out.println(" " +
+ (instanceEscaping[index] ? 'E' : '.') +
+ (instanceReturned[index] ? 'R' : '.') +
+ (instanceModified[index] ? 'M' : '.') +
+ (externalInstance[index] ? 'X' : '.') +
+ ' ' +
+ InstructionFactory.create(codeAttribute.code, index).toString(index));
+ }
+ }
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_AASTORE:
+ // Mark array reference values whose element is modified.
+ markModifiedReferenceValues(offset,
+ simpleInstruction.stackPopCount(clazz) - 1);
+
+ // Mark reference values that are put in the array.
+ markEscapingReferenceValues(offset, 0);
+ break;
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ // Mark array reference values whose element is modified.
+ markModifiedReferenceValues(offset,
+ simpleInstruction.stackPopCount(clazz) - 1);
+ break;
+
+ case InstructionConstants.OP_ARETURN:
+ // Mark the returned reference values.
+ markReturnedReferenceValues(offset, 0);
+ break;
+
+ case InstructionConstants.OP_ATHROW:
+ // Mark the escaping reference values.
+ markEscapingReferenceValues(offset, 0);
+ break;
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ // Mark external reference values.
+ markExternalReferenceValue(offset);
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ // Mark reference values that are put in the field.
+ markEscapingReferenceValues(offset, 0);
+ break;
+
+ case InstructionConstants.OP_PUTFIELD:
+ // Mark reference reference values whose field is modified.
+ markModifiedReferenceValues(offset,
+ constantInstruction.stackPopCount(clazz) - 1);
+
+ // Mark reference values that are put in the field.
+ markEscapingReferenceValues(offset, 0);
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // Mark reference reference values that are modified as parameters
+ // of the invoked method.
+ // Mark reference values that are escaping as parameters
+ // of the invoked method.
+ // Mark escaped reference reference values in the invoked method.
+ referencingMethod = method;
+ referencingOffset = offset;
+ referencingPopCount = constantInstruction.stackPopCount(clazz);
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this);
+ }
+
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ Method referencedMethod = (Method)refConstant.referencedMember;
+
+ // Mark reference reference values that are passed to the method.
+ for (int index = 0; index < referencingPopCount; index++)
+ {
+ int stackEntryIndex = referencingPopCount - index - 1;
+
+ TracedStack stackBefore = partialEvaluator.getStackBefore(referencingOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ // Is the parameter escaping from the referenced method?
+ if (referencedMethod == null ||
+ ParameterEscapeMarker.isParameterEscaping(referencedMethod, index))
+ {
+ markEscapingReferenceValues(referencingOffset,
+ stackEntryIndex);
+ }
+
+ // Is the parameter being modified in the referenced method?
+ if (referencedMethod == null ||
+ ParameterEscapeMarker.isParameterModified(referencedMethod, index))
+ {
+ markModifiedReferenceValues(referencingOffset,
+ stackEntryIndex);
+ }
+ }
+ }
+
+ // Is the return value from the referenced method external?
+ String returnType =
+ ClassUtil.internalMethodReturnType(refConstant.getType(clazz));
+
+ if (referencedMethod == null ||
+ ((ClassUtil.isInternalClassType(returnType) ||
+ ClassUtil.isInternalArrayType(returnType)) &&
+ ParameterEscapeMarker.returnsExternalValues(referencedMethod)))
+ {
+ markExternalReferenceValue(referencingOffset);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the producing offsets of the specified stack entry at the given
+ * instruction offset.
+ */
+ private void markEscapingReferenceValues(int instructionOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(instructionOffset);
+ Value stackEntry = stackBefore.getTop(stackEntryIndex);
+
+ if (stackEntry.computationalType() == Value.TYPE_REFERENCE)
+ {
+ ReferenceValue referenceValue = stackEntry.referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ markEscapingReferenceValues(referenceValue);
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the given traced reference value.
+ */
+ private void markEscapingReferenceValues(ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue instructionOffsetValue = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int parameterCount = instructionOffsetValue.instructionOffsetCount();
+ for (int index = 0; index < parameterCount; index++)
+ {
+ if (!instructionOffsetValue.isMethodParameter(index))
+ {
+ instanceEscaping[instructionOffsetValue.instructionOffset(index)] = true;
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the specified stack entry at the given
+ * instruction offset.
+ */
+ private void markReturnedReferenceValues(int instructionOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(instructionOffset);
+ ReferenceValue referenceValue = stackBefore.getTop(stackEntryIndex).referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ markReturnedReferenceValues(referenceValue);
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the given traced reference value.
+ */
+ private void markReturnedReferenceValues(ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue instructionOffsetValue = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int parameterCount = instructionOffsetValue.instructionOffsetCount();
+ for (int index = 0; index < parameterCount; index++)
+ {
+ if (!instructionOffsetValue.isMethodParameter(index))
+ {
+ instanceReturned[instructionOffsetValue.instructionOffset(index)] = true;
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the specified stack entry at the given
+ * instruction offset.
+ */
+ private void markModifiedReferenceValues(int instructionOffset,
+ int stackEntryIndex)
+ {
+ TracedStack stackBefore = partialEvaluator.getStackBefore(instructionOffset);
+ ReferenceValue referenceValue = stackBefore.getTop(stackEntryIndex).referenceValue();
+
+ // The null reference value may not have a trace value.
+ if (referenceValue.isNull() != Value.ALWAYS)
+ {
+ markModifiedReferenceValues(referenceValue);
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the given traced reference value.
+ */
+ private void markModifiedReferenceValues(ReferenceValue referenceValue)
+ {
+ TracedReferenceValue tracedReferenceValue = (TracedReferenceValue)referenceValue;
+ InstructionOffsetValue instructionOffsetValue = tracedReferenceValue.getTraceValue().instructionOffsetValue();
+
+ int parameterCount = instructionOffsetValue.instructionOffsetCount();
+ for (int index = 0; index < parameterCount; index++)
+ {
+ if (!instructionOffsetValue.isMethodParameter(index))
+ {
+ instanceModified[instructionOffsetValue.instructionOffset(index)] = true;
+ }
+ }
+ }
+
+
+ /**
+ * Marks the producing offsets of the specified stack entry at the given
+ * instruction offset.
+ */
+ private void markExternalReferenceValue(int offset)
+ {
+ externalInstance[offset] = true;
+ }
+}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/info/RepeatedClassPoolVisitor.java b/core/src/proguard/optimize/info/RepeatedClassPoolVisitor.java
new file mode 100644
index 0000000..6dd4818
--- /dev/null
+++ b/core/src/proguard/optimize/info/RepeatedClassPoolVisitor.java
@@ -0,0 +1,87 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.ClassPool;
+import proguard.classfile.visitor.ClassPoolVisitor;
+
+/**
+ * This ClassPoolVisitor repeatedly delegates to a given class pool visitor, as
+ * long as it keeps setting a given flag.
+ *
+ * @author Eric Lafortune
+ */
+public class RepeatedClassPoolVisitor
+implements ClassPoolVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("rcpv") != null;
+ //*/
+
+
+ private final MutableBoolean repeatTrigger;
+ private final ClassPoolVisitor classPoolVisitor;
+
+
+ /**
+ * Creates a new RepeatedClassPoolVisitor.
+ * @param repeatTrigger the mutable boolean flag that the class pool
+ * visitor can set to indicate that the class pool
+ * should be visited again.
+ * @param classPoolVisitor the class pool visitor to apply.
+ */
+ public RepeatedClassPoolVisitor(MutableBoolean repeatTrigger,
+ ClassPoolVisitor classPoolVisitor)
+ {
+ this.repeatTrigger = repeatTrigger;
+ this.classPoolVisitor = classPoolVisitor;
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ // Visit all classes at least once, until the class visitors stop
+ // setting the repeat trigger.
+ do
+ {
+ if (DEBUG)
+ {
+ System.out.println("RepeatedClassPoolVisitor: new iteration");
+ }
+
+ repeatTrigger.reset();
+
+ // Visit over all classes once.
+ classPoolVisitor.visitClassPool(classPool);
+ }
+ while (repeatTrigger.isSet());
+
+ if (DEBUG)
+ {
+ System.out.println("RepeatedClassPoolVisitor: done iterating");
+ }
+ }
+}
diff --git a/core/src/proguard/optimize/info/SideEffectClassChecker.java b/core/src/proguard/optimize/info/SideEffectClassChecker.java
new file mode 100644
index 0000000..44e985b
--- /dev/null
+++ b/core/src/proguard/optimize/info/SideEffectClassChecker.java
@@ -0,0 +1,84 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.ClassCollector;
+
+import java.util.*;
+
+/**
+ * This utility class contains methods to check whether referencing classes
+ * may have side effects due to them being loaded and initialized.
+ *
+ * @see NoSideEffectClassMarker
+ * @see SideEffectClassMarker
+ * @author Eric Lafortune
+ */
+public class SideEffectClassChecker
+{
+ /**
+ * Returns whether accessing the given class member from the given class may
+ * have side effects when they are initialized.
+ */
+ public static boolean mayHaveSideEffects(Clazz referencingClass,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ // Is the referenced class member static or an initializer method?
+ // Does accessing the referenced class then have side effects?
+ return
+ ((referencedMember.getAccessFlags() & ClassConstants.ACC_STATIC) != 0 ||
+ referencedMember.getName(referencedClass).equals(ClassConstants.METHOD_NAME_INIT)) &&
+ mayHaveSideEffects(referencingClass, referencedClass);
+ }
+
+
+ /**
+ * Returns whether accessing the given class from another given class may
+ * have side effects when they are initialized.
+ */
+ public static boolean mayHaveSideEffects(Clazz referencingClass,
+ Clazz referencedClass)
+ {
+ return
+ !NoSideEffectClassMarker.hasNoSideEffects(referencedClass) &&
+ !referencingClass.extendsOrImplements(referencedClass) &&
+ !sideEffectSuperClasses(referencingClass).containsAll(sideEffectSuperClasses(referencedClass));
+ }
+
+
+ /**
+ * Returns the set of superclasses and interfaces that are initialized.
+ */
+ private static Set sideEffectSuperClasses(Clazz clazz)
+ {
+ Set set = new HashSet();
+
+ // Visit all superclasses and interfaces, collecting the ones that have
+ // side effects when they are initialized.
+ clazz.hierarchyAccept(true, true, true, false,
+ new SideEffectClassFilter(
+ new ClassCollector(set)));
+
+ return set;
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java b/core/src/proguard/optimize/info/SideEffectClassFilter.java
similarity index 78%
rename from src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
rename to core/src/proguard/optimize/info/SideEffectClassFilter.java
index 0000b7d..ab5e2b8 100644
--- a/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
+++ b/core/src/proguard/optimize/info/SideEffectClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +25,17 @@
/**
* This ClassVisitor delegates all its method calls to another ClassVisitor,
- * but only for Clazz objects that are instantiated.
+ * but only for Clazz objects that have side effects when they are initialized.
*
* @author Eric Lafortune
*/
-public class StaticInitializerContainingClassFilter
+public class SideEffectClassFilter
implements ClassVisitor
{
private final ClassVisitor classVisitor;
- public StaticInitializerContainingClassFilter(ClassVisitor classVisitor)
+ public SideEffectClassFilter(ClassVisitor classVisitor)
{
this.classVisitor = classVisitor;
}
@@ -45,7 +45,7 @@ public StaticInitializerContainingClassFilter(ClassVisitor classVisitor)
public void visitProgramClass(ProgramClass programClass)
{
- if (StaticInitializerContainingClassMarker.containsStaticInitializer(programClass))
+ if (SideEffectClassMarker.hasSideEffects(programClass))
{
classVisitor.visitProgramClass(programClass);
}
@@ -54,7 +54,7 @@ public void visitProgramClass(ProgramClass programClass)
public void visitLibraryClass(LibraryClass libraryClass)
{
- if (StaticInitializerContainingClassMarker.containsStaticInitializer(libraryClass))
+ if (SideEffectClassMarker.hasSideEffects(libraryClass))
{
classVisitor.visitLibraryClass(libraryClass);
}
diff --git a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java b/core/src/proguard/optimize/info/SideEffectClassMarker.java
similarity index 62%
rename from src/proguard/optimize/info/ClassOptimizationInfoSetter.java
rename to core/src/proguard/optimize/info/SideEffectClassMarker.java
index ea143d6..46d7e13 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
+++ b/core/src/proguard/optimize/info/SideEffectClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,28 +20,37 @@
*/
package proguard.optimize.info;
-import proguard.classfile.ProgramClass;
+import proguard.classfile.*;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.ClassVisitor;
-import proguard.optimize.KeepMarker;
+import proguard.classfile.visitor.*;
/**
- * This ClassVisitor attaches a ClassOptimizationInfo instance to every class
- * that is not being kept that it visits.
+ * This ClassVisitor marks all classes that it visits as having side effects.
*
* @author Eric Lafortune
*/
-public class ClassOptimizationInfoSetter
+public class SideEffectClassMarker
extends SimplifiedVisitor
implements ClassVisitor
{
- // Implementations for MemberVisitor.
+ // Implementations for ClassVisitor.
public void visitProgramClass(ProgramClass programClass)
{
- if (!KeepMarker.isKept(programClass))
- {
- ClassOptimizationInfo.setClassOptimizationInfo(programClass);
- }
+ markSideEffects(programClass);
+ }
+
+
+ // Small utility methods.
+
+ private static void markSideEffects(Clazz clazz)
+ {
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setSideEffects();
+ }
+
+
+ public static boolean hasSideEffects(Clazz clazz)
+ {
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).hasSideEffects();
}
}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/SideEffectInstructionChecker.java b/core/src/proguard/optimize/info/SideEffectInstructionChecker.java
similarity index 76%
rename from src/proguard/optimize/info/SideEffectInstructionChecker.java
rename to core/src/proguard/optimize/info/SideEffectInstructionChecker.java
index 5374c4e..8dd4602 100644
--- a/src/proguard/optimize/info/SideEffectInstructionChecker.java
+++ b/core/src/proguard/optimize/info/SideEffectInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,17 +27,14 @@
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.*;
-
-import java.util.*;
+import proguard.classfile.visitor.MemberVisitor;
/**
- * This class can tell whether an instruction has any side effects outside of
- * its method. Return instructions and local field accesses can be included or
- * not.
+ * This class can tell whether an instruction has any side effects. Return
+ * instructions and array store instructions can be included or not.
*
* @see ReadWriteFieldMarker
- * @see StaticInitializerContainingClassMarker
+ * @see SideEffectClassMarker
* @see NoSideEffectMethodMarker
* @see SideEffectMethodMarker
* @author Eric Lafortune
@@ -48,13 +45,13 @@ public class SideEffectInstructionChecker
ConstantVisitor,
MemberVisitor
{
- static final boolean OPTIMIZE_CONSERVATIVELY = System.getProperty("optimize.conservatively") != null;
+ public static final boolean OPTIMIZE_CONSERVATIVELY = System.getProperty("optimize.conservatively") != null;
private final boolean includeReturnInstructions;
- private final boolean includeLocalFieldAccess;
+ private final boolean includeArrayStoreInstructions;
- // A return value for the visitor methods.
+ // Parameters and return values for the visitor methods.
private boolean writingField;
private Clazz referencingClass;
private boolean hasSideEffects;
@@ -62,28 +59,21 @@ public class SideEffectInstructionChecker
/**
* 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.
+ * @param includeReturnInstructions specifies whether return
+ * instructions count as side
+ * effects.
+ * @param includeArrayStoreInstructions specifies whether storing values
+ * in arrays counts as side effects.
*/
public SideEffectInstructionChecker(boolean includeReturnInstructions,
- boolean includeLocalFieldAccess)
+ boolean includeArrayStoreInstructions)
{
- this.includeReturnInstructions = includeReturnInstructions;
- this.includeLocalFieldAccess = includeLocalFieldAccess;
+ this.includeReturnInstructions = includeReturnInstructions;
+ this.includeArrayStoreInstructions = includeArrayStoreInstructions;
}
- /**
- * Returns whether the given instruction has side effects outside of its
- * method.
- */
- public boolean hasSideEffects(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int offset,
- Instruction instruction)
+ public boolean hasSideEffects(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
{
hasSideEffects = false;
@@ -109,6 +99,10 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
case InstructionConstants.OP_LDIV:
case InstructionConstants.OP_IREM:
case InstructionConstants.OP_LREM:
+ case InstructionConstants.OP_FDIV:
+ case InstructionConstants.OP_FREM:
+ case InstructionConstants.OP_DDIV:
+ case InstructionConstants.OP_DREM:
case InstructionConstants.OP_IALOAD:
case InstructionConstants.OP_LALOAD:
case InstructionConstants.OP_FALOAD:
@@ -119,8 +113,6 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
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
// (ArithmeticException, NullPointerException,
// ArrayIndexOutOfBoundsException, NegativeArraySizeException).
@@ -135,6 +127,10 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
case InstructionConstants.OP_BASTORE:
case InstructionConstants.OP_CASTORE:
case InstructionConstants.OP_SASTORE:
+ // These instructions may cause a side effect.
+ hasSideEffects = includeArrayStoreInstructions;
+ break;
+
case InstructionConstants.OP_ATHROW :
case InstructionConstants.OP_MONITORENTER:
case InstructionConstants.OP_MONITOREXIT:
@@ -242,8 +238,8 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
break;
case InstructionConstants.OP_ANEWARRAY:
- case InstructionConstants.OP_CHECKCAST:
case InstructionConstants.OP_MULTIANEWARRAY:
+ case InstructionConstants.OP_CHECKCAST:
// This instructions strictly taken may cause a side effect
// (ClassCastException, NegativeArraySizeException).
hasSideEffects = OPTIMIZE_CONSERVATIVELY;
@@ -307,10 +303,11 @@ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
hasSideEffects =
- (includeLocalFieldAccess || !programClass.equals(referencingClass)) &&
- ((writingField && ReadWriteFieldMarker.isRead(programField)) ||
- (programField.getAccessFlags() & ClassConstants.ACC_VOLATILE) != 0 ||
- mayHaveSideEffects(referencingClass, programClass));
+ (writingField && ReadWriteFieldMarker.isRead(programField)) ||
+ (programField.getAccessFlags() & ClassConstants.ACC_VOLATILE) != 0 ||
+ SideEffectClassChecker.mayHaveSideEffects(referencingClass,
+ programClass,
+ programField);
}
@@ -319,9 +316,10 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
// Note that side effects already include synchronization of some
// implementation of the method.
hasSideEffects =
- !NoSideEffectMethodMarker.hasNoSideEffects(programMethod) &&
- (SideEffectMethodMarker.hasSideEffects(programMethod) ||
- mayHaveSideEffects(referencingClass, programClass));
+ SideEffectMethodMarker.hasSideEffects(programMethod) ||
+ SideEffectClassChecker.mayHaveSideEffects(referencingClass,
+ programClass,
+ programMethod);
}
@@ -336,40 +334,4 @@ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryM
hasSideEffects =
!NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod);
}
-
-
- // 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.
- */
- private Set initializedSuperClasses(Clazz clazz)
- {
- Set set = new HashSet();
-
- // Visit all superclasses and interfaces, collecting the ones that have
- // static initializers.
- clazz.hierarchyAccept(true, true, true, false,
- new StaticInitializerContainingClassFilter(
- new NamedMethodVisitor(ClassConstants.METHOD_NAME_CLINIT,
- ClassConstants.METHOD_TYPE_CLINIT,
- new SideEffectMethodFilter(
- new MemberToClassVisitor(
- new ClassCollector(set))))));
-
- return set;
- }
}
diff --git a/src/proguard/optimize/info/SideEffectMethodFilter.java b/core/src/proguard/optimize/info/SideEffectMethodFilter.java
similarity index 97%
rename from src/proguard/optimize/info/SideEffectMethodFilter.java
rename to core/src/proguard/optimize/info/SideEffectMethodFilter.java
index 2e38245..dd0765b 100644
--- a/src/proguard/optimize/info/SideEffectMethodFilter.java
+++ b/core/src/proguard/optimize/info/SideEffectMethodFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/info/SideEffectMethodMarker.java b/core/src/proguard/optimize/info/SideEffectMethodMarker.java
new file mode 100644
index 0000000..a94a62e
--- /dev/null
+++ b/core/src/proguard/optimize/info/SideEffectMethodMarker.java
@@ -0,0 +1,120 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+import proguard.optimize.OptimizationInfoClassFilter;
+
+/**
+ * This MemberVisitor and InstructionVisitor marks all methods and classes
+ * that have side effects.
+ *
+ * @see NoSideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class SideEffectMethodMarker
+extends SimplifiedVisitor
+implements MemberVisitor,
+ InstructionVisitor
+{
+ private final MutableBoolean repeatTrigger;
+
+ private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false, true);
+ private final ClassVisitor sideEffectClassMarker = new OptimizationInfoClassFilter(
+ new SideEffectClassMarker());
+
+
+
+ /**
+ * Creates a new SideEffectMethodMarker.
+ */
+ public SideEffectMethodMarker(MutableBoolean repeatTrigger)
+ {
+ this.repeatTrigger = repeatTrigger;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if ((programMethod.getAccessFlags() &
+ (ClassConstants.ACC_NATIVE |
+ ClassConstants.ACC_SYNCHRONIZED)) != 0)
+ {
+ markSideEffects(programClass, programMethod);
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ {
+ // Check if it may be throwing exceptions.
+ if (sideEffectInstructionChecker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction))
+ {
+ markSideEffects(clazz, method);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private void markSideEffects(Clazz clazz, Method method)
+ {
+ MethodOptimizationInfo methodOptimizationInfo =
+ MethodOptimizationInfo.getMethodOptimizationInfo(method);
+
+ if (!methodOptimizationInfo.hasSideEffects() &&
+ methodOptimizationInfo instanceof ProgramMethodOptimizationInfo)
+ {
+ ((ProgramMethodOptimizationInfo)methodOptimizationInfo).setSideEffects();
+
+ // Trigger the repeater if the setter has changed the value.
+ if (methodOptimizationInfo.hasSideEffects())
+ {
+ repeatTrigger.set();
+
+ // Also mark the class if the method is a static initializer.
+ if (method.getName(clazz).equals(ClassConstants.METHOD_NAME_CLINIT))
+ {
+ clazz.accept(sideEffectClassMarker);
+ }
+ }
+ }
+ }
+
+
+ public static boolean hasSideEffects(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasSideEffects();
+ }
+}
diff --git a/src/proguard/optimize/info/SimpleEnumFilter.java b/core/src/proguard/optimize/info/SimpleEnumFilter.java
similarity index 98%
rename from src/proguard/optimize/info/SimpleEnumFilter.java
rename to core/src/proguard/optimize/info/SimpleEnumFilter.java
index 9d05a9f..b076b31 100644
--- a/src/proguard/optimize/info/SimpleEnumFilter.java
+++ b/core/src/proguard/optimize/info/SimpleEnumFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/SimpleEnumMarker.java b/core/src/proguard/optimize/info/SimpleEnumMarker.java
similarity index 82%
rename from src/proguard/optimize/info/SimpleEnumMarker.java
rename to core/src/proguard/optimize/info/SimpleEnumMarker.java
index 6877f37..bd4f4ba 100644
--- a/src/proguard/optimize/info/SimpleEnumMarker.java
+++ b/core/src/proguard/optimize/info/SimpleEnumMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -59,17 +59,12 @@ public void visitProgramClass(ProgramClass programClass)
private void setSimpleEnum(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setSimpleEnum(simple);
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setSimpleEnum(simple);
}
public static boolean isSimpleEnum(Clazz clazz)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- return info != null && info.isSimpleEnum();
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).isSimpleEnum();
}
}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/SuperInvocationMarker.java b/core/src/proguard/optimize/info/SuperInvocationMarker.java
similarity index 87%
rename from src/proguard/optimize/info/SuperInvocationMarker.java
rename to core/src/proguard/optimize/info/SuperInvocationMarker.java
index 63e6225..e3a670a 100644
--- a/src/proguard/optimize/info/SuperInvocationMarker.java
+++ b/core/src/proguard/optimize/info/SuperInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -77,17 +77,12 @@ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
private static void setInvokesSuperMethods(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- if (info != null)
- {
- info.setInvokesSuperMethods();
- }
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setInvokesSuperMethods();
}
public static boolean invokesSuperMethods(Method method)
{
- MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
- return info == null || info.invokesSuperMethods();
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).invokesSuperMethods();
}
}
diff --git a/core/src/proguard/optimize/info/SynchronizedBlockMethodMarker.java b/core/src/proguard/optimize/info/SynchronizedBlockMethodMarker.java
new file mode 100644
index 0000000..963843e
--- /dev/null
+++ b/core/src/proguard/optimize/info/SynchronizedBlockMethodMarker.java
@@ -0,0 +1,69 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This InstructionVisitor marks the existence of synchronized blocks
+ * of the methods whose instructions it visits.
+ *
+ * @author Thomas Neidhart
+ */
+public class SynchronizedBlockMethodMarker
+extends SimplifiedVisitor
+implements InstructionVisitor
+{
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (simpleInstruction.opcode == InstructionConstants.OP_MONITORENTER ||
+ simpleInstruction.opcode == InstructionConstants.OP_MONITOREXIT)
+ {
+ setHasSynchronizedBlock(method);
+ }
+ }
+
+ // Small utility methods.
+
+ private static void setHasSynchronizedBlock(Method method)
+ {
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method).setHasSynchronizedBlock();
+ }
+
+
+ /**
+ * Returns whether the given method accesses private class members.
+ */
+ public static boolean hasSynchronizedBlock(Method method)
+ {
+ return MethodOptimizationInfo.getMethodOptimizationInfo(method).hasSynchronizedBlock();
+ }
+
+}
diff --git a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java b/core/src/proguard/optimize/info/UnusedParameterMethodFilter.java
similarity index 56%
rename from src/proguard/optimize/info/MemberOptimizationInfoSetter.java
rename to core/src/proguard/optimize/info/UnusedParameterMethodFilter.java
index 4a09e09..47f500f 100644
--- a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
+++ b/core/src/proguard/optimize/info/UnusedParameterMethodFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,39 +21,45 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
-import proguard.optimize.KeepMarker;
/**
- * This MemberVisitor attaches a FieldOptimizationInfo instance to every field
- * and a MethodOptimizationInfo instance to every method that is not being kept
- * that it visits.
+ * This MemberVisitor delegates all its method calls to another MemberVisitor,
+ * but only for Method objects that are marked as having unused parameters.
+ *
+ * @see ParameterUsageMarker
*
* @author Eric Lafortune
*/
-public class MemberOptimizationInfoSetter
-extends SimplifiedVisitor
+public class UnusedParameterMethodFilter
implements MemberVisitor
{
- // Implementations for MemberVisitor.
+ private final MemberVisitor memberVisitor;
+
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ /**
+ * Creates a new UnusedParameterMethodFilter.
+ * @param memberVisitor the member visitor to which the visiting will be
+ * delegated.
+ */
+ public UnusedParameterMethodFilter(MemberVisitor memberVisitor)
{
- if (!KeepMarker.isKept(programField))
- {
- FieldOptimizationInfo.setFieldOptimizationInfo(programClass,
- programField);
- }
+ this.memberVisitor = memberVisitor;
}
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField) {}
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {}
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {}
+
+
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- if (!KeepMarker.isKept(programMethod))
+ if (ParameterUsageMarker.hasUnusedParameters(programMethod))
{
- MethodOptimizationInfo.setMethodOptimizationInfo(programClass,
- programMethod);
+ memberVisitor.visitProgramMethod(programClass, programMethod);
}
}
-}
+}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/info/UnusedParameterOptimizationInfoUpdater.java b/core/src/proguard/optimize/info/UnusedParameterOptimizationInfoUpdater.java
new file mode 100644
index 0000000..6432d56
--- /dev/null
+++ b/core/src/proguard/optimize/info/UnusedParameterOptimizationInfoUpdater.java
@@ -0,0 +1,140 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
+
+/**
+ * This AttributeVisitor removes unused parameters from the optimization info
+ * of the methods that it visits. This includes 'this' parameters.
+ *
+ * @see ParameterUsageMarker
+ * @see MethodStaticizer
+ * @see MethodDescriptorShrinker
+ * @author Eric Lafortune
+ */
+public class UnusedParameterOptimizationInfoUpdater
+extends SimplifiedVisitor
+implements AttributeVisitor,
+
+ // Internal implementations.
+ ParameterVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = System.getProperty("upoiu") != null;
+ //*/
+
+
+ private final MemberVisitor extraUnusedParameterMethodVisitor;
+
+ private final MemberVisitor unusedParameterRemover = new AllParameterVisitor(true,
+ new UsedParameterFilter(null, this));
+
+ // Parameters and return values for visitor methods.
+ private int removedParameterSize;
+ private int removedParameterCount;
+
+
+ /**
+ * Creates a new UnusedParameterOptimizationInfoUpdater.
+ */
+ public UnusedParameterOptimizationInfoUpdater()
+ {
+ this(null);
+ }
+
+
+ /**
+ * Creates a new UnusedParameterOptimizationInfoUpdater with an extra
+ * visitor.
+ * @param extraUnusedParameterMethodVisitor an optional extra visitor for
+ * all removed parameters.
+ */
+ public UnusedParameterOptimizationInfoUpdater(MemberVisitor extraUnusedParameterMethodVisitor)
+ {
+ this.extraUnusedParameterMethodVisitor = extraUnusedParameterMethodVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ if (DEBUG)
+ {
+ System.out.println("UnusedParameterOptimizationInfoUpdater: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ }
+
+ // Update the optimization info.
+ removedParameterCount = 0;
+ removedParameterSize = 0;
+
+ method.accept(clazz, unusedParameterRemover);
+
+ // Compute the new parameter size from the shrunk descriptor.
+ ProgramMethodOptimizationInfo programMethodOptimizationInfo =
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method);
+
+ int newParameterSize =
+ programMethodOptimizationInfo.getParameterSize() - removedParameterSize;
+
+ programMethodOptimizationInfo.setParameterSize(newParameterSize);
+ programMethodOptimizationInfo.updateUsedParameters(-1L);
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ if (DEBUG)
+ {
+ System.out.println(" Deleting parameter #"+parameterIndex+" (v"+parameterOffset+")");
+ }
+
+ Method method = (Method)member;
+
+ // Remove the unused parameter in the optimization info.
+ // Take into acount the delta from previously removed parameters.
+ ProgramMethodOptimizationInfo programMethodOptimizationInfo =
+ ProgramMethodOptimizationInfo.getProgramMethodOptimizationInfo(method);
+
+ programMethodOptimizationInfo.removeParameter(parameterIndex - removedParameterCount++);
+
+ removedParameterSize += ClassUtil.internalTypeSize(parameterType);
+
+ // Visit the method, if required.
+ if (extraUnusedParameterMethodVisitor != null)
+ {
+ method.accept(clazz, extraUnusedParameterMethodVisitor);
+ }
+ }
+}
diff --git a/core/src/proguard/optimize/info/UsedParameterFilter.java b/core/src/proguard/optimize/info/UsedParameterFilter.java
new file mode 100644
index 0000000..c3f293f
--- /dev/null
+++ b/core/src/proguard/optimize/info/UsedParameterFilter.java
@@ -0,0 +1,85 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.*;
+
+/**
+ * This ParameterVisitor delegates all its visits to one of two other
+ * ParameterVisitor instances, depending on whether the parameter is
+ * used or not.
+ *
+ * @see ParameterUsageMarker
+ * @author Eric Lafortune
+ */
+public class UsedParameterFilter
+implements ParameterVisitor
+{
+ private final ParameterVisitor usedParameterVisitor;
+ private final ParameterVisitor unusedParameterVisitor;
+
+
+ /**
+ * Creates a new UsedParameterFilter that delegates visits to used
+ * parameters to the given parameter visitor.
+ */
+ public UsedParameterFilter(ParameterVisitor usedParameterVisitor)
+ {
+ this(usedParameterVisitor, null);
+ }
+
+
+ /**
+ * Creates a new UsedParameterFilter that delegates to one of the two
+ * given parameter visitors.
+ */
+ public UsedParameterFilter(ParameterVisitor usedParameterVisitor,
+ ParameterVisitor unusedParameterVisitor)
+ {
+ this.usedParameterVisitor = usedParameterVisitor;
+ this.unusedParameterVisitor = unusedParameterVisitor;
+ }
+
+
+ // Implementations for ParameterVisitor.
+
+ public void visitParameter(Clazz clazz, Member member, int parameterIndex, int parameterCount, int parameterOffset, int parameterSize, String parameterType, Clazz referencedClass)
+ {
+ ParameterVisitor parameterVisitor =
+ ParameterUsageMarker.isParameterUsed((Method)member,
+ parameterOffset) ?
+ usedParameterVisitor :
+ unusedParameterVisitor;
+
+ if (parameterVisitor != null)
+ {
+ parameterVisitor.visitParameter(clazz,
+ member,
+ parameterIndex,
+ parameterCount,
+ parameterOffset,
+ parameterSize,
+ parameterType,
+ referencedClass);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/VariableUsageMarker.java b/core/src/proguard/optimize/info/VariableUsageMarker.java
similarity index 94%
rename from src/proguard/optimize/info/VariableUsageMarker.java
rename to core/src/proguard/optimize/info/VariableUsageMarker.java
index ba31ac4..11cf274 100644
--- a/src/proguard/optimize/info/VariableUsageMarker.java
+++ b/core/src/proguard/optimize/info/VariableUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -88,7 +88,8 @@ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute c
variableUsed[variableInstruction.variableIndex] = true;
// Account for Category 2 instructions, which take up two entries.
- if (variableInstruction.isCategory2())
+ if (variableInstruction.stackPopCount(clazz) == 2 ||
+ variableInstruction.stackPushCount(clazz) == 2)
{
variableUsed[variableInstruction.variableIndex + 1] = true;
}
diff --git a/core/src/proguard/optimize/info/WrapperClassMarker.java b/core/src/proguard/optimize/info/WrapperClassMarker.java
new file mode 100644
index 0000000..aebb682
--- /dev/null
+++ b/core/src/proguard/optimize/info/WrapperClassMarker.java
@@ -0,0 +1,225 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.evaluation.value.*;
+import proguard.optimize.evaluation.StoringInvocationUnit;
+
+/**
+ * This ClassVisitor marks all program classes that are a simple wrapper for a
+ * single non-null instance of another class.
+ *
+ * A wrapper class has
+ * - exactly one non-static field, which references an object,
+ * - exactly one initializer, with a single parameter that is never null,
+ * that initializes the field,
+ * - no subclasses.
+ *
+ * @see StoringInvocationUnit
+ * @author Eric Lafortune
+ */
+public class WrapperClassMarker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor,
+ AttributeVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ public static boolean DEBUG = System.getProperty("wcm") != null;
+ //*/
+
+
+ private final Constant[] INITIALIZER_CONSTANTS = new Constant[]
+ {
+ new FieldrefConstant(InstructionSequenceMatcher.A,
+ InstructionSequenceMatcher.B, null, null),
+ };
+
+ // Instruction pattern:
+ // this.x = arg0;
+ // super.;
+ // return;
+ private final Instruction[] INITIALIZER_INSTRUCTIONS = new Instruction[]
+ {
+ new VariableInstruction(InstructionConstants.OP_ALOAD_0, 0),
+ new VariableInstruction(InstructionConstants.OP_ALOAD_1, 1),
+ new ConstantInstruction(InstructionConstants.OP_PUTFIELD, 0),
+ new VariableInstruction(InstructionConstants.OP_ALOAD_0, 0),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, InstructionSequenceMatcher.X),
+ new SimpleInstruction(InstructionConstants.OP_RETURN),
+ };
+
+ private final InstructionSequenceMatcher INITIALIZER_MATCHER = new InstructionSequenceMatcher(INITIALIZER_CONSTANTS, INITIALIZER_INSTRUCTIONS);
+
+ // Fields acting as parameters and return values for the visitor methods.
+ private Clazz wrappedClass;
+ private int wrapCounter;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (programClass.subClasses == null ||
+ programClass.subClasses.length == 0)
+ {
+ wrappedClass = null;
+
+ // Can we find one non-static field with a class type?
+ wrapCounter = 0;
+ programClass.fieldsAccept(this);
+ if (wrapCounter == 1)
+ {
+ // Can we find exactly one initializer that initializes this
+ // field?
+ wrapCounter = 0;
+ programClass.methodsAccept(this);
+ if (wrapCounter == 1)
+ {
+ setWrappedClass(programClass, wrappedClass);
+ }
+ }
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ // Is the field non-static and of a class type?
+ if ((programField.getAccessFlags() & ClassConstants.ACC_STATIC) == 0 &&
+ ClassUtil.isInternalClassType(programField.getDescriptor(programClass)) &&
+ !ClassUtil.isInternalArrayType(programField.getDescriptor(programClass)))
+ {
+ wrappedClass = programField.referencedClass;
+ if (wrappedClass != null)
+ {
+ wrapCounter++;
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Is the method an initializer?
+ if (ClassUtil.isInitializer(programMethod.getName(programClass)))
+ {
+ // Does it have exactly one parameter?
+ if (ClassUtil.internalMethodParameterCount(programMethod.getDescriptor(programClass)) == 1)
+ {
+ // Is the parameter a non-null reference?
+ Value value =
+ StoringInvocationUnit.getMethodParameterValue(programMethod, 1);
+
+ if (value != null &&
+ value.computationalType() == Value.TYPE_REFERENCE &&
+ value.referenceValue().isNotNull() == Value.ALWAYS)
+ {
+ // Does the method initialize the field?
+ programMethod.attributesAccept(programClass, this);
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Is the initializer initializing the field?
+ if (codeAttribute.u4codeLength == 10)
+ {
+ INITIALIZER_MATCHER.reset();
+ codeAttribute.instructionsAccept(clazz, method, INITIALIZER_MATCHER);
+ if (INITIALIZER_MATCHER.isMatching())
+ {
+ String initializerClassName = clazz.getName();
+ String fieldClassName = clazz.getClassName(INITIALIZER_MATCHER.matchedConstantIndex(InstructionSequenceMatcher.A));
+ if (fieldClassName.equals(initializerClassName))
+ {
+ wrapCounter++;
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+ else
+ {
+ wrapCounter = Integer.MIN_VALUE;
+ }
+ }
+
+
+ // Small utility methods.
+
+ private static void setWrappedClass(Clazz clazz, Clazz wrappedClass)
+ {
+ if (DEBUG)
+ {
+ System.out.println("WrapperClassMarker: ["+clazz.getName()+"] wraps ["+wrappedClass.getName()+"]");
+ }
+
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setWrappedClass(wrappedClass);
+ }
+
+
+ public static Clazz getWrappedClass(Clazz clazz)
+ {
+ return ClassOptimizationInfo.getClassOptimizationInfo(clazz).getWrappedClass();
+ }
+}
diff --git a/src/proguard/optimize/info/package.html b/core/src/proguard/optimize/info/package.html
similarity index 100%
rename from src/proguard/optimize/info/package.html
rename to core/src/proguard/optimize/info/package.html
diff --git a/src/proguard/optimize/package.html b/core/src/proguard/optimize/package.html
similarity index 100%
rename from src/proguard/optimize/package.html
rename to core/src/proguard/optimize/package.html
diff --git a/src/proguard/evaluation/BranchTargetFinder.java b/core/src/proguard/optimize/peephole/BranchTargetFinder.java
similarity index 81%
rename from src/proguard/evaluation/BranchTargetFinder.java
rename to core/src/proguard/optimize/peephole/BranchTargetFinder.java
index 4b08773..195020d 100644
--- a/src/proguard/evaluation/BranchTargetFinder.java
+++ b/core/src/proguard/optimize/peephole/BranchTargetFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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
@@ -18,7 +18,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-package proguard.evaluation;
+package proguard.optimize.peephole;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
@@ -28,15 +28,15 @@
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.optimize.evaluation.PartialEvaluator;
+import proguard.optimize.evaluation.InitializationFinder;
import java.util.Arrays;
/**
- * This AttributeVisitor finds all instruction offsets, branch targets,
- * exception offsets, and subroutine offsets in the CodeAttribute instances
- * that it visits.
+ * This AttributeVisitor finds all instruction offsets, branch targets, and
+ * exception targets in the CodeAttribute objects that it visits.
*
+ * @see InitializationFinder
* @author Eric Lafortune
*/
public class BranchTargetFinder
@@ -52,8 +52,6 @@ public class BranchTargetFinder
private static boolean DEBUG = System.getProperty("btf") != null;
//*/
- public static final int NONE = PartialEvaluator.NONE;
-
// 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
@@ -63,31 +61,26 @@ public class BranchTargetFinder
public static final int UNKNOWN = -1;
public static final int NO_SUBROUTINE = -2;
- private static final short INSTRUCTION = 1 << 0;
- private static final short BRANCH_ORIGIN = 1 << 1;
- private static final short BRANCH_TARGET = 1 << 2;
- private static final short AFTER_BRANCH = 1 << 3;
- private static final short EXCEPTION_START = 1 << 4;
- private static final short EXCEPTION_END = 1 << 5;
- private static final short EXCEPTION_HANDLER = 1 << 6;
- private static final short SUBROUTINE_INVOCATION = 1 << 7;
- private static final short SUBROUTINE_RETURNING = 1 << 8;
-
- private static final int MAXIMUM_CREATION_OFFSETS = 32;
+ private static final short INSTRUCTION = 1 << 0;
+ private static final short CREATION = 1 << 1;
+ private static final short INITIALIZER = 1 << 2;
+ private static final short BRANCH_ORIGIN = 1 << 3;
+ private static final short BRANCH_TARGET = 1 << 4;
+ private static final short AFTER_BRANCH = 1 << 5;
+ private static final short EXCEPTION_START = 1 << 6;
+ private static final short EXCEPTION_END = 1 << 7;
+ private static final short EXCEPTION_HANDLER = 1 << 8;
+ private static final short SUBROUTINE_INVOCATION = 1 << 9;
+ private static final short SUBROUTINE_RETURNING = 1 << 10;
private short[] instructionMarks = new short[ClassConstants.TYPICAL_CODE_LENGTH + 1];
private int[] subroutineStarts = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private int[] subroutineEnds = new int[ClassConstants.TYPICAL_CODE_LENGTH];
- private int[] creationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
- private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
- private int superInitializationOffset;
private boolean containsSubroutines;
private boolean repeat;
private int currentSubroutineStart;
- private int[] recentCreationOffsets = new int[MAXIMUM_CREATION_OFFSETS];
- private int recentCreationOffsetIndex;
private boolean isInitializer;
@@ -101,6 +94,28 @@ public boolean isInstruction(int offset)
}
+ /**
+ * Returns whether the instruction at the given offset creates a new,
+ * uninitialized object instance, in the CodeAttribute that was visited
+ * most recently.
+ */
+ public boolean isCreation(int offset)
+ {
+ return (instructionMarks[offset] & CREATION) != 0;
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is the special
+ * invocation of an instance initializer, in the CodeAttribute that was
+ * visited most recently.
+ */
+ public boolean isInitializer(int offset)
+ {
+ return (instructionMarks[offset] & INITIALIZER) != 0;
+ }
+
+
/**
* Returns whether the instruction at the given offset is the target of
* any kind in the CodeAttribute that was visited most recently.
@@ -168,7 +183,7 @@ public boolean isExceptionEnd(int offset)
/**
* Returns whether the instruction at the given offset is the start of an
- * exception catch block in the CodeAttribute that was visited most recently.
+ * exception handler in the CodeAttribute that was visited most recently.
*/
public boolean isExceptionHandler(int offset)
{
@@ -236,70 +251,36 @@ public int subroutineEnd(int offset)
}
- /**
- * Returns whether the instruction at the given offset is a 'new'
- * instruction, in the CodeAttribute that was visited most recently.
- */
- public boolean isNew(int offset)
- {
- return initializationOffsets[offset] != NONE;
- }
-
-
- /**
- * Returns the instruction offset at which the object instance that is
- * created at the given 'new' instruction offset is initialized, or
- * NONE if it is not being created.
- */
- public int initializationOffset(int offset)
- {
- return initializationOffsets[offset];
- }
-
-
- /**
- * Returns whether the method is an instance initializer, in the
- * CodeAttribute that was visited most recently.
- */
- public boolean isInitializer()
- {
- return superInitializationOffset != NONE;
- }
+// /**
+// * Returns the instruction offset at which the object instance that is
+// * created at the given 'new' instruction offset is initialized, or
+// * NONE if it is not being created.
+// */
+// public int initializationOffset(int offset)
+// {
+// return initializationOffsets[offset];
+// }
- /**
- * Returns the instruction offset at which this initializer is calling
- * the "super" or "this" initializer method, or NONE if it is
- * not an initializer.
- */
- public int superInitializationOffset()
- {
- return superInitializationOffset;
- }
-
-
- /**
- * Returns whether the instruction at the given offset is the special
- * invocation of an instance initializer, in the CodeAttribute that was
- * visited most recently.
- */
- public boolean isInitializer(int offset)
- {
- return creationOffsets[offset] != NONE;
- }
+// /**
+// * Returns whether the method is an instance initializer, in the
+// * CodeAttribute that was visited most recently.
+// */
+// public boolean isInitializer()
+// {
+// return superInitializationOffset != NONE;
+// }
- /**
- * Returns the offset of the 'new' instruction that corresponds to the
- * invocation of the instance initializer at the given offset, or
- * AT_METHOD_ENTRY if the invocation is calling the "super" or
- * "this" initializer method, , or NONE if it is not a 'new'
- * instruction.
- */
- public int creationOffset(int offset)
- {
- return creationOffsets[offset];
- }
+// /**
+// * Returns the instruction offset at which this initializer is calling
+// * the "super" or "this" initializer method, or NONE if it is
+// * not an initializer.
+// */
+// public int superInitializationOffset()
+// {
+// return superInitializationOffset;
+// }
/**
@@ -331,14 +312,12 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
instructionMarks = new short[codeLength + 1];
subroutineStarts = new int[codeLength];
subroutineEnds = new int[codeLength];
- creationOffsets = new int[codeLength];
- initializationOffsets = new int[codeLength];
+// initializationOffsets = new int[codeLength];
// Reset the arrays.
Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN);
Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN);
- Arrays.fill(creationOffsets, 0, codeLength, NONE);
- Arrays.fill(initializationOffsets, 0, codeLength, NONE);
+// Arrays.fill(initializationOffsets, 0, codeLength, NONE);
}
else
{
@@ -346,13 +325,12 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
Arrays.fill(instructionMarks, 0, codeLength, (short)0);
Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN);
Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN);
- Arrays.fill(creationOffsets, 0, codeLength, NONE);
- Arrays.fill(initializationOffsets, 0, codeLength, NONE);
+// Arrays.fill(initializationOffsets, 0, codeLength, NONE);
instructionMarks[codeLength] = 0;
}
- superInitializationOffset = NONE;
+// superInitializationOffset = NONE;
containsSubroutines = false;
// Iterate until all subroutines have been fully marked.
@@ -360,7 +338,6 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
{
repeat = false;
currentSubroutineStart = NO_SUBROUTINE;
- recentCreationOffsetIndex = 0;
// Mark branch targets by going over all instructions.
codeAttribute.instructionsAccept(clazz, method, this);
@@ -379,6 +356,7 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
// subroutine start.
int previousSubroutineStart = NO_SUBROUTINE;
+
for (int offset = 0; offset < codeLength; offset++)
{
if (isInstruction(offset))
@@ -434,6 +412,7 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
if (isInstruction(index))
{
System.out.println("" +
+ (isInitializer(index) ? 'I' : '-') +
(isBranchOrigin(index) ? 'B' : '-') +
(isAfterBranch(index) ? 'b' : '-') +
(isBranchTarget(index) ? 'T' : '-') +
@@ -444,7 +423,6 @@ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAtt
(isSubroutineStart(index) ? 'S' : '-') +
(isSubroutineReturning(index) ? 'r' : '-') +
(isSubroutine(index) ? " ["+subroutineStart(index)+" -> "+subroutineEnd(index)+"]" : "") +
- (isNew(index) ? " ["+initializationOffset(index)+"] " : " ---- ") +
InstructionFactory.create(codeAttribute.code, index).toString(index));
}
}
@@ -468,6 +446,7 @@ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute cod
opcode == InstructionConstants.OP_FRETURN ||
opcode == InstructionConstants.OP_DRETURN ||
opcode == InstructionConstants.OP_ARETURN ||
+ opcode == InstructionConstants.OP_RETURN ||
opcode == InstructionConstants.OP_ATHROW)
{
// Mark the branch origin.
@@ -490,8 +469,8 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
byte opcode = constantInstruction.opcode;
if (opcode == InstructionConstants.OP_NEW)
{
- // Push the 'new' instruction offset on the stack.
- recentCreationOffsets[recentCreationOffsetIndex++] = offset;
+ // Mark the creation.
+ instructionMarks[offset] |= CREATION;
}
else if (opcode == InstructionConstants.OP_INVOKESPECIAL)
{
@@ -500,27 +479,8 @@ else if (opcode == InstructionConstants.OP_INVOKESPECIAL)
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
if (isInitializer)
{
- // 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];
-
- // Link the creation offset and the initialization offset.
- // TODO: There could be multiple initialization offsets.
- creationOffsets[offset] = recentCreationOffset;
-
- initializationOffsets[recentCreationOffset] = offset;
- }
- else
- {
- // 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;
- }
+ // Mark the initializer.
+ instructionMarks[offset] |= INITIALIZER;
}
}
}
diff --git a/src/proguard/optimize/peephole/ClassFinalizer.java b/core/src/proguard/optimize/peephole/ClassFinalizer.java
similarity index 97%
rename from src/proguard/optimize/peephole/ClassFinalizer.java
rename to core/src/proguard/optimize/peephole/ClassFinalizer.java
index b0fe5a1..b052337 100644
--- a/src/proguard/optimize/peephole/ClassFinalizer.java
+++ b/core/src/proguard/optimize/peephole/ClassFinalizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/ClassMerger.java b/core/src/proguard/optimize/peephole/ClassMerger.java
similarity index 81%
rename from src/proguard/optimize/peephole/ClassMerger.java
rename to core/src/proguard/optimize/peephole/ClassMerger.java
index 11ac0ca..9fcb8d2 100644
--- a/src/proguard/optimize/peephole/ClassMerger.java
+++ b/core/src/proguard/optimize/peephole/ClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,7 @@
package proguard.optimize.peephole;
import proguard.classfile.*;
-import proguard.classfile.attribute.visitor.AttributeNameFilter;
+import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.visitor.*;
import proguard.classfile.editor.*;
import proguard.classfile.util.*;
@@ -60,6 +60,7 @@ public class ClassMerger
private final ProgramClass targetClass;
private final boolean allowAccessModification;
private final boolean mergeInterfacesAggressively;
+ private final boolean mergeWrapperClasses;
private final ClassVisitor extraClassVisitor;
private final MemberVisitor fieldOptimizationInfoCopier = new FieldOptimizationInfoCopier();
@@ -78,9 +79,14 @@ public class ClassMerger
*/
public ClassMerger(ProgramClass targetClass,
boolean allowAccessModification,
- boolean mergeInterfacesAggressively)
+ boolean mergeInterfacesAggressively,
+ boolean mergeWrapperClasses)
{
- this(targetClass, allowAccessModification, mergeInterfacesAggressively, null);
+ this(targetClass,
+ allowAccessModification,
+ mergeInterfacesAggressively,
+ mergeWrapperClasses,
+ null);
}
@@ -100,11 +106,13 @@ public ClassMerger(ProgramClass targetClass,
public ClassMerger(ProgramClass targetClass,
boolean allowAccessModification,
boolean mergeInterfacesAggressively,
+ boolean mergeWrapperClasses,
ClassVisitor extraClassVisitor)
{
this.targetClass = targetClass;
this.allowAccessModification = allowAccessModification;
this.mergeInterfacesAggressively = mergeInterfacesAggressively;
+ this.mergeWrapperClasses = mergeWrapperClasses;
this.extraClassVisitor = extraClassVisitor;
}
@@ -152,9 +160,14 @@ public void visitProgramClass0(ProgramClass programClass)
getTargetClass(programClass) == null &&
getTargetClass(targetClass) == null &&
- // Don't merge annotation classes, with all their introspection and
+ // Don't merge annotation classes, with all their reflection and
// infinite recursion.
- (programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) == 0 &&
+ (programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATION) == 0 &&
+
+ (!DETAILS || print(programClass, "Version?")) &&
+
+ // Only merge classes with equal class versions.
+ programClass.u4version == targetClass.u4version &&
(!DETAILS || print(programClass, "Package visibility?")) &&
@@ -205,7 +218,7 @@ public void visitProgramClass0(ProgramClass programClass)
// The two classes must have the same superclasses and interfaces
// with static initializers.
- initializedSuperClasses(programClass).equals(initializedSuperClasses(targetClass)) &&
+ sideEffectSuperClasses(programClass).equals(sideEffectSuperClasses(targetClass)) &&
(!DETAILS || print(programClass, "Same instanceofed superclasses?")) &&
@@ -228,19 +241,22 @@ public void visitProgramClass0(ProgramClass programClass)
(!DETAILS || print(programClass, "No clashing fields?")) &&
// The classes must not have clashing fields.
- !haveAnyIdenticalFields(programClass, targetClass) &&
+ (mergeWrapperClasses ||
+ !haveAnyIdenticalFields(programClass, targetClass)) &&
(!DETAILS || print(programClass, "No unwanted fields?")) &&
// The two classes must not introduce any unwanted fields.
- !introducesUnwantedFields(programClass, targetClass) &&
- !introducesUnwantedFields(targetClass, programClass) &&
+ (mergeWrapperClasses ||
+ !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) &&
+ (mergeWrapperClasses ||
+ !shadowsAnyFields(programClass, targetClass) &&
+ !shadowsAnyFields(targetClass, programClass)) &&
(!DETAILS || print(programClass, "No clashing methods?")) &&
@@ -265,7 +281,16 @@ public void visitProgramClass0(ProgramClass programClass)
// The classes must not shadow each others non-private methods.
!shadowsAnyMethods(programClass, targetClass) &&
- !shadowsAnyMethods(targetClass, programClass))
+ !shadowsAnyMethods(targetClass, programClass) &&
+
+ (!DETAILS || print(programClass, "No non-copiable attributes?")) &&
+
+ // The class to be merged into the target class must not have
+ // non-copiable attributes (InnerClass, EnclosingMethod),
+ // unless it is a synthetic class.
+ (mergeWrapperClasses ||
+ (programClass.getAccessFlags() & ClassConstants.ACC_SYNTHETIC) != 0 ||
+ !hasNonCopiableAttributes(programClass)))
{
// We're not actually merging the classes, but only copying the
// contents from the source class to the target class. We'll
@@ -299,7 +324,7 @@ public void visitProgramClass0(ProgramClass programClass)
sourceAccessFlags) &
(ClassConstants.ACC_PUBLIC |
ClassConstants.ACC_SUPER |
- ClassConstants.ACC_ANNOTATTION |
+ ClassConstants.ACC_ANNOTATION |
ClassConstants.ACC_ENUM));
// Copy over the superclass, if it's a non-interface class being
@@ -328,8 +353,13 @@ public void visitProgramClass0(ProgramClass programClass)
MemberAdder memberAdder =
new MemberAdder(targetClass, fieldOptimizationInfoCopier);
- programClass.fieldsAccept(memberAdder);
- programClass.methodsAccept(memberAdder);
+ programClass.fieldsAccept(mergeWrapperClasses ?
+ new MemberAccessFilter(ClassConstants.ACC_STATIC, 0, memberAdder) :
+ memberAdder);
+
+ programClass.methodsAccept(mergeWrapperClasses ?
+ new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)), memberAdder) :
+ memberAdder);
// Copy over the other attributes.
programClass.attributesAccept(
@@ -341,12 +371,8 @@ public void visitProgramClass0(ProgramClass programClass)
new AttributeAdder(targetClass, true)));
// Update the optimization information of the target class.
- ClassOptimizationInfo info =
- ClassOptimizationInfo.getClassOptimizationInfo(targetClass);
- if (info != null)
- {
- info.merge(ClassOptimizationInfo.getClassOptimizationInfo(programClass));
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(targetClass)
+ .merge(ClassOptimizationInfo.getClassOptimizationInfo(programClass));
// Remember to replace the inlined class by the target class.
setTargetClass(programClass, targetClass);
@@ -437,14 +463,14 @@ private Set subInterfaces(Clazz clazz, Clazz exceptClass)
/**
* Returns the set of superclasses and interfaces that are initialized.
*/
- private Set initializedSuperClasses(Clazz clazz)
+ private Set sideEffectSuperClasses(Clazz clazz)
{
Set set = new HashSet();
// Visit all superclasses and interfaces, collecting the ones that have
// static initializers.
clazz.hierarchyAccept(true, true, true, false,
- new StaticInitializerContainingClassFilter(
+ new SideEffectClassFilter(
new ClassCollector(set)));
return set;
@@ -496,7 +522,8 @@ private Set caughtSuperClasses(Clazz clazz)
* Returns whether the two given classes have fields with the same
* names and descriptors.
*/
- private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass)
+ private boolean haveAnyIdenticalFields(Clazz clazz,
+ Clazz targetClass)
{
MemberCounter counter = new MemberCounter();
@@ -513,11 +540,11 @@ private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass)
* Returns whether the given class would introduce any unwanted fields
* in the target class.
*/
- private boolean introducesUnwantedFields(ProgramClass programClass,
+ private boolean introducesUnwantedFields(Clazz programClass,
ProgramClass targetClass)
{
- // It's ok if the target class is never instantiated, without any other
- // subclasses except for maybe the source class.
+ // It's ok if the target class is never instantiated and does not
+ // have any subclasses except for maybe the source class.
if (!InstantiationClassMarker.isInstantiated(targetClass) &&
(targetClass.subClasses == null ||
isOnlySubClass(programClass, targetClass)))
@@ -539,7 +566,8 @@ private boolean introducesUnwantedFields(ProgramClass programClass,
* Returns whether the given class or its subclasses shadow any fields in
* the given target class.
*/
- private boolean shadowsAnyFields(Clazz clazz, Clazz targetClass)
+ private boolean shadowsAnyFields(Clazz clazz,
+ Clazz targetClass)
{
MemberCounter counter = new MemberCounter();
@@ -559,7 +587,8 @@ private boolean shadowsAnyFields(Clazz clazz, Clazz targetClass)
* Returns whether the two given classes have class members with the same
* name and descriptor.
*/
- private boolean haveAnyIdenticalMethods(Clazz clazz, Clazz targetClass)
+ private boolean haveAnyIdenticalMethods(Clazz clazz,
+ Clazz targetClass)
{
MemberCounter counter = new MemberCounter();
@@ -581,8 +610,8 @@ private boolean haveAnyIdenticalMethods(Clazz clazz, Clazz targetClass)
private boolean introducesUnwantedAbstractMethods(Clazz clazz,
ProgramClass targetClass)
{
- // It's ok if the target class is already abstract and it has at most
- // the class as a subclass.
+ // It's ok if the target class is already abstract and does not
+ // have any subclasses except for maybe the source class.
if ((targetClass.getAccessFlags() &
(ClassConstants.ACC_ABSTRACT |
ClassConstants.ACC_INTERFACE)) != 0 &&
@@ -598,13 +627,13 @@ private boolean introducesUnwantedAbstractMethods(Clazz clazz,
// Collect all abstract methods, and similar abstract methods in the
// class hierarchy of the target class.
clazz.methodsAccept(new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
- new MultiMemberVisitor(new MemberVisitor[]
- {
+ new MultiMemberVisitor(
counter,
+
new SimilarMemberVisitor(targetClass, true, true, true, false,
- new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
- new MemberCollector(targetSet)))
- })));
+ new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0,
+ new MemberCollector(false, true, true, targetSet)))
+ )));
return targetSet.size() < counter.getCount();
}
@@ -614,13 +643,23 @@ private boolean introducesUnwantedAbstractMethods(Clazz clazz,
* Returns whether the given class overrides any methods in the given
* target class.
*/
- private boolean overridesAnyMethods(Clazz clazz, Clazz targetClass)
+ private boolean overridesAnyMethods(Clazz clazz,
+ ProgramClass targetClass)
{
+ // It's ok if the target class is never instantiated and does
+ // not have any subclasses except for maybe the source class.
+ if (!InstantiationClassMarker.isInstantiated(targetClass) &&
+ (targetClass.subClasses == null ||
+ isOnlySubClass(clazz, targetClass)))
+ {
+ return false;
+ }
+
MemberCounter counter = new MemberCounter();
- // 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.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT,
+ // Visit all non-abstract methods, counting the ones that are
+ // overriding methods in the class hierarchy of the target class.
+ clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT,
new InitializerMethodFilter(null,
new SimilarMemberVisitor(targetClass, true, true, false, false,
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT,
@@ -631,11 +670,20 @@ private boolean overridesAnyMethods(Clazz clazz, Clazz targetClass)
/**
- * Returns whether the given class or its subclasses shadow any methods in
- * the given target class.
+ * Returns whether the given class or its subclasses have private or
+ * static methods that shadow any methods in the given target class.
*/
- private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
+ private boolean shadowsAnyMethods(Clazz clazz,
+ Clazz targetClass)
{
+ // It's ok if the source class already extends the target class
+ // or (in practice) vice versa.
+ if (clazz.extends_(targetClass) ||
+ targetClass.extends_(clazz))
+ {
+ return false;
+ }
+
MemberCounter counter = new MemberCounter();
// Visit all methods, counting the ones that are shadowing
@@ -645,8 +693,7 @@ private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
new InitializerMethodFilter(null,
new SimilarMemberVisitor(targetClass, true, true, false, false,
new MemberAccessFilter(ClassConstants.ACC_FINAL, 0,
- counter)))));
-
+ counter)))));
if (counter.getCount() > 0)
{
return true;
@@ -657,11 +704,10 @@ private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
clazz.hierarchyAccept(true, false, false, true,
new AllMethodVisitor(
new MemberAccessFilter(ClassConstants.ACC_PRIVATE, 0,
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)),
+ new InitializerMethodFilter(null,
new SimilarMemberVisitor(targetClass, true, true, true, false,
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
- counter))))));
-
+ counter))))));
if (counter.getCount() > 0)
{
return true;
@@ -672,7 +718,7 @@ private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
clazz.hierarchyAccept(true, false, false, true,
new AllMethodVisitor(
new MemberAccessFilter(ClassConstants.ACC_STATIC, 0,
- new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_CLINIT)),
+ new InitializerMethodFilter(null,
new SimilarMemberVisitor(targetClass, true, true, true, false,
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
counter))))));
@@ -681,13 +727,28 @@ private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
}
+ /**
+ * Returns whether the given class has any attributes that can not be copied when
+ * merging it into another class.
+ */
+ private boolean hasNonCopiableAttributes(Clazz clazz)
+ {
+ AttributeCounter counter = new AttributeCounter();
+
+ // Copy over the other attributes.
+ clazz.attributesAccept(
+ new AttributeNameFilter(
+ new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_InnerClasses),
+ new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod)),
+ counter));
+
+ return counter.getCount() > 0;
+ }
+
+
public static void setTargetClass(Clazz clazz, Clazz targetClass)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info != null)
- {
- info.setTargetClass(targetClass);
- }
+ ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(clazz).setTargetClass(targetClass);
}
@@ -698,13 +759,7 @@ public static Clazz getTargetClass(Clazz clazz)
// Return the last target class, if any.
while (true)
{
- ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
- if (info == null)
- {
- return targetClass;
- }
-
- clazz = info.getTargetClass();
+ clazz = ClassOptimizationInfo.getClassOptimizationInfo(clazz).getTargetClass();
if (clazz == null)
{
return targetClass;
@@ -728,8 +783,8 @@ public void visitProgramField(ProgramClass programClass, ProgramField programFie
ProgramField copiedField = (ProgramField)programField.getVisitorInfo();
Object info = copiedField.getVisitorInfo();
- programField.setVisitorInfo(info instanceof FieldOptimizationInfo ?
- new FieldOptimizationInfo((FieldOptimizationInfo)info) :
+ programField.setVisitorInfo(info instanceof ProgramFieldOptimizationInfo ?
+ new ProgramFieldOptimizationInfo((ProgramFieldOptimizationInfo)info) :
info);
}
diff --git a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java b/core/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
similarity index 98%
rename from src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
rename to core/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
index c1bf6bf..6d7db5a 100644
--- a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
+++ b/core/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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,6 @@
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.evaluation.BranchTargetFinder;
/**
* This AttributeVisitor redirects unconditional branches so any common code
@@ -51,7 +50,7 @@ public class GotoCommonCodeReplacer
private final InstructionVisitor extraInstructionVisitor;
private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, false);
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
/**
@@ -134,7 +133,7 @@ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute cod
if (newBranchOffset != branchInstruction.length(offset))
{
Instruction newGotoInstruction =
- new BranchInstruction(opcode, newBranchOffset).shrink();
+ new BranchInstruction(opcode, newBranchOffset);
codeAttributeEditor.replaceInstruction(offset,
newGotoInstruction);
}
diff --git a/src/proguard/optimize/peephole/GotoGotoReplacer.java b/core/src/proguard/optimize/peephole/GotoGotoReplacer.java
similarity index 98%
rename from src/proguard/optimize/peephole/GotoGotoReplacer.java
rename to core/src/proguard/optimize/peephole/GotoGotoReplacer.java
index de31a69..c9d8e0d 100644
--- a/src/proguard/optimize/peephole/GotoGotoReplacer.java
+++ b/core/src/proguard/optimize/peephole/GotoGotoReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/peephole/GotoReturnReplacer.java
similarity index 98%
rename from src/proguard/optimize/peephole/GotoReturnReplacer.java
rename to core/src/proguard/optimize/peephole/GotoReturnReplacer.java
index 9cf8b64..2f2efd2 100644
--- a/src/proguard/optimize/peephole/GotoReturnReplacer.java
+++ b/core/src/proguard/optimize/peephole/GotoReturnReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* 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/core/src/proguard/optimize/peephole/HorizontalClassMerger.java
similarity index 89%
rename from src/proguard/optimize/peephole/HorizontalClassMerger.java
rename to core/src/proguard/optimize/peephole/HorizontalClassMerger.java
index 8f57574..3809946 100644
--- a/src/proguard/optimize/peephole/HorizontalClassMerger.java
+++ b/core/src/proguard/optimize/peephole/HorizontalClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ * Copyright (c) 2002-2018 GuardSquare NV
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -35,13 +35,14 @@ public class HorizontalClassMerger
extends SimplifiedVisitor
implements ClassVisitor
{
- private final boolean allowAccessModification;
- private final boolean mergeInterfacesAggressively;
- private final ClassVisitor extraClassVisitor;
+ private final boolean allowAccessModification;
+ private final boolean mergeInterfacesAggressively;
+ private final ClassVisitor extraClassVisitor;
/**
* Creates a new HorizontalClassMerger.
+ *
* @param allowAccessModification specifies whether the access modifiers
* of classes can be changed in order to
* merge them.
@@ -57,6 +58,7 @@ public HorizontalClassMerger(boolean allowAccessModification,
/**
* Creates a new VerticalClassMerger.
+ *
* @param allowAccessModification specifies whether the access modifiers
* of classes can be changed in order to
* merge them.
@@ -67,7 +69,7 @@ public HorizontalClassMerger(boolean allowAccessModification,
*/
public HorizontalClassMerger(boolean allowAccessModification,
boolean mergeInterfacesAggressively,
- ClassVisitor extraClassVisitor)
+ ClassVisitor extraClassVisitor )
{
this.allowAccessModification = allowAccessModification;
this.mergeInterfacesAggressively = mergeInterfacesAggressively;
@@ -84,6 +86,7 @@ public void visitProgramClass(ProgramClass programClass)
new ClassMerger(programClass,
allowAccessModification,
mergeInterfacesAggressively,
+ false,
extraClassVisitor))));
}
}
\ No newline at end of file
diff --git a/core/src/proguard/optimize/peephole/InstructionSequenceConstants.java b/core/src/proguard/optimize/peephole/InstructionSequenceConstants.java
new file mode 100644
index 0000000..574daf7
--- /dev/null
+++ b/core/src/proguard/optimize/peephole/InstructionSequenceConstants.java
@@ -0,0 +1,4772 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2018 GuardSquare NV
+ *
+ * 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.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.visitor.ClassPrinter;
+
+/**
+ * This class contains a set of instruction sequences with their suggested
+ * more compact or more efficient replacements.
+ *
+ * @see InstructionSequencesReplacer
+ * @see InstructionSequenceReplacer
+ * @author Eric Lafortune
+ */
+public class InstructionSequenceConstants
+{
+ // The arrays with constants and instructions used to be static,
+ // but now they are initialized with references to classes and
+ // class members, inside an instance of this class. As an added
+ // benefit, they can be garbage collected after they have been used.
+ public final Instruction[][][] VARIABLE_SEQUENCES;
+ public final Instruction[][][] ARITHMETIC_SEQUENCES;
+ public final Instruction[][][] FIELD_SEQUENCES;
+ public final Instruction[][][] CAST_SEQUENCES;
+ public final Instruction[][][] BRANCH_SEQUENCES;
+ public final Instruction[][][] STRING_SEQUENCES;
+ public final Instruction[][][] OBJECT_SEQUENCES;
+ public final Instruction[][][] MATH_SEQUENCES;
+ public final Instruction[][][] MATH_ANDROID_SEQUENCES;
+
+ public final Constant[] CONSTANTS;
+
+ // Internal short-hand constants.
+ private static final String BOOLEAN = ClassConstants.NAME_JAVA_LANG_BOOLEAN;
+ private static final String BYTE = ClassConstants.NAME_JAVA_LANG_BYTE;
+ private static final String CHARACTER = ClassConstants.NAME_JAVA_LANG_CHARACTER;
+ private static final String SHORT = ClassConstants.NAME_JAVA_LANG_SHORT;
+ private static final String INTEGER = ClassConstants.NAME_JAVA_LANG_INTEGER;
+ private static final String LONG = ClassConstants.NAME_JAVA_LANG_LONG;
+ private static final String FLOAT = ClassConstants.NAME_JAVA_LANG_FLOAT;
+ private static final String DOUBLE = ClassConstants.NAME_JAVA_LANG_DOUBLE;
+ private static final String STRING = ClassConstants.NAME_JAVA_LANG_STRING;
+ private static final String STRING_BUFFER = ClassConstants.NAME_JAVA_LANG_STRING_BUFFER;
+ private static final String STRING_BUILDER = ClassConstants.NAME_JAVA_LANG_STRING_BUILDER;
+ private static final String MATH = ClassConstants.NAME_JAVA_LANG_MATH;
+ private static final String FLOAT_MATH = ClassConstants.NAME_ANDROID_UTIL_FLOAT_MATH;
+
+ private static final int X = InstructionSequenceReplacer.X;
+ private static final int Y = InstructionSequenceReplacer.Y;
+ private static final int Z = InstructionSequenceReplacer.Z;
+
+ private static final int A = InstructionSequenceReplacer.A;
+ private static final int B = InstructionSequenceReplacer.B;
+ private static final int C = InstructionSequenceReplacer.C;
+ private static final int D = InstructionSequenceReplacer.D;
+
+ // Replacement constants that are derived from matched variables.
+ private static final int STRING_A_LENGTH = InstructionSequenceReplacer.STRING_A_LENGTH;
+ private static final int BOOLEAN_A_STRING = InstructionSequenceReplacer.BOOLEAN_A_STRING;
+ private static final int CHAR_A_STRING = InstructionSequenceReplacer.CHAR_A_STRING;
+ private static final int INT_A_STRING = InstructionSequenceReplacer.INT_A_STRING;
+ private static final int LONG_A_STRING = InstructionSequenceReplacer.LONG_A_STRING;
+ private static final int FLOAT_A_STRING = InstructionSequenceReplacer.FLOAT_A_STRING;
+ private static final int DOUBLE_A_STRING = InstructionSequenceReplacer.DOUBLE_A_STRING;
+ private static final int STRING_A_STRING = InstructionSequenceReplacer.STRING_A_STRING;
+ private static final int BOOLEAN_B_STRING = InstructionSequenceReplacer.BOOLEAN_B_STRING;
+ private static final int CHAR_B_STRING = InstructionSequenceReplacer.CHAR_B_STRING;
+ private static final int INT_B_STRING = InstructionSequenceReplacer.INT_B_STRING;
+ private static final int LONG_B_STRING = InstructionSequenceReplacer.LONG_B_STRING;
+ private static final int FLOAT_B_STRING = InstructionSequenceReplacer.FLOAT_B_STRING;
+ private static final int DOUBLE_B_STRING = InstructionSequenceReplacer.DOUBLE_B_STRING;
+ private static final int STRING_B_STRING = InstructionSequenceReplacer.STRING_B_STRING;
+
+
+ /**
+ * Creates a new instance of InstructionSequenceConstants, with constants
+ * that reference classes from the given class pools.
+ */
+ public InstructionSequenceConstants(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ InstructionSequenceBuilder ____ =
+ new InstructionSequenceBuilder(programClassPool,
+ libraryClassPool);
+
+ // Create fieldref constants with wildcards, for fields in class X,
+ // with name Y, and the given primitive types.
+ ConstantPoolEditor constantPoolEditor = ____.getConstantPoolEditor();
+ final int FIELD_Z = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("Z"))), null, null));
+ final int FIELD_B = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("B"))), null, null));
+ final int FIELD_C = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("C"))), null, null));
+ final int FIELD_S = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("S"))), null, null));
+ final int FIELD_I = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("I"))), null, null));
+ final int FIELD_F = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("F"))), null, null));
+ final int FIELD_J = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("J"))), null, null));
+ final int FIELD_D = constantPoolEditor.addConstant(new FieldrefConstant(X, constantPoolEditor.addConstant(new NameAndTypeConstant(Y, constantPoolEditor.addUtf8Constant("D"))), null, null));
+
+ // Create methodref constants with wildcards, for methods in class X,
+ // with the given names and descriptors.
+ final int EQUALS = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant(ClassConstants.METHOD_NAME_EQUALS, ClassConstants.METHOD_TYPE_EQUALS), null, null));
+ final int TO_STRING = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant(ClassConstants.METHOD_NAME_TOSTRING, ClassConstants.METHOD_TYPE_TOSTRING), null, null));
+ final int BOOLEAN_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("booleanValue", "()Z"), null, null));
+ final int BYTE_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("byteValue", "()B"), null, null));
+ final int CHAR_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("charValue", "()C"), null, null));
+ final int SHORT_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("shortValue", "()S"), null, null));
+ final int INT_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("intValue", "()I"), null, null));
+ final int FLOAT_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("floatValue", "()F"), null, null));
+ final int LONG_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("longValue", "()J"), null, null));
+ final int DOUBLE_VALUE = constantPoolEditor.addConstant(new MethodrefConstant(X, constantPoolEditor.addNameAndTypeConstant("doubleValue", "()D"), null, null));
+
+ final InstructionSequenceReplacer.Label TRY_START = InstructionSequenceReplacer.label();
+ final InstructionSequenceReplacer.Label TRY_END = InstructionSequenceReplacer.label();
+ final InstructionSequenceReplacer.Label CATCH_END = InstructionSequenceReplacer.label();
+
+ final InstructionSequenceReplacer.Label CATCH_EXCEPTION = InstructionSequenceReplacer.catch_(TRY_START.offset(), TRY_END.offset(), constantPoolEditor.addClassConstant(ClassConstants.NAME_JAVA_LANG_EXCEPTION, null));
+
+ VARIABLE_SEQUENCES = new Instruction[][][]
+ {
+ { // nop = nothing
+ ____.nop().__(),
+ },
+ { // iload/pop = nothing
+ ____.iload(X)
+ .pop().__(),
+ },
+ { // lload/pop2 = nothing
+ ____.lload(X)
+ .pop2().__(),
+ },
+ { // fload/pop = nothing
+ ____.fload(X)
+ .pop().__(),
+ },
+ { // dload/pop2 = nothing
+ ____.dload(X)
+ .pop2().__(),
+ },
+ { // aload/pop = nothing
+ ____.aload(X)
+ .pop().__(),
+ },
+ { // i = i = nothing
+ ____.iload(X)
+ .istore(X).__(),
+ },
+ { // l = l = nothing
+ ____.lload(X)
+ .lstore(X).__(),
+ },
+ { // f = f = nothing
+ ____.fload(X)
+ .fstore(X).__(),
+ },
+ { // d = d = nothing
+ ____.dload(X)
+ .dstore(X).__(),
+ },
+ { // a = a = nothing
+ ____.aload(X)
+ .astore(X).__(),
+ },
+ { // iload/iload = iload/dup
+ ____.iload(X)
+ .iload(X).__(),
+
+ ____.iload(X)
+ .dup().__()
+ },
+ { // lload/lload = lload/dup2
+ ____.lload(X)
+ .lload(X).__(),
+
+ ____.lload(X)
+ .dup2().__()
+ },
+ { // fload/fload = fload/dup
+ ____.fload(X)
+ .fload(X).__(),
+
+ ____.fload(X)
+ .dup().__()
+ },
+ { // dload/dload = dload/dup2
+ ____.dload(X)
+ .dload(X).__(),
+
+ ____.dload(X)
+ .dup2().__()
+ },
+ { // aload/aload = aload/dup
+ ____.aload(X)
+ .aload(X).__(),
+
+ ____.aload(X)
+ .dup().__()
+ },
+ { // istore/istore = pop/istore
+ ____.istore(X)
+ .istore(X).__(),
+
+ ____.pop()
+ .istore(X).__()
+ },
+ { // lstore/lstore = pop2/lstore
+ ____.lstore(X)
+ .lstore(X).__(),
+
+ ____.pop2()
+ .lstore(X).__()
+ },
+ { // fstore/fstore = pop/fstore
+ ____.fstore(X)
+ .fstore(X).__(),
+
+ ____.pop()
+ .fstore(X).__()
+ },
+ { // dstore/dstore = pop2/dstore
+ ____.dstore(X)
+ .dstore(X).__(),
+
+ ____.pop2()
+ .dstore(X).__()
+ },
+ { // astore/astore = pop/astore
+ ____.astore(X)
+ .astore(X).__(),
+
+ ____.pop()
+ .astore(X).__()
+ },
+ { // istore/iload = dup/istore
+ ____.istore(X)
+ .iload(X).__(),
+
+ ____.dup()
+ .istore(X).__()
+ },
+ { // lstore/lload = dup2/lstore
+ ____.lstore(X)
+ .lload(X).__(),
+
+ ____.dup2()
+ .lstore(X).__()
+ },
+ { // fstore/fload = dup/fstore
+ ____.fstore(X)
+ .fload(X).__(),
+
+ ____.dup()
+ .fstore(X).__()
+ },
+ { // dstore/dload = dup2/dstore
+ ____.dstore(X)
+ .dload(X).__(),
+
+ ____.dup2()
+ .dstore(X).__()
+ },
+ { // astore/aload = dup/astore
+ ____.astore(X)
+ .aload(X).__(),
+
+ ____.dup()
+ .astore(X).__()
+ },
+ { // iload/dup/istore = iload
+ ____.iload(X)
+ .dup()
+ .istore(X).__(),
+
+ ____.iload(X).__()
+ },
+ { // lload/dup2/lstore = lload
+ ____.lload(X)
+ .dup2()
+ .lstore(X).__(),
+
+ ____.lload(X).__()
+ },
+ { // fload/dup/fstore = iload
+ ____.fload(X)
+ .dup()
+ .fstore(X).__(),
+
+ ____.fload(X).__()
+ },
+ { // dload/dup2/dstore = dload
+ ____.dload(X)
+ .dup2()
+ .dstore(X).__(),
+
+ ____.dload(X).__()
+ },
+ { // aload/dup/astore = aload
+ ____.aload(X)
+ .dup()
+ .astore(X).__(),
+
+ ____.aload(X).__()
+ },
+ };
+
+ ARITHMETIC_SEQUENCES = new Instruction[][][]
+ {
+ { // c + i = i + c
+ ____.iconst(A)
+ .iload(X)
+ .iadd().__(),
+
+ ____.iload(X)
+ .iconst(A)
+ .iadd().__()
+ },
+ { // b + i = i + b
+ ____.bipush(A)
+ .iload(X)
+ .iadd().__(),
+
+ ____.iload(X)
+ .bipush(A)
+ .iadd().__()
+ },
+ { // s + i = i + s
+ ____.sipush(A)
+ .iload(X)
+ .iadd().__(),
+
+ ____.iload(X)
+ .sipush(A)
+ .iadd().__()
+ },
+ { // c + i = i + c
+ ____.ldc_(A)
+ .iload(X)
+ .iadd().__(),
+
+ ____.iload(X)
+ .ldc_(A)
+ .iadd().__()
+ },
+ { // c * i = i * c
+ ____.sipush(A)
+ .iload(X)
+ .imul().__(),
+
+ ____.iload(X)
+ .sipush(A)
+ .imul().__()
+ },
+ { // b * i = i * b
+ ____.bipush(A)
+ .iload(X)
+ .imul().__(),
+
+ ____.iload(X)
+ .bipush(A)
+ .imul().__()
+ },
+ { // s * i = i * s
+ ____.sipush(A)
+ .iload(X)
+ .imul().__(),
+
+ ____.iload(X)
+ .sipush(A)
+ .imul().__()
+ },
+ { // c * i = i * c
+ ____.ldc_(A)
+ .iload(X)
+ .imul().__(),
+
+ ____.iload(X)
+ .ldc_(A)
+ .imul().__()
+ },
+ { // c + l = l + c
+ ____.lconst(A)
+ .lload(X)
+ .ladd().__(),
+
+ ____.lload(X)
+ .lconst(A)
+ .ladd().__()
+ },
+ { // c + l = l + c
+ ____.ldc2_w(A)
+ .lload(X)
+ .ladd().__(),
+
+ ____.lload(X)
+ .ldc2_w(A)
+ .ladd().__()
+ },
+ { // c * l = l * c
+ ____.lconst(A)
+ .lload(X)
+ .lmul().__(),
+
+ ____.lload(X)
+ .lconst(A)
+ .lmul().__()
+ },
+ { // c + f = f + c
+ ____.fconst(A)
+ .fload(X)
+ .fadd().__(),
+
+ ____.fload(X)
+ .fconst(A)
+ .fadd().__()
+ },
+ { // c + f = f + c
+ ____.ldc_(A)
+ .fload(X)
+ .fadd().__(),
+
+ ____.fload(X)
+ .ldc_(A)
+ .fadd().__()
+ },
+ { // c * f = f * c
+ ____.fconst(A)
+ .fload(X)
+ .fmul().__(),
+
+ ____.fload(X)
+ .fconst(A)
+ .fmul().__()
+ },
+ { // c * f = f * c
+ ____.ldc_(A)
+ .fload(X)
+ .lmul().__(),
+
+ ____.fload(X)
+ .ldc_(A)
+ .lmul().__()
+ },
+ { // c + d = d + c
+ ____.dconst(A)
+ .dload(X)
+ .dadd().__(),
+
+ ____.dload(X)
+ .dconst(A)
+ .dadd().__()
+ },
+ { // c + d = d + c
+ ____.ldc2_w(A)
+ .dload(X)
+ .dadd().__(),
+
+ ____.dload(X)
+ .ldc2_w(A)
+ .dadd().__()
+ },
+ { // c * d = d * c
+ ____.dconst(A)
+ .dload(X)
+ .dmul().__(),
+
+ ____.dload(X)
+ .dconst(A)
+ .dmul().__()
+ },
+ { // c * d = d * c
+ ____.ldc2_w(A)
+ .dload(X)
+ .dmul().__(),
+
+ ____.dload(X)
+ .ldc2_w(A)
+ .dmul().__()
+ },
+ { // i = i + c = i += c
+ ____.iload(X)
+ .sipush(A)
+ .iadd()
+ .istore(X).__(),
+
+ ____.iinc(X, A).__()
+ },
+ { // i = i + b = i += b
+ ____.iload(X)
+ .bipush(A)
+ .iadd()
+ .istore(X).__(),
+
+ ____.iinc(X, A).__()
+ },
+ { // i = i + s = i += s
+ ____.iload(X)
+ .sipush(A)
+ .iadd()
+ .istore(X).__(),
+
+ ____.iinc(X, A).__()
+ },
+ { // i = i - -1 = i++
+ ____.iload(X)
+ .iconst_m1()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, 1).__()
+ },
+ { // i = i - 1 = i--
+ ____.iload(X)
+ .iconst_1()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, -1).__()
+ },
+ { // i = i - 2 = i -= 2
+ ____.iload(X)
+ .iconst_2()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, -2).__()
+ },
+ { // i = i - 3 = i -= 3
+ ____.iload(X)
+ .iconst_3()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, -3).__()
+ },
+ { // i = i - 4 = i -= 4
+ ____.iload(X)
+ .iconst_4()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, -4).__()
+ },
+ { // i = i - 5 = i -= 5
+ ____.iload(X)
+ .iconst_5()
+ .isub()
+ .istore(X).__(),
+
+ ____.iinc(X, -5).__()
+ },
+ { // ... + 0 = ...
+ ____.iconst_0()
+ .iadd().__(),
+ },
+ { // ... + 0L = ...
+ ____.lconst_0()
+ .ladd().__(),
+ },
+ // Not valid for -0.0.
+// { // ... + 0f = ...
+// ____.fconst_0()
+// .fadd().__(),
+//
+// },
+// { // ... + 0d = ...
+// ____.dconst_0()
+// .dadd().__(),
+//
+// },
+ { // ... - 0 = ...
+ ____.iconst_0()
+ .isub().__(),
+ },
+ { // ... - 0L = ...
+ ____.lconst_0()
+ .lsub().__(),
+ },
+ { // ... - 0f = ...
+ ____.fconst_0()
+ .fsub().__(),
+ },
+ { // ... - 0d = ...
+ ____.dconst_0()
+ .dsub().__(),
+ },
+ { // ... * -1 = -...
+ ____.iconst_m1()
+ .imul().__(),
+
+ ____.ineg().__()
+ },
+ { // ... * 0 = 0
+ ____.iconst_0()
+ .imul().__(),
+
+ ____.pop()
+ .iconst_0().__()
+ },
+ { // ... * 1 = ...
+ ____.iconst_1()
+ .imul().__(),
+ },
+ { // ... * 2 = ... << 1
+ ____.iconst_2()
+ .imul().__(),
+
+ ____.iconst_1()
+ .ishl().__()
+ },
+ { // ... * 4 = ... << 2
+ ____.iconst_4()
+ .imul().__(),
+
+ ____.iconst_2()
+ .ishl().__()
+ },
+ { // ... * 8 = ... << 3
+ ____.bipush(8)
+ .imul().__(),
+
+ ____.iconst_3()
+ .ishl().__()
+ },
+ { // ... * 16 = ... << 4
+ ____.bipush(16)
+ .imul().__(),
+
+ ____.bipush(4)
+ .ishl().__()
+ },
+ { // ... * 32 = ... << 5
+ ____.bipush(32)
+ .imul().__(),
+
+ ____.bipush(5)
+ .ishl().__()
+ },
+ { // ... * 64 = ... << 6
+ ____.bipush(64)
+ .imul().__(),
+
+ ____.bipush(6)
+ .ishl().__()
+ },
+ { // ... * 128 = ... << 7
+ ____.sipush(128)
+ .imul().__(),
+
+ ____.bipush(7)
+ .ishl().__()
+ },
+ { // ... * 256 = ... << 8
+ ____.sipush(256)
+ .imul().__(),
+
+ ____.bipush(8)
+ .ishl().__()
+ },
+ { // ... * 512 = ... << 9
+ ____.sipush(512)
+ .imul().__(),
+
+ ____.bipush(9)
+ .ishl().__()
+ },
+ { // ... * 1024 = ... << 10
+ ____.sipush(1024)
+ .imul().__(),
+
+ ____.bipush(10)
+ .ishl().__()
+ },
+ { // ... * 2048 = ... << 11
+ ____.sipush(2048)
+ .imul().__(),
+
+ ____.bipush(11)
+ .ishl().__()
+ },
+ { // ... * 4096 = ... << 12
+ ____.sipush(4096)
+ .imul().__(),
+
+ ____.bipush(12)
+ .ishl().__()
+ },
+ { // ... * 8192 = ... << 13
+ ____.sipush(8192)
+ .imul().__(),
+
+ ____.bipush(13)
+ .ishl().__()
+ },
+ { // ... * 16384 = ... << 14
+ ____.sipush(16384)
+ .imul().__(),
+
+ ____.bipush(14)
+ .ishl().__()
+ },
+ { // ... * 32768 = ... << 15
+ ____.ldc(32768)
+ .imul().__(),
+
+ ____.bipush(15)
+ .ishl().__()
+ },
+ { // ... * 65536 = ... << 16
+ ____.ldc(65536)
+ .imul().__(),
+
+ ____.bipush(16)
+ .ishl().__()
+ },
+ { // ... * 16777216 = ... << 24
+ ____.ldc(16777216)
+ .imul().__(),
+
+ ____.bipush(24)
+ .ishl().__()
+ },
+ { // ... * -1L = -...
+ ____.ldc2_w(-1L)
+ .lmul().__(),
+
+ ____.lneg().__()
+ },
+ { // ... * 0L = 0L
+ ____.lconst_0()
+ .lmul().__(),
+
+ ____.pop2()
+ .lconst_0().__()
+ },
+ { // ... * 1L = ...
+ ____.lconst_1()
+ .lmul().__(),
+ },
+ { // ... * 2L = ... << 1
+ ____.ldc2_w(2L)
+ .lmul().__(),
+
+ ____.iconst_1()
+ .lshl().__()
+ },
+ { // ... * 4L = ... << 2
+ ____.ldc2_w(4L)
+ .lmul().__(),
+
+ ____.iconst_2()
+ .lshl().__()
+ },
+ { // ... * 8L = ... << 3
+ ____.ldc2_w(8L)
+ .lmul().__(),
+
+ ____.iconst_3()
+ .lshl().__()
+ },
+ { // ... * 16L = ... << 4
+ ____.ldc2_w(16L)
+ .lmul().__(),
+
+ ____.bipush(4)
+ .lshl().__()
+ },
+ { // ... * 32L = ... << 5
+ ____.ldc2_w(32L)
+ .lmul().__(),
+
+ ____.bipush(5)
+ .lshl().__()
+ },
+ { // ... * 64L = ... << 6
+ ____.ldc2_w(64L)
+ .lmul().__(),
+
+ ____.bipush(6)
+ .lshl().__()
+ },
+ { // ... * 128L = ... << 7
+ ____.ldc2_w(128L)
+ .lmul().__(),
+
+ ____.bipush(7)
+ .lshl().__()
+ },
+ { // ... * 256L = ... << 8
+ ____.ldc2_w(256L)
+ .lmul().__(),
+
+ ____.bipush(8)
+ .lshl().__()
+ },
+ { // ... * 512L = ... << 9
+ ____.ldc2_w(512L)
+ .lmul().__(),
+
+ ____.bipush(9)
+ .lshl().__()
+ },
+ { // ... * 1024L = ... << 10
+ ____.ldc2_w(1024L)
+ .lmul().__(),
+
+ ____.bipush(10)
+ .lshl().__()
+ },
+ { // ... * 2048L = ... << 11
+ ____.ldc2_w(2048L)
+ .lmul().__(),
+
+ ____.bipush(11)
+ .lshl().__()
+ },
+ { // ... * 4096L = ... << 12
+ ____.ldc2_w(4096L)
+ .lmul().__(),
+
+ ____.bipush(12)
+ .lshl().__()
+ },
+ { // ... * 8192L = ... << 13
+ ____.ldc2_w(8192L)
+ .lmul().__(),
+
+ ____.bipush(13)
+ .lshl().__()
+ },
+ { // ... * 16384L = ... << 14
+ ____.ldc2_w(16384L)
+ .lmul().__(),
+
+ ____.bipush(14)
+ .lshl().__()
+ },
+ { // ... * 32768L = ... << 15
+ ____.ldc2_w(32768L)
+ .lmul().__(),
+
+ ____.bipush(15)
+ .lshl().__()
+ },
+ { // ... * 65536LL = ... << 16
+ ____.ldc2_w(65536L)
+ .lmul().__(),
+
+ ____.bipush(16)
+ .lshl().__()
+ },
+ { // ... * 16777216L = ... << 24
+ ____.ldc2_w(16777216L)
+ .lmul().__(),
+
+ ____.bipush(24)
+ .lshl().__()
+ },
+ { // ... * 4294967296L = ... << 32
+ ____.ldc2_w(4294967296L)
+ .lmul().__(),
+
+ ____.bipush(32)
+ .lshl().__()
+ },
+ { // ... * -1f = -...
+ ____.ldc(-1f)
+ .fmul().__(),
+
+ ____.fneg().__()
+ },
+ // Not valid for -0.0 and for NaN.
+// { // ... * 0f = 0f
+// ____.fconst_0()
+// .fmul().__(),
+//
+// ____.pop()
+// .fconst_0().__()
+// },
+ { // ... * 1f = ...
+ ____.fconst_1()
+ .fmul().__(),
+ },
+ { // ... * -1d = -...
+ ____.ldc2_w(-1.)
+ .dmul().__(),
+
+ ____.dneg().__()
+ },
+ // Not valid for -0.0 and for NaN.
+// { // ... * 0d = 0d
+// ____.dconst_0()
+// .dmul().__(),
+//
+// ____.pop2()
+// .dconst_0().__()
+// },
+ { // ... * 1d = ...
+ ____.dconst_1()
+ .dmul().__(),
+ },
+ { // ... / -1 = -...
+ ____.iconst_m1()
+ .idiv().__(),
+
+ ____.ineg().__()
+ },
+ { // ... / 1 = ...
+ ____.iconst_1()
+ .idiv().__(),
+ },
+ // Not valid for negative values.
+// { // ... / 2 = ... >> 1
+// ____.iconst_2()
+// .idiv().__(),
+//
+// ____.iconst_1()
+// .ishr().__()
+// },
+// { // ... / 4 = ... >> 2
+// ____.iconst_4()
+// .idiv().__(),
+//
+// ____.iconst_2()
+// .ishr().__()
+// },
+// { // ... / 8 = ... >> 3
+// ____.bipush(8)
+// .idiv().__(),
+//
+// ____.iconst_3()
+// .ishr().__()
+// },
+// { // ... / 16 = ... >> 4
+// ____.bipush(16)
+// .idiv().__(),
+//
+// ____.bipush(4)
+// .ishr().__()
+// },
+// { // ... / 32 = ... >> 5
+// ____.bipush(32)
+// .idiv().__(),
+//
+// ____.bipush(5)
+// .ishr().__()
+// },
+// { // ... / 64 = ... >> 6
+// ____.bipush(64)
+// .idiv().__(),
+//
+// ____.bipush(6)
+// .ishr().__()
+// },
+// { // ... / 128 = ... >> 7
+// ____.sipush(128)
+// .idiv().__(),
+//
+// ____.bipush(7)
+// .ishr().__()
+// },
+// { // ... / 256 = ... >> 8
+// ____.sipush(256)
+// .idiv().__(),
+//
+// ____.bipush(8)
+// .ishr().__()
+// },
+// { // ... / 512 = ... >> 9
+// ____.sipush(512)
+// .idiv().__(),
+//
+// ____.bipush(9)
+// .ishr().__()
+// },
+// { // ... / 1024 = ... >> 10
+// ____.sipush(1024)
+// .idiv().__(),
+//
+// ____.bipush(10)
+// .ishr().__()
+// },
+// { // ... / 2048 = ... >> 11
+// ____.sipush(2048)
+// .idiv().__(),
+//
+// ____.bipush(11)
+// .ishr().__()
+// },
+// { // ... / 4096 = ... >> 12
+// ____.sipush(4096)
+// .idiv().__(),
+//
+// ____.bipush(12)
+// .ishr().__()
+// },
+// { // ... / 8192 = ... >> 13
+// ____.sipush(8192)
+// .idiv().__(),
+//
+// ____.bipush(13)
+// .ishr().__()
+// },
+// { // ... / 16384 = ... >> 14
+// ____.sipush(16384)
+// .idiv().__(),
+//
+// ____.bipush(14)
+// .ishr().__()
+// },
+// { // ... / 32768 = ... >> 15
+// ____.ldc(32768)
+// .idiv().__(),
+//
+// ____.bipush(15)
+// .ishr().__()
+// },
+// { // ... / 65536 = ... >> 16
+// ____.ldc(65536)
+// .idiv().__(),
+//
+// ____.bipush(16)
+// .ishr().__()
+// },
+// { // ... / 16777216 = ... >> 24
+// ____.ldc(16777216)
+// .idiv().__(),
+//
+// ____.bipush(24)
+// .ishr().__()
+// },
+ { // ... / -1L = -...
+ ____.ldc2_w(-1L)
+ .ldiv().__(),
+
+ ____.lneg().__()
+ },
+ { // ... / 1L = ...
+ ____.lconst_1()
+ .ldiv().__(),
+ },
+ // Not valid for negative values.
+// { // ... / 2L = ... >> 1
+// ____.ldc2_w(2L)
+// .ldiv().__(),
+//
+// ____.iconst_1()
+// .lshr().__()
+// },
+// { // ... / 4L = ... >> 2
+// ____.ldc2_w(4L)
+// .ldiv().__(),
+//
+// ____.iconst_2()
+// .lshr().__()
+// },
+// { // ... / 8L = ... >> 3
+// ____.ldc2_w(8L)
+// .ldiv().__(),
+//
+// ____.iconst_3()
+// .lshr().__()
+// },
+// { // ... / 16L = ... >> 4
+// ____.ldc2_w(16L)
+// .ldiv().__(),
+//
+// ____.bipush(4)
+// .lshr().__()
+// },
+// { // ... / 32L = ... >> 5
+// ____.ldc2_w(32L)
+// .ldiv().__(),
+//
+// ____.bipush(5)
+// .lshr().__()
+// },
+// { // ... / 64L = ... >> 6
+// ____.ldc2_w(64L)
+// .ldiv().__(),
+//
+// ____.bipush(6)
+// .lshr().__()
+// },
+// { // ... / 128L = ... >> 7
+// ____.ldc2_w(128L)
+// .ldiv().__(),
+//
+// ____.bipush(7)
+// .lshr().__()
+// },
+// { // ... / 256L = ... >> 8
+// ____.ldc2_w(256L)
+// .ldiv().__(),
+//
+// ____.bipush(8)
+// .lshr().__()
+// },
+// { // ... / 512L = ... >> 9
+// ____.ldc2_w(512L)
+// .ldiv().__(),
+//
+// ____.bipush(9)
+// .lshr().__()
+// },
+// { // ... / 1024L = ... >> 10
+// ____.ldc2_w(1024L)
+// .ldiv().__(),
+//
+// ____.bipush(10)
+// .lshr().__()
+// },
+// { // ... / 2048L = ... >> 11
+// ____.ldc2_w(2048L)
+// .ldiv().__(),
+//
+// ____.bipush(11)
+// .lshr().__()
+// },
+// { // ... / 4096L = ... >> 12
+// ____.ldc2_w(4096L)
+// .ldiv().__(),
+//
+// ____.bipush(12)
+// .lshr().__()
+// },
+// { // ... / 8192L = ... >> 13
+// ____.ldc2_w(8192L)
+// .ldiv().__(),
+//
+// ____.bipush(13)
+// .lshr().__()
+// },
+// { // ... / 16384L = ... >> 14
+// ____.ldc2_w(16384L)
+// .ldiv().__(),
+//
+// ____.bipush(14)
+// .lshr().__()
+// },
+// { // ... / 32768L = ... >> 15
+// ____.ldc2_w(32768L)
+// .ldiv().__(),
+//
+// ____.bipush(15)
+// .lshr().__()
+// },
+// { // ... / 65536LL = ... >> 16
+// ____.ldc2_w(65536L)
+// .ldiv().__(),
+//
+// ____.bipush(16)
+// .lshr().__()
+// },
+// { // ... / 16777216L = ... >> 24
+// ____.ldc2_w(16777216L)
+// .ldiv().__(),
+//
+// ____.bipush(24)
+// .lshr().__()
+// },
+// { // ... / 4294967296L = ... >> 32
+// ____.ldc2_w(4294967296L)
+// .ldiv().__(),
+//
+// ____.bipush(32)
+// .lshr().__()
+// },
+ { // ... / -1f = -...
+ ____.ldc(-1f)
+ .fdiv().__(),
+
+ ____.fneg().__()
+ },
+ { // ... / 1f = ...
+ ____.fconst_1()
+ .fdiv().__(),
+ },
+ { // ... / -1d = -...
+ ____.ldc2_w(-1.)
+ .ddiv().__(),
+
+ ____.dneg().__()
+ },
+ { // ... / 1d = ...
+ ____.dconst_1()
+ .ddiv().__(),
+ },
+ { // ... % 1 = 0
+ ____.iconst_1()
+ .irem().__(),
+
+ ____.pop()
+ .iconst_0().__()
+ },
+ // Not valid for negative values.
+// { // ... % 2 = ... & 0x1
+// ____.iconst_2()
+// .irem().__(),
+//
+// ____.iconst_1()
+// .iand().__()
+// },
+// { // ... % 4 = ... & 0x3
+// ____.iconst_4()
+// .irem().__(),
+//
+// ____.iconst_3()
+// .iand().__()
+// },
+// { // ... % 8 = ... & 0x07
+// ____.bipush(8)
+// .irem().__(),
+//
+// ____.bipush(0x07)
+// .iand().__()
+// },
+// { // ... % 16 = ... & 0x0f
+// ____.bipush(16)
+// .irem().__(),
+//
+// ____.bipush(0x0f)
+// .iand().__()
+// },
+// { // ... % 32 = ... & 0x1f
+// ____.bipush(32)
+// .irem().__(),
+//
+// ____.bipush(0x1f)
+// .iand().__()
+// },
+// { // ... % 64 = ... & 0x3f
+// ____.bipush(64)
+// .irem().__(),
+//
+// ____.bipush(0x3f)
+// .iand().__()
+// },
+// { // ... % 128 = ... & 0x7f
+// ____.sipush(128)
+// .irem().__(),
+//
+// ____.bipush(0x7f)
+// .iand().__()
+// },
+// { // ... % 256 = ... & 0x00ff
+// ____.sipush(256)
+// .irem().__(),
+//
+// ____.sipush(0x00ff)
+// .iand().__()
+// },
+// { // ... % 512 = ... & 0x01ff
+// ____.sipush(512)
+// .irem().__(),
+//
+// ____.sipush(0x01ff)
+// .iand().__()
+// },
+// { // ... % 1024 = ... & 0x03ff
+// ____.sipush(1024)
+// .irem().__(),
+//
+// ____.sipush(0x03ff)
+// .iand().__()
+// },
+// { // ... % 2048 = ... & 0x07ff
+// ____.sipush(2048)
+// .irem().__(),
+//
+// ____.sipush(0x07ff)
+// .iand().__()
+// },
+// { // ... % 4096 = ... & 0x0fff
+// ____.sipush(4096)
+// .irem().__(),
+//
+// ____.sipush(0x0fff)
+// .iand().__()
+// },
+// { // ... % 8192 = ... & 0x1fff
+// ____.sipush(8192)
+// .irem().__(),
+//
+// ____.sipush(0x1fff)
+// .iand().__()
+// },
+// { // ... % 16384 = ... & 0x3fff
+// ____.sipush(16384)
+// .irem().__(),
+//
+// ____.sipush(0x3fff)
+// .iand().__()
+// },
+ { // ... % 1L = 0L
+ ____.lconst_1()
+ .lrem().__(),
+
+ ____.pop2()
+ .lconst_0().__()
+ },
+// { // ... % 1f = 0f
+// ____.fconst_1()
+// .frem().__(),
+//
+// ____.pop()
+// .fconst_0().__()
+// },
+// { // ... % 1d = 0d
+// ____.dconst_1()
+// .drem().__(),
+//
+// ____.pop2()
+// .dconst_0().__()
+// },
+ { // -(-...) = ...
+ ____.ineg()
+ .ineg().__(),
+ },
+ { // -(-...) = ...
+ ____.lneg()
+ .lneg().__(),
+ },
+ { // -(-...) = ...
+ ____.fneg()
+ .fneg().__(),
+ },
+ { // -(-...) = ...
+ ____.dneg()
+ .dneg().__(),
+ },
+ { // +(-...) = -...
+ ____.ineg()
+ .iadd().__(),
+
+ ____.isub().__()
+ },
+ { // +(-...) = -...
+ ____.lneg()
+ .ladd().__(),
+
+ ____.lsub().__()
+ },
+ { // +(-...) = -...
+ ____.fneg()
+ .fadd().__(),
+
+ ____.fsub().__()
+ },
+ { // +(-...) = -...
+ ____.dneg()
+ .dadd().__(),
+
+ ____.dsub().__()
+ },
+ { // ... << 0 = ...
+ ____.iconst_0()
+ .ishl().__(),
+ },
+ { // ... << 0 = ...
+ ____.iconst_0()
+ .lshl().__(),
+ },
+ { // ... >> 0 = ...
+ ____.iconst_0()
+ .ishr().__(),
+ },
+ { // ... >> 0 = ...
+ ____.iconst_0()
+ .lshr().__(),
+ },
+ { // ... >>> 0 = ...
+ ____.iconst_0()
+ .iushr().__(),
+ },
+ { // ... >>> 0 = ...
+ ____.iconst_0()
+ .lushr().__(),
+ },
+ { // ... & -1 = ...
+ ____.iconst_m1()
+ .iand().__(),
+ },
+ { // ... & 0 = 0
+ ____.iconst_0()
+ .iand().__(),
+
+ ____.pop()
+ .iconst_0().__()
+ },
+ { // ... & -1L = ...
+ ____.ldc2_w(-1L)
+ .land().__(),
+ },
+ { // ... & 0L = 0L
+ ____.lconst_0()
+ .land().__(),
+
+ ____.pop2()
+ .lconst_0().__()
+ },
+ { // ... | -1 = -1
+ ____.iconst_m1()
+ .ior().__(),
+
+ ____.pop()
+ .iconst_m1().__()
+ },
+ { // ... | 0 = ...
+ ____.iconst_0()
+ .ior().__(),
+ },
+ { // ... | -1L = -1L
+ ____.ldc2_w(-1L)
+ .land().__(),
+
+ ____.pop2()
+ .ldc2_w(-1L).__()
+ },
+ { // ... | 0L = ...
+ ____.lconst_0()
+ .lor().__(),
+ },
+ { // ... ^ 0 = ...
+ ____.iconst_0()
+ .ixor().__(),
+ },
+ { // ... ^ 0L = ...
+ ____.lconst_0()
+ .lxor().__(),
+ },
+ { // (... & 0x0000ff00) >> 8 = (... >> 8) & 0xff
+ ____.ldc(0x0000ff00)
+ .iand()
+ .bipush(8)
+ .ishr().__(),
+
+ ____.bipush(8)
+ .ishr()
+ .sipush(0xff)
+ .iand().__()
+ },
+ { // (... & 0x0000ff00) >>> 8 = (... >>> 8) & 0xff
+ ____.ldc(0x0000ff00)
+ .iand()
+ .bipush(8)
+ .iushr().__(),
+
+ ____.bipush(8)
+ .iushr()
+ .sipush(0xff)
+ .iand().__()
+ },
+ { // (... & 0x00ff0000) >> 16 = (... >> 16) & 0xff
+ ____.ldc(0x00ff0000)
+ .iand()
+ .bipush(16)
+ .ishr().__(),
+
+ ____.bipush(16)
+ .ishr()
+ .sipush(0xff)
+ .iand().__()
+ },
+ { // (... & 0x00ff0000) >>> 16 = (... >>> 16) & 0xff
+ ____.ldc(0x00ff0000)
+ .iand()
+ .bipush(16)
+ .iushr().__(),
+
+ ____.bipush(16)
+ .iushr()
+ .sipush(0xff)
+ .iand().__()
+ },
+ { // (... & 0xff000000) >> 24 = ... >> 24
+ ____.ldc(0xff000000)
+ .iand()
+ .bipush(24)
+ .ishr().__(),
+
+ ____.bipush(24)
+ .ishr().__()
+ },
+ { // (... & 0xffff0000) >> 16 = ... >> 16
+ ____.ldc(0xffff0000)
+ .iand()
+ .bipush(16)
+ .ishr().__(),
+
+ ____.bipush(16)
+ .ishr().__()
+ },
+ { // (... & 0xffff0000) >>> 16 = ... >>> 16
+ ____.ldc(0xffff0000)
+ .iand()
+ .bipush(16)
+ .iushr().__(),
+
+ ____.bipush(16)
+ .iushr().__()
+ },
+ { // (... >> 24) & 0xff = ... >>> 24
+ ____.bipush(24)
+ .ishr()
+ .sipush(0xff)
+ .iand().__(),
+
+ ____.bipush(24)
+ .iushr().__()
+ },
+ { // (... >>> 24) & 0xff = ... >>> 24
+ ____.bipush(24)
+ .iushr()
+ .sipush(0xff)
+ .iand().__(),
+
+ ____.bipush(24)
+ .iushr().__()
+ },
+ { // (byte)(... & 0x000000ff) = (byte)...
+ ____.sipush(0xff)
+ .iand()
+ .i2b().__(),
+
+ ____.i2b().__()
+ },
+ { // (char)(... & 0x0000ffff) = (char)...
+ ____.ldc(0x0000ffff)
+ .iand()
+ .i2c().__(),
+
+ ____.i2c().__()
+ },
+ { // (short)(... & 0x0000ffff) = (short)...
+ ____.ldc(0x0000ffff)
+ .iand()
+ .i2s().__(),
+
+ ____.i2s().__()
+ },
+ // The Dalvik VM on Android 4.4 throws a VFY error or crashes if
+ // the byte/short cast is removed before an array store.
+// { // (byte)(... >> 24) = ... >> 24
+// ____.bipush(24)
+// .ishr()
+// .i2b().__(),
+//
+// ____.bipush(24)
+// .ishr().__()
+// },
+// { // (byte)(... >>> 24) = ... >> 24
+// ____.bipush(24)
+// .iushr()
+// .i2b().__(),
+//
+// ____.bipush(24)
+// .ishr().__()
+// },
+// { // (char)(... >> 16) = ... >>> 16
+// ____.bipush(16)
+// .ishr()
+// .i2c().__(),
+//
+// ____.bipush(16)
+// .iushr().__()
+// },
+// { // (char)(... >>> 16) = ... >>> 16
+// ____.bipush(16)
+// .iushr()
+// .i2c().__(),
+//
+// ____.bipush(16)
+// .iushr().__()
+// },
+// { // (short)(... >> 16) = ... >> 16
+// ____.bipush(16)
+// .ishr()
+// .i2s().__(),
+//
+// ____.bipush(16)
+// .ishr().__()
+// },
+// { // (short)(... >>> 16) = ... >> 16
+// ____.bipush(16)
+// .iushr()
+// .i2s().__(),
+//
+// ____.bipush(16)
+// .ishr().__()
+// },
+ { // ... << 24 >> 24 = (byte)...
+ ____.bipush(24)
+ .ishl()
+ .bipush(24)
+ .ishr().__(),
+
+ ____.i2b().__()
+ },
+ { // ... << 16 >>> 16 = (char)...
+ ____.bipush(16)
+ .ishl()
+ .bipush(16)
+ .iushr().__(),
+
+ ____.i2c().__()
+ },
+ { // ... << 16 >> 16 = (short)...
+ ____.bipush(16)
+ .ishl()
+ .bipush(16)
+ .ishr().__(),
+
+ ____.i2s().__()
+ },
+ { // ... << 32 >> 32 = (long)(int)...
+ ____.bipush(32)
+ .lshl()
+ .bipush(32)
+ .lshr().__(),
+
+ ____.l2i()
+ .i2l().__()
+ },
+ { // (int)(... & 0x00000000ffffffffL) = (int)...
+ ____.ldc2_w(0x00000000ffffffffL)
+ .land()
+ .l2i().__(),
+
+ ____.l2i().__()
+ },
+ { // (... & 0xffffffff00000000L) >> 32 = ... >> 32
+ ____.ldc2_w(0xffffffff00000000L)
+ .land()
+ .bipush(32)
+ .lshr().__(),
+
+ ____.bipush(32)
+ .lshr().__()
+ },
+ { // (... & 0xffffffff00000000L) >>> 32 = ... >>> 32
+ ____.ldc2_w(0xffffffff00000000L)
+ .land()
+ .bipush(32)
+ .lushr().__(),
+
+ ____.bipush(32)
+ .lushr().__()
+ },
+ { // ... += 0 = nothing
+ ____.iinc(X, 0).__(),
+ },
+ };
+
+ FIELD_SEQUENCES = new Instruction[][][]
+ {
+ { // getfield/putfield = nothing
+ ____.aload(X)
+ .aload(X)
+ .getfield(Y)
+ .putfield(Y).__(),
+ },
+// { // putfield_L/putfield_L = pop2_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(FIELD_J)
+// .aload(X)
+// // ...
+// .putfield(FIELD_J).__(),
+//
+// ____.aload(X)
+// // ...
+// .pop2()
+// // ...
+// .putfield(FIELD_J).__()
+// },
+// { // putfield_D/putfield_D = pop2_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(FIELD_D)
+// .aload(X)
+// // ...
+// .putfield(FIELD_D).__(),
+//
+// ____.aload(X)
+// // ...
+// .pop2()
+// // ...
+// .putfield(FIELD_D).__()
+// },
+// { // putfield/putfield = pop_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(Y)
+// .aload(X)
+// // ...
+// .putfield(Y).__(),
+//
+// ____.aload(X)
+// // ...
+// .pop()
+// // ...
+// .putfield(Y).__()
+// },
+// { // putfield_L/getfield_L = dup2_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(FIELD_J)
+// .aload(X)
+// .getfield(FIELD_J).__(),
+//
+// ____.aload(X)
+// // ...
+// .dup2_x1()
+// .putfield(FIELD_J).__()
+// },
+// { // putfield_D/getfield_D = dup2_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(FIELD_D)
+// .aload(X)
+// .getfield(FIELD_D).__(),
+//
+// ____.aload(X)
+// // ...
+// .dup2_x1()
+// .putfield(FIELD_D).__()
+// },
+// { // putfield/getfield = dup_x1/putfield
+// ____.aload(X)
+// // ...
+// .putfield(Y)
+// .aload(X)
+// .getfield(Y).__(),
+//
+// ____.aload(X)
+// // ...
+// .dup_x1()
+// .putfield(Y).__()
+// },
+ { // getstatic/putstatic = nothing
+ ____.getstatic(X)
+ .putstatic(X).__(),
+ },
+ { // getstatic_L/getstatic_L = getstatic/dup2
+ ____.getstatic(FIELD_J)
+ .getstatic(FIELD_J).__(),
+
+ ____.getstatic(FIELD_J)
+ .dup2().__()
+ },
+ { // getstatic_D/getstatic_D = getstatic/dup2
+ ____.getstatic(FIELD_D)
+ .getstatic(FIELD_D).__(),
+
+ ____.getstatic(FIELD_D)
+ .dup2().__()
+ },
+ { // getstatic/getstatic = getstatic/dup
+ ____.getstatic(X)
+ .getstatic(X).__(),
+
+ ____.getstatic(X)
+ .dup().__()
+ },
+ { // putstatic_L/putstatic_L = pop2/putstatic
+ ____.putstatic(FIELD_J)
+ .putstatic(FIELD_J).__(),
+
+ ____.pop2()
+ .putstatic(FIELD_J).__()
+ },
+ { // putstatic_D/putstatic_D = pop2/putstatic
+ ____.putstatic(FIELD_D)
+ .putstatic(FIELD_D).__(),
+
+ ____.pop2()
+ .putstatic(FIELD_D).__()
+ },
+ { // putstatic/putstatic = pop/putstatic
+ ____.putstatic(X)
+ .putstatic(X).__(),
+
+ ____.pop()
+ .putstatic(X).__()
+ },
+ { // putstatic_L/getstatic_L = dup2/putstatic
+ ____.putstatic(FIELD_J)
+ .getstatic(FIELD_J).__(),
+
+ ____.dup2()
+ .putstatic(FIELD_J).__()
+ },
+ { // putstatic_D/getstatic_D = dup2/putstatic
+ ____.putstatic(FIELD_D)
+ .getstatic(FIELD_D).__(),
+
+ ____.dup2()
+ .putstatic(FIELD_D).__()
+ },
+ { // putstatic/getstatic = dup/putstatic
+ ____.putstatic(X)
+ .getstatic(X).__(),
+
+ ____.dup()
+ .putstatic(X).__()
+ },
+ { // L i L: getfield_L/iload/getfield_L = iload/getfield_L/dup2_x1
+ ____.aload(A)
+ .getfield(FIELD_J)
+ .iload(B)
+ .aload(A)
+ .getfield(FIELD_J).__(),
+
+ ____.iload(B)
+ .aload(A)
+ .getfield(FIELD_J)
+ .dup2_x1().__()
+ },
+ { // D i D: getfield_D/iload/getfield_D = iload/getfield_D/dup2_x1
+ ____.aload(A)
+ .getfield(FIELD_D)
+ .iload(B)
+ .aload(A)
+ .getfield(FIELD_D).__(),
+
+ ____.iload(B)
+ .aload(A)
+ .getfield(FIELD_D)
+ .dup2_x1().__()
+ },
+ { // X i X (e.g. X[i] = X[.] ...): getfield/iload/getfield = iload/getfield/dup_x1
+ ____.aload(A)
+ .getfield(X)
+ .iload(B)
+ .aload(A)
+ .getfield(X).__(),
+
+ ____.iload(B)
+ .aload(A)
+ .getfield(X)
+ .dup_x1().__()
+ },
+ { // L i L: getstatic_L/iload/getstatic_L = iload/getstatic_L/dup2_x1
+ ____.getstatic(FIELD_J)
+ .iload(A)
+ .getstatic(FIELD_J).__(),
+
+ ____.iload(A)
+ .getstatic(FIELD_J)
+ .dup2_x1().__()
+ },
+ { // D i D: getstatic_D/iload/getstatic_D = iload/getstatic_D/dup2_x1
+ ____.getstatic(FIELD_D)
+ .iload(A)
+ .getstatic(FIELD_D).__(),
+
+ ____.iload(A)
+ .getstatic(FIELD_D)
+ .dup2_x1().__()
+ },
+ { // X i X (e.g. X[i] = X[.] ...): getstatic/iload/getstatic = iload/getstatic/dup_x1
+ ____.getstatic(X)
+ .iload(A)
+ .getstatic(X).__(),
+
+ ____.iload(A)
+ .getstatic(X)
+ .dup_x1().__()
+ },
+ { // X[i] j X[i] (e.g. X[i][j] = X[i][.] ...): getfield/iload/aaload/iload/getfield/iload/aaload = iload/getfield//iload/aaload/iload/dup_x1
+ ____.aload(A)
+ .getfield(X)
+ .iload(B)
+ .aaload()
+ .iload(C)
+ .aload(A)
+ .getfield(X)
+ .iload(B)
+ .aaload().__(),
+
+ ____.iload(C)
+ .aload(A)
+ .getfield(X)
+ .iload(B)
+ .aaload()
+ .dup_x1().__()
+ },
+ { // X[i] j X[i] (e.g. X[i][j] = X[i][.] ...): getstatic/iload/aaload/iload/getstatic/iload/aaload = iload/getstatic//iload/aaload/iload/dup_x1
+ ____.getstatic(X)
+ .iload(B)
+ .aaload()
+ .iload(C)
+ .getstatic(X)
+ .iload(B)
+ .aaload().__(),
+
+ ____.iload(C)
+ .getstatic(X)
+ .iload(B)
+ .aaload()
+ .dup_x1().__()
+ },
+ };
+
+ CAST_SEQUENCES = new Instruction[][][]
+ {
+ { // (byte)(byte)... = (byte)...
+ ____.i2b()
+ .i2b().__(),
+
+ ____.i2b().__()
+ },
+ { // (byte)(char)... = (byte)...
+ ____.i2c()
+ .i2b().__(),
+
+ ____.i2b().__()
+ },
+ { // (byte)(short)... = (byte)...
+ ____.i2s()
+ .i2b().__(),
+
+ ____.i2b().__()
+ },
+ { // (char)(char)... = (char)...
+ ____.i2c()
+ .i2c().__(),
+
+ ____.i2c().__()
+ },
+ { // (char)(short)... = (char)...
+ ____.i2s()
+ .i2c().__(),
+
+ ____.i2c().__()
+ },
+// { // (short)(byte)... = (byte)...
+// ____.i2b()
+// .i2s().__(),
+//
+// ____.i2b().__()
+// },
+ { // (short)(char)... = (short)...
+ ____.i2c()
+ .i2s().__(),
+
+ ____.i2s().__()
+ },
+ { // (short)(short)... = (short)...
+ ____.i2s()
+ .i2s().__(),
+
+ ____.i2s().__()
+ },
+ { // (int)(long)... = ...
+ ____.i2l()
+ .l2i().__(),
+ },
+ { // (int)(double)... = ...
+ ____.i2d()
+ .d2i().__(),
+ },
+ { // (float)(double)... = (float)... for ints
+ ____.i2d()
+ .d2f().__(),
+
+ ____.i2f().__()
+ },
+ { // (float)(double)... = (float)... for longs
+ ____.l2d()
+ .d2f().__(),
+
+ ____.l2f().__()
+ },
+ { // (int)(double)... = (int)...
+ ____.f2d()
+ .d2i().__(),
+
+ ____.f2i().__()
+ },
+ { // (long)(double)... = (long)...
+ ____.f2d()
+ .d2l().__(),
+
+ ____.f2l().__()
+ },
+ { // (X)(X)... = (X)...
+ ____.checkcast(X)
+ .checkcast(X).__(),
+
+ ____.checkcast(X).__()
+ },
+ // Not handled correctly in all cases by VMs prior to Java 6...
+// { // (byte)bytes[...] = bytes[...]
+// ____.baload()
+// .i2b().__(),
+//
+// ____.baload().__()
+// },
+// { // (short)bytes[...] = bytes[...]
+// ____.baload()
+// .i2s().__(),
+//
+// ____.baload().__()
+// },
+// { // (char)chars[...] = chars[...]
+// ____.caload()
+// .i2c().__(),
+//
+// ____.caload().__()
+// },
+// { // (short)shorts[...] = shorts[...]
+// ____.saload()
+// .i2s().__(),
+//
+// ____.saload().__()
+// },
+// { // bytes[...] = (byte)... = bytes[...] = ...
+// ____.i2b()
+// .bastore().__(),
+//
+// ____.bastore().__()
+// },
+// { // chars[...] = (char)... = chars[...] = ...
+// ____.i2c()
+// .castore().__(),
+//
+// ____.castore().__()
+// },
+// { // shorts[...] = (short)... = shorts[...] = ...
+// ____.i2s()
+// .sastore().__(),
+//
+// ____.sastore().__()
+// },
+ };
+
+ BRANCH_SEQUENCES = new Instruction[][][]
+ {
+ { // goto +3 = nothing
+ ____.goto_(3).__(),
+ },
+ { // ifeq +3 = pop
+ ____.ifeq(3).__(),
+
+ ____.pop().__()
+ },
+ { // ifne +3 = pop
+ ____.ifne(3).__(),
+
+ ____.pop().__()
+ },
+ { // iflt +3 = pop
+ ____.iflt(3).__(),
+
+ ____.pop().__()
+ },
+ { // ifge +3 = pop
+ ____.ifge(3).__(),
+
+ ____.pop().__()
+ },
+ { // ifgt +3 = pop
+ ____.ifgt(3).__(),
+
+ ____.pop().__()
+ },
+ { // ifle +3 = pop
+ ____.ifle(3).__(),
+
+ ____.pop().__()
+ },
+ { // ificmpeq +3 = pop2
+ ____.ificmpeq(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ificmpne +3 = pop2
+ ____.ificmpne(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ificmplt +3 = pop2
+ ____.ificmplt(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ificmpge +3 = pop2
+ ____.ificmpge(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ificmpgt +3 = pop2
+ ____.ificmpgt(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ificmple +3 = pop2
+ ____.ificmple(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ifacmpeq +3 = pop2
+ ____.ifacmpeq(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ifacmpne +3 = pop2
+ ____.ifacmpne(3).__(),
+
+ ____.pop2().__()
+ },
+ { // ifnull +3 = pop
+ ____.ifnull(3).__(),
+
+ ____.pop().__()
+ },
+ { // ifnonnull +3 = pop
+ ____.ifnonnull(3).__(),
+
+ ____.pop().__()
+ },
+ { // if (... == 0) = ifeq
+ ____.iconst_0()
+ .ificmpeq(X).__(),
+
+ ____.ifeq(X).__()
+ },
+ { // if (0 == i) = iload/ifeq
+ ____.iconst_0()
+ .iload(Y)
+ .ificmpeq(X).__(),
+
+ ____.iload(Y)
+ .ifeq(X).__()
+ },
+ { // if (0 == i) = getstatic/ifeq
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmpeq(X).__(),
+
+ ____.getstatic(Y)
+ .ifeq(X).__()
+ },
+ { // if (0 == i) = getfield/ifeq
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpeq(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifeq(X).__()
+ },
+ { // if (... != 0) = ifne
+ ____.iconst_0()
+ .ificmpne(X).__(),
+
+ ____.ifne(X).__()
+ },
+ { // if (0 != i) = iload/ifeq
+ ____.iconst_0()
+ .iload(Y)
+ .ificmpne(X).__(),
+
+ ____.iload(Y)
+ .ifne(X).__()
+ },
+ { // if (0 != i) = getstatic/ifeq
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmpne(X).__(),
+
+ ____.getstatic(Y)
+ .ifne(X).__()
+ },
+ { // if (0 != i) = getfield/ifeq
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpne(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifne(X).__()
+ },
+ { // if (... < 0) = iflt
+ ____.iconst_0()
+ .ificmplt(X).__(),
+
+ ____.iflt(X).__()
+ },
+ { // if (... < 1) = ifle
+ ____.iconst_1()
+ .ificmplt(X).__(),
+
+ ____.ifle(X).__()
+ },
+ { // if (0 > i) = iload/iflt
+ ____.iconst_0()
+ .iload(Y)
+ .ificmpgt(X).__(),
+
+ ____.iload(Y)
+ .iflt(X).__()
+ },
+ { // if (1 > i) = iload/ifle
+ ____.iconst_1()
+ .iload(Y)
+ .ificmpgt(X).__(),
+
+ ____.iload(Y)
+ .ifle(X).__()
+ },
+ { // if (0 > i) = getstatic/iflt
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmpgt(X).__(),
+
+ ____.getstatic(Y)
+ .iflt(X).__()
+ },
+ { // if (1 > i) = getstatic/ifle
+ ____.iconst_1()
+ .getstatic(Y)
+ .ificmpgt(X).__(),
+
+ ____.getstatic(Y)
+ .ifle(X).__()
+ },
+ { // if (0 > i) = getfield/iflt
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpgt(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .iflt(X).__()
+ },
+ { // if (1 > i) = getfield/ifle
+ ____.iconst_1()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpgt(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifle(X).__()
+ },
+ { // if (... >= 0) = ifge
+ ____.iconst_0()
+ .ificmpge(X).__(),
+
+ ____.ifge(X).__()
+ },
+ { // if (... >= 1) = ifgt
+ ____.iconst_1()
+ .ificmpge(X).__(),
+
+ ____.ifgt(X).__()
+ },
+ { // if (0 <= i) = iload/ifge
+ ____.iconst_0()
+ .iload(Y)
+ .ificmple(X).__(),
+
+ ____.iload(Y)
+ .ifge(X).__()
+ },
+ { // if (1 <= i) = iload/ifgt
+ ____.iconst_1()
+ .iload(Y)
+ .ificmple(X).__(),
+
+ ____.iload(Y)
+ .ifgt(X).__()
+ },
+ { // if (0 <= i) = getstatic/ifge
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmple(X).__(),
+
+ ____.getstatic(Y)
+ .ifge(X).__()
+ },
+ { // if (1 <= i) = getstatic/ifgt
+ ____.iconst_1()
+ .getstatic(Y)
+ .ificmple(X).__(),
+
+ ____.getstatic(Y)
+ .ifgt(X).__()
+ },
+ { // if (0 <= i) = getfield/ifge
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmple(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifge(X).__()
+ },
+ { // if (1 <= i) = getfield/ifgt
+ ____.iconst_1()
+ .aload(Y)
+ .getfield(Z)
+ .ificmple(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifgt(X).__()
+ },
+ { // if (... > 0) = ifgt
+ ____.iconst_0()
+ .ificmpgt(X).__(),
+
+ ____.ifgt(X).__()
+ },
+ { // if (... > -1) = ifge
+ ____.iconst_m1()
+ .ificmpgt(X).__(),
+
+ ____.ifge(X).__()
+ },
+ { // if (0 < i) = iload/ifgt
+ ____.iconst_0()
+ .iload(Y)
+ .ificmplt(X).__(),
+
+ ____.iload(Y)
+ .ifgt(X).__()
+ },
+ { // if (-1 < i) = iload/ifge
+ ____.iconst_m1()
+ .iload(Y)
+ .ificmplt(X).__(),
+
+ ____.iload(Y)
+ .ifge(X).__()
+ },
+ { // if (0 < i) = getstatic/ifgt
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmplt(X).__(),
+
+ ____.getstatic(Y)
+ .ifgt(X).__()
+ },
+ { // if (-1 < i) = getstatic/ifge
+ ____.iconst_m1()
+ .getstatic(Y)
+ .ificmplt(X).__(),
+
+ ____.getstatic(Y)
+ .ifge(X).__()
+ },
+ { // if (0 < i) = getfield/ifgt
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmplt(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifgt(X).__()
+ },
+ { // if (-1 < i) = getfield/ifge
+ ____.iconst_m1()
+ .aload(Y)
+ .getfield(Z)
+ .ificmplt(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifge(X).__()
+ },
+ { // if (... <= 0) = ifle
+ ____.iconst_0()
+ .ificmple(X).__(),
+
+ ____.ifle(X).__()
+ },
+ { // if (... <= -1) = iflt
+ ____.iconst_m1()
+ .ificmple(X).__(),
+
+ ____.iflt(X).__()
+ },
+ { // if (0 >= i) = iload/ifle
+ ____.iconst_0()
+ .iload(Y)
+ .ificmpge(X).__(),
+
+ ____.iload(Y)
+ .ifle(X).__()
+ },
+ { // if (-1 >= i) = iload/iflt
+ ____.iconst_m1()
+ .iload(Y)
+ .ificmpge(X).__(),
+
+ ____.iload(Y)
+ .iflt(X).__()
+ },
+ { // if (0 >= i) = getstatic/ifle
+ ____.iconst_0()
+ .getstatic(Y)
+ .ificmpge(X).__(),
+
+ ____.getstatic(Y)
+ .ifle(X).__()
+ },
+ { // if (-1 >= i) = getstatic/iflt
+ ____.iconst_m1()
+ .getstatic(Y)
+ .ificmpge(X).__(),
+
+ ____.getstatic(Y)
+ .iflt(X).__()
+ },
+ { // if (0 >= i) = getfield/ifle
+ ____.iconst_0()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpge(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifle(X).__()
+ },
+ { // if (-1 >= i) = getfield/iflt
+ ____.iconst_m1()
+ .aload(Y)
+ .getfield(Z)
+ .ificmpge(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .iflt(X).__()
+ },
+ { // if (... == null) = ifnull
+ ____.aconst_null()
+ .ifacmpeq(X).__(),
+
+ ____.ifnull(X).__()
+ },
+ { // if (null == a) = aload/ifnull
+ ____.aconst_null()
+ .aload(Y)
+ .ifacmpeq(X).__(),
+
+ ____.aload(Y)
+ .ifnull(X).__()
+ },
+ { // if (null == a) = getstatic/ifnull
+ ____.aconst_null()
+ .getstatic(Y)
+ .ifacmpeq(X).__(),
+
+ ____.getstatic(Y)
+ .ifnull(X).__()
+ },
+ { // if (null == a) = getfield/ifnull
+ ____.aconst_null()
+ .aload(Y)
+ .getfield(Z)
+ .ifacmpeq(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifnull(X).__()
+ },
+ { // if (... != null) = ifnonnull
+ ____.aconst_null()
+ .ifacmpne(X).__(),
+
+ ____.ifnonnull(X).__()
+ },
+ { // if (null != a) = aload/ifnonnull
+ ____.aconst_null()
+ .aload(Y)
+ .ifacmpne(X).__(),
+
+ ____.aload(Y)
+ .ifnonnull(X).__()
+ },
+ { // if (null != a) = getstatic/ifnonnull
+ ____.aconst_null()
+ .getstatic(Y)
+ .ifacmpne(X).__(),
+
+ ____.getstatic(Y)
+ .ifnonnull(X).__()
+ },
+ { // if (null != a) = getfield/ifnonnull
+ ____.aconst_null()
+ .aload(Y)
+ .getfield(Z)
+ .ifacmpne(X).__(),
+
+ ____.aload(Y)
+ .getfield(Z)
+ .ifnonnull(X).__()
+ },
+ { // iconst_0/ifeq = goto
+ ____.iconst_0()
+ .ifeq(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // iconst/ifeq = nothing
+ ____.iconst(A)
+ .ifeq(X).__(),
+ },
+ { // bipush/ifeq = nothing
+ ____.bipush(A)
+ .ifeq(X).__(),
+ },
+ { // sipush/ifeq = nothing
+ ____.sipush(A)
+ .ifeq(X).__(),
+ },
+ { // iconst_0/ifne = nothing
+ ____.iconst_0()
+ .ifne(X).__(),
+ },
+ { // iconst/ifne = goto
+ ____.iconst(A)
+ .ifne(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // bipush/ifne = goto
+ ____.bipush(A)
+ .ifne(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // sipush/ifne = goto
+ ____.sipush(A)
+ .ifne(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // iconst_0/iflt = nothing
+ ____.iconst_0()
+ .iflt(X).__(),
+ },
+ { // iconst_0/ifge = goto
+ ____.iconst_0()
+ .ifge(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // iconst_0/ifgt = nothing
+ ____.iconst_0()
+ .ifgt(X).__(),
+ },
+ { // iconst_0/ifle = goto
+ ____.iconst_0()
+ .ifle(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // aconst_null/ifnull = goto
+ ____.aconst_null()
+ .ifnull(X).__(),
+
+ ____.goto_(X).__()
+ },
+ { // aconst_null/ifnonnul = nothing
+ ____.aconst_null()
+ .ifnonnull(X).__(),
+ },
+ { // ifeq/goto = ifne
+ ____.ifeq(6)
+ .goto_(X).__(),
+
+ ____.ifne(X).__()
+ },
+ { // ifne/goto = ifeq
+ ____.ifne(6)
+ .goto_(X).__(),
+
+ ____.ifeq(X).__()
+ },
+ { // iflt/goto = ifge
+ ____.iflt(6)
+ .goto_(X).__(),
+
+ ____.ifge(X).__()
+ },
+ { // ifge/goto = iflt
+ ____.ifge(6)
+ .goto_(X).__(),
+
+ ____.iflt(X).__()
+ },
+ { // ifgt/goto = ifle
+ ____.ifgt(6)
+ .goto_(X).__(),
+
+ ____.ifle(X).__()
+ },
+ { // ifle/goto = ifgt
+ ____.ifle(6)
+ .goto_(X).__(),
+
+ ____.ifgt(X).__()
+ },
+ { // ificmpeq/goto = ificmpne
+ ____.ificmpeq(6)
+ .goto_(X).__(),
+
+ ____.ificmpne(X).__()
+ },
+ { // ificmpne/goto = ificmpeq
+ ____.ificmpne(6)
+ .goto_(X).__(),
+
+ ____.ificmpeq(X).__()
+ },
+ { // ificmplt/goto = ificmpge
+ ____.ificmplt(6)
+ .goto_(X).__(),
+
+ ____.ificmpge(X).__()
+ },
+ { // ificmpge/goto = ificmplt
+ ____.ificmpge(6)
+ .goto_(X).__(),
+
+ ____.ificmplt(X).__()
+ },
+ { // ificmpgt/goto = ificmple
+ ____.ificmpgt(6)
+ .goto_(X).__(),
+
+ ____.ificmple(X).__()
+ },
+ { // ificmple/goto = ificmpgt
+ ____.ificmple(6)
+ .goto_(X).__(),
+
+ ____.ificmpgt(X).__()
+ },
+ { // ifacmpeq/goto = ifacmpne
+ ____.ifacmpeq(6)
+ .goto_(X).__(),
+
+ ____.ifacmpne(X).__()
+ },
+ { // ifacmpne/goto = ifacmpeq
+ ____.ifacmpne(6)
+ .goto_(X).__(),
+
+ ____.ifacmpeq(X).__()
+ },
+ { // ifnull/goto = ifnonnull
+ ____.ifnull(6)
+ .goto_(X).__(),
+
+ ____.ifnonnull(X).__()
+ },
+ { // ifnonnull/goto = ifnull
+ ____.ifnonnull(6)
+ .goto_(X).__(),
+
+ ____.ifnull(X).__()
+ },
+// { // switch (...) { default: ... } = pop/goto ...
+// ____.tableswitch(A, X, Y, 0, new int[0]).__(),
+//
+// ____.pop()
+// .goto_(A).__()
+// },
+// { // switch (...) { default: ... } = pop/goto ...
+// ____.lookupswitch(A, 0, new int[0], new int[0]).__(),
+//
+// ____.pop()
+// .goto_(A).__()
+// },
+ { // switch (...) { case/case/default: ... } = switch (...) { case/default: ... }
+ ____.lookupswitch(A, new int[] { X, Y }, new int[] { A, B }).__(),
+
+ ____.lookupswitch(A, new int[] { Y }, new int[] { B }).__()
+ },
+ { // switch (...) { case/case/default: ... } = switch (...) { case/default: ... }
+ ____.lookupswitch(B, new int[] { X, Y }, new int[] { A, B }).__(),
+
+ ____.lookupswitch(B, new int[] { X }, new int[] { A }).__()
+ },
+ { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... }
+ ____.lookupswitch(A, new int[] { X, Y, Z }, new int[] { A, B, C }).__(),
+
+ ____.lookupswitch(A, new int[] { Y, Z }, new int[] { B, C }).__()
+ },
+ { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... }
+ ____.lookupswitch(B, new int[] { X, Y, Z }, new int[] { A, B, C }).__(),
+
+ ____.lookupswitch(B, new int[] { X, Z }, new int[] { A, C }).__()
+ },
+ { // switch (...) { case/case/case/default: ... } = switch (...) { case/case/default: ... }
+ ____.lookupswitch(C, new int[] { X, Y, Z }, new int[] { A, B, C }).__(),
+
+ ____.lookupswitch(C, new int[] { X, Y }, new int[] { A, B }).__()
+ },
+// { // switch (...) { case ...: ... default: ... }
+// // = if (... == ...) ... else ...
+// ____.tableswitch(A, X, Y, 1, new int[] { B }).__(),
+//
+// ____.sipush(X)
+// .ificmpne(A)
+// .goto_(B).__()
+// },
+// { // switch (...) { case ...: ... default: ... }
+// // = if (... == ...) ... else ...
+// ____.lookupswitch(A, 1, new int[] { X }, new int[] { B }).__(),
+//
+// ____.sipush(X)
+// .ificmpne(A)
+// .goto_(B).__()
+// }
+ };
+
+ OBJECT_SEQUENCES = new Instruction[][][]
+ {
+ { // "...".equals("...") = X.class.equals(X.class) = true (ignoring class loader)
+ ____.ldc_(A)
+ .ldc_(A)
+ .invokevirtual(EQUALS).__(),
+
+ ____.iconst_1().__()
+ },
+ { // ....equals(dup) = true (discarding any NullPointerException)
+ ____.dup()
+ .invokevirtual(EQUALS).__(),
+
+ ____.pop()
+ .iconst_1().__()
+ },
+ { // object.equals(object) = true (ignoring implementation and discarding any NullPointerException)
+ ____.aload(A)
+ .aload(A)
+ .invokevirtual(EQUALS).__(),
+
+ ____.iconst_1().__()
+ },
+ { // object.equals(object) = true (ignoring implementation and discarding any NullPointerException)
+ ____.getstatic(A)
+ .getstatic(A)
+ .invokevirtual(EQUALS).__(),
+
+ ____.iconst_1().__()
+ },
+ { // object.equals(object) = true (ignoring implementation and discarding any NullPointerException)
+ ____.aload(A)
+ .getfield(B)
+ .aload(A)
+ .getfield(B)
+ .invokevirtual(EQUALS).__(),
+
+ ____.iconst_1().__()
+ },
+ { // Boolean.valueOf(false) = Boolean.FALSE
+ ____.iconst_0()
+ .invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;").__(),
+
+ ____.getstatic(BOOLEAN, "FALSE", "Ljava/lang/Boolean;").__()
+ },
+ { // Boolean.valueOf(true) = Boolean.TRUE
+ ____.iconst_1()
+ .invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;").__(),
+
+ ____.getstatic(BOOLEAN, "TRUE", "Ljava/lang/Boolean;").__()
+ },
+ { // new Boolean(false) = Boolean.FALSE (ignoring identity)
+ ____.new_(BOOLEAN)
+ .dup()
+ .iconst_0()
+ .invokespecial(BOOLEAN, "", "(Z)V").__(),
+
+ ____.getstatic(BOOLEAN, "FALSE", "Ljava/lang/Boolean;").__()
+ },
+ { // new Boolean(true) = Boolean.TRUE (ignoring identity)
+ ____.new_(BOOLEAN)
+ .dup()
+ .iconst_1()
+ .invokespecial(BOOLEAN, "", "(Z)V").__(),
+
+ ____.getstatic(BOOLEAN, "TRUE", "Ljava/lang/Boolean;").__()
+ },
+ { // new Boolean(v) = Boolean.valueof(v) (ignoring identity)
+ ____.new_(BOOLEAN)
+ .dup()
+ .iload(A)
+ .invokespecial(BOOLEAN, "", "(Z)V").__(),
+
+ ____.iload(A)
+ .invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;").__()
+ },
+ { // new Boolean(s) = Boolean.valueof(s) (ignoring identity)
+ ____.new_(BOOLEAN)
+ .dup()
+ .getstatic(FIELD_Z)
+ .invokespecial(BOOLEAN, "", "(Z)V").__(),
+
+ ____.getstatic(FIELD_Z)
+ .invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;").__()
+ },
+ { // new Boolean(v.f) = Boolean.valueof(v.f) (ignoring identity)
+ ____.new_(BOOLEAN)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_Z)
+ .invokespecial(BOOLEAN, "", "(Z)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_Z)
+ .invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;").__()
+ },
+ { // Boolean.FALSE.booleanValue() = false
+ ____.getstatic(BOOLEAN, "FALSE", "Ljava/lang/Boolean;")
+ .invokevirtual(BOOLEAN_VALUE).__(),
+
+ ____.iconst_0().__()
+ },
+ { // Boolean.TRUE.booleanValue() = true
+ ____.getstatic(BOOLEAN, "TRUE", "Ljava/lang/Boolean;")
+ .invokevirtual(BOOLEAN_VALUE).__(),
+
+ ____.iconst_1().__()
+ },
+ { // Boolean.valueOf(...).booleanValue() = nothing
+ ____.invokestatic(BOOLEAN, "valueOf", "(Z)Ljava/lang/Boolean;")
+ .invokevirtual(BOOLEAN_VALUE).__(),
+ },
+ { // new Byte(B) = Byte.valueof(B) (ignoring identity)
+ ____.new_(BYTE)
+ .dup()
+ .iconst(A)
+ .invokespecial(BYTE, "", "(B)V").__(),
+
+ ____.iconst(A)
+ .invokestatic(BYTE, "valueOf", "(B)Ljava/lang/Byte;").__()
+ },
+ { // new Byte(v) = Byte.valueof(v) (ignoring identity)
+ ____.new_(BYTE)
+ .dup()
+ .iload(A)
+ .invokespecial(BYTE, "", "(B)V").__(),
+
+ ____.iload(A)
+ .invokestatic(BYTE, "valueOf", "(B)Ljava/lang/Byte;").__()
+ },
+ { // new Byte(s) = Byte.valueof(s) (ignoring identity)
+ ____.new_(BYTE)
+ .dup()
+ .getstatic(FIELD_B)
+ .invokespecial(BYTE, "", "(B)V").__(),
+
+ ____.getstatic(FIELD_B)
+ .invokestatic(BYTE, "valueOf", "(B)Ljava/lang/Byte;").__()
+ },
+ { // new Byte(v.f) = Byte.valueof(v.f) (ignoring identity)
+ ____.new_(BYTE)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_B)
+ .invokespecial(BYTE, "", "(B)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_B)
+ .invokestatic(BYTE, "valueOf", "(B)Ljava/lang/Byte;").__()
+ },
+ { // Byte.valueOf(...).byteValue() = nothing
+ ____.invokestatic(BYTE, "valueOf", "(B)Ljava/lang/Byte;")
+ .invokevirtual(BYTE_VALUE).__(),
+ },
+ { // new Character(C) = Character.valueof(C) (ignoring identity)
+ ____.new_(CHARACTER)
+ .dup()
+ .iconst(A)
+ .invokespecial(CHARACTER, "", "(C)V").__(),
+
+ ____.iconst(A)
+ .invokestatic(CHARACTER, "valueOf", "(C)Ljava/lang/Character;").__()
+ },
+ { // new Character(v) = Character.valueof(v) (ignoring identity)
+ ____.new_(CHARACTER)
+ .dup()
+ .iload(A)
+ .invokespecial(CHARACTER, "", "(C)V").__(),
+
+ ____.iload(A)
+ .invokestatic(CHARACTER, "valueOf", "(C)Ljava/lang/Character;").__()
+ },
+ { // new Character(s) = Character.valueof(s) (ignoring identity)
+ ____.new_(CHARACTER)
+ .dup()
+ .getstatic(FIELD_C)
+ .invokespecial(CHARACTER, "", "(C)V").__(),
+
+ ____.getstatic(FIELD_C)
+ .invokestatic(CHARACTER, "valueOf", "(C)Ljava/lang/Character;").__()
+ },
+ { // new Character(v.f) = Character.valueof(v.f) (ignoring identity)
+ ____.new_(CHARACTER)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_C)
+ .invokespecial(CHARACTER, "", "(C)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_C)
+ .invokestatic(CHARACTER, "valueOf", "(C)Ljava/lang/Character;").__()
+ },
+ { // Character.valueOf(...).charValue() = nothing
+ ____.invokestatic(CHARACTER, "valueOf", "(C)Ljava/lang/Character;")
+ .invokevirtual(CHAR_VALUE).__(),
+ },
+ { // new Short(S) = Short.valueof(S) (ignoring identity)
+ ____.new_(SHORT)
+ .dup()
+ .iconst(A)
+ .invokespecial(SHORT, "", "(S)V").__(),
+
+ ____.iconst(A)
+ .invokestatic(SHORT, "valueOf", "(S)Ljava/lang/Short;").__()
+ },
+ { // new Short(v) = Short.valueof(v) (ignoring identity)
+ ____.new_(SHORT)
+ .dup()
+ .iload(A)
+ .invokespecial(SHORT, "", "(S)V").__(),
+
+ ____.iload(A)
+ .invokestatic(SHORT, "valueOf", "(S)Ljava/lang/Short;").__()
+ },
+ { // new Short(s) = Short.valueof(s) (ignoring identity)
+ ____.new_(SHORT)
+ .dup()
+ .getstatic(FIELD_S)
+ .invokespecial(SHORT, "", "(S)V").__(),
+
+ ____.getstatic(FIELD_S)
+ .invokestatic(SHORT, "valueOf", "(S)Ljava/lang/Short;").__()
+ },
+ { // new Short(v.f) = Short.valueof(v.f) (ignoring identity)
+ ____.new_(SHORT)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_S)
+ .invokespecial(SHORT, "", "(S)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_S)
+ .invokestatic(SHORT, "valueOf", "(S)Ljava/lang/Short;").__()
+ },
+ { // Short.valueOf(...).shortValue() = nothing
+ ____.invokestatic(SHORT, "valueOf", "(S)Ljava/lang/Short;")
+ .invokevirtual(SHORT_VALUE).__(),
+ },
+ { // new Integer(I) = Integer.valueof(I) (ignoring identity)
+ ____.new_(INTEGER)
+ .dup()
+ .iconst(A)
+ .invokespecial(INTEGER, "", "(I)V").__(),
+
+ ____.iconst(A)
+ .invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;").__()
+ },
+ { // new Integer(I) = Integer.valueof(I) (ignoring identity)
+ ____.new_(INTEGER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(INTEGER, "", "(I)V").__(),
+
+ ____.ldc_(A)
+ .invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;").__()
+ },
+ { // new Integer(v) = Integer.valueof(v) (ignoring identity)
+ ____.new_(INTEGER)
+ .dup()
+ .iload(A)
+ .invokespecial(INTEGER, "", "(I)V").__(),
+
+ ____.iload(A)
+ .invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;").__()
+ },
+ { // new Integer(c) = Integer.valueof(c) (ignoring identity)
+ ____.new_(INTEGER)
+ .dup()
+ .getstatic(FIELD_I)
+ .invokespecial(INTEGER, "", "(I)V").__(),
+
+ ____.getstatic(FIELD_I)
+ .invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;").__()
+ },
+ { // new Integer(v.f) = Integer.valueof(v.f) (ignoring identity)
+ ____.new_(INTEGER)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_I)
+ .invokespecial(INTEGER, "", "(I)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_I)
+ .invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;").__()
+ },
+ { // Integer.valueOf(...).intValue() = nothing
+ ____.invokestatic(INTEGER, "valueOf", "(I)Ljava/lang/Integer;")
+ .invokevirtual(INT_VALUE).__(),
+ },
+ { // new Float(F) = Float.valueof(F) (ignoring identity)
+ ____.new_(FLOAT)
+ .dup()
+ .fconst(A)
+ .invokespecial(FLOAT, "", "(F)V").__(),
+
+ ____.fconst(A)
+ .invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;").__()
+ },
+ { // new Float(F) = Float.valueof(F) (ignoring identity)
+ ____.new_(FLOAT)
+ .dup()
+ .ldc_(A)
+ .invokespecial(FLOAT, "", "(F)V").__(),
+
+ ____.ldc_(A)
+ .invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;").__()
+ },
+ { // new Float(v) = Float.valueof(v) (ignoring identity)
+ ____.new_(FLOAT)
+ .dup()
+ .fload(A)
+ .invokespecial(FLOAT, "", "(F)V").__(),
+
+ ____.fload(A)
+ .invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;").__()
+ },
+ { // new Float(s) = Float.valueof(s) (ignoring identity)
+ ____.new_(FLOAT)
+ .dup()
+ .getstatic(FIELD_F)
+ .invokespecial(FLOAT, "", "(F)V").__(),
+
+ ____.getstatic(FIELD_F)
+ .invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;").__()
+ },
+ { // new Float(v.f) = Float.valueof(v.f) (ignoring identity)
+ ____.new_(FLOAT)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_F)
+ .invokespecial(FLOAT, "", "(F)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_F)
+ .invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;").__()
+ },
+ { // Float.valueOf(...).floatValue() = nothing
+ ____.invokestatic(FLOAT, "valueOf", "(F)Ljava/lang/Float;")
+ .invokevirtual(FLOAT_VALUE).__(),
+ },
+ { // new Long(J) = Long.valueof(J) (ignoring identity)
+ ____.new_(LONG)
+ .dup()
+ .lconst(A)
+ .invokespecial(LONG, "", "(J)V").__(),
+
+ ____.lconst(A)
+ .invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;").__()
+ },
+ { // new Long(J) = Long.valueof(J) (ignoring identity)
+ ____.new_(LONG)
+ .dup()
+ .ldc2_w(A)
+ .invokespecial(LONG, "", "(J)V").__(),
+
+ ____.ldc2_w(A)
+ .invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;").__()
+ },
+ { // new Long(v) = Long.valueof(v) (ignoring identity)
+ ____.new_(LONG)
+ .dup()
+ .iload(A)
+ .invokespecial(LONG, "", "(J)V").__(),
+
+ ____.iload(A)
+ .invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;").__()
+ },
+ { // new Long(s) = Long.valueof(s) (ignoring identity)
+ ____.new_(LONG)
+ .dup()
+ .getstatic(FIELD_J)
+ .invokespecial(LONG, "", "(J)V").__(),
+
+ ____.getstatic(FIELD_J)
+ .invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;").__()
+ },
+ { // new Long(v.f) = Long.valueof(v.f) (ignoring identity)
+ ____.new_(LONG)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_J)
+ .invokespecial(LONG, "", "(J)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_J)
+ .invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;").__()
+ },
+ { // Long.valueOf(...).longValue() = nothing
+ ____.invokestatic(LONG, "valueOf", "(J)Ljava/lang/Long;")
+ .invokevirtual(LONG_VALUE).__(),
+ },
+ { // new Double(D) = Double.valueof(D) (ignoring identity)
+ ____.new_(DOUBLE)
+ .dup()
+ .dconst(A)
+ .invokespecial(DOUBLE, "", "(D)V").__(),
+
+ ____.dconst(A)
+ .invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;").__()
+ },
+ { // new Double(D) = Double.valueof(D) (ignoring identity)
+ ____.new_(DOUBLE)
+ .dup()
+ .ldc2_w(A)
+ .invokespecial(DOUBLE, "", "(D)V").__(),
+
+ ____.ldc2_w(A)
+ .invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;").__()
+ },
+ { // new Double(v) = Double.valueof(v) (ignoring identity)
+ ____.new_(DOUBLE)
+ .dup()
+ .dload(A)
+ .invokespecial(DOUBLE, "", "(D)V").__(),
+
+ ____.dload(A)
+ .invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;").__()
+ },
+ { // new Double(s) = Double.valueof(s) (ignoring identity)
+ ____.new_(DOUBLE)
+ .dup()
+ .getstatic(FIELD_D)
+ .invokespecial(DOUBLE, "", "(D)V").__(),
+
+ ____.getstatic(FIELD_D)
+ .invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;").__()
+ },
+ { // new Double(v.f) = Double.valueof(v.f) (ignoring identity)
+ ____.new_(DOUBLE)
+ .dup()
+ .aload(A)
+ .getfield(FIELD_D)
+ .invokespecial(DOUBLE, "", "(D)V").__(),
+
+ ____.aload(A)
+ .getfield(FIELD_D)
+ .invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;").__()
+ },
+ { // Double.valueOf(...).doubleValue() = nothing
+ ____.invokestatic(DOUBLE, "valueOf", "(D)Ljava/lang/Double;")
+ .invokevirtual(DOUBLE_VALUE).__(),
+ },
+ };
+
+ STRING_SEQUENCES = new Instruction[][][]
+ {
+ { // "...".equals("...") = true
+ ____.ldc_(A)
+ .ldc_(A)
+ .invokevirtual(STRING, "equals", "(Ljava/lang/Object;)Z").__(),
+
+ ____.iconst_1().__()
+ },
+ { // "...".length() = ...
+ ____.ldc_(A)
+ .invokevirtual(STRING, "length", "()I").__(),
+
+ ____.sipush(STRING_A_LENGTH).__()
+ },
+ { // String.valueOf(Z) = "....
+ ____.iconst(A)
+ .invokestatic(STRING, "valueOf", "(Z)Ljava/lang/String;").__(),
+
+ ____.ldc_(BOOLEAN_A_STRING).__()
+ },
+ { // String.valueOf(C) = "...."
+ ____.iconst(A)
+ .invokestatic(STRING, "valueOf", "(C)Ljava/lang/String;").__(),
+
+ ____.ldc_(CHAR_A_STRING).__()
+ },
+ { // String.valueOf(Cc) = "...."
+ ____.ldc_(A)
+ .invokestatic(STRING, "valueOf", "(C)Ljava/lang/String;").__(),
+
+ ____.ldc_(CHAR_A_STRING).__()
+ },
+ { // String.valueOf(I) = "...."
+ ____.iconst(A)
+ .invokestatic(STRING, "valueOf", "(I)Ljava/lang/String;").__(),
+
+ ____.ldc_(INT_A_STRING).__()
+ },
+ { // String.valueOf(Ic) = "...."
+ ____.ldc_(A)
+ .invokestatic(STRING, "valueOf", "(I)Ljava/lang/String;").__(),
+
+ ____.ldc_(INT_A_STRING).__()
+ },
+ { // String.valueOf(J) = "...."
+ ____.lconst(A)
+ .invokestatic(STRING, "valueOf", "(J)Ljava/lang/String;").__(),
+
+ ____.ldc_(LONG_A_STRING).__()
+ },
+ { // String.valueOf(Jc) = "...."
+ ____.ldc2_w(A)
+ .invokestatic(STRING, "valueOf", "(J)Ljava/lang/String;").__(),
+
+ ____.ldc_(LONG_A_STRING).__()
+ },
+ { // String.valueOf(F) = "...."
+ ____.fconst(A)
+ .invokestatic(STRING, "valueOf", "(F)Ljava/lang/String;").__(),
+
+ ____.ldc_(FLOAT_A_STRING).__()
+ },
+ { // String.valueOf(Fc) = "...."
+ ____.ldc_(A)
+ .invokestatic(STRING, "valueOf", "(F)Ljava/lang/String;").__(),
+
+ ____.ldc_(FLOAT_A_STRING).__()
+ },
+ { // String.valueOf(D) = "...."
+ ____.dconst(A)
+ .invokestatic(STRING, "valueOf", "(D)Ljava/lang/String;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING).__()
+ },
+ { // String.valueOf(Dc) = "...."
+ ____.ldc2_w(A)
+ .invokestatic(STRING, "valueOf", "(D)Ljava/lang/String;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING).__()
+ },
+ { // "...".concat("...") = "......"
+ ____.ldc_(A)
+ .ldc_(B)
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__(),
+
+ ____.ldc_(STRING_A_STRING | STRING_B_STRING).__(),
+ },
+
+ { // new StringBuffer("...").toString() = "..." (ignoring identity)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A).__()
+ },
+ { // new StringBuffer(string).toString() = string (ignoring identity and discarding any NullPointerException)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .aload(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.aload(A).__()
+ },
+ { // new StringBuffer("...").length() = length
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(STRING_BUFFER, "length", "()I").__(),
+
+ ____.sipush(STRING_A_LENGTH).__()
+ },
+ { // new StringBuffer() (without dup) = nothing
+ ____.new_(STRING_BUFFER)
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "()V").__(),
+ },
+ { // new StringBuffer("...") (without dup) = nothing
+ ____.new_(STRING_BUFFER)
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__(),
+ },
+ { // new StringBuffer()/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .pop().__(),
+ },
+ { // new StringBuffer("...")/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(z)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(c)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(i)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(l)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .lload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(f)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .fload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(d)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .dload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // new StringBuffer("...").append(s)/pop = nothing
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .aload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .pop().__(),
+ },
+ { // StringBuffer#toString()/pop = pop
+ ____.invokevirtual(TO_STRING)
+ .pop().__(),
+
+ ____.pop().__()
+ },
+ { // StringBuffer#append("") = nothing
+ ____.ldc("")
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__(),
+ },
+ { // new StringBuffer().append(Z) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(BOOLEAN_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(C) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(CHAR_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(Cc) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(CHAR_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(I) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(INT_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(Ic) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(INT_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(J) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .lconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(LONG_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(Jc) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc2_w(A)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(LONG_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(F) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .fconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(FLOAT_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(Fc) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(FLOAT_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(D) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .dconst(A)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append(Dc) = new StringBuffer("....")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc2_w(A)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer().append("...") = new StringBuffer("...")
+ ____.invokespecial(STRING_BUFFER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Z) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | BOOLEAN_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(C) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Cc) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(I) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | INT_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Ic) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | INT_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(J) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .lconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | LONG_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Jc) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc2_w(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | LONG_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(F) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .fconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | FLOAT_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Fc) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | FLOAT_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(D) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .dconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | DOUBLE_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(Dc) = new StringBuffer("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc2_w(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | DOUBLE_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append("...") = new StringBuffer("......")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | STRING_B_STRING)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuffer("...").append(z).toString() = "...".concat(String.valueOf(z))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .iload(B)
+ .invokestatic(STRING, "valueOf", "(Z)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(c).toString() = "...".concat(String.valueOf(c))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .iload(B)
+ .invokestatic(STRING, "valueOf", "(C)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(i).toString() = "...".concat(String.valueOf(i))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .iload(B)
+ .invokestatic(STRING, "valueOf", "(I)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(l).toString() = "...".concat(String.valueOf(l))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .lload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .lload(B)
+ .invokestatic(STRING, "valueOf", "(J)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(f).toString() = "...".concat(String.valueOf(f))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .fload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .fload(B)
+ .invokestatic(STRING, "valueOf", "(F)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(d).toString() = "...".concat(String.valueOf(d))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .dload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .dload(B)
+ .invokestatic(STRING, "valueOf", "(D)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(string).toString() = "...".concat(String.valueOf(string))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .aload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .aload(B)
+ .invokestatic(STRING, "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer("...").append(object).toString() = "...".concat(String.valueOf(object))
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUFFER, "", "(Ljava/lang/String;)V")
+ .aload(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A)
+ .aload(B)
+ .invokestatic(STRING, "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;")
+ .invokevirtual(STRING, "concat", "(Ljava/lang/String;)Ljava/lang/String;").__()
+ },
+ { // StringBuffer#append("...").append(Z) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | BOOLEAN_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(C) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(Cc) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(I) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .iconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | INT_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(Ic) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | INT_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(J) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .lconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | LONG_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(Jc) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc2_w(B)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | LONG_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(F) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .fconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | FLOAT_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(Fc) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | FLOAT_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(D) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .dconst(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | DOUBLE_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append(Dc) = StringBuffer#append("....")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc2_w(B)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | DOUBLE_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // StringBuffer#append("...").append("...") = StringBuffer#append("......")
+ ____.ldc_(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .ldc_(B)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__(),
+
+ ____.ldc_(STRING_A_STRING | STRING_B_STRING)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;").__()
+ },
+ { // new StringBuffer().append(z).toString() = String.valueOf(z)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .iload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Z)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.iload(A)
+ .invokestatic(STRING, "valueOf", "(Z)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(c).toString() = String.valueOf(c)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .iload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(C)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.iload(A)
+ .invokestatic(STRING, "valueOf", "(C)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(i).toString() = String.valueOf(i)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .iload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(I)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.iload(A)
+ .invokestatic(STRING, "valueOf", "(I)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(j).toString() = String.valueOf(j)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .lload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(J)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.lload(A)
+ .invokestatic(STRING, "valueOf", "(J)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(f).toString() = String.valueOf(f)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .fload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(F)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.fload(A)
+ .invokestatic(STRING, "valueOf", "(F)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(d).toString() = String.valueOf(d)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .dload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(D)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.dload(A)
+ .invokestatic(STRING, "valueOf", "(D)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(string).toString() = String.valueOf(string)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .aload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.aload(A)
+ .invokestatic(STRING, "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;").__()
+ },
+ { // new StringBuffer().append(object).toString() = String.valueOf(object)
+ ____.new_(STRING_BUFFER)
+ .dup()
+ .invokespecial(STRING_BUFFER, "", "()V")
+ .aload(A)
+ .invokevirtual(STRING_BUFFER, "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.aload(A)
+ .invokestatic(STRING, "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;").__()
+ },
+
+ { // new StringBuilder("...").toString() = "..." (ignoring identity)
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.ldc_(A).__()
+ },
+ { // new StringBuilder(string).toString() = string (ignoring identity and discarding any NullPointerException)
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .aload(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(TO_STRING).__(),
+
+ ____.aload(A).__()
+ },
+ { // new StringBuilder("...").length() = length
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .invokevirtual(STRING_BUILDER, "length", "()I").__(),
+
+ ____.sipush(STRING_A_LENGTH).__()
+ },
+ { // new StringBuilder() (without dup) = nothing
+ ____.new_(STRING_BUILDER)
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "()V").__(),
+ },
+ { // new StringBuilder("...") (without dup) = nothing
+ ____.new_(STRING_BUILDER)
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__(),
+ },
+ { // new StringBuilder()/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "()V")
+ .pop().__(),
+ },
+ { // new StringBuilder("...")/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(z)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(Z)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(c)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(C)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(i)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(I)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(l)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .lload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(J)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(f)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .fload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(F)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(d)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .dload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(D)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // new StringBuilder("...").append(s)/pop = nothing
+ ____.new_(STRING_BUILDER)
+ .dup()
+ .ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .aload(B)
+ .invokevirtual(STRING_BUILDER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;")
+ .pop().__(),
+ },
+ { // StringBuilder#toString()/pop = pop
+ ____.invokevirtual(TO_STRING)
+ .pop().__(),
+
+ ____.pop().__()
+ },
+ { // StringBuilder#append("") = nothing
+ ____.ldc("")
+ .invokevirtual(STRING_BUILDER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;").__(),
+ },
+ { // new StringBuilder().append(Z) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(Z)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(BOOLEAN_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(C) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(C)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(CHAR_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(Cc) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUILDER, "append", "(C)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(CHAR_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(I) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .iconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(I)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(INT_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(Ic) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUILDER, "append", "(I)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(INT_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(J) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .lconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(J)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(LONG_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(Jc) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc2_w(A)
+ .invokevirtual(STRING_BUILDER, "append", "(J)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(LONG_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(F) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .fconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(F)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(FLOAT_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(Fc) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUILDER, "append", "(F)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(FLOAT_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(D) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .dconst(A)
+ .invokevirtual(STRING_BUILDER, "append", "(D)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append(Dc) = new StringBuilder("....")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc2_w(A)
+ .invokevirtual(STRING_BUILDER, "append", "(D)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(DOUBLE_A_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder().append("...") = new StringBuilder("...")
+ ____.invokespecial(STRING_BUILDER, "", "()V")
+ .ldc_(A)
+ .invokevirtual(STRING_BUILDER, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder("...").append(Z) = new StringBuilder("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUILDER, "append", "(Z)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(STRING_A_STRING | BOOLEAN_B_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder("...").append(C) = new StringBuilder("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUILDER, "append", "(C)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder("...").append(Cc) = new StringBuilder("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .ldc_(B)
+ .invokevirtual(STRING_BUILDER, "append", "(C)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(STRING_A_STRING | CHAR_B_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder("...").append(I) = new StringBuilder("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V")
+ .iconst(B)
+ .invokevirtual(STRING_BUILDER, "append", "(I)Ljava/lang/StringBuilder;").__(),
+
+ ____.ldc_(STRING_A_STRING | INT_B_STRING)
+ .invokespecial(STRING_BUILDER, "", "(Ljava/lang/String;)V").__()
+ },
+ { // new StringBuilder("...").append(Ic) = new StringBuilder("....")
+ ____.ldc_(A)
+ .invokespecial(STRING_BUILDER, "