From 8a6199f0c36a778f22394364347a301b0b28e94b Mon Sep 17 00:00:00 2001
From: Ying Wang
Some notable optimizations that aren't supported yet:
-Copyright © 2002-2009 Eric Lafortune
+Copyright © 2002-2013 Eric Lafortune
@@ -33,13 +33,18 @@ Place, Suite 330, Boston, MA 02111-1307 USA
In addition, as a special exception, Eric Lafortune gives permission to link
the code of this program with the following stand-alone applications:
-Since its first public release, many people have expressed their enthusiasm and
-have chimed in with interesting ideas, bug reports, and bug fixes: Thorsten
-Heit, Oliver Retzl, Jonathan Knudsen, Tarcisio Camara, Bob Drury, Dave Jarvis,
-Marc Chapman, Dave Morehouse, Richard Osbaldeston, Peter Hawkins, Mark
-Sherington, David Sitsky, James Manning, Ptolemy Oberin, Frank-Michael Moser,
-QZ Shines, Thomas Singer, Michele Puccini, Roman Bednarek, Natalia Pujol,
-Daniel Sjöblom, Jan Filipsky, Charles Smith, Gerrit Telkamp, Noel
-Grandin, Torbjörn Söderstedt, Clemens Eisserer, Clark Bassett,
-Eduard Welch, Dawid Weiss, Andrew Wilson, Sean Owen, Niels Gron, Ishan Mehta,
-Steven Adams, Xavier Kral,
-and many others. Thanks! Your feedback has been invaluable.
+Marcel Patzlaff has initiated a series of artifacts in the Maven Central
+repository. I am now maintaining them as part of the official builds.
-I am developing ProGuard in my spare time, which is possible thanks to my
-day-time job at Luciad.
+Many other people have expressed their enthusiasm and have chimed in with
+interesting ideas, bug reports, and bug fixes: Thorsten Heit, Oliver Retzl,
+Jonathan Knudsen, Tarcisio Camara, Bob Drury, Dave Jarvis, Marc Chapman, Dave
+Morehouse, Richard Osbaldeston, Peter Hawkins, Mark Sherington, David Sitsky,
+James Manning, Ptolemy Oberin, Frank-Michael Moser, QZ Shines, Thomas Singer,
+Michele Puccini, Roman Bednarek, Natalia Pujol, Daniel Sjöblom, Jan
+Filipsky, Charles Smith, Gerrit Telkamp, Noel Grandin, Torbjörn
+Söderstedt, Clemens Eisserer, Clark Bassett, Eduard Welch, Dawid Weiss,
+Andrew Wilson, Sean Owen, Niels Gron, Ishan Mehta, Steven Adams, Xavier Kral,
+Stefan Martin, Toby Reyelts, Bernhard Eder, Manfred Moser, Marco Blümel,
+David Reiss,
+and many more. Thanks! Your feedback has been invaluable.
+
+
+Saikoa is providing the
+financial resources for this project. At Saikoa, we're also developing
+ProGuard's sibling for Android,
+DexGuard.
SourceForge is generously providing the resources for
-hosting this project and many other projects.
+target="other">SourceForge is providing the resources for hosting this
+project and many other projects.
-JetBrains is kindly providing a license for its IntelliJ IDEA development
-environment.
+Sonatype and
+the Maven Central repository are hosting the Maven artifacts.
-The code and these web pages were written using Sun's JDKs, Linux, IntelliJ
-IDEA, GNU emacs, bash, sed, awk, and a whole host of other tools that continue
-to make programming interesting.
+The code and these web pages were written using Oracle/Sun's JDKs, Linux,
+IntelliJ IDEA, GNU emacs, bash, sed, awk, and a whole host of other tools that
+continue to make programming interesting.
-And finally, I'm a great fan of the Java Docking Library.
-
All trademarks are property of their respective holders.
-
ProGuard is written in Java, so it requires a Java Runtime Environment
- (JRE 1.4 or higher).
+ (JRE 1.5 or higher).
-You can download the latest release (containing the program jar, the
-documentation you're reading now, examples, and the source code) from this
+You can download the latest release (containing the program jars, the
+documentation that you're reading now, examples, and the source code) from this
location:
-
+The proguard section contains major releases and updates with
+sub-minor version numbers, for applying emergency fixes. The
+proguard beta section contains beta releases. These include
+new features and any less urgent bug fixes collected since the previous
+release.
+
If you're still working with an older version of ProGuard, check out
the summary of changes below, to see if you're missing something essential.
Better look at the up-to-date on-line version if
-you're reading a local copy of this page.
-
-The download section may also contain updates with sub-minor version numbers.
-These versions are typically released shortly after their parent versions, for
-applying emergency fixes. Please make sure to look at those if you are
-encountering any problems with recent releases.
-
-Finally, there may be beta versions of upcoming releases. They may be of
-interest too, because they typically contain any less urgent bug fixes
-collected since the previous release.
+you're reading a local copy of this page. Unless noted otherwise,
+ProGuard remains compatible across versions, so don't be afraid to
+update.
+If you're only interested in individual jar files for your build process, you
+can also download them from the Maven Central repository, with GroupId
+net.sf.proguard and ArtifactIds
+proguard-parent,
+proguard-base,
+proguard-gui,
+proguard-anttask,
+proguard-gradle,
+proguard-wtk-plugin, and
+proguard-retrace.
+
+
-
+
-
-
+
+ ideas.
+ href="http://software.freecode.com/projects/proguard"
+ target="other">project page at Freecode (Freshmeat) offer the
+ possibility to subscribe to the announcements of new releases. They are
+ the most efficient way to stay abreast of the latest developments.
-I can't promise a swift answer, or any answer at all, for that matter, but I
-like seeing any constructive comments.
+I can't promise a swift answer, or any answer at all, for that matter, but it's
+always great to see constructive comments.
ProGuard isn't a typical open source project, in the sense that I am
@@ -96,10 +107,11 @@ like seeing any constructive comments.
do things my way, without the overhead and compromises associated with larger
projects.
-
-ProGuard is a free Java class file shrinker, optimizer, and obfuscator.
-It can detect and remove unused classes, fields, methods, and attributes. It
-can then optimize bytecode and remove unused instructions. Finally, it can
-rename the remaining classes, fields, and methods using short meaningless
-names. The resulting jars are smaller and harder to reverse-engineer.
+ProGuard is a free Java class file shrinker, optimizer, obfuscator, and
+preverifier. It detects and removes unused classes, fields, methods, and
+attributes. It optimizes bytecode and removes unused instructions. It renames
+the remaining classes, fields, and methods using short meaningless names.
+Finally, it preverifies the processed code for Java 6 or for Java Micro
+Edition.
Your browser doesn't support frames, but that's cool.
You can go straight to the main page.
-
The ProGuard user documentation represents an important part of this
work. It may only be redistributed without changes, along with the unmodified
version of the code.
-Contents
-
-
-Class.forName
- calls?
-What is shrinking?
+What is shrinking?
Java source code (.java files) is typically compiled to bytecode (.class
files). Bytecode is more compact than Java source code, but it may still
@@ -50,8 +65,7 @@ Shrinking programs such as ProGuard can analyze bytecode and remove
unused classes, fields, and methods. The program remains functionally
equivalent, including the information given in exception stack traces.
-
-What is obfuscation?
+What is obfuscation?
By default, compiled bytecode still contains a lot of debugging information:
source file names, line numbers, field names, method names, argument names,
@@ -63,8 +77,7 @@ it much harder to reverse-engineer the code. It further compacts the code as a
bonus. The program remains functionally equivalent, except for the class
names, method names, and line numbers given in exception stack traces.
-
-What is preverification?
+What is preverification?
When loading class files, the class loader performs some sophisticated
verification of the byte code. This analysis makes sure the code can't
@@ -77,8 +90,7 @@ then be loaded faster and in a more memory-efficient way. ProGuard can
perform the preverification step too, for instance allowing to retarget older
class files at Java 6.
-
-What kind of optimizations does ProGuard support?
+What kind of optimizations does ProGuard support?
Apart from removing unused classes, fields, and methods in the shrinking step,
ProGuard can also perform optimizations at the bytecode level, inside
@@ -87,24 +99,24 @@ analysis, partial evaluation, static single assignment, global value numbering,
and liveness analysis, ProGuard can:
-
The positive effects of these optimizations will depend on your code and on
the virtual machine on which the code is executed. Simple virtual machines may
@@ -113,27 +125,28 @@ At the very least, your bytecode may become a bit smaller.
-
-
-Can I use ProGuard to process my commercial application?
+Can I use ProGuard to process my commercial application?
Yes, you can. ProGuard itself is distributed under the GPL, but this
doesn't affect the programs that you process. Your code remains yours, and
its license can remain the same.
-
-Does ProGuard work with Java 2? Java 5? Java 6?
+Does ProGuard work with Java 2? Java 5? Java 6? Java 7?
-Yes, ProGuard supports all JDKs from 1.1 up to and including 6.0. Java 2
+Yes, ProGuard supports all JDKs from 1.1 up to and including 7.0. Java 2
introduced some small differences in the class file format. Java 5 added
-attributes for generics and for annotations. Java 6 introduced preverification
-attributes. ProGuard handles all versions correctly.
+attributes for generics and for annotations. Java 6 introduced optional
+preverification attributes. Java 7 made preverification obligatory and
+introduced support for dynamic languages. ProGuard handles all versions
+correctly.
-
-Does ProGuard work with Java Micro Edition?
+Does ProGuard work with Java Micro Edition?
Yes. ProGuard itself runs in Java Standard Edition, but you can freely
specify the run-time environment at which your programs are targeted,
@@ -144,16 +157,17 @@ preverifier.
ProGuard also comes with an obfuscator plug-in for the JME Wireless
Toolkit.
-
-Does ProGuard work for Google Android code?
+Does ProGuard work for Google Android code?
Yes. Google's dx
compiler converts ordinary jar files into files
that run on Android devices. By preprocessing the original jar files,
ProGuard can significantly reduce the file sizes and boost the run-time
-performance of the code.
+performance of the code. It is distributed as part of the Android SDK.
+DexGuard,
+ProGuard's closed-source sibling for Android, offers additional
+optimizations and more application protection.
-
-Does ProGuard work for Blackberry code?
+Does ProGuard work for Blackberry code?
It should. RIM's proprietary rapc
compiler converts ordinary JME
jar files into cod files that run on Blackberry devices. The compiler performs
@@ -163,24 +177,40 @@ percent. However, the rapc
compiler also seems to contain some
bugs. It sometimes fails on obfuscated code that is valid and accepted by other
JME tools and VMs. Your mileage may therefore vary.
-
-Does ProGuard have support for Ant?
+Does ProGuard have support for Ant?
Yes. ProGuard provides an Ant task, so that it integrates seamlessly
-into your Ant build processes. You can still use configurations in
+into your Ant build process. You can still use configurations in
ProGuard's own readable format. Alternatively, if you prefer XML, you
can specify the equivalent XML configuration.
-
-Does ProGuard come with a GUI?
+Does ProGuard have support for Gradle?
+
+Yes. ProGuard also provides a Gradle task, so that it integrates into
+your Gradle build process. You can specify configurations in
+ProGuard's own format or embedded in the Groovy configuration.
+
+Does ProGuard have support for Maven?
+
+ProGuard's jar files are also distributed as artefacts from
+the Maven Central repository. There are some third-party
+plugins that support ProGuard, such as the
+android-maven-plugin and the
+IDFC Maven
+ProGuard Plug-in.
+DexGuard
+also comes with a Maven plugin.
+
+Does ProGuard come with a GUI?
Yes. First of all, ProGuard is perfectly usable as a command-line tool
that can easily be integrated into any automatic build process. For casual
users, there's also a graphical user interface that simplifies creating,
loading, editing, executing, and saving ProGuard configurations.
-
-Does ProGuard handle
+Class.forName
calls?Does ProGuard handle
Yes. ProGuard automatically handles constructs like
Class.forName
calls?Class.forName("SomeClass")
and SomeClass.class
. The
@@ -192,25 +222,24 @@ possible values. They might be read from a configuration file, for instance.
However, ProGuard will note a number of constructs like
"(SomeClass)Class.forName(variable).newInstance()
". These might
be an indication that the class or interface SomeClass
and/or its
-implementations may need to be preserved. The user can adapt his configuration
-accordingly.
+implementations may need to be preserved. The developer can adapt his
+configuration accordingly.
-
-Does ProGuard handle resource files?
+Does ProGuard handle resource files?
Yes. ProGuard copies all non-class resource files, optionally adapting
their names and their contents to the obfuscation that has been applied.
-
-Does ProGuard encrypt strings constants?
+Does ProGuard encrypt string constants?
-No. Storing encrypted string constants in program code is fairly futile, since
-the encryption has to be perfectly reversible by definition. Moreover, the
-decryption costs additional memory and computation at run-time. If this feature
-is ever incorporated, I'll provide a tool to decrypt the strings as well.
+No. String encryption in program code has to be perfectly reversible by
+definition, so it only improves the obfuscation level. It increases the
+footprint of the code. However, by popular demand, ProGuard's
+closed-source sibling for Android, DexGuard, does provide string encryption, along with
+more protection techniques against static and dynamic analysis.
-
-Does ProGuard perform flow obfuscation?
+Does ProGuard perform flow obfuscation?
Not explicitly. Control flow obfuscation injects additional branches into the
bytecode, in an attempt to fool decompilers. ProGuard does not do this,
@@ -218,15 +247,13 @@ in order to avoid any negative effects on performance and size. However, the
optimization step often already restructures the code to the point where most
decompilers get confused.
-
-Does ProGuard support incremental obfuscation?
+Does ProGuard support incremental obfuscation?
Yes. This feature allows you to specify a previous obfuscation mapping file in
a new obfuscation step, in order to produce add-ons or patches for obfuscated
code.
-
-Can ProGuard obfuscate using reserved keywords?
+Can ProGuard obfuscate using reserved keywords?
Yes. You can specify your own obfuscation dictionary, such as a list of
reserved key words, identifiers with foreign characters, random source files,
@@ -234,8 +261,7 @@ or a text by Shakespeare. Note that this hardly improves the obfuscation.
Decent decompilers can automatically replace reserved keywords, and the effect
can be undone fairly easily, by obfuscating again with simpler names.
-
-Can ProGuard reconstruct obfuscated stack traces?
+Can ProGuard reconstruct obfuscated stack traces?
Yes. ProGuard comes with a companion tool, ReTrace, that can
'de-obfuscate' stack traces produced by obfuscated applications. The
@@ -245,10 +271,11 @@ names is presented for each obfuscated method name that has an ambiguous
reverse mapping. Please refer to the ProGuard User
Manual for more details.
-
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/GPL_exception.html b/docs/GPL_exception.html
index 0a44d66..d610af8 100644
--- a/docs/GPL_exception.html
+++ b/docs/GPL_exception.html
@@ -7,7 +7,7 @@
Special Exception to the GNU General Public License
-
and distribute linked combinations including the two. You must obey the GNU
General Public License in all respects for all of the code used other than
diff --git a/docs/acknowledgements.html b/docs/acknowledgements.html
index af19461..14fdc74 100644
--- a/docs/acknowledgements.html
+++ b/docs/acknowledgements.html
@@ -1,10 +1,21 @@
-
+
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/alternatives.html b/docs/alternatives.html
index fa5db0c..7aeffad 100644
--- a/docs/alternatives.html
+++ b/docs/alternatives.html
@@ -1,10 +1,21 @@
-
+
-
Eric Lafortune
+Eric Lafortune
ProGuard
-
-
-
-
+
+
+
+
Free (GPL)
-Jochen Hoenicke
Jode
-
-
-
-
+
+
+
+ Free (GPL)
-
-
NQ4
-Joga
-
-
-
-
-Free (no source)
-
Nate Nystrom
Bloat
-
-
-
-
+
+
+
+Free
-Hidetoshi Ohuchi
Jarg
-
-
-
-
+
+
+
+ Free (BSD)
-
-
Alexander Shvets
-CafeBabe
-
-
-
-
-Free
-
-yWorks
yGuard
-
-
-
-
+
+
+
+ Free (no source)
-
-
Christian Grothoff
-Jamit
-
-
-
-
-Free (GPL)
-
Mojo
Minijar
-
-
-
-
+
+
+
+Free (Apache)
RiggsHill Software
GenJar
-
-
-
-
+
+
+
+Free (Apache)
+
+Apache
-Ant Classfileset
-
-
-
-
+Ant Classfileset
+
+
+
+
+Free (Apache)
+
+
+Carsten Elton Sørensen
+Treeshaker
+
+
+
+Free (Apache)
+
+
Jörg Spieler
+UCDetector
+
+
+
+
+Free (EPL)
+
Romain Guy
Harvester
-
-
-
-
+
+
+
+Free (BSD)
-
Emeric Vernat
-DCD
-
-
-
-
+Emeric Vernat
+DCD
+
+
+
+Free (LGPL)
-
-Cristiano Sadun
Pack
-
-
-
-
-Free (LGPL)
-
-
Brian Alliet
-Gcclass
-
-
-
-
+
+
+
+Free (LGPL)
Sable
Soot
-
-
-
-
+
+
+
+Free (LGPL)
-
-Konstantin Knizhnik
JavaGO
-
-
-
-
-Free
-
-
Haruaki Tamada
-DonQuixote
-
-
-
-
+
+
+
+Free
+Sable
JBCO
-
-
-
-
+
+
+
+ Free (LGPL)
+
+
Jeffrey Wheaton
+ClassEncrypt
+
+
+
+
+Free (GPL)
+
Thorsten Heit
JavaGuard
-
-
-
-
+
+
+
+ Free (LGPL)
-Patrick Mueller
Mwobfu
-
-
-
-
+
+
+
+ Free (GPL)
-
-
Elegant Software
-JMangle
-
-
-
-
-Free
-
BebboSoft
-Bb_mug
-
-
-
-
+Bb_mug
+
+
+
+ Free (no source)
-
Dr. Java
-Marvin Obfuscator
-
-
-
-
-Free (no source)
+Vít Šesták
+Preverifier
+
+
+
+
+ Free (EPL)
-
IBM
-WSDD
-
-
-
-
+Saikoa
+DexGuard
+
+
+
+ Commercial
PreEmptive
DashOPro
-
-
-
-
+
+
+
+ Commercial
-
-Zelix
KlassMaster
-
-
-
-
-Commercial
-
-
S5 Systems
-jPresto
-
-
-
-
+
+
+
+ Commercial
Sophia Cradle
SophiaCompress
-
-
-
-
+
+
+
+ Commercial
-
-
-RetroLogic
-RetroGuard
-
-
-
-
-Commercial
-
-
CodingArt
-CodeShield
-
-
-
-
+Eduardo Coca
+Shield4J
+
+
+
+ Commercial
-
-Eastridge Technology
Jshrink
-
-
-
-
-Commercial
-
-
Helseth
-JObfuscator
-
-
-
-
+
+
+
+ Commercial
-
-LeeSoftware
Smokescreen Obfuscator
-
-
-
-
-Commercial
-
-
Vega Technologies
-JZipper
-
-
-
-
+
+
+
+ Commercial
Innaworks
-mBooster
-
-
-
-
+ mBooster
+
+
+
+
Commercial
Sergey Sverdlov
J.Class Optimizer
-
-
-
-
+
+
+
+Commercial
Smardec
-Allatori
-
-
-
-
+Allatori
+
+
+
+ Commercial
U. of Arizona
SandMark
-
-
-
-
+
+
+
+ Commercial
-
Force 5
-JCloak
-
-
-
-
+Zenofx
+ClassGuard
+
+
+
+ Commercial
-
Semantic Designs
-Obfuscator
-
-
-
-
+BIS Guard & Co.
+Java Antidecompiler
+
+
+
+ Commercial
-
Duckware
-Jobfuscate
-
-
-
-
+Force 5
+JCloak
+
+
+
+ Commercial
-
JProof
-JProof
-
-
-
-
+Semantic Designs
+Obfuscator
+
+
+
+ Commercial
-
GITS
-Blurfuscator
-
-
-
-
+Duckware
+Jobfuscate
+
+
+
+ Commercial
-
ChainKey
-Java Code Protector
-
-
-
-
+Secureteam
+Jfuscator
+
+
+
+ Commercial
-
Alain Moran
-flmObf
-
-
-
-
-Free (BSD)
+Arxan
+GuardIT
+
+
+
+
+Commercial
Vasile Calmatui
VasObfuLite
-
-
-
-
+
+
+
+ Free
+IBM AlphaWorks
JAX
-
-
-
-
+
+
+
+ (discontinued)
+
+
NQ4
+Joga
+
+
+
+
+(discontinued?)
+
+
+Markus Jansen
Jopt
-
-
-
-
+
+
+
+
+(disappeared?)
+
+
+
+Alexander Shvets
+CafeBabe
+
+
+
+
+(disappeared?)
+
+
+
+Brian Alliet
+Gcclass
+
+
+
+
+(disappeared?)
+
+
+
+Christian Grothoff
+Jamit
+
+
+
+
+(disappeared?)
+
+
+
+Haruaki Tamada
+DonQuixote
+
+
+
+
+(disappeared?)
+
+
+
+Bajie
+JCMP
+
+
+
+
+(disappeared?)
+
+
Elegant Software
+JMangle
+
+
+
+ (disappeared?)
Eron Jokipii
Jobe
-
-
-
-
+
+
+
+ (disappeared?)
JRC
DeCaf
-
-
-
-
+
+
+
+ (disappeared?)
-
+Bajie
-JCMP
-
-
-
-
+Dr. Java
+Marvin Obfuscator
+
+
+
+ (disappeared?)
+
+
+IBM
+WSDD
+
+
+
+
+Commercial (discontinued?)
+
+
+
S5 Systems
+jPresto
+
+
+
+
+Commercial (discontinued?)
+
Plumb Design
Condensity
-
-
-
-
+
+
+
+ Commercial (discontinued)
+
+4th Pass
SourceGuard
-
-
-
-
+
+
+
+
+Commercial (discontinued?)
+
+
CodingArt
+CodeShield
+
+
+
+ Commercial (discontinued?)
Software4j
Obfuscate4j
-
-
-
-
+
+
+
+ Commercial (discontinued?)
JAMM Consulting
ObfuscatePro
-
-
-
-
+
+
+
+ Commercial (discontinued?)
JDevelop
JSCO
-
-
-
-
+
+
+
+ Commercial (discontinued?)
+4Fang
JMix
-
-
-
-
+
+
+
+ Commercial (discontinued?)
+
+
+RetroLogic
+RetroGuard
+
+
+
+
+Commercial (disappeared?)
+
+
+
+Helseth
+JObfuscator
+
+
+
+
+Commercial (disappeared?)
+
+
+
+Vega Technologies
+JZipper
+
+
+
+
+Commercial (disappeared?)
+
+
+
+JProof
+JProof
+
+
+
+
+Commercial (disappeared?)
+
+
+
ChainKey
+Java Code Protector
+
+
+
+
+Commercial (disappeared?)
+
2LKit
2LKit Obfuscator
-
-
-
-
+
+
+
+ Commercial (disappeared?)
WingSoft
WingGuard
-
-
-
-
+
+
+
+ Commercial (disappeared?)
+
+HashJava
HashJava
-
-
-
-
+
+
+
+
+Commercial (disappeared?)
+
+
@@ -647,10 +748,11 @@ below is incorrect.
GITS
+Blurfuscator
+
+
+
+ Commercial (disappeared?)
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/android_shades.png b/docs/android_shades.png
new file mode 100644
index 0000000..96e54f0
Binary files /dev/null and b/docs/android_shades.png differ
diff --git a/docs/dexguard.png b/docs/dexguard.png
new file mode 100644
index 0000000..ed8f1f4
Binary files /dev/null and b/docs/dexguard.png differ
diff --git a/docs/downloads.html b/docs/downloads.html
index ebd1b28..2baa929 100644
--- a/docs/downloads.html
+++ b/docs/downloads.html
@@ -1,11 +1,22 @@
-
+
+
+
+
+
+
+
+
+optimize.conservatively
to allow
+ for instructions intentionally throwing NullPointerException
,
+ ArrayIndexOutOfBoundsException
, or
+ ClassCastException
without other useful effects.
+
+
+
+
+-keepparameternames
or -keepattributes
.
+
+
+
+
+-keepclassmembers
+ without specific class or class members.
+
+
+
+
+-keep
options.
+
+
+
-keepparameternames
.
+-dontskipnonpubliclibraryclasses
is now set by default. Added
+ -skipnonpubliclibraryclasses
as an option.
+
@@ -511,10 +690,11 @@ Upgrade considerations:
RetroGuard.
-
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/feedback.html b/docs/feedback.html
index a7e770b..dd9c509 100644
--- a/docs/feedback.html
+++ b/docs/feedback.html
@@ -1,4 +1,4 @@
-
+
@@ -6,52 +6,63 @@
Feedback
-By now, I've invested a fair amount of time in ProGuard. You can help
-by providing feedback! If you have problems, bugs, bug fixes, ideas,
+By now, I've invested an enormous amount of time in ProGuard. You can
+help by providing feedback! If you have problems, bugs, bug fixes, ideas,
encouragements, etc., please let me know:
-
+
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/index.html b/docs/index.html
index 771bb6a..ba40d16 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,4 +1,4 @@
-
+
@@ -11,18 +11,38 @@
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
+
+
-Copyright © 2002-2009
-Eric Lafortune.
+Copyright © 2002-2013
+Eric Lafortune.
diff --git a/docs/luciadlogo.png b/docs/luciadlogo.png
deleted file mode 100644
index 0147ce3..0000000
Binary files a/docs/luciadlogo.png and /dev/null differ
diff --git a/docs/main.html b/docs/main.html
index e988c79..988d87c 100644
--- a/docs/main.html
+++ b/docs/main.html
@@ -1,4 +1,4 @@
-
+
@@ -8,6 +8,16 @@
ProGuard's main advantage compared to other Java obfuscators is probably its compact template-based configuration. A few intuitive command -line options or a simple configuration file are usually sufficient. For -instance, the following configuration option preserves all applets in a jar: -
- -keep public class * extends java.applet.Applet --The user manual explains all available options and shows more examples of this +line options or a simple configuration file are usually sufficient. +The user manual explains all available options and shows examples of this powerful configuration style.
ProGuard is fast. It only takes seconds to process programs and @@ -51,42 +57,48 @@ libraries of several megabytes. The results section presents actual figures for a number of applications.
ProGuard is a command-line tool with an optional graphical user -interface. It also comes with plugins for Ant and for the JME Wireless -Toolkit. +interface. It also comes with plugins for Ant, for Gradle, and for the JME +Wireless Toolkit.
-Version 4.0 introduced preverification and more bytecode optimizations. Please -report any problems, so they can be fixed soon. + + +ProGuard now has a sibling optimizer and obfuscator for Android: +DexGuard. It +focuses on code protection, with additional features like string encryption +and class encryption. It directly targets Dalvik bytecode and streamlines the +Android build process.
The following sections provide more detailed information:-There are three ways to configure the ProGuard task: using an external -configuration file, using embedded ProGuard configuration options, or using -the equivalent XML configuration tags. These three ways can be combined, -depending on practical circumstances and personal preference. +There are three ways to configure the ProGuard task: +
Secondly, the use of <
and >
characters would
-upset the structure of the XML build file. Environment variables are now
-enclosed by an opening ${
and a closing }
. This
-syntax also allows you to use Ant properties within the ProGuard
-configuration. Other occurrences of <
and >
-have to be encoded as <
and >
.
+upset the structure of the XML build file. Environment variables can be
+specified with the usual Ant style ${...}
, instead of the ProGuard
+style <...>
. Other occurrences of <
and
+>
have to be encoded as <
and
+>
respectively.
examples/ant
directory of the ProGuard distribution.
<proguard>
task and the
<proguardconfiguration>
task can have the following
@@ -120,13 +134,14 @@ elements:
configuration
= "filename"configuration
element.skipnonpubliclibraryclasses
+skipnonpubliclibraryclasses
= "boolean"
- (default = true)skipnonpubliclibraryclassmembers
@@ -242,6 +257,11 @@ elements:
keepparameternames
+ = "boolean"
+ (default = false)renamesourcefileattribute
= "string"
(default = none)microedition
= "boolean"
(default = false)verbose
= "boolean"
@@ -305,7 +325,7 @@ elements:
<outjar
class_path
/>
<libraryjar
@@ -436,23 +456,27 @@ elements:
filter. Only use this option if you know what you're doing!
<configuration refid =
"ref_id"
+ />
<configuration file =
"name"
/>
<proguardconfiguration>
task (or
- <proguard>
task) with the attribute id
=
- "ref_id". Note that only the nested elements of this configuration
- are considered, not the attributes. Also note: for reading ProGuard-style
- configuration files, use the configuration
- attribute.<proguard>
task) with attribute id
=
+ "ref_id". Only the nested elements of this configuration are
+ considered, not the attributes.
+
+ The second form includes the ProGuard-style configuration from the specified
+ file. The element is actually a fileset
element and supports
+ all of its attributes and nested elements, including multiple files.
+
path
elements, so they can have any of the
+standard path
attributes and nested elements. The most common
+attributes are:
annotation
= "annotation_name"type
= "type"extendsannotation
= "annotation_name"extends
= "class_name"annotation
= "annotation_name"type
= "type"examples
directory of the ProGuard distribution.
-
-proguard.pro
and then type:
+myconfig.pro
, which can be used
+with
-java -jar proguard.jar @proguard.pro +bin/proguard @myconfig.pro
-The configuration file would contain the following options: +The configuration file specifies the input, the output, and the entry points +of the application:
--injars proguard.jar --outjars proguard_out.jar +-injars myapplication.jar +-outjars myapplication_out.jar -libraryjars <java.home>/lib/rt.jar --printmapping proguard.map +-printmapping myapplication.map --keep public class proguard.ProGuard { +-keep public class mypackage.MyMain { public static void main(java.lang.String[]); }
-Note the use of the <java.home>
system property; it is
-replaced automatically.
-
-Also note that all type names are fully specified:
-proguard.ProGuard
and java.lang.String[]
.
+Note the use of the <java.home>
system property. ProGuard
+automatically replaces it when parsing the file.
+The -keep
option specifies the
+entry point of the application that has to be preserved.
The access modifiers public
and static
are not
really required in this case, since we know a priori that the specified class
and method have the proper access flags. It just looks more familiar this way.
+Note that all type names are fully specified:
+mypackage.MyMain
and java.lang.String[]
.
+
We're writing out an obfuscation mapping file with -printmapping
, for
de-obfuscating any stack traces later on, or for incremental obfuscation of
@@ -103,11 +122,10 @@ href="#native">native methods, callback methods,
enumerations, serializable
classes, bean classes, annotations, and resource
-files. For processing 'simple' applications like ProGuard, that is not
-required.
+files.
+
+
mypackage.MyApplet
:
@@ -129,15 +147,15 @@ classes, bean classes, annotations, and resource files. - -A typical midlet
+A typical midlet
+ These options shrink, optimize, obfuscate, and preverify the midletmypackage.MyMIDlet
:-injars in.jar -outjars out.jar --libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar --libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -overloadaggressively -repackageclasses '' -allowaccessmodification @@ -172,8 +190,8 @@ methods and resource files. Note that you will still have to adapt the midlet jar size in the corresponding jad file; ProGuard doesn't do that for you. - -A typical Java Card applet
+A typical Java Card applet
+ These options shrink, optimize, and obfuscate the Java Card appletmypackage.MyApplet
:@@ -192,8 +210,8 @@ The configuration is very similar to the configuration for midlets, except that it now targets the Java Card run-time environment. This environment doesn't have java.lang.Class, so we're telling ProGuard not to worry about it. - -A typical xlet
+A typical xlet
+ These options shrink, optimize, and obfuscate the xletmypackage.MyXlet
:@@ -212,15 +230,16 @@ These options shrink, optimize, and obfuscate the xlet The configuration is very similar to the configuration for midlets, except that it now targets the CDC run-time environment with the Java TV API. - -A typical Android application
-These options shrink, optimize, and obfuscate the simple Android application -based on a single activitymypackage.MyActivity
: +A simple Android activity
+ +These options shrink, optimize, and obfuscate the single Android +activitymypackage.MyActivity
:--injars in.jar --outjars out.jar --libraryjars /usr/local/java/android-1.5_r1/platforms/android-1.5/android.jar --overloadaggressively +-injars bin/classes +-outjars bin/classes-processed.jar +-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar + +-dontpreverify -repackageclasses '' -allowaccessmodification -optimizations !code/simplification/arithmetic @@ -228,27 +247,180 @@ based on a single activitymypackage.MyActivity
: -keep public class mypackage.MyActivity-The configuration is very similar to the configuration for midlets, except that -it now targets the Android run-time environment. +We're targeting the Android run-time and keeping the activity as an entry +point. +
+Preverification is irrelevant for the dex compiler and the Dalvik VM, so we +can switch it off with the +
-dontpreverify
option.The
-optimizations
option disables some arithmetic simplifications that Dalvik 1.0 and 1.5 can't handle. +Note that the Dalvik VM also can't +handle aggressive overloading +(of static fields).If applicable, you should add options for processing native -methods, callback methods, and resource files. +methods, callback methods, +enumerations, +annotations, and +resource files. + +
A complete Android application
+ + +The Ant and Eclipse build processes of the Android SDK already integrate +ProGuard by default, with all the proper settings. You only need to enable +ProGuard (for release builds), by uncommenting the line +"proguard.config=.....
" in the file +project.properties
(created or updated by Android SDK revision 17 +or higher). Notes: +
proguard-project.txt
,...) contain
+ the necessary settings for your application.${sdk.dir}/tools/proguard/proguard-android-optimize.txt
+ instead of the default
+ ${sdk.dir}/tools/proguard/proguard-android.txt
.+For more information, you can consult the official Developer +Guide in the Android SDK. +
+If you're constructing a build process from scratch: these options shrink, +optimize, and obfuscate all public activities, services, broadcast receivers, +and content providers from the compiled classes and external libraries: +
+-injars bin/classes +-injars libs +-outjars bin/classes-processed.jar +-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar + +-dontpreverify +-repackageclasses '' +-allowaccessmodification +-optimizations !code/simplification/arithmetic +-keepattributes *Annotation* + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider + +-keep public class * extends android.view.View { + public <init>(android.content.Context); + public <init>(android.content.Context, android.util.AttributeSet); + public <init>(android.content.Context, android.util.AttributeSet, int); + public void set*(...); +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.content.Context { + public void *(android.view.View); + public void *(android.view.MenuItem); +} + +-keepclassmembers class * implements android.os.Parcelable { + static android.os.Parcelable$Creator CREATOR; +} + +-keepclassmembers class **.R$* { + public static <fields>; +} + +-keepclassmembers class * { + @android.webkit.JavascriptInterface <methods>; +} ++
+Most importantly, we're keeping all fundamental classes that may be referenced
+by the AndroidManifest.xml
file of the application. If your
+manifest file contains other classes and methods, you may have to specify
+those as well.
+
+We're keeping annotations, since they might be used by custom
+RemoteViews
.
+
+We're keeping any custom View
extensions and other classes with
+typical constructors, since they might be referenced from XML layout files.
+
+We're also keeping possible onClick
handlers in
+custom Context
extensions, since they might be referenced from
+XML layout files.
+
+We're also keeping the required static fields in Parcelable
+implementations, since they are accessed by introspection.
+
+We're keeping the static fields of referenced inner classes of auto-generated
+ R
classes, just in case your code is accessing those fields by
+introspection. Note that the compiler already inlines primitive fields, so
+ProGuard can generally remove all these classes entirely anyway (because the
+classes are not referenced and therefore not required).
+
+Finally, we're keeping annotated Javascript interface methods, so they can be +exported and accessed by their original names. Javascript interface methods +that are not annotated (in code targeted at Android versions older than 4.2) +still need to be preserved manually. +
+If you're using additional Google APIs, you'll have to specify +those as well, for instance: +
+-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar ++
+If you're using Google's optional License Verification Library, you can
+obfuscate its code along with your own code. You do have to preserve
+its ILicensingService
interface for the library to work:
+
+-keep public interface com.android.vending.licensing.ILicensingService ++
+If you're using the Android Compatibility library, you should add the +following line, to let ProGuard know it's ok that the library references some +classes that are not available in all versions of the API: +
+-dontwarn android.support.** ++
+If applicable, you should add options for processing native
+methods, callback methods,
+enumerations,
+and resource files. You may also want to add
+options for producing useful stack traces and
+to remove logging. You can find a complete sample
+configuration in examples/android.pro
in the ProGuard
+distribution.
+
+
-injars in.jar -outjars out.jar -libraryjars <java.home>/lib/rt.jar -printmapping out.map +-keepparameternames -renamesourcefileattribute SourceFile -keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,*Annotation*,EnclosingMethod @@ -273,6 +445,7 @@ serialization code: -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); @@ -289,12 +462,12 @@ The-keepclassmembernames
option for theclass$
methods is not strictly necessary. These methods are inserted by thejavac
compiler and the -jikes
compiler respectively, to implement the.class
-construct. ProGuard will automatically detect them and deal with them, even -when their names have been obfuscated. However, older versions of ProGuard and -other obfuscators may rely on the original method names. It may therefore be -helpful to preserve them, in case these other obfuscators are ever used for -further obfuscation of the library. +jikes
compiler respectively, in JDK 1.2 and older, to implement +the.class
construct. ProGuard will automatically detect them and +deal with them, even when their names have been obfuscated. However, other +obfuscators may rely on the original method names. It may therefore be helpful +to preserve them, in case these other obfuscators are ever used for further +obfuscation of the library.The "Exceptions" attribute has to be preserved, so the compiler knows which exceptions methods may throw. @@ -307,6 +480,11 @@ classes otherwise. The "Signature" attribute is required to be able to access generic types when compiling in JDK 5.0 and higher.
+The
-keepparameternames
+option keeps the parameter names in the "LocalVariableTable" and +"LocalVariableTypeTable" attributes of public library methods. Some IDEs can +present these names to the developers who use the library. +Finally, we're keeping the "Deprecated" attribute and the attributes for producing useful stack traces.
@@ -316,8 +494,8 @@ href="#serializable">serializable classes, and annotations, which are all discussed in their respective examples. - -
All possible applications in the input jars
+All possible applications in the input jars
+ These options shrink, optimize, and obfuscate all public applications inin.jar
:@@ -347,8 +525,8 @@ classes, bean classes, annotations, and resource files. - -All possible applets in the input jars
+All possible applets in the input jars
+ These options shrink, optimize, and obfuscate all public applets inin.jar
:@@ -372,15 +550,15 @@ classes, bean classes, annotations, and resource files. - -All possible midlets in the input jars
+All possible midlets in the input jars
+ These options shrink, optimize, obfuscate, and preverify all public midlets inin.jar
:-injars in.jar -outjars out.jar --libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar --libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -overloadaggressively -repackageclasses '' -allowaccessmodification @@ -412,8 +590,8 @@ methods and resource files. Note that you will still have to adapt the midlet jar size in the corresponding jad file; ProGuard doesn't do that for you. - -All possible Java Card applets in the input jars
+All possible Java Card applets in the input jars
+ These options shrink, optimize, and obfuscate all public Java Card applets inin.jar
:@@ -435,8 +613,8 @@ interface. The-printseeds
option prints out which applets exactly will be preserved. - -All possible xlets in the input jars
+All possible xlets in the input jars
+ These options shrink, optimize, and obfuscate all public xlets inin.jar
:@@ -458,38 +636,8 @@ We're simply keeping all classes that implement theXlet
interface. The-printseeds
option prints out which xlets exactly will be preserved. - -All possible Android applications in the input jars
-These options shrink, optimize, and obfuscate all public activities, services, -broadcast receivers, and content providers inin.jar
: ---injars in.jar --outjars out.jar --libraryjars /usr/local/java/android-1.5_r1/platforms/android-1.5/android.jar --overloadaggressively --repackageclasses '' --allowaccessmodification --optimizations !code/simplification/arithmetic --printseeds - --keep public class * extends android.app.Activity --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider ---We're keeping all classes that extend the base classes that may be referenced -by the
AndroidManifest.xml
file of the application. --The
-printseeds
option prints -out which implementations exactly will be preserved. --If applicable, you should add options for processing native -methods, callback methods, and resource files. +
All possible servlets in the input jars
- -All possible servlets in the input jars
These options shrink, optimize, and obfuscate all public servlets inin.jar
:@@ -521,8 +669,77 @@ classes, bean classes, annotations, and resource files. - -- -Processing native methods
+Scala applications with the Scala runtime
+ +These options shrink, optimize, and obfuscate all public Scala applications in +in.jar
: ++-injars in.jar +-injars /usr/local/java/scala-2.9.1/lib/scala-library.jar +-outjars out.jar +-libraryjars <java.home>/lib/rt.jar + +-dontwarn scala.** + +-keepclasseswithmembers public class * { + public static void main(java.lang.String[]); +} + +-keep class * implements org.xml.sax.EntityResolver + +-keepclassmembers class * { + ** MODULE$; +} + +-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { + long eventCount; + int workerCounts; + int runControl; + scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; + scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; +} + +-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { + int base; + int sp; + int runState; +} + +-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { + int status; +} + +-keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { + scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; + scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; + scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; +} +++The configuration is essentially the same as +for processing applications, because Scala is +compiled to ordinary Java bytecode. However, the example processes the Scala +runtime library as well. The processed jar can be an order of magnitude +smaller and a few times faster than the original code (for the Scala code +examples, for instance). +
+The
-dontwarn
option tells +ProGuard not to complain about some artefacts in the Scala runtime, the way it +is compiled by thescalac
compiler (at least in Scala 2.9.1 and +older). Note that this option should always be used with care. ++The additional
-keep
+options make sure that some classes and some fields that are accessed by means +of introspection are not removed or renamed. ++If applicable, you should add options for processing native +methods, callback methods, enumerations, serializable +classes, bean classes, annotations, and resource +files. +
Processing native methods
+ If your application, applet, servlet, library, etc., contains native methods, you'll want to preserve their names and their classes' names, so they can still be linked to the native library. The following additional option will @@ -543,8 +760,8 @@ the classes or class members that are invoked by the native code. These are entry points, which you'll have to specify explicitly. Callback methods are discussed below as a typical example. - -Processing callback methods
+Processing callback methods
+ If your application, applet, servlet, library, etc., contains callback methods, which are called from external code (native code, scripts,...), you'll want to preserve them, and probably their classes too. They are just @@ -559,8 +776,8 @@ the following option will keep the callback class and method:This will preserve the given class and method from being removed or renamed. - -
Processing enumeration classes
+Processing enumeration classes
+ If your application, applet, servlet, library, etc., contains enumeration classes, you'll have to preserve some special methods. Enumerations were introduced in Java 5. The java compiler translates enumerations into classes @@ -576,8 +793,8 @@ removed or obfuscated: }Processing serializable classes
+Processing serializable classes
+ More complex applications, applets, servlets, libraries, etc., may contain classes that are serialized. Depending on the way in which they are used, they may require special attention: @@ -589,6 +806,7 @@ may require special attention:-keepclassmembers class * implements java.io.Serializable { + private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); @@ -602,8 +820,7 @@ may require special attention: option makes sure that any serialization methods are kept. By using this option instead of the basic-keep
option, we're not forcing preservation of all serializable classes, just preservation - of the listed members of classes that are actually used. -+ of the listed members of classes that are actually used.
<fields>
line preserves all non-static,
non-transient fields, with their original names. The introspection of the
serialization process and the de-serialization process will then find
- consistent names.
+ consistent names.serialVersionUID
fields. I imagine the
@@ -651,7 +868,7 @@ may require special attention:
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
- static final java.io.ObjectStreamField[] serialPersistentFields;
+ private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
@@ -668,7 +885,7 @@ may require special attention:
interfaces of the serializable classes (using something like "-keep
interface MyInterface
"), since these names are also used when
computing the UID. A fast but sub-optimal alternative would be simply
- keeping all interfaces with "-keep interface *
".
+ keeping all interfaces with "-keep interface *
".
@@ -679,8 +896,8 @@ the Serialization
interface, yet only a small number may actually
ever be serialized. Knowing your application and tuning the configuration
often produces more compact results.
-
-
If there are too many elements to list explicitly, wildcards in class names
-and method signatures might be helpful. This example should encompasses all
-possible setters and getters in classes in the package mybeans
:
+and method signatures might be helpful. This example preserves all possible
+setters and getters in classes in the package mybeans
:
-keep class mybeans.** { void set*(***); @@ -715,8 +932,8 @@ The '- -***
' wildcard matches any type (primitive or non-primitive, array or non-array). The methods with the 'int
' arguments matches properties that are lists. - -Processing annotations
+Processing annotations
+ If your application, applet, servlet, library, etc., uses annotations, you may want to preserve them in the processed output. Annotations are represented by attributes that have no direct effect on the execution of the code. However, @@ -744,8 +961,8 @@ has to be preserved as well: -keepattributes EnclosingMethod
Driver
interface.
Since they are often created dynamically, you may want to preserve any
implementations that you are processing as entry points:
@@ -758,8 +975,8 @@ This option also gets rid of the note that ProGuard prints out about
instantiating a driver in your code (without necessarily implementing any
drivers yourself).
-
-ComponentUI
class. For some reason, these have to contain a
static method createUI
, which the Swing API invokes using
@@ -773,8 +990,8 @@ point, for instance like this:
This option also keeps the classes themselves. - -
rmic
tool. If that is not
possible, you may want to try something like this:
@@ -798,8 +1015,29 @@ The Exceptions
attribute has to be kept too, because the RMI
handling code performs introspection to check whether the method signatures
are compatible.
-
-@Resource
. The container applies
+introspection, even accessing private class members directly. It typically
+constructs a resource name based on the type name and the class member name.
+We then have to avoid that such class members are removed or renamed:
++-keepclassmembers class * { + @javax.annotation.Resource *; +} ++
+The Spring framework has another similar annotation @Autowired
:
+
+-keepclassmembers class * { + @org.springframework.beans.factory.annotation.Autowired *; +} ++ +
+If you're merging several input jars into a single output jar, you'll have to +pick one, typically by specifying filters: +
+-injars in1.jar +-injars in2.jar(!META-INF/MANIFEST.MF) +-injars in3.jar(!META-INF/MANIFEST.MF) +-outjars out.jar ++
+The filters will let ProGuard copy the manifest file from the first jar and +ignore any manifest files in the second and third input jars. Note that +ProGuard will leave the order of the files in the jars unchanged; manifest +files are not necessarily put first. + +
@@ -844,8 +1105,8 @@ their original names, so we're saving the mapping to a fileout.map
. The information can then be used by the ReTrace tool to restore the original stack trace. - -Obfuscating package names
+Obfuscating package names
+ Package names can be obfuscated in various ways, with increasing levels of obfuscation and compactness. For example, consider the following classes:@@ -951,8 +1212,37 @@ Note that not all levels of obfuscation of package names may be acceptable for all code. Notably, you may have to take into account that your application may contain resource files that have to be adapted. - -Restructuring the output archives
+Removing logging code
+ +You can let ProGuard remove logging code. The trick is to specify that the +logging methods don't have side-effects — even though they actually do, +since they write to the console or to a log file. ProGuard will take your word +for it and remove the invocations (in the optimization step) and if possible +the logging classes and methods themselves (in the shrinking step). ++For example, this configuration removes invocations of the Android logging +methods: +
+-assumenosideeffects class android.util.Log { + public static boolean isLoggable(java.lang.String, int); + public static int v(...); + public static int i(...); + public static int w(...); + public static int d(...); + public static int e(...); +} +++The wildcards are a shortcut to match all versions of the methods. +
+Note that you generally can't remove logging code that uses +
System.out.println
, since you would be removing all invocations +ofjava.io.PrintStream#println
, which could break your +application. You can work around it by creating your own logging methods and +let ProGuard remove those. + +Restructuring the output archives
+ In simple applications, all output classes and resources files are merged into a single jar. For example:@@ -1022,12 +1312,12 @@ This grouping, archiving, and flattening can be arbitrarily complex. ProGuard always tries to package output archives in a sensible way, reconstructing the input entries as much as required. - -- -Filtering the input and the output
+Filtering the input and the output
-If you want even greater control, you can add filters to the input and the -output, filtering out zips, ears, wars, jars, and/or ordinary files. For -example, if you want to disregard certain files from an input jar: +If you want even greater control, you can add +filters to the input and the output, +filtering out zips, ears, wars, jars, and/or ordinary files. For example, if +you want to disregard certain files from an input jar:-injars in.jar(!images/**) -outjars out.jar @@ -1080,10 +1370,10 @@ files tocode_out.jar
, and all remaining files toresources_out.jar
.Again, the filtering can be arbitrarily complex, especially when combined with -the grouping of input and output. +grouping input and output. + +
Processing multiple applications at once
- -Processing multiple applications at once
You can process several dependent or independent applications (or applets, midlets,...) in one go, in order to save time and effort. ProGuard's input and output handling offers various ways to keep the output nicely structured. @@ -1100,10 +1390,10 @@ just the input and output options:After processing, the directory
processed_applications
will -contain the processed application jars, with their original names. +contain processed versions of application jars, with their original names. + +Incremental obfuscation
- -Incremental obfuscation
After having processed an application, e.g. ProGuard itself, you can still incrementally add other pieces of code that depend on it, e.g. the ProGuard GUI: @@ -1149,18 +1439,18 @@ jar as a library jar: }Preverifying class files for Java Micro Edition
+Preverifying class files for Java Micro Edition
+ Even if you're not interested in shrinking, optimizing, and obfuscating your midlets, as shown in the midlets example, you can still use ProGuard to preverify the class files for Java Micro Edition. ProGuard -produces slightly more compact results compared to the traditional external +produces slightly more compact results than the traditional external preverifier.-injars in.jar -outjars out.jar --libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar --libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar +-libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar -dontshrink -dontoptimize @@ -1175,8 +1465,8 @@ href="usage.html#microedition">-microedition
option. Note that we don't need any-keep
options to specify entry points; all class files are simply preverified. - -Upgrading class files to Java 6
+Upgrading class files to Java 6
+ The following options upgrade class files to Java 6, by updating their internal version numbers and preverifying them. The class files can then be loaded more efficiently by the Java 6 Virtual Machine. @@ -1198,8 +1488,8 @@ automatically be preverified for Java 6 as a result. Note that we don't need any-keep
options to specify entry points; all class files are simply updated and preverified. - -Finding dead code
+Finding dead code
+ These options list unused classes, fields, and methods in the applicationmypackage.MyApplication
:@@ -1232,8 +1522,8 @@ that keeps those fields a priori, in order to avoid having them listed: }- -Printing out the internal structure of class files
+Printing out the internal structure of class files
+ These options print out the internal structure of all class files in the input jar:@@ -1250,8 +1540,7 @@ jar: Note how we don't need to specify the Java run-time jar, because we're not processing the input jar at all. - -Using annotations to configure ProGuard
+Using annotations to configure ProGuard
The traditional ProGuard configuration allows to keep a clean separation between the code and the configuration for shrinking, optimization, and @@ -1291,12 +1580,12 @@ href="#annotations">annotations.The directory
examples/annotations
contains more examples that illustrate some of the possibilities. --
+
+ -Copyright © 2002-2009 -Eric Lafortune. +Copyright © 2002-2013 +Eric Lafortune. diff --git a/docs/manual/gradle.html b/docs/manual/gradle.html new file mode 100644 index 0000000..3e0e500 --- /dev/null +++ b/docs/manual/gradle.html @@ -0,0 +1,545 @@ + + + + + + +Gradle Task + + + + +Gradle Task
+ +ProGuard can be run as a task in the Java-based build tool Gradle +(version 1.3 or higher). ++ +Before you can use the
proguard
task, you have to make sure +Gradle can find it in its class path at build time. One way is to add the +following line to yourbuild.gradle
file: ++ +
+buildscript { + repositories { + flatDir dirs: '/usr/local/java/proguard/lib' + } + dependencies { + classpath ':proguard' + } +} +++ +Please make sure the class path is set correctly for your system. +
+ +You can then define a task: +
+
+task myProguardTask(type: proguard.gradle.ProGuardTask) { + ..... +} +++ +The embedded configuration is much like a standard ProGuard configuration. +Notable similarities and differences: +
+You can find some sample build files in the examples/gradle
+directory of the ProGuard distribution.
+
+If you prefer a more verbose configuration derived from the Ant task, you can +import the Ant task as a Gradle task. + +
configuration
+ filesinjars
+ class_pathoutjars
+ class_pathlibraryjars
+ class_pathskipnonpubliclibraryclasses
dontskipnonpubliclibraryclassmembers
keepdirectories
+ ['directory_filter']target
+ 'version'forceprocessing
keep
+ [modifier,...]
+ class_specificationkeepclassmembers
+ [modifier,...]
+ class_specificationkeepclasseswithmembers
+ [modifier,...]
+ class_specificationkeepnames
+ class_specificationkeepclassmembernames
+ class_specificationkeepclasseswithmembernames
+ class_specificationprintseeds
+ [file]keep
+ commands, to the standard output or to the given file.dontshrink
printusage
+ [file]whyareyoukeeping
+ class_specificationdontoptimize
optimizations
'optimization_filter'optimizationpasses
+ nassumenosideeffects
+ class_specificationallowaccessmodification
mergeinterfacesaggressively
dontobfuscate
printmapping
+ [file]applymapping
+ fileobfuscationdictionary
+ fileclassobfuscationdictionary
+ filepackageobfuscationdictionary
+ fileoverloadaggressively
useuniqueclassmembernames
dontusemixedcaseclassnames
keeppackagenames
['package_filter']flattenpackagehierarchy
+ 'package_name'repackageclasses
+ ['package_name']keepattributes
['attribute_filter']keepparameternames
renamesourcefileattribute
+ ['string']SourceFile
+ attributes.adaptclassstrings
+ ['class_filter']adaptresourcefilenames
+ ['file_filter']adaptresourcefilecontents
+ ['file_filter']dontpreverify
microedition
verbose
dontnote
'class_filter'dontwarn
'class_filter'ignorewarnings
printconfiguration
+ [file]dump
+ [file]files(Object)
, etc.
++In addition, they can have ProGuard-style filters, specified as +comma-separated named arguments after the file: + +
filter:
+ 'file_filter'jarfilter:
+ 'file_filter'warfilter:
+ 'file_filter'earfilter:
+ 'file_filter'zipfilter:
+ 'file_filter'file(Object)
, etc.
+
+In Gradle, file names (any strings really) in double quotes can contain
+properties or code inside ${...}
. These are automatically
+expanded.
+
+For example, "${System.getProperty('java.home')}/lib/rt.jar"
is
+expanded to something like '/usr/local/java/jdk/jre/lib/rt.jar'
.
+Similarly, System.getProperty('user.home')
is expanded to the
+user's home directory, and System.getProperty('user.dir')
is
+expanded to the current working directory.
+
+
allowshrinking:
+ boolean
+ (default = false)allowoptimization:
+ boolean
+ (default = false)allowobfuscation:
+ boolean
+ (default = false)+keep 'public class mypackage.MyMainClass { \ + public static void main(java.lang.String[]); \ +}' +
+keep access: 'public', + name: 'mypackage.MyMainClass', { + method access: 'public static', + type: 'void', + name: 'main', + parameters: 'java.lang.String[]' +} +
+ +The ProGuard-style class +specification is described on the traditional Usage page. +
+A Gradle-style class specification can have the following named arguments: + +
access:
'access_modifiers'annotation:
'annotation_name'type:
'type'name:
'class_name'extendsannotation:
'annotation_name''extends':
'class_name''implements':
'class_name'+ +
field
field_constraintsmethod
method_constraintsconstructor
constructor_constraintsaccess:
'access_modifiers''annotation':
'annotation_name'type:
'type'parameters
argument is specified.name:
'name'parameters:
'parameters'type
argument is
+ specified.+A class member setting doesn't have a closure. + +
+
+ant.project.basedir = '../..' + +ant.taskdef(resource: 'proguard/ant/task.properties', + classpath: '/usr/local/java/proguard/lib/proguard.jar') ++
+ +Gradle automatically converts the elements and attributes to Groovy methods, +so converting the configuration is essentially mechanical. The one-on-one +mapping can be useful, but the resulting configuration is more verbose. For +instance: +
+task proguard << { + ant.proguard(printmapping: 'proguard.map', + overloadaggressively: 'on', + repackageclasses: '', + renamesourcefileattribute: 'SourceFile') { + + injar(file: 'application.jar') + injar(file: 'gui.jar', filter: '!META-INF/**') + + ..... + } +} ++
+ +
java -jar proguardgui.jar [-nosplash]
[configuration_file]
-nosplash
option, you
-can switch off the short opening animation. If you have specified a ProGuard
-configuration file, it will be loaded. The GUI works like a wizard. You can
-edit the configuration and execute ProGuard through a few tabs:
+Alternatively, the bin
directory contains some short Linux and
+Windows scripts containing this command. The GUI will pop up in a window. With
+the -nosplash
option, you can switch off the short opening
+animation. If you have specified a ProGuard configuration file, it will be
+loaded. The GUI works like a wizard. You can edit the configuration and
+execute ProGuard through a few tabs:
-
Each of these steps is optional. For instance, ProGuard can also be used to just list dead code in an application, or to preverify class files for @@ -62,13 +72,13 @@ efficient use in Java 6.
-ProGuard typically reads the input jars (or wars, ears, zips, or -directories). It then shrinks, optimizes, obfuscates, and preverifies them. -Optionally, multiple optimization passes can be performed, each typically -followed by another shrinking step. ProGuard writes the processed results to -one or more output jars (or wars, ears, zips, or directories). The -input may contain resource files, whose names and contents can optionally be -updated to reflect the obfuscated class names. +ProGuard first reads the input jars (or wars, ears, zips, or +directories). It then subsequently shrinks, optimizes, obfuscates, and +preverifies them. You can optionally let ProGuard perform multiple +optimization passes. ProGuard writes the processed results to one or +more output jars (or wars, ears, zips, or directories). The input may +contain resource files, whose names and contents can optionally be updated to +reflect the obfuscated class names.
ProGuard requires the library jars (or wars, ears, zips, or directories) of the input jars to be specified. These are essentially the @@ -76,63 +86,69 @@ libraries that you would need for compiling the code. ProGuard uses them to reconstruct the class dependencies that are necessary for proper processing. The library jars themselves always remain unchanged. You should still put them in the class path of your final application. -
+ +
The Usage section of this manual describes the
necessary -keep
options and
the Examples section provides plenty of examples.
-
Class.forName()
constructs may refer to any
-class at run-time. It is generally impossible to foresee which classes have to
-be preserved (with their original names), since the class names might be read
-from a configuration file, for instance. You therefore have to specify them in
-your ProGuard configuration, with the same simple -keep
options.
+Class.forName()
constructs may
+refer to any class at run-time. It is generally impossible to compute which
+classes have to be preserved (with their original names), since the class
+names might be read from a configuration file, for instance. You therefore
+have to specify them in your ProGuard configuration, with the same
+simple -keep
options.
However, ProGuard will already detect and handle the following cases for you:
Class.forName("SomeClass")
-SomeClass.class
-SomeClass.class.getField("someField")
-SomeClass.class.getDeclaredField("someField")
-SomeClass.class.getMethod("someMethod", new Class[] {})
-SomeClass.class.getMethod("someMethod", new Class[] { A.class })
-SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
-SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
-SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
-SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
+Class.forName("SomeClass")
SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod", new Class[] {})
SomeClass.class.getMethod("someMethod", new Class[] { A.class })
SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")
Furthermore, ProGuard will offer some suggestions if keeping some classes or class members appears necessary. For example, ProGuard will note constructs @@ -142,15 +158,15 @@ and/or its implementations may need to be preserved. You can then adapt your configuration accordingly.
For proper results, you should at least be somewhat familiar with the code -that you are processing. Obfuscating code that performs a lot of introspection +that you are processing. Obfuscating code that performs a lot of reflection may require trial and error, especially without the necessary information about the internals of the code. -
-
-
-dontskipnonpubliclibraryclasses
option, and
- maybe even the -dontskipnonpubliclibraryclassmembers
option.
- The graphical user interface has checkboxes for these settings.
- +
myObject
might be null, causing a NullPointerException. In
some way this is a good thing: optimized code may throw fewer exceptions.
Should this entire assumption be false, you'll have to switch off
- optimization using the -dontoptimize
option.
-
+ optimization using the -dontoptimize
option.
-dontoptimize
option.+ across input jars and library jars.
a.class
", "b.class
", etc. If there is a large
- numbers of classes in the same package, it may also write out
- "aux.class
". Windows doesn't allow creating files with
- this reserved name (among a few other names), so it's generally better to
- write the output to a jar, in order to avoid such problems.
- +
a.class
", "b.class
", etc. If a package contains
+ a large number of classes, ProGuard may also write out
+ "aux.class
". Inconveniently, Windows refuses to create
+ files with this reserved name (among a few other names). It's generally
+ better to write the output to a jar, in order to avoid such problems.-
code/simplification/branch
code/simplification/string
code/removal/advanced
)code/simplification/advanced
code/removal/exception
code/allocation/variable
-
-D.....)
:
+maximum.inlined.code.length
(default = 8 bytes)maximum.resulting.code.length
(default = 8000 bytes
+ for JSE, 2000 bytes for JME)optimize.conservatively
(default = unset)NullPointerException
,
+ ArrayIndexOutOfBoundsException
, or
+ ClassCastException
, without any other useful purposes. By
+ default, ProGuard may just discard such seemingly useless instructions,
+ resulting in better optimization of most common code.-outjars
class_path-skipnonpubliclibraryclasses
-dontskipnonpubliclibraryclasses
*Annotation*
.
-keepparameternames
-renamesourcefileattribute
[string]-printconfiguration
[filename]-dump
[filename]@@ -443,23 +464,23 @@ Notes: Notes:
?
' for a
single character, '*
' for any number of characters
(but not the package separator), '**
' for any number
of (any) characters, '%
' for any primitive type,
- '***
' for any type, and '...
' for any number of arguments..
+ '***
' for any type, and '...
' for any number of arguments.?
' for a single character and '*
'
- for any number of characters.
+ for any number of characters.-
@@ -189,8 +199,7 @@ Exception in thread "main" java.lang.Error: Random exception- -
-
-
java -jar retrace.jar
[options...]
mapping_file [stacktrace_file]
-These are the arguments:
+Alternatively, the bin
directory contains some short Linux and
+Windows scripts containing this command. These are the arguments:
- (?:\s*%c:.*)|(?:\s*at\s+%c.%m\s*\(.*?(?::%l)?\)\s*) + (?:.*?\bat\s+%c.%m\s*\(.*?(?::%l)?\)\s*)|(?:(?:.*?[:"]\s+)?%c(?::.*)?)The regular expression is a Java regular expression (cfr. the documentation of
java.util.regex.Pattern
), with a few additional wildcards:
@@ -87,14 +99,13 @@ the obfuscated class files:
+ ReTrace will be able to restore the stack trace completely.
@@ -105,12 +116,12 @@ href="../examples.html#stacktrace">example in the ProGuard User Manual. Unobfuscated elements and obfuscated elements for which no mapping is available will be left unchanged. -
-
+
+
-
-
-
-
+
+With support of
+
-
- -
-dontnote
option.
+-keep
option to preserve the
@@ -118,6 +155,21 @@ ProGuard may print out some notes and non-fatal warnings:
API. You can switch off these notes by specifying the -dontnote
option.-keepclassmembers
/-keepclasseswithmembers
+ option to preserve fields or methods in the given class, but it doesn't
+ specify which fields or methods. This way, the option simply won't have
+ any effect. You probably want to specify one or more fields or methods, as
+ usual between curly braces. You can specify all fields or methods with a
+ wildcard "*;
". You should also consider if you just need the
+ more common -keep
option, which
+ preserves all specified classes and class members.
+ The overview of all keep
+ options can help. You can switch off these notes by specifying
+ the -dontnote
option.-dontnote
option.-dontnote
option.
+
+ The standard Android build process automatically
+ specifies the input jars for you. There may not be an easy way to filter
+ them to remove these notes. You could remove the duplicate classes
+ manually from your libraries. You should never explicitly specify the
+ input jars yourself (with -injars
or
+ -libraryjars
), since you'll then get duplicate definitions.
+ You should also not add libraries to your application that are already
+ part of the Android run-time (notably org.w3c.dom
,
+ org.xml.sax
, org.xmlpull.v1
,
+ org.apache.commons.logging.Log
, org.apache.http
,
+ and org.json
). They are possibly inconsistent, and the
+ run-time libraries would get precedence anyway.
+ The standard Android build process automatically + specifies the input jars for you. There may not be an easy way to filter + them to remove these warnings. You could remove the duplicate resource files + manually from the input and the libraries.
@@ -146,60 +218,133 @@ some more serious warnings:
-libraryjars
option.
+
- If the class that is reported as missing is a non-public library class,
- you should specify the -dontskipnonpubliclibraryclasses
- option. Common examples are the classes
- javax.swing.TransferHandler$HasGetTransferHandler
and
- java.util.zip.ZipConstants
, which are used as interfaces in
- some public classes, even though they are only package visible. This
- option is not set by default for reasons of efficiency. Setting it increases
- the processing time a bit, but it won't hurt the output in any way.
+
-injars
, otherwise you
+ should specify it with
+ -libraryjars
.
+
+ For example, if ProGuard complains that it can't find a
+ java.lang
class, you have to make sure that you are
+ specifying the run-time library of your platform. For JSE, these are
+ typically packaged in lib/rt.jar
(vm.jar
for
+ IBM's JVM, and classes.jar
in MacOS X). Other platforms
+ like JME and Android have their own run-time libraries.
+ The examples section provides more details
+ for the various platforms.
+
+ If ProGuard still complains that it can't find a
+ javax.crypto
class, you probably still have to specify
+ jce.jar
, next to the more common rt.jar
.
-libraryjars
+ mylibrary.jar(!somepackage/SomeUnusedReferencingClass.class)
".
+ ProGuard will then skip this class entirely in the input, and it will
+ not bump into the problem of its missing reference. However, you may
+ then have to filter out other classes that are in turn referencing the
+ removed class. In practice, this works best if you can filter out
+ entire unused packages at once, with a wildcard filter like
+ "-libraryjars
+ mylibrary.jar(!someunusedpackage/**)
".-ignorewarnings
+ option, or even
+ the -dontwarn
option.
+ Only use these options if you really know what you're doing though.
- If you're missing a library and you're absolutely sure it isn't used
- anyway, you can try your luck with the -ignorewarnings
option,
- or even the -dontwarn
- option. Only use these options if you really know what you're doing
- though.
java.awt
class, then some library that you are using is
+ referring to java.awt
. This is a bit shady, since Android
+ doesn't have this package at all, but if your application works anyway,
+ you can let ProGuard accept it with "-dontwarn java.awt.**
",
+ for instance.-ignorewarnings
+ or -dontwarn
, but it didn't
+ work out. ProGuard's optimization step and preverification step really
+ need the missing classes to make sense of the code. Preferably, you would
+ solve the problem by adding the missing library, as discussed. If you're
+ sure the class that references the missing class isn't used either, you
+ could also try filtering it out from the input, by adding a filter to the
+ corresponding -injars
option:
+ "-injars
+ myapplication.jar(!somepackage/SomeUnusedClass.class)
". As a final
+ solution, you could switch off optimization
+ (-dontoptimize
) and
+ preverification
+ (-dontpreverify
).
- If the class member that is reported as missing is actually implemented in
- a non-public library class, you should specify the
- -dontskipnonpubliclibraryclasses
option. A common example is
- the method setLength(int)
in the public class
- java.lang.StringBuilder
. This method is actually defined in
- the package visible superclass
- java.lang.AbstractStringBuilder
, which ProGuard ignores by
- default.
+ If you're developing for Android and ProGuard complains
+ that it can't find a method that is only available in a recent version of
+ the Android run-time, you should change the build target in your
+ project.properties
file or build.gradle
file to
+ that recent version. You can still specify a different
+ minSdkVersion
and a different targetSdkVersion
+ in your AndroidManifest.xml
file.
- If your program classes reside in the same packages as library classes,
- and refer to their package visible class members, then you should specify
- the -dontskipnonpubliclibraryclassmembers
+ Alternatively, you may get away with ignoring the inconsistency with the
+ options
+ -ignorewarnings
or
+ even
+ -dontwarn
. For instance, you
+ can specify "-dontwarn mypackage.MyInconsistentClass
".
+
+ Finally, should your program classes reside in the same packages as
+ library classes and should they refer to their package visible class
+ members, then you should also specify the
+ -dontskipnonpubliclibraryclassmembers
option.
-injars
) and library code
+ (specified with -libraryjars
), and try
+ again.
+
+ In Android development, sloppy libraries may contain
+ duplicates of classes that are already present in the Android run-time
+ (notably org.w3c.dom
, org.xml.sax
,
+ org.xmlpull.v1
, org.apache.commons.logging.Log
,
+ org.apache.http
, and org.json
). You must remove
+ these classes from your libraries, since they are possibly inconsistent,
+ and the run-time libraries would get precedence anyway.
<java.home>/lib/rt.jar
by
<java.home>/../Classes/classes.jar
.-DsuppressSwingDropSupport=true
when running the
+ GUI.
@@ -304,7 +492,7 @@ Should ProGuard crash while processing your application:
size of the Java virtual machine (with the usual -Xss
option)
should help too. In practice however, the -Xss
setting
doesn't have any effect on the main thread, due to Sun Bug
+ href="http://bugs.sun.com/view_bug.do?bug_id=4362291">Sun Bug
#4362291. As a result, this solution will only work when running
ProGuard in a different thread, e.g. from its GUI.
@@ -326,8 +514,7 @@ Should ProGuard crash while processing your application:
If you are using marker interfaces to keep other classes, the marker
interfaces themselves are probably being removed in the shrinking step.
- You should therefore always explicitly keep any marker interfaces.
+ You should therefore always explicitly keep any marker interfaces, with
+ an option like "-keep interface MyMarkerInterface
".
+
+ Similarly, if you are keeping classes based on annotations, you may have
+ to avoid that the annotation classes themselves are removed in the
+ shrinking step. You should package the annotation classes as a library, or
+ explicitly keep them in your program code with an option like "-keep
+ @interface *
".
-g:none
), or let
+ ProGuard's obfuscation step remove the debug information again
+ (by not keeping the attributes LocalVariableTable
+ and LocalVariableTypeTable
+ with -keepattributes
),
+ or otherwise just disable optimization
+ (-dontoptimize
).android-sdk/tools/proguard/lib
. If that doesn't help,
+ please report the problem, preferably with the simplest example that still
+ brings out the error.-keep class * implements
mypackage.MyInterface
".
+myClass.getField
, trying to find some field dynamically.
+ Since ProGuard can't always detect this automatically, you have to keep
+ the missing field in using the
+ appropriate -keep
option, e.g.
+ "-keepclassmembers class mypackage.MyClass { int myField;
+ }
".myClass.getMethod
, trying to find some method dynamically.
- Since ProGuard isn't detecting this (yet), you have to keep the missing
- method in using the appropriate -keep
option, e.g. "-keep
- class mypackage.MyClass { void myMethod(); }
".-keep
option, e.g.
+ "-keepclassmembers class mypackage.MyClass { void myMethod();
+ }
".
+
+ More specifically, if the method reported as missing is
+ values
or valueOf
, you probably have to keep
+ some methods related to enumerations.
Furthermore, directory entries in jar files aren't copied, unless you
specify the option -keepdirectories
.
+ href="usage.html#keepdirectories">-keepdirectories
.
+ Note that Sun advises against calling Class.getResource()
for
+ directories (Sun
+ Bug #4761949).
+
+
-keepattributes
+ *Annotation*
.META-INF/INDEX.LIST
, listing all class files in the jar.
+ ProGuard by default copies files like these unchanged. ProGuard may however
+ remove or rename classes, thus invalidating the file. You should filter the
+ index file out of the input
+ (-injars in.jar(!META-INF/INDEX.LIST)
) or update the file
+ after having applied ProGuard (jar -i out.jar
).
+ sun.tools.java.MethodSet.add
in Sun's JDK 1.2.2, which is
used for (dynamic) compilation. You should then avoid this option.LocalVariableTable
or
+ LocalVariableTypeTable
attributes, ProGuard's optimizing step
+ is sometimes unable to update them consistently. You should then let the
+ obfuscation step remove these attributes or disable the optimization
+ step.java -jar proguard.jar
options ...
You can find the ProGuard jar in the lib
directory of the
-ProGuard distribution. Options can also be put in one or more configuration
-files. Typically, you'll put most options in a configuration file (say,
-myconfig.pro
), and just call:
+ProGuard distribution. Alternatively, the bin
directory contains
+some short Linux and Windows scripts containing this command. Typically, you'll
+put most options in a configuration file (say, myconfig.pro
), and
+just call:
java -jar proguard.jar @myconfig.pro
java -jar proguard.jar @myconfig.pro -verbose
-In a configuration file, a #
sign and all remaining
-characters on that line are ignored, allowing you to add comments.
+You can add comments in a configuration file, starting with a
+#
character and continuing until the end of the line.
-Extra whitespace between words and delimiters is ignored. To specify file -names with spaces or special characters, words can be quoted with single or -double quotes. Note that the quotes may need to be escaped when used on the -command line, to avoid them being gobbled by the shell. +Extra whitespace between words and delimiters is ignored. File names with +spaces or special characters should be quoted with single or double quotes.
Options can be grouped arbitrarily in arguments on the command line and in -lines in configuration files. This means that you can quote any arbitrary -section of command line options, to avoid shell expansion of special -characters, for instance. +lines in configuration files. This means that you can quote arbitrary sections +of command line options, to avoid shell expansion of special characters, for +instance.
-The order of the options is generally irrelevant. They can be abbreviated to -their first unique characters. +The order of the options is generally irrelevant. For quick experiments, you +can abbreviate them to their first unique characters.
The sections below provide more details:
Keep
Options
-Keep
Options@
filename-skipnonpubliclibraryclasses
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-keepdirectories
[directory_filter]MyClass.class.getResource("")
". If the
- option is specified without a filter, all directories are kept. With a
- filter, only matching directories are kept.mypackage.MyClass.class.getResource("")
". You'll then want to
+ keep the directory corresponding to the package, "-keepdirectories
+ mypackage
". If the option is specified without a filter, all
+ directories are kept. With a filter, only matching directories are
+ kept.-target
version1.0
, 1.1
,
1.2
, 1.3
, 1.4
, 1.5
(or
- just 5
), or 1.6
(or just 6
). By
- default, the version numbers of the class files are left unchanged. For
- example, you may want to upgrade class
- files to Java 6, by changing their version numbers and having them
- preverified.5
), 1.6
(or just 6
), or
+ 1.7
(or just 7
). By default, the version numbers
+ of the class files are left unchanged. For example, you may want to
+ upgrade class files to Java 6, by
+ changing their version numbers and having them preverified.
-forceprocessing
-keep
@@ -245,11 +261,11 @@ The sections below provide more details:
Specifies class members whose names are to be preserved, if they aren't
removed in the shrinking phase. For example, you may want to preserve the
- name of the synthetic class$
methods when processing a library, so obfuscators can
- detect it again when processing an application that uses the processed
- library (although ProGuard itself doesn't need this). Only applicable when
- obfuscating.
+ name of the synthetic class$
methods
+ when processing a library compiled by
+ JDK 1.2 or older, so obfuscators can detect it again when processing an
+ application that uses the processed library (although ProGuard itself
+ doesn't need this). Only applicable when obfuscating.
-keepclasseswithmembernames
class_specification-dontshrink
-dontoptimize
System.currentTimeMillis()
, so that any idle calls to it will
- be removed. Note that ProGuard applies the option to the entire hierarchy
- of the specified methods. Only applicable when optimizing. In general,
- making assumptions can be dangerous; you can easily break the processed
- code. Only use this option if you know what you're doing!-allowaccessmodification
InternalError
when
encountering more than 256 Miranda methods (interface methods
- without implementations) in a class.
+ without implementations) in a class.-dontobfuscate
-useuniqueclassmembernames
.
- Only applicable when obfuscating.
+ piece of code. If the structure of the code changes fundamentally,
+ ProGuard may print out warnings that applying a mapping is causing
+ conflicts. You may be able to reduce this risk by specifying the option -useuniqueclassmembernames
+ in both obfuscation runs. Only a single mapping file is allowed. Only
+ applicable when obfuscating.
-obfuscationdictionary
filenamejavac
compiler produces an exception when
compiling with such a library (cfr. Bug
- #4216736). You probably shouldn't use this option for processing
- libraries.
+ "http://bugs.sun.com/view_bug.do?bug_id=4216736">Bug #4216736).
+ You probably shouldn't use this option for processing libraries.pack200
tool reportedly has problems with
- overloaded class members.
+ overloaded class members.-useuniqueclassmembernames
-keeppackagenames
[package_filter]-flattenpackagehierarchy
[package_name]Exceptions
, InnerClasses
, and
- Signature
attributes when processing a library. As another example,
- you should keep the SourceFile
and
- LineNumberTable
attributes for producing useful obfuscated stack
- traces. Only applicable when obfuscating.
+ Signature
attributes
+ when processing a library. You should
+ also keep the SourceFile
and
+ LineNumberTable
attributes
+ for producing useful obfuscated stack
+ traces. Finally, you may want
+ to keep annotations if your code
+ depends on them. Only applicable when obfuscating.
+
+-keepparameternames
LocalVariableTable
and
+ LocalVariableTypeTable
. It can be useful when
+ processing a library. Some IDEs can
+ use the information to assist developers who use the library, for example
+ with tool tips or autocompletion. Only applicable when obfuscating.-renamesourcefileattribute
[string]-dontpreverify
-microedition
-verbose
Each input entry can be:
The paths of directly specified class files and resource files is ignored, so @@ -776,11 +803,11 @@ any additional directory prefixes inside the archives or directories. Each output entry can be:
When writing output entries, ProGuard will generally package the results in a @@ -801,12 +828,12 @@ class path entry can be followed by up to 5 types of file filters between parentheses, separated by semi-colons:
If fewer than 5 filters are specified, they are assumed to be the latter
@@ -826,8 +853,8 @@ For example, "input.jar(!**.gif,images/**)
" matches all files in
the images
directory inside the input
jar, except
gif files.
-Note that the different filters are applied to all corresponding file types, -irrespective of their nesting levels in the input; they are orthogonal. +The different filters are applied to all corresponding file types, irrespective +of their nesting levels in the input; they are orthogonal.
For example,
"input.war(lib/**.jar,support/**.jar;**.class,**.gif)
" only
@@ -840,40 +867,37 @@ possibilities. The Examples section provides a few more examples
for filtering input and output.
-The names can contain Java system properties delimited by '<' and -'>'. The system properties -are automatically replaced by their respective values. +The names can contain Java system properties (or Ant properties, when using +Ant), delimited by angular brackets, '<' and '>'. The +properties are automatically replaced by their corresponding values.
-For example, <java.home>/lib/rt.jar
will automatically be
+For example, <java.home>/lib/rt.jar
is automatically
expanded to something like /usr/local/java/jdk/jre/lib/rt.jar
.
-Similarly, <user.home>
will be expanded to the user's home
-directory, and <user.dir>
will be expanded to the current
+Similarly, <user.home>
is expanded to the user's home
+directory, and <user.dir>
is expanded to the current
working directory.
Names with special characters like spaces and parentheses must be quoted with -single or double quotes. Note that each file name in a list of names has to be -quoted individually. Also note that the quotes themselves may need to be -escaped when used on the command line, to avoid them being gobbled by the -shell. +single or double quotes. Each file name in a list of names has to be quoted +individually. Note that the quotes themselves may need to be escaped when used +on the command line, to avoid them being gobbled by the shell.
For example, on the command line, you could use an option like '-injars
"my program.jar":"/your directory/your program.jar"'
.
!**.gif,images/**
" matches all files in the
The Examples section provides a few more examples for filtering input and output.
-
-!foobar,*bar
" matches all names ending with
bar
, except foobar
.
Keep
OptionsKeep
Options-keep
options for shrinking and obfuscation may seem
a bit confusing at first, but there's actually a pattern behind them. The
@@ -989,24 +1011,17 @@ If you're not sure which option you need, you should probably simply use
-keep
. It will make sure the specified classes and class members
are not removed in the shrinking step, and not renamed in the obfuscation step.
-
- - |
-Always remember:
-
|
allowshrinking
-keep
options and in the
@@ -1071,18 +1085,20 @@ of the specification that belong together. The indentation tries to clarify
the intended meaning, but white-space is irrelevant in actual configuration
files.
-
class
keyword refers to any interface or class.
The interface
keyword restricts matches to interface
classes. The enum
keyword restricts matches to
enumeration classes. Preceding the interface
or
enum
keywords by a !
restricts
- matches to classes that are not interfaces or enumerations, respectively.
- + matches to classes that are not interfaces or enumerations, + respectively.
java.lang.String
. Class names may be specified as regular
+ java.lang.String
. Inner classes are separated by a dollar sign
+ "$
", e.g. java.lang.Thread$State
. Class names
+ may be specified as regular
expressions containing the following wildcards:
Worm, a sample midlet from Sun's JME | +Worm, a sample midlet from Oracle's JME | 10.3 K | 9.8 K | 9.6 K | @@ -75,7 +86,7 @@ presents some typical results:
the run-time classes from Sun's Java 6 | +the run-time classes from Oracle's Java 6 | 53 M | 23 M | 22 M | @@ -86,7 +97,7 @@ presents some typical results:
Tomcat, the Apache servlet container | +Tomcat, the Apache servlet container | 1.1 M | 466 K | 426 K | @@ -97,7 +108,7 @@ presents some typical results:
JavaNCSS, a Java source metrics tool | +JavaNCSS, a Java source metrics tool | 632 K | 242 K | 212 K | @@ -121,7 +132,8 @@ presents some typical results:
Results were measured with ProGuard 4.0 on a 2.6 GHz Pentium 4 with 512 MB -of memory, using Sun JDK 1.5.0 in Fedora Core 3 Linux. +of memory, using Sun JDK 1.5.0 in Fedora Core 3 Linux. All of this technology +and software has evolved since, but the gist of the results remains the same.
The program sizes include companion libraries. The shrinking step produces the best results for programs that use only small parts of their libraries. The @@ -145,10 +157,12 @@ minutes. Memory usage (the amount of physical memory used by ProGuard while processing) is governed by the basic java virtual machine and by the total size of the library jars and program jars. -
+ alt="GUI screenshot" usemap="#guimap" /> |
-
+With support of
ProGuard is probably the most popular java shrinker, optimizer, and obfuscator world-wide. It is being used by developers at companies and -organizations like Sun, IBM, HP, Siemens, Nokia, Google, and NATO. It is the -default tool in many development environments like Sun's Wireless Toolkit, -Netbeans, EclipseME, and more. Although the quotes below probably don't -represent official views of any kind, encouragements like these do keep me -happy. +organizations like IBM, HP, Siemens, Nokia, Google, Intel, and NATO. It is the +default tool in many development environments like Oracle's Wireless Toolkit, +Netbeans, EclipseME, Google's Android SDK, and more. Although the quotes below +probably don't represent official views of any kind, encouragements like these +do keep me happy.
- | + | |
+ |
@@ -38,9 +49,9 @@ Also: ProGuard is pure quality - powerful and trouble-free.
-@@ -50,9 +61,9 @@ And: It is the simplest and most robust obfuscator we have ever used.
-@@ -62,9 +73,9 @@ And indeed: ProGuard rules. Much easier to use than the commercial alternatives.
-@@ -77,9 +88,9 @@ obfuscators and shrinkers, ProGuard stands out as the simplest, most robust, and accurate shrinker of them all.
-@@ -93,9 +104,9 @@ powerful configuration options make it an excellent addition to your MIDlet development toolbox.
-@@ -106,16 +117,16 @@ And, of course, the price is stunning: You could've been rich.
--
String
s specifying a filter for clases whose
+ * A list of String
s specifying a filter for classes whose
* string constants are to be adapted, based on corresponding obfuscated
* class names.
*/
diff --git a/src/proguard/ConfigurationConstants.java b/src/proguard/ConfigurationConstants.java
index 694e006..14c5654 100644
--- a/src/proguard/ConfigurationConstants.java
+++ b/src/proguard/ConfigurationConstants.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -73,6 +73,7 @@ class ConfigurationConstants
public static final String REPACKAGE_CLASSES_OPTION = "-repackageclasses";
public static final String DEFAULT_PACKAGE_OPTION = "-defaultpackage";
public static final String KEEP_ATTRIBUTES_OPTION = "-keepattributes";
+ public static final String KEEP_PARAMETER_NAMES_OPTION = "-keepparameternames";
public static final String RENAME_SOURCE_FILE_ATTRIBUTE_OPTION = "-renamesourcefileattribute";
public static final String ADAPT_CLASS_STRINGS_OPTION = "-adaptclassstrings";
public static final String ADAPT_RESOURCE_FILE_NAMES_OPTION = "-adaptresourcefilenames";
@@ -87,6 +88,7 @@ class ConfigurationConstants
public static final String IGNORE_WARNINGS_OPTION = "-ignorewarnings";
public static final String PRINT_CONFIGURATION_OPTION = "-printconfiguration";
public static final String DUMP_OPTION = "-dump";
+ public static final String SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION = "-skipnonpubliclibraryclasses";
public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION = "-dontskipnonpubliclibraryclasses";
public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION = "-dontskipnonpubliclibraryclassmembers";
public static final String TARGET_OPTION = "-target";
diff --git a/src/proguard/ConfigurationParser.java b/src/proguard/ConfigurationParser.java
index e01809e..a38e9ed 100644
--- a/src/proguard/ConfigurationParser.java
+++ b/src/proguard/ConfigurationParser.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,56 +31,101 @@ import java.util.*;
/**
* This class parses ProGuard configurations. Configurations can be read from an
- * array of arguments or from a configuration file or URL.
+ * array of arguments or from a configuration file or URL. External references
+ * in file names ('<...>') can be resolved against a given set of properties.
*
* @author Eric Lafortune
*/
public class ConfigurationParser
{
- private WordReader reader;
+ private final WordReader reader;
+ private final Properties properties;
+
private String nextWord;
private String lastComments;
/**
- * Creates a new ConfigurationParser for the given String arguments.
+ * Creates a new ConfigurationParser for the given String arguments and
+ * the given Properties.
*/
- public ConfigurationParser(String[] args) throws IOException
+ public ConfigurationParser(String[] args,
+ Properties properties) throws IOException
{
- this(args, null);
+ this(args, null, properties);
}
/**
* Creates a new ConfigurationParser for the given String arguments,
- * with the given base directory.
+ * with the given base directory and the given Properties.
*/
- public ConfigurationParser(String[] args,
- File baseDir) throws IOException
+ public ConfigurationParser(String[] args,
+ File baseDir,
+ Properties properties) throws IOException
{
- reader = new ArgumentWordReader(args, baseDir);
+ this(new ArgumentWordReader(args, baseDir), properties);
+ }
- readNextWord();
+
+ /**
+ * Creates a new ConfigurationParser for the given lines,
+ * with the given base directory and the given Properties.
+ */
+ public ConfigurationParser(String lines,
+ String description,
+ File baseDir,
+ Properties properties) throws IOException
+ {
+ this(new LineWordReader(new LineNumberReader(new StringReader(lines)),
+ description,
+ baseDir),
+ properties);
}
/**
- * Creates a new ConfigurationParser for the given file.
+ * Creates a new ConfigurationParser for the given file, with the system
+ * Properties.
+ * @deprecated Temporary code for backward compatibility in Obclipse.
*/
public ConfigurationParser(File file) throws IOException
{
- reader = new FileWordReader(file);
+ this(file, System.getProperties());
+ }
- readNextWord();
+
+ /**
+ * Creates a new ConfigurationParser for the given file and the given
+ * Properties.
+ */
+ public ConfigurationParser(File file,
+ Properties properties) throws IOException
+ {
+ this(new FileWordReader(file), properties);
+ }
+
+
+ /**
+ * Creates a new ConfigurationParser for the given URL and the given
+ * Properties.
+ */
+ public ConfigurationParser(URL url,
+ Properties properties) throws IOException
+ {
+ this(new FileWordReader(url), properties);
}
/**
- * Creates a new ConfigurationParser for the given URL.
+ * Creates a new ConfigurationParser for the given word reader and the
+ * given Properties.
*/
- public ConfigurationParser(URL url) throws IOException
+ public ConfigurationParser(WordReader reader,
+ Properties properties) throws IOException
{
- reader = new FileWordReader(url);
+ this.reader = reader;
+ this.properties = properties;
readNextWord();
}
@@ -110,6 +155,7 @@ public class ConfigurationParser
else if (ConfigurationConstants.OUTJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, true);
else if (ConfigurationConstants.LIBRARYJARS_OPTION .startsWith(nextWord)) configuration.libraryJars = parseClassPathArgument(configuration.libraryJars, false);
else if (ConfigurationConstants.RESOURCEJARS_OPTION .startsWith(nextWord)) throw new ParseException("The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input");
+ else if (ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(true);
else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(false);
else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION.startsWith(nextWord)) configuration.skipNonPublicLibraryClassMembers = parseNoArgument(false);
else if (ConfigurationConstants.TARGET_OPTION .startsWith(nextWord)) configuration.targetClassVersion = parseClassVersion();
@@ -124,7 +170,7 @@ public class ConfigurationParser
else if (ConfigurationConstants.PRINT_SEEDS_OPTION .startsWith(nextWord)) configuration.printSeeds = parseOptionalFile();
// After '-keep'.
- else if (ConfigurationConstants.KEEP_DIRECTORIES_OPTION .startsWith(nextWord)) configuration.keepDirectories = parseCommaSeparatedList("directory name", true, true, false, false, true, false, false, configuration.keepDirectories);
+ else if (ConfigurationConstants.KEEP_DIRECTORIES_OPTION .startsWith(nextWord)) configuration.keepDirectories = parseCommaSeparatedList("directory name", true, true, false, true, false, true, false, false, configuration.keepDirectories);
else if (ConfigurationConstants.DONT_SHRINK_OPTION .startsWith(nextWord)) configuration.shrink = parseNoArgument(false);
else if (ConfigurationConstants.PRINT_USAGE_OPTION .startsWith(nextWord)) configuration.printUsage = parseOptionalFile();
@@ -132,7 +178,7 @@ public class ConfigurationParser
else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION .startsWith(nextWord)) configuration.optimize = parseNoArgument(false);
else if (ConfigurationConstants.OPTIMIZATION_PASSES .startsWith(nextWord)) configuration.optimizationPasses = parseIntegerArgument();
- else if (ConfigurationConstants.OPTIMIZATIONS .startsWith(nextWord)) configuration.optimizations = parseCommaSeparatedList("optimization name", true, false, false, false, false, false, false, configuration.optimizations);
+ else if (ConfigurationConstants.OPTIMIZATIONS .startsWith(nextWord)) configuration.optimizations = parseCommaSeparatedList("optimization name", true, false, false, false, false, false, false, false, configuration.optimizations);
else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION .startsWith(nextWord)) configuration.assumeNoSideEffects = parseClassSpecificationArguments(configuration.assumeNoSideEffects);
else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION .startsWith(nextWord)) configuration.allowAccessModification = parseNoArgument(true);
else if (ConfigurationConstants.MERGE_INTERFACES_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.mergeInterfacesAggressively = parseNoArgument(true);
@@ -146,22 +192,23 @@ public class ConfigurationParser
else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.overloadAggressively = parseNoArgument(true);
else if (ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.useUniqueClassMemberNames = parseNoArgument(true);
else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION .startsWith(nextWord)) configuration.useMixedCaseClassNames = parseNoArgument(false);
- else if (ConfigurationConstants.KEEP_PACKAGE_NAMES_OPTION .startsWith(nextWord)) configuration.keepPackageNames = parseCommaSeparatedList("package name", true, true, false, true, false, true, false, configuration.keepPackageNames);
+ else if (ConfigurationConstants.KEEP_PACKAGE_NAMES_OPTION .startsWith(nextWord)) configuration.keepPackageNames = parseCommaSeparatedList("package name", true, true, false, false, true, false, true, false, configuration.keepPackageNames);
else if (ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION .startsWith(nextWord)) configuration.flattenPackageHierarchy = ClassUtil.internalClassName(parseOptionalArgument());
else if (ConfigurationConstants.REPACKAGE_CLASSES_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument());
else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION .startsWith(nextWord)) configuration.repackageClasses = ClassUtil.internalClassName(parseOptionalArgument());
- else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION .startsWith(nextWord)) configuration.keepAttributes = parseCommaSeparatedList("attribute name", true, true, false, true, false, false, false, configuration.keepAttributes);
+ else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION .startsWith(nextWord)) configuration.keepAttributes = parseCommaSeparatedList("attribute name", true, true, false, false, true, false, false, false, configuration.keepAttributes);
+ else if (ConfigurationConstants.KEEP_PARAMETER_NAMES_OPTION .startsWith(nextWord)) configuration.keepParameterNames = parseNoArgument(true);
else if (ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION .startsWith(nextWord)) configuration.newSourceFileAttribute = parseOptionalArgument();
- else if (ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION .startsWith(nextWord)) configuration.adaptClassStrings = parseCommaSeparatedList("class name", true, true, false, true, false, true, false, configuration.adaptClassStrings);
- else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION .startsWith(nextWord)) configuration.adaptResourceFileNames = parseCommaSeparatedList("resource file name", true, true, false, false, false, false, false, configuration.adaptResourceFileNames);
- else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION .startsWith(nextWord)) configuration.adaptResourceFileContents = parseCommaSeparatedList("resource file name", true, true, false, false, false, false, false, configuration.adaptResourceFileContents);
+ else if (ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION .startsWith(nextWord)) configuration.adaptClassStrings = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.adaptClassStrings);
+ else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION .startsWith(nextWord)) configuration.adaptResourceFileNames = parseCommaSeparatedList("resource file name", true, true, false, true, false, false, false, false, configuration.adaptResourceFileNames);
+ else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION .startsWith(nextWord)) configuration.adaptResourceFileContents = parseCommaSeparatedList("resource file name", true, true, false, true, false, false, false, false, configuration.adaptResourceFileContents);
else if (ConfigurationConstants.DONT_PREVERIFY_OPTION .startsWith(nextWord)) configuration.preverify = parseNoArgument(false);
else if (ConfigurationConstants.MICRO_EDITION_OPTION .startsWith(nextWord)) configuration.microEdition = parseNoArgument(true);
else if (ConfigurationConstants.VERBOSE_OPTION .startsWith(nextWord)) configuration.verbose = parseNoArgument(true);
- else if (ConfigurationConstants.DONT_NOTE_OPTION .startsWith(nextWord)) configuration.note = parseCommaSeparatedList("class name", true, true, false, true, false, true, false, configuration.note);
- else if (ConfigurationConstants.DONT_WARN_OPTION .startsWith(nextWord)) configuration.warn = parseCommaSeparatedList("class name", true, true, false, true, false, true, false, configuration.warn);
+ else if (ConfigurationConstants.DONT_NOTE_OPTION .startsWith(nextWord)) configuration.note = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.note);
+ else if (ConfigurationConstants.DONT_WARN_OPTION .startsWith(nextWord)) configuration.warn = parseCommaSeparatedList("class name", true, true, false, false, true, false, true, false, configuration.warn);
else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION .startsWith(nextWord)) configuration.ignoreWarnings = parseNoArgument(true);
else if (ConfigurationConstants.PRINT_CONFIGURATION_OPTION .startsWith(nextWord)) configuration.printConfiguration = parseOptionalFile();
else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalFile();
@@ -190,7 +237,7 @@ public class ConfigurationParser
private long parseIncludeArgument(long lastModified) throws ParseException, IOException
{
// Read the configuation file name.
- readNextWord("configuration file name");
+ readNextWord("configuration file name", true, false);
File file = file(nextWord);
reader.includeWordReader(new FileWordReader(file));
@@ -204,7 +251,7 @@ public class ConfigurationParser
private void parseBaseDirectoryArgument() throws ParseException, IOException
{
// Read the base directory name.
- readNextWord("base directory name");
+ readNextWord("base directory name", true, false);
reader.setBaseDir(file(nextWord));
@@ -225,7 +272,7 @@ public class ConfigurationParser
while (true)
{
// Read the next jar name.
- readNextWord("jar or directory name");
+ readNextWord("jar or directory name", true, false);
// Create a new class path entry.
ClassPathEntry entry = new ClassPathEntry(file(nextWord), isOutput);
@@ -245,7 +292,7 @@ public class ConfigurationParser
{
// Read the filter.
filters[counter++] =
- parseCommaSeparatedList("filter", true, false, true, false, true, false, false, null);
+ parseCommaSeparatedList("filter", true, true, true, true, false, true, false, false, null);
}
while (counter < filters.length &&
ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord));
@@ -343,7 +390,7 @@ public class ConfigurationParser
throws ParseException, IOException
{
// Read the obligatory file name.
- readNextWord("file name");
+ readNextWord("file name", true, false);
// Make sure the file is properly resolved.
File file = file(nextWord);
@@ -358,12 +405,12 @@ public class ConfigurationParser
throws ParseException, IOException
{
// Read the optional file name.
- readNextWord();
+ readNextWord(true);
// Didn't the user specify a file name?
if (configurationEnd())
{
- return new File("");
+ return Configuration.STD_OUT;
}
// Make sure the file is properly resolved.
@@ -386,11 +433,11 @@ public class ConfigurationParser
return "";
}
- String fileName = nextWord;
+ String argument = nextWord;
readNextWord();
- return fileName;
+ return argument;
}
@@ -431,7 +478,8 @@ public class ConfigurationParser
{
readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD +
"', '" + ClassConstants.EXTERNAL_ACC_INTERFACE +
- "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", true);
+ "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'",
+ false, true);
if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord))
{
@@ -491,7 +539,8 @@ public class ConfigurationParser
// Read and add the class configuration.
readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD +
"', '" + ClassConstants.EXTERNAL_ACC_INTERFACE +
- "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", true);
+ "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'",
+ false, true);
classSpecifications.add(parseClassSpecificationArguments());
@@ -499,7 +548,13 @@ public class ConfigurationParser
}
- private ClassSpecification parseClassSpecificationArguments()
+ /**
+ * Parses and returns a class specification.
+ * @throws ParseException if the class specification contains a syntax error.
+ * @throws IOException if an IO error occurs while reading the class
+ * specification.
+ */
+ public ClassSpecification parseClassSpecificationArguments()
throws ParseException, IOException
{
// Clear the annotation type.
@@ -512,30 +567,21 @@ public class ConfigurationParser
// Parse the class annotations and access modifiers until the class keyword.
while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord))
{
- // Parse the annotation type, if any.
-// if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord))
-// {
-// annotationType =
-// ClassUtil.internalType(
-// ListUtil.commaSeparatedString(
-// parseCommaSeparatedList("annotation type",
-// true, false, false, true, false, null)));
-//
-// continue;
-// }
-
// Strip the negating sign, if any.
- String strippedWord = nextWord.startsWith(ConfigurationConstants.NEGATOR_KEYWORD) ?
+ boolean negated =
+ nextWord.startsWith(ConfigurationConstants.NEGATOR_KEYWORD);
+
+ String strippedWord = negated ?
nextWord.substring(1) :
nextWord;
// Parse the class access modifiers.
- // TODO: Distinguish annotation from annotation modifier.
int accessFlag =
strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_ANNOTATION) ? ClassConstants.INTERNAL_ACC_ANNOTATTION :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_ENUM) ? ClassConstants.INTERNAL_ACC_ENUM :
unknownAccessFlag();
@@ -543,9 +589,11 @@ public class ConfigurationParser
// Is it an annotation modifier?
if (accessFlag == ClassConstants.INTERNAL_ACC_ANNOTATTION)
{
- // Is the next word actually an annotation type?
- readNextWord("annotation type or keyword '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'", false);
+ // Already read the next word.
+ readNextWord("annotation type or keyword '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'",
+ false, false);
+ // Is the next word actually an annotation type?
if (!nextWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) &&
!nextWord.equals(ClassConstants.EXTERNAL_ACC_ENUM) &&
!nextWord.equals(ConfigurationConstants.CLASS_KEYWORD))
@@ -554,13 +602,17 @@ public class ConfigurationParser
annotationType =
ListUtil.commaSeparatedString(
parseCommaSeparatedList("annotation type",
- false, false, false, true, false, false, true, null));
+ false, false, false, false, true, false, false, true, null), false);
+ // Continue parsing the access modifier that we just read
+ // in the next cycle.
continue;
}
+
+ // Otherwise just handle the annotation modifier.
}
- if (strippedWord.equals(nextWord))
+ if (!negated)
{
requiredSetClassAccessFlags |= accessFlag;
}
@@ -569,7 +621,6 @@ public class ConfigurationParser
requiredUnsetClassAccessFlags |= accessFlag;
}
-
if ((requiredSetClassAccessFlags &
requiredUnsetClassAccessFlags) != 0)
{
@@ -585,16 +636,21 @@ public class ConfigurationParser
break;
}
- readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD +
- "', '" + ClassConstants.EXTERNAL_ACC_INTERFACE +
- "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'", true);
+ // Should we read the next word?
+ if (accessFlag != ClassConstants.INTERNAL_ACC_ANNOTATTION)
+ {
+ readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD +
+ "', '" + ClassConstants.EXTERNAL_ACC_INTERFACE +
+ "', or '" + ClassConstants.EXTERNAL_ACC_ENUM + "'",
+ false, true);
+ }
}
// Parse the class name part.
String externalClassName =
ListUtil.commaSeparatedString(
parseCommaSeparatedList("class name or interface name",
- true, false, false, true, false, false, false, null));
+ true, false, false, false, true, false, false, false, null), false);
// For backward compatibility, allow a single "*" wildcard to match any
// class.
@@ -612,7 +668,7 @@ public class ConfigurationParser
if (ConfigurationConstants.IMPLEMENTS_KEYWORD.equals(nextWord) ||
ConfigurationConstants.EXTENDS_KEYWORD.equals(nextWord))
{
- readNextWord("class name or interface name", true);
+ readNextWord("class name or interface name", false, true);
// Parse the annotation type, if any.
if (ConfigurationConstants.ANNOTATION_KEYWORD.equals(nextWord))
@@ -620,13 +676,13 @@ public class ConfigurationParser
extendsAnnotationType =
ListUtil.commaSeparatedString(
parseCommaSeparatedList("annotation type",
- true, false, false, true, false, false, true, null));
+ true, false, false, false, true, false, false, true, null), false);
}
String externalExtendsClassName =
ListUtil.commaSeparatedString(
parseCommaSeparatedList("class name or interface name",
- false, false, false, true, false, false, false, null));
+ false, false, false, false, true, false, false, false, null), false);
extendsClassName = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalExtendsClassName) ?
null :
@@ -659,7 +715,8 @@ public class ConfigurationParser
while (true)
{
readNextWord("class member description" +
- " or closing '" + ConfigurationConstants.CLOSE_KEYWORD + "'", true);
+ " or closing '" + ConfigurationConstants.CLOSE_KEYWORD + "'",
+ false, true);
if (nextWord.equals(ConfigurationConstants.CLOSE_KEYWORD))
{
@@ -697,8 +754,7 @@ public class ConfigurationParser
annotationType =
ListUtil.commaSeparatedString(
parseCommaSeparatedList("annotation type",
- true, false, false, true, false, false, true, null));
-
+ true, false, false, false, true, false, false, true, null), false);
continue;
}
@@ -716,9 +772,12 @@ public class ConfigurationParser
strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_BRIDGE) ? ClassConstants.INTERNAL_ACC_BRIDGE :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_VARARGS) ? ClassConstants.INTERNAL_ACC_VARARGS :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
strippedWord.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC :
0;
if (accessFlag == 0)
{
@@ -875,7 +934,7 @@ public class ConfigurationParser
// Parse the method arguments.
String descriptor =
ClassUtil.internalMethodDescriptor(type,
- parseCommaSeparatedList("argument", true, true, true, true, false, false, false, null));
+ parseCommaSeparatedList("argument", true, true, true, false, true, false, false, false, null));
if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord))
{
@@ -913,14 +972,30 @@ public class ConfigurationParser
/**
- * Reads a comma-separated list of java identifiers or of file names. If an
- * empty list is allowed, the reading will end after a closing parenthesis
- * or semi-colon.
+ * Reads a comma-separated list of java identifiers or of file names.
+ * Examples of invocation arguments:
+ * ("directory n", true, true, false, true, false, true, false, false, ...)
+ * ("optimizatio", true, false, false, false, false, false, false, false, ...)
+ * ("package nam", true, true, false, false, true, false, true, false, ...)
+ * ("attribute n", true, true, false, false, true, false, false, false, ...)
+ * ("class name", true, true, false, false, true, false, true, false, ...)
+ * ("resource fi", true, true, false, true, false, false, false, false, ...)
+ * ("resource fi", true, true, false, true, false, false, false, false, ...)
+ * ("class name", true, true, false, false, true, false, true, false, ...)
+ * ("class name", true, true, false, false, true, false, true, false, ...)
+ * ("filter", true, true, true, true, false, true, false, false, ...)
+ * ("annotation ", false, false, false, false, true, false, false, true, ...)
+ * ("class name ", true, false, false, false, true, false, false, false, ...)
+ * ("annotation ", true, false, false, false, true, false, false, true, ...)
+ * ("class name ", false, false, false, false, true, false, false, false, ...)
+ * ("annotation ", true, false, false, false, true, false, false, true, ...)
+ * ("argument", true, true, true, false, true, false, false, false, ...)
*/
private List parseCommaSeparatedList(String expectedDescription,
boolean readFirstWord,
boolean allowEmptyList,
boolean expectClosingParenthesis,
+ boolean isFileName,
boolean checkJavaIdentifiers,
boolean replaceSystemProperties,
boolean replaceExternalClassNames,
@@ -935,19 +1010,38 @@ public class ConfigurationParser
if (readFirstWord)
{
- if (expectClosingParenthesis || !allowEmptyList)
+ if (!allowEmptyList)
{
// Read the first list entry.
- readNextWord(expectedDescription);
+ readNextWord(expectedDescription, isFileName, false);
+ }
+ else if (expectClosingParenthesis)
+ {
+ // Read the first list entry.
+ readNextWord(expectedDescription, isFileName, false);
+
+ // Return if the entry is actually empty (an empty file name or
+ // a closing parenthesis).
+ if (nextWord.length() == 0)
+ {
+ // Read the closing parenthesis
+ readNextWord("closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD +
+ "'");
+
+ return list;
+ }
+ else if (nextWord.equals(ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD))
+ {
+ return list;
+ }
}
else
{
// Read the first list entry, if there is any.
- readNextWord();
+ readNextWord(isFileName);
// Check if the list is empty.
- if (configurationEnd() ||
- nextWord.equals(ConfigurationConstants.ANY_ATTRIBUTE_KEYWORD))
+ if (configurationEnd())
{
return list;
}
@@ -956,14 +1050,6 @@ public class ConfigurationParser
while (true)
{
- if (expectClosingParenthesis &&
- list.size() == 0 &&
- (ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord) ||
- ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)))
- {
- break;
- }
-
if (checkJavaIdentifiers)
{
checkJavaIdentifier("java type");
@@ -1001,14 +1087,12 @@ public class ConfigurationParser
if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord))
{
- break;
+ return list;
}
// Read the next list entry.
- readNextWord(expectedDescription);
+ readNextWord(expectedDescription, isFileName, false);
}
-
- return list;
}
@@ -1035,23 +1119,13 @@ public class ConfigurationParser
file = new File(reader.getBaseDir(), fileName);
}
- // Try to get a canonical representation.
- try
- {
- file = file.getCanonicalFile();
- }
- catch (IOException ex)
- {
- // Just keep the original representation.
- }
-
return file;
}
/**
- * Replaces any system properties in the given word by their values
- * (e.g. the substring "WordReader
that returns words from a line number reader.
+ *
+ * @author Eric Lafortune
+ */
+public class LineWordReader extends WordReader
+{
+ private final LineNumberReader reader;
+ private final String description;
+
+
+ /**
+ * Creates a new LineWordReader for the given input.
+ */
+ public LineWordReader(LineNumberReader lineNumberReader,
+ String description,
+ File baseDir) throws IOException
+ {
+ super(baseDir);
+
+ this.reader = lineNumberReader;
+ this.description = description;
+ }
+
+
+ // Implementations for WordReader.
+
+ protected String nextLine() throws IOException
+ {
+ return reader.readLine();
+ }
+
+
+ protected String lineLocationDescription()
+ {
+ return "line " + reader.getLineNumber() + " of " + description;
+ }
+
+
+ public void close() throws IOException
+ {
+ super.close();
+
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+}
diff --git a/src/proguard/MemberSpecification.java b/src/proguard/MemberSpecification.java
index 1cfa962..e771fde 100644
--- a/src/proguard/MemberSpecification.java
+++ b/src/proguard/MemberSpecification.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/OutputWriter.java b/src/proguard/OutputWriter.java
index 10c18fb..c4467cf 100644
--- a/src/proguard/OutputWriter.java
+++ b/src/proguard/OutputWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -63,13 +63,12 @@ public class OutputWriter
"] must be specified after an input jar, or it will be empty.");
}
- // Perform some checks on the output jars.
+ // Check if the first of two subsequent the output jars has a filter.
for (int index = 0; index < programJars.size() - 1; index++)
{
ClassPathEntry entry = programJars.get(index);
if (entry.isOutput())
{
- // Check if all but the last output jars have filters.
if (entry.getFilter() == null &&
entry.getJarFilter() == null &&
entry.getWarFilter() == null &&
@@ -78,10 +77,17 @@ public class OutputWriter
programJars.get(index + 1).isOutput())
{
throw new IOException("The output jar [" + entry.getName() +
- "] must have a filter, or all subsequent jars will be empty.");
+ "] must have a filter, or all subsequent output jars will be empty.");
}
+ }
+ }
- // Check if the output jar name is different from the input jar names.
+ // Check if the output jar names are different from the input jar names.
+ for (int outIndex = 0; outIndex < programJars.size() - 1; outIndex++)
+ {
+ ClassPathEntry entry = programJars.get(outIndex);
+ if (entry.isOutput())
+ {
for (int inIndex = 0; inIndex < programJars.size(); inIndex++)
{
ClassPathEntry otherEntry = programJars.get(inIndex);
@@ -96,6 +102,40 @@ public class OutputWriter
}
}
+ // Check for potential problems with mixed-case class names on
+ // case-insensitive file systems.
+ if (configuration.obfuscate &&
+ configuration.useMixedCaseClassNames &&
+ configuration.classObfuscationDictionary == null &&
+ (configuration.note == null ||
+ !configuration.note.isEmpty()))
+ {
+ String os = System.getProperty("os.name").toLowerCase();
+ if (os.startsWith("windows") ||
+ os.startsWith("mac os"))
+ {
+ // Go over all program class path entries.
+ for (int index = 0; index < programJars.size(); index++)
+ {
+ // Is it an output directory?
+ ClassPathEntry entry = programJars.get(index);
+ if (entry.isOutput() &&
+ !entry.isJar() &&
+ !entry.isWar() &&
+ !entry.isEar() &&
+ !entry.isZip())
+ {
+ System.out.println("Note: you're writing the processed class files to a directory [" + entry.getName() +"].");
+ System.out.println(" This will likely cause problems with obfuscated mixed-case class names.");
+ System.out.println(" You should consider writing the output to a jar file, or otherwise");
+ System.out.println(" specify '-dontusemixedcaseclassnames'.");
+
+ break;
+ }
+ }
+ }
+ }
+
int firstInputIndex = 0;
int lastInputIndex = 0;
@@ -166,7 +206,7 @@ public class OutputWriter
{
resourceRewriter =
new NameFilter(configuration.adaptResourceFileContents,
- new NameFilter("META-INF/**",
+ new NameFilter("META-INF/MANIFEST.MF,META-INF/*.SF",
new ManifestRewriter(programClassPool, writer),
new DataEntryRewriter(programClassPool, writer)),
resourceRewriter);
@@ -221,7 +261,7 @@ public class OutputWriter
}
catch (IOException ex)
{
- throw new IOException("Can't write [" + classPath.get(fromOutputIndex).getName() + "] (" + ex.getMessage() + ")");
+ throw (IOException)new IOException("Can't write [" + classPath.get(fromOutputIndex).getName() + "] (" + ex.getMessage() + ")").initCause(ex);
}
}
@@ -232,25 +272,25 @@ public class OutputWriter
*/
private static Map createPackagePrefixMap(ClassPool classPool)
{
- Map PackagePrefixMap = new HashMap();
+ Map packagePrefixMap = new HashMap();
Iterator iterator = classPool.classNames();
while (iterator.hasNext())
{
String className = (String)iterator.next();
- String PackagePrefix = ClassUtil.internalPackagePrefix(className);
+ String packagePrefix = ClassUtil.internalPackagePrefix(className);
- String mappedNewPackagePrefix = (String)PackagePrefixMap.get(PackagePrefix);
+ String mappedNewPackagePrefix = (String)packagePrefixMap.get(packagePrefix);
if (mappedNewPackagePrefix == null ||
- !mappedNewPackagePrefix.equals(PackagePrefix))
+ !mappedNewPackagePrefix.equals(packagePrefix))
{
String newClassName = classPool.getClass(className).getName();
String newPackagePrefix = ClassUtil.internalPackagePrefix(newClassName);
- PackagePrefixMap.put(PackagePrefix, newPackagePrefix);
+ packagePrefixMap.put(packagePrefix, newPackagePrefix);
}
}
- return PackagePrefixMap;
+ return packagePrefixMap;
}
}
diff --git a/src/proguard/ParseException.java b/src/proguard/ParseException.java
index 9294200..b4af6c2 100644
--- a/src/proguard/ParseException.java
+++ b/src/proguard/ParseException.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ProGuard.java b/src/proguard/ProGuard.java
index 8c30e10..f9dbf54 100644
--- a/src/proguard/ProGuard.java
+++ b/src/proguard/ProGuard.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,11 +24,12 @@ import proguard.classfile.ClassPool;
import proguard.classfile.editor.ClassElementSorter;
import proguard.classfile.visitor.*;
import proguard.obfuscate.Obfuscator;
-import proguard.optimize.Optimizer;
+import proguard.optimize.*;
import proguard.preverify.*;
import proguard.shrink.Shrinker;
import java.io.*;
+import java.util.Properties;
/**
* Tool for shrinking, optimizing, obfuscating, and preverifying Java classes.
@@ -37,7 +38,7 @@ import java.io.*;
*/
public class ProGuard
{
- public static final String VERSION = "ProGuard, version 4.4";
+ public static final String VERSION = "ProGuard, version 4.10";
private final Configuration configuration;
private ClassPool programClassPool = new ClassPool();
@@ -77,7 +78,8 @@ public class ProGuard
readInput();
- if (configuration.shrink ||
+ if (configuration.printSeeds != null ||
+ configuration.shrink ||
configuration.optimize ||
configuration.obfuscate ||
configuration.preverify)
@@ -236,30 +238,10 @@ public class ProGuard
System.out.println("Printing kept classes, fields, and methods...");
}
- // Check if we have at least some keep commands.
- if (configuration.keep == null)
- {
- throw new IOException("You have to specify '-keep' options for the shrinking step.");
- }
-
PrintStream ps = createPrintStream(configuration.printSeeds);
try
{
- // Create a visitor for printing out the seeds. We're printing out
- // the program elements that are preserved against shrinking,
- // optimization, or obfuscation.
- SimpleClassPrinter printer = new SimpleClassPrinter(false, ps);
- ClassPoolVisitor classPoolvisitor =
- ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
- new ProgramClassFilter(printer),
- new ProgramMemberFilter(printer),
- true,
- true,
- true);
-
- // Print out the seeds.
- programClassPool.accept(classPoolvisitor);
- libraryClassPool.accept(classPoolvisitor);
+ new SeedPrinter(ps).write(configuration, programClassPool, libraryClassPool);
}
finally
{
@@ -421,9 +403,10 @@ public class ProGuard
private PrintStream createPrintStream(File file)
throws FileNotFoundException
{
- return isFile(file) ?
- new PrintStream(new BufferedOutputStream(new FileOutputStream(file))) :
- System.out;
+ return file == Configuration.STD_OUT ? System.out :
+ new PrintStream(
+ new BufferedOutputStream(
+ new FileOutputStream(file)));
}
@@ -445,24 +428,26 @@ public class ProGuard
/**
- * Returns the absolute file name for the given file, or the standard output
+ * Returns the canonical file name for the given file, or "standard output"
* if the file name is empty.
*/
private String fileName(File file)
{
- return isFile(file) ?
- file.getAbsolutePath() :
- "standard output";
- }
-
-
- /**
- * Returns whether the given file is actually a file, or just a placeholder
- * for the standard output.
- */
- private boolean isFile(File file)
- {
- return file.getPath().length() > 0;
+ if (file == Configuration.STD_OUT)
+ {
+ return "standard output";
+ }
+ else
+ {
+ try
+ {
+ return file.getCanonicalPath();
+ }
+ catch (IOException ex)
+ {
+ return file.getPath();
+ }
+ }
}
@@ -484,8 +469,8 @@ public class ProGuard
try
{
// Parse the options specified in the command line arguments.
- ConfigurationParser parser = new ConfigurationParser(args);
-
+ ConfigurationParser parser = new ConfigurationParser(args,
+ System.getProperties());
try
{
parser.parse(configuration);
diff --git a/src/proguard/SeedPrinter.java b/src/proguard/SeedPrinter.java
new file mode 100644
index 0000000..8ed74b6
--- /dev/null
+++ b/src/proguard/SeedPrinter.java
@@ -0,0 +1,97 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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;
+
+import proguard.classfile.ClassPool;
+import proguard.classfile.attribute.visitor.AllAttributeVisitor;
+import proguard.classfile.constant.visitor.AllConstantVisitor;
+import proguard.classfile.instruction.visitor.AllInstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
+import proguard.util.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This class prints out the seeds specified by keep options.
+ *
+ * @author Eric Lafortune
+ */
+public class SeedPrinter
+{
+ private final PrintStream ps;
+
+
+ /**
+ * Creates a new ConfigurationWriter for the given PrintStream.
+ */
+ public SeedPrinter(PrintStream ps) throws IOException
+ {
+ this.ps = ps;
+ }
+
+
+ /**
+ * Prints out the seeds for the classes in the given program class pool.
+ * @param configuration the configuration containing the keep options.
+ * @throws IOException if an IO error occurs while writing the configuration.
+ */
+ public void write(Configuration configuration,
+ ClassPool programClassPool,
+ ClassPool libraryClassPool) throws IOException
+ {
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the shrinking step.");
+ }
+
+ // Clean up any old visitor info.
+ programClassPool.classesAccept(new ClassCleaner());
+ libraryClassPool.classesAccept(new ClassCleaner());
+
+ // Create a visitor for printing out the seeds. We're printing out
+ // the program elements that are preserved against shrinking,
+ // optimization, or obfuscation.
+ KeepMarker keepMarker = new KeepMarker();
+ ClassPoolVisitor classPoolvisitor =
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+ keepMarker,
+ keepMarker,
+ true,
+ true,
+ true);
+ // Mark the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ // Print out the seeds.
+ SimpleClassPrinter printer = new SimpleClassPrinter(false, ps);
+ programClassPool.classesAcceptAlphabetically(new MultiClassVisitor(
+ new ClassVisitor[]
+ {
+ new KeptClassFilter(printer),
+ new AllMemberVisitor(new KeptMemberFilter(printer))
+ }));
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/SubclassedClassFilter.java b/src/proguard/SubclassedClassFilter.java
index 27cac11..1b9c1fe 100644
--- a/src/proguard/SubclassedClassFilter.java
+++ b/src/proguard/SubclassedClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/Targeter.java b/src/proguard/Targeter.java
index 5067205..675f0df 100644
--- a/src/proguard/Targeter.java
+++ b/src/proguard/Targeter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/UpToDateChecker.java b/src/proguard/UpToDateChecker.java
index 9fa5d16..7f5e7a6 100644
--- a/src/proguard/UpToDateChecker.java
+++ b/src/proguard/UpToDateChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -47,107 +47,186 @@ public class UpToDateChecker
*/
public boolean check()
{
- long inputLastModified = configuration.lastModified;
- long outputLastModified = Long.MAX_VALUE;
+ try
+ {
+ ModificationTimeChecker checker = new ModificationTimeChecker();
- ClassPath programJars = configuration.programJars;
- ClassPath libraryJars = configuration.libraryJars;
+ checker.updateInputModificationTime(configuration.lastModified);
- // Check the dates of the program jars, if any.
- if (programJars != null)
- {
- for (int index = 0; index < programJars.size(); index++)
+ ClassPath programJars = configuration.programJars;
+ ClassPath libraryJars = configuration.libraryJars;
+
+ // Check the dates of the program jars, if any.
+ if (programJars != null)
{
- // Break early, if possible.
- if (inputLastModified >= outputLastModified)
+ for (int index = 0; index < programJars.size(); index++)
{
- break;
- }
+ // Update the input and output modification times.
+ ClassPathEntry classPathEntry = programJars.get(index);
- // Update the input and output modification times.
- ClassPathEntry classPathEntry = programJars.get(index);
- if (classPathEntry.isOutput())
- {
- long lastModified = lastModified(classPathEntry.getFile(), true);
- if (outputLastModified > lastModified)
- {
- outputLastModified = lastModified;
- }
- }
- else
- {
- long lastModified = lastModified(classPathEntry.getFile(), false);
- if (inputLastModified < lastModified)
- {
- inputLastModified = lastModified;
- }
+ checker.updateModificationTime(classPathEntry.getFile(),
+ classPathEntry.isOutput());
}
}
- }
- // Check the dates of the library jars, if any.
- if (libraryJars != null)
- {
- for (int index = 0; index < libraryJars.size(); index++)
+ // Check the dates of the library jars, if any.
+ if (libraryJars != null)
{
- // Break early, if possible.
- if (inputLastModified >= outputLastModified)
+ for (int index = 0; index < libraryJars.size(); index++)
{
- break;
- }
+ // Update the input modification time.
+ ClassPathEntry classPathEntry = libraryJars.get(index);
- // Update the input modification time.
- ClassPathEntry classPathEntry = libraryJars.get(index);
- long lastModified = lastModified(classPathEntry.getFile(), false);
- if (inputLastModified < lastModified)
- {
- inputLastModified = lastModified;
+ checker.updateModificationTime(classPathEntry.getFile(),
+ false);
}
}
- }
- boolean outputUpToDate = inputLastModified < outputLastModified;
- if (outputUpToDate)
+ // Check the dates of the auxiliary input files.
+ checker.updateInputModificationTime(configuration.applyMapping);
+ checker.updateInputModificationTime(configuration.obfuscationDictionary);
+ checker.updateInputModificationTime(configuration.classObfuscationDictionary);
+ checker.updateInputModificationTime(configuration.packageObfuscationDictionary);
+
+ // Check the dates of the auxiliary output files.
+ checker.updateOutputModificationTime(configuration.printSeeds);
+ checker.updateOutputModificationTime(configuration.printUsage);
+ checker.updateOutputModificationTime(configuration.printMapping);
+ checker.updateOutputModificationTime(configuration.printConfiguration);
+ checker.updateOutputModificationTime(configuration.dump);
+ }
+ catch (IllegalStateException e)
{
- System.out.println("The output is up to date");
+ // The output is outdated.
+ return false;
}
- return outputUpToDate;
+ System.out.println("The output seems up to date");
+
+ return true;
}
/**
- * Returns the minimum or maximum modification time of the given file or
- * of the files in the given directory (recursively).
+ * This class maintains the modification times of input and output.
+ * The methods throw an IllegalStateException if the output appears
+ * outdated.
*/
- private long lastModified(File file, boolean minimum)
- {
- // Is it a directory?
- if (file.isDirectory())
+ private static class ModificationTimeChecker {
+
+ private long inputModificationTime = Long.MIN_VALUE;
+ private long outputModificationTime = Long.MAX_VALUE;
+
+
+ /**
+ * Updates the input modification time based on the given file or
+ * directory (recursively).
+ */
+ public void updateInputModificationTime(File file)
{
- // Ignore the directory's modification time; just recurse on its files.
- File[] files = file.listFiles();
+ if (file != null)
+ {
+ updateModificationTime(file, false);
+ }
+ }
- // Still, an empty output directory is probably a sign that it is
- // not up to date.
- long lastModified = files.length != 0 && minimum ?
- Long.MAX_VALUE : 0L;
- for (int index = 0; index < files.length; index++)
+ /**
+ * Updates the input modification time based on the given file or
+ * directory (recursively).
+ */
+ public void updateOutputModificationTime(File file)
+ {
+ if (file != null && file.getName().length() > 0)
{
- long fileLastModified = lastModified(files[index], minimum);
- if ((lastModified < fileLastModified) ^ minimum)
+ updateModificationTime(file, true);
+ }
+ }
+
+
+ /**
+ * Updates the specified modification time based on the given file or
+ * directory (recursively).
+ */
+ public void updateModificationTime(File file, boolean isOutput)
+ {
+ // Is it a directory?
+ if (file.isDirectory())
+ {
+ // Ignore the directory's modification time; just recurse on
+ // its files.
+ File[] files = file.listFiles();
+
+ // Still, an empty output directory is probably a sign that it
+ // is not up to date.
+ if (files.length == 0 && isOutput)
{
- lastModified = fileLastModified;
+ updateOutputModificationTime(Long.MIN_VALUE);
}
+
+ for (int index = 0; index < files.length; index++)
+ {
+ updateModificationTime(files[index], isOutput);
+ }
+ }
+ else
+ {
+ // Update with the file's modification time.
+ updateModificationTime(file.lastModified(), isOutput);
}
+ }
+
- return lastModified;
+ /**
+ * Updates the specified modification time.
+ */
+ public void updateModificationTime(long time, boolean isOutput)
+ {
+ if (isOutput)
+ {
+ updateOutputModificationTime(time);
+ }
+ else
+ {
+ updateInputModificationTime(time);
+ }
}
- else
+
+
+ /**
+ * Updates the input modification time.
+ */
+ public void updateInputModificationTime(long time)
{
- // Return the file's modification time.
- return file.lastModified();
+ if (inputModificationTime < time)
+ {
+ inputModificationTime = time;
+
+ checkModificationTimes();
+ }
+ }
+
+
+ /**
+ * Updates the output modification time.
+ */
+ public void updateOutputModificationTime(long time)
+ {
+ if (outputModificationTime > time)
+ {
+ outputModificationTime = time;
+
+ checkModificationTimes();
+ }
+ }
+
+
+ private void checkModificationTimes()
+ {
+ if (inputModificationTime > outputModificationTime)
+ {
+ throw new IllegalStateException("The output is outdated");
+ }
}
}
}
diff --git a/src/proguard/WordReader.java b/src/proguard/WordReader.java
index d73505a..110fce3 100644
--- a/src/proguard/WordReader.java
+++ b/src/proguard/WordReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -105,9 +105,11 @@ public abstract class WordReader
* Reads a word from this WordReader, or from one of its active included
* WordReader objects.
*
+ * @param isFileName return a complete line (or argument), if the word
+ * isn't an option (it doesn't start with '-').
* @return the read word.
*/
- public String nextWord() throws IOException
+ public String nextWord(boolean isFileName) throws IOException
{
currentWord = null;
@@ -115,7 +117,7 @@ public abstract class WordReader
if (includeWordReader != null)
{
// Does the included word reader still produce a word?
- currentWord = includeWordReader.nextWord();
+ currentWord = includeWordReader.nextWord(isFileName);
if (currentWord != null)
{
// Return it if so.
@@ -129,12 +131,22 @@ public abstract class WordReader
// Get a word from this reader.
- // Skip leading whitespace.
- while (currentLine != null &&
- currentIndex < currentLineLength &&
- Character.isWhitespace(currentLine.charAt(currentIndex)))
+ // Skip any whitespace and comments left on the current line.
+ if (currentLine != null)
{
- currentIndex++;
+ // Skip any leading whitespace.
+ while (currentIndex < currentLineLength &&
+ Character.isWhitespace(currentLine.charAt(currentIndex)))
+ {
+ currentIndex++;
+ }
+
+ // Skip any comments.
+ if (currentIndex < currentLineLength &&
+ isComment(currentLine.charAt(currentIndex)))
+ {
+ currentIndex = currentLineLength;
+ }
}
// Make sure we have a non-blank line.
@@ -146,29 +158,28 @@ public abstract class WordReader
return null;
}
- // Trim off any comments.
- int comments_start = currentLine.indexOf(COMMENT_CHARACTER);
- if (comments_start >= 0)
+ currentLineLength = currentLine.length();
+
+ // Skip any leading whitespace.
+ currentIndex = 0;
+ while (currentIndex < currentLineLength &&
+ Character.isWhitespace(currentLine.charAt(currentIndex)))
{
- currentLineLength = comments_start;
+ currentIndex++;
+ }
+ // Remember any leading comments.
+ if (currentIndex < currentLineLength &&
+ isComment(currentLine.charAt(currentIndex)))
+ {
// Remember the comments.
- String comment = currentLine.substring(comments_start + 1);
+ String comment = currentLine.substring(currentIndex + 1);
currentComments = currentComments == null ?
comment :
currentComments + '\n' + comment;
- }
- else
- {
- currentLineLength = currentLine.length();
- }
- // Skip leading whitespace.
- currentIndex = 0;
- while (currentIndex < currentLineLength &&
- Character.isWhitespace(currentLine.charAt(currentIndex)))
- {
- currentIndex++;
+ // Skip the comments.
+ currentIndex = currentLineLength;
}
}
@@ -178,12 +189,7 @@ public abstract class WordReader
char startChar = currentLine.charAt(startIndex);
- if (isDelimiter(startChar))
- {
- // The next word is a single delimiting character.
- endIndex = ++currentIndex;
- }
- else if (isQuote(startChar))
+ if (isQuote(startChar))
{
// The next word is starting with a quote character.
// Skip the opening quote.
@@ -205,6 +211,39 @@ public abstract class WordReader
endIndex = currentIndex++;
}
+ else if (isFileName &&
+ !isOption(startChar))
+ {
+ // The next word is a (possibly optional) file name.
+ // Find the end of the line, the first path separator, the first
+ // option, or the first comment.
+ while (currentIndex < currentLineLength)
+ {
+ char currentCharacter = currentLine.charAt(currentIndex);
+ if (isFileDelimiter(currentCharacter) ||
+ ((isOption(currentCharacter) ||
+ isComment(currentCharacter)) &&
+ Character.isWhitespace(currentLine.charAt(currentIndex-1)))) {
+ break;
+ }
+
+ currentIndex++;
+ }
+
+ endIndex = currentIndex;
+
+ // Trim any trailing whitespace.
+ while (endIndex > startIndex &&
+ Character.isWhitespace(currentLine.charAt(endIndex-1)))
+ {
+ endIndex--;
+ }
+ }
+ else if (isDelimiter(startChar))
+ {
+ // The next word is a single delimiting character.
+ endIndex = ++currentIndex;
+ }
else
{
// The next word is a simple character string.
@@ -213,9 +252,9 @@ public abstract class WordReader
while (currentIndex < currentLineLength)
{
char currentCharacter = currentLine.charAt(currentIndex);
- if (isDelimiter(currentCharacter) ||
- Character.isWhitespace(currentCharacter))
- {
+ if (isDelimiter(currentCharacter) ||
+ Character.isWhitespace(currentCharacter) ||
+ isComment(currentCharacter)) {
break;
}
@@ -305,6 +344,18 @@ public abstract class WordReader
// Small utility methods.
+ private boolean isOption(char character)
+ {
+ return character == '-';
+ }
+
+
+ private boolean isComment(char character)
+ {
+ return character == COMMENT_CHARACTER;
+ }
+
+
private boolean isDelimiter(char character)
{
return character == '@' ||
@@ -318,6 +369,16 @@ public abstract class WordReader
}
+ private boolean isFileDelimiter(char character)
+ {
+ return character == '(' ||
+ character == ')' ||
+ character == ',' ||
+ character == ';' ||
+ character == File.pathSeparatorChar;
+ }
+
+
private boolean isQuote(char character)
{
return character == '\'' ||
diff --git a/src/proguard/ant/ClassPathElement.java b/src/proguard/ant/ClassPathElement.java
index b5c2df4..b496123 100644
--- a/src/proguard/ant/ClassPathElement.java
+++ b/src/proguard/ant/ClassPathElement.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ant/ClassSpecificationElement.java b/src/proguard/ant/ClassSpecificationElement.java
index f4ea2ff..c07e101 100644
--- a/src/proguard/ant/ClassSpecificationElement.java
+++ b/src/proguard/ant/ClassSpecificationElement.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -222,6 +222,7 @@ public class ClassSpecificationElement extends DataType
strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC :
strippedToken.equals(ClassConstants.EXTERNAL_ACC_ANNOTATION) ? ClassConstants.INTERNAL_ACC_ANNOTATTION :
0;
diff --git a/src/proguard/ant/ConfigurationElement.java b/src/proguard/ant/ConfigurationElement.java
index 76e9418..d184aef 100644
--- a/src/proguard/ant/ConfigurationElement.java
+++ b/src/proguard/ant/ConfigurationElement.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,34 +20,105 @@
*/
package proguard.ant;
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.types.DataType;
-import proguard.Configuration;
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+import proguard.*;
+import proguard.util.ListUtil;
+
+import java.io.*;
+import java.util.Properties;
/**
- * This DataType represents a reference to a ProGuard configuration in Ant.
+ * This DataType represents a reference to an XML-style ProGuard configuration
+ * in Ant, or a file set of ProGuard-style configuration files.
*
* @author Eric Lafortune
*/
-public class ConfigurationElement extends DataType
+public class ConfigurationElement extends FileSet
{
/**
- * Adds the contents of this configuration task to the given configuration.
+ * Adds the contents of this configuration element to the given
+ * configuration.
* @param configuration the configuration to be extended.
*/
public void appendTo(Configuration configuration)
{
- // Get the referenced element.
- if (!isReference())
+ File baseDir;
+ String[] fileNames;
+
+ if (isReference())
{
- throw new BuildException("Nested element null
if the class with the given name is not in the class
- * pool. Returns the base class if the class name is an array type.
+ * pool.
*/
public Clazz getClass(String className)
{
- return (Clazz)classes.get(ClassUtil.internalClassNameFromClassType(className));
+ return (Clazz)classes.get(className);
}
@@ -122,8 +133,11 @@ public class ClassPool
*/
public void classesAcceptAlphabetically(ClassVisitor classVisitor)
{
- TreeMap sortedClasses = new TreeMap(classes);
- Iterator iterator = sortedClasses.values().iterator();
+ // We're already using a tree map.
+ //TreeMap sortedClasses = new TreeMap(classes);
+ //Iterator iterator = sortedClasses.values().iterator();
+
+ Iterator iterator = classes.values().iterator();
while (iterator.hasNext())
{
Clazz clazz = (Clazz)iterator.next();
diff --git a/src/proguard/classfile/Clazz.java b/src/proguard/classfile/Clazz.java
index da37d9a..35f8a1c 100644
--- a/src/proguard/classfile/Clazz.java
+++ b/src/proguard/classfile/Clazz.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -90,6 +90,16 @@ public interface Clazz extends VisitorAccepter
*/
public String getType(int constantIndex);
+ /**
+ * Returns the name of the RefConstant at the specified index.
+ */
+ public String getRefName(int constantIndex);
+
+ /**
+ * Returns the type of the RefConstant at the specified index.
+ */
+ public String getRefType(int constantIndex);
+
// Methods pertaining to related classes.
@@ -115,6 +125,13 @@ public interface Clazz extends VisitorAccepter
*/
public boolean extends_(Clazz clazz);
+ /**
+ * Returns whether this class extends the specified class.
+ * A class is always considered to extend itself.
+ * Interfaces are considered to only extend the root Object class.
+ */
+ public boolean extends_(String className);
+
/**
* Returns whether this class implements the given class.
* A class is always considered to implement itself.
@@ -122,6 +139,13 @@ public interface Clazz extends VisitorAccepter
*/
public boolean extendsOrImplements(Clazz clazz);
+ /**
+ * Returns whether this class implements the specified class.
+ * A class is always considered to implement itself.
+ * Interfaces are considered to implement all their superinterfaces.
+ */
+ public boolean extendsOrImplements(String className);
+
// Methods for getting specific class members.
@@ -229,4 +253,9 @@ public interface Clazz extends VisitorAccepter
* Lets the given attribute info visitor visit all attributes of this class.
*/
public void attributesAccept(AttributeVisitor attributeVisitor);
+
+ /**
+ * Lets the given attribute info visitor visit the specified attribute.
+ */
+ public void attributeAccept(String name, AttributeVisitor attributeVisitor);
}
diff --git a/src/proguard/classfile/Field.java b/src/proguard/classfile/Field.java
index ba1315a..61bf2da 100644
--- a/src/proguard/classfile/Field.java
+++ b/src/proguard/classfile/Field.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/LibraryClass.java b/src/proguard/classfile/LibraryClass.java
index 0a27593..151a32a 100644
--- a/src/proguard/classfile/LibraryClass.java
+++ b/src/proguard/classfile/LibraryClass.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -137,6 +137,17 @@ public class LibraryClass implements Clazz
}
+ public String getRefName(int constantIndex)
+ {
+ throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
+ }
+
+ public String getRefType(int constantIndex)
+ {
+ throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
+ }
+
+
public void addSubClass(Clazz clazz)
{
if (subClasses == null)
@@ -179,6 +190,18 @@ public class LibraryClass implements Clazz
}
+ public boolean extends_(String className)
+ {
+ if (getName().equals(className))
+ {
+ return true;
+ }
+
+ return superClass != null &&
+ superClass.extends_(className);
+ }
+
+
public boolean extendsOrImplements(Clazz clazz)
{
if (this.equals(clazz))
@@ -209,6 +232,36 @@ public class LibraryClass implements Clazz
}
+ public boolean extendsOrImplements(String className)
+ {
+ if (getName().equals(className))
+ {
+ return true;
+ }
+
+ if (superClass != null &&
+ superClass.extendsOrImplements(className))
+ {
+ return true;
+ }
+
+ if (interfaceClasses != null)
+ {
+ for (int index = 0; index < interfaceClasses.length; index++)
+ {
+ Clazz interfaceClass = interfaceClasses[index];
+ if (interfaceClass != null &&
+ interfaceClass.extendsOrImplements(className))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
public Field findField(String name, String descriptor)
{
for (int index = 0; index < fields.length; index++)
@@ -467,6 +520,12 @@ public class LibraryClass implements Clazz
}
+ public void attributeAccept(String name, AttributeVisitor attributeVisitor)
+ {
+ throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
+ }
+
+
// Implementations for VisitorAccepter.
public Object getVisitorInfo()
diff --git a/src/proguard/classfile/LibraryField.java b/src/proguard/classfile/LibraryField.java
index 2908c37..1c1c427 100644
--- a/src/proguard/classfile/LibraryField.java
+++ b/src/proguard/classfile/LibraryField.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/LibraryMember.java b/src/proguard/classfile/LibraryMember.java
index 41ccb60..8d8d00e 100644
--- a/src/proguard/classfile/LibraryMember.java
+++ b/src/proguard/classfile/LibraryMember.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/LibraryMethod.java b/src/proguard/classfile/LibraryMethod.java
index a49a5f1..ac07857 100644
--- a/src/proguard/classfile/LibraryMethod.java
+++ b/src/proguard/classfile/LibraryMethod.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/Member.java b/src/proguard/classfile/Member.java
index 1400b9c..ee2cf19 100644
--- a/src/proguard/classfile/Member.java
+++ b/src/proguard/classfile/Member.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/Method.java b/src/proguard/classfile/Method.java
index ebcae2b..64ff50a 100644
--- a/src/proguard/classfile/Method.java
+++ b/src/proguard/classfile/Method.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/ProgramClass.java b/src/proguard/classfile/ProgramClass.java
index 9d0fc0c..54bb8b1 100644
--- a/src/proguard/classfile/ProgramClass.java
+++ b/src/proguard/classfile/ProgramClass.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -117,8 +117,7 @@ public class ProgramClass implements Clazz
}
catch (ClassCastException ex)
{
- new ClassPrinter().visitProgramClass(this);
- throw new ClassCastException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
+ throw ((IllegalStateException)new IllegalStateException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
}
}
@@ -130,7 +129,7 @@ public class ProgramClass implements Clazz
}
catch (ClassCastException ex)
{
- throw new ClassCastException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
+ throw ((IllegalStateException)new IllegalStateException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
}
}
@@ -142,7 +141,7 @@ public class ProgramClass implements Clazz
}
catch (ClassCastException ex)
{
- throw new ClassCastException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
+ throw ((IllegalStateException)new IllegalStateException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
}
}
@@ -154,7 +153,7 @@ public class ProgramClass implements Clazz
}
catch (ClassCastException ex)
{
- throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
+ throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
}
}
@@ -166,7 +165,32 @@ public class ProgramClass implements Clazz
}
catch (ClassCastException ex)
{
- throw new ClassCastException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"], found ["+ex.getMessage()+"]");
+ throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
+ }
+ }
+
+
+ public String getRefName(int constantIndex)
+ {
+ try
+ {
+ return ((RefConstant)constantPool[constantIndex]).getName(this);
+ }
+ catch (ClassCastException ex)
+ {
+ throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
+ }
+ }
+
+ public String getRefType(int constantIndex)
+ {
+ try
+ {
+ return ((RefConstant)constantPool[constantIndex]).getType(this);
+ }
+ catch (ClassCastException ex)
+ {
+ throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
}
}
@@ -216,6 +240,19 @@ public class ProgramClass implements Clazz
}
+ public boolean extends_(String className)
+ {
+ if (getName().equals(className))
+ {
+ return true;
+ }
+
+ Clazz superClass = getSuperClass();
+ return superClass != null &&
+ superClass.extends_(className);
+ }
+
+
public boolean extendsOrImplements(Clazz clazz)
{
if (this.equals(clazz))
@@ -244,6 +281,34 @@ public class ProgramClass implements Clazz
}
+ public boolean extendsOrImplements(String className)
+ {
+ if (getName().equals(className))
+ {
+ return true;
+ }
+
+ Clazz superClass = getSuperClass();
+ if (superClass != null &&
+ superClass.extendsOrImplements(className))
+ {
+ return true;
+ }
+
+ for (int index = 0; index < u2interfacesCount; index++)
+ {
+ Clazz interfaceClass = getInterface(index);
+ if (interfaceClass != null &&
+ interfaceClass.extendsOrImplements(className))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
public Field findField(String name, String descriptor)
{
for (int index = 0; index < u2fieldsCount; index++)
@@ -472,6 +537,19 @@ public class ProgramClass implements Clazz
}
+ public void attributeAccept(String name, AttributeVisitor attributeVisitor)
+ {
+ for (int index = 0; index < u2attributesCount; index++)
+ {
+ Attribute attribute = attributes[index];
+ if (attribute.getAttributeName(this).equals(name))
+ {
+ attribute.accept(this, attributeVisitor);
+ }
+ }
+ }
+
+
// Implementations for VisitorAccepter.
public Object getVisitorInfo()
diff --git a/src/proguard/classfile/ProgramField.java b/src/proguard/classfile/ProgramField.java
index 5991b00..3bdfd85 100644
--- a/src/proguard/classfile/ProgramField.java
+++ b/src/proguard/classfile/ProgramField.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/ProgramMember.java b/src/proguard/classfile/ProgramMember.java
index ea6f46d..240d344 100644
--- a/src/proguard/classfile/ProgramMember.java
+++ b/src/proguard/classfile/ProgramMember.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -53,7 +53,7 @@ public abstract class ProgramMember implements Member
/**
- * Creates an initialized ProgramMember.
+ * Creates an initialized ProgramMember.
*/
protected ProgramMember(int u2accessFlags,
int u2nameIndex,
@@ -69,34 +69,6 @@ public abstract class ProgramMember implements Member
}
- /**
- * Returns the line number range of the given class member as "m:n",
- * if it can find it, or null
otherwise.
- */
- public String getLineNumberRange(Clazz clazz)
- {
- CodeAttribute codeAttribute =
- (CodeAttribute)getAttribute(clazz, ClassConstants.ATTR_Code);
- if (codeAttribute == null)
- {
- return null;
- }
-
- LineNumberTableAttribute lineNumberTableAttribute =
- (LineNumberTableAttribute)codeAttribute.getAttribute(clazz,
- ClassConstants.ATTR_LineNumberTable);
- if (lineNumberTableAttribute == null)
- {
- return null;
- }
-
- return "" +
- lineNumberTableAttribute.getLineNumber(0) +
- ":" +
- lineNumberTableAttribute.getLineNumber(Integer.MAX_VALUE);
- }
-
-
/**
* Returns the (first) attribute with the given name.
*/
diff --git a/src/proguard/classfile/ProgramMethod.java b/src/proguard/classfile/ProgramMethod.java
index 943c3d6..26f793f 100644
--- a/src/proguard/classfile/ProgramMethod.java
+++ b/src/proguard/classfile/ProgramMethod.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/VisitorAccepter.java b/src/proguard/classfile/VisitorAccepter.java
index e38f888..9c7a062 100644
--- a/src/proguard/classfile/VisitorAccepter.java
+++ b/src/proguard/classfile/VisitorAccepter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/Attribute.java b/src/proguard/classfile/attribute/Attribute.java
index 2e16e22..f34a0ee 100644
--- a/src/proguard/classfile/attribute/Attribute.java
+++ b/src/proguard/classfile/attribute/Attribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/BootstrapMethodInfo.java b/src/proguard/classfile/attribute/BootstrapMethodInfo.java
new file mode 100755
index 0000000..f246766
--- /dev/null
+++ b/src/proguard/classfile/attribute/BootstrapMethodInfo.java
@@ -0,0 +1,89 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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;
+
+import proguard.classfile.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * Representation of a bootstrap method.
+ *
+ * @author Eric Lafortune
+ */
+public class BootstrapMethodInfo implements VisitorAccepter
+{
+ public int u2methodHandleIndex;
+ public int u2methodArgumentCount;
+ public int[] u2methodArguments;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates an uninitialized BootstrapMethodInfo.
+ */
+ public BootstrapMethodInfo()
+ {
+ }
+
+
+ /**
+ * Creates an initialized BootstrapMethodInfo.
+ */
+ public BootstrapMethodInfo(int u2methodHandleIndex,
+ int u2methodArgumentCount,
+ int[] u2methodArguments)
+ {
+ this.u2methodHandleIndex = u2methodHandleIndex;
+ this.u2methodArgumentCount = u2methodArgumentCount;
+ this.u2methodArguments = u2methodArguments;
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the argument constants of the
+ * bootstrap method.
+ */
+ public void methodArgumentsAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ for (int index = 0; index < u2methodArgumentCount; index++)
+ {
+ clazz.constantPoolEntryAccept(u2methodArguments[index],
+ constantVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java b/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
new file mode 100755
index 0000000..4471a75
--- /dev/null
+++ b/src/proguard/classfile/attribute/BootstrapMethodsAttribute.java
@@ -0,0 +1,95 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+
+/**
+ * This Attribute represents a bootstrap methods attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class BootstrapMethodsAttribute extends Attribute
+{
+ public int u2bootstrapMethodsCount;
+ public BootstrapMethodInfo[] bootstrapMethods;
+
+
+ /**
+ * Creates an uninitialized BootstrapMethodsAttribute.
+ */
+ public BootstrapMethodsAttribute()
+ {
+ }
+
+
+ /**
+ * Creates an initialized BootstrapMethodsAttribute.
+ */
+ public BootstrapMethodsAttribute(int u2attributeNameIndex,
+ int u2bootstrapMethodsCount,
+ BootstrapMethodInfo[] bootstrapMethods)
+ {
+ super(u2attributeNameIndex);
+
+ this.u2bootstrapMethodsCount = u2bootstrapMethodsCount;
+ this.bootstrapMethods = bootstrapMethods;
+ }
+
+
+ // Implementations for Attribute.
+
+ public void accept(Clazz clazz, AttributeVisitor attributeVisitor)
+ {
+ attributeVisitor.visitBootstrapMethodsAttribute(clazz, this);
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all bootstrap method info
+ * entries.
+ */
+ public void bootstrapMethodEntriesAccept(Clazz clazz, BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor)
+ {
+ for (int index = 0; index < u2bootstrapMethodsCount; index++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of BootstrapMethodInfo.
+ bootstrapMethodInfoVisitor.visitBootstrapMethodInfo(clazz, bootstrapMethods[index]);
+ }
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to the specified bootstrap method
+ * info entry.
+ */
+ public void bootstrapMethodEntryAccept(Clazz clazz,
+ int bootstrapMethodIndex,
+ BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of BootstrapMethodInfo.
+ bootstrapMethodInfoVisitor.visitBootstrapMethodInfo(clazz, bootstrapMethods[bootstrapMethodIndex]);
+ }
+}
diff --git a/src/proguard/classfile/attribute/CodeAttribute.java b/src/proguard/classfile/attribute/CodeAttribute.java
index 92ff9ea..b3d4f4c 100644
--- a/src/proguard/classfile/attribute/CodeAttribute.java
+++ b/src/proguard/classfile/attribute/CodeAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/ConstantValueAttribute.java b/src/proguard/classfile/attribute/ConstantValueAttribute.java
index 3ae991e..056e377 100644
--- a/src/proguard/classfile/attribute/ConstantValueAttribute.java
+++ b/src/proguard/classfile/attribute/ConstantValueAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/DeprecatedAttribute.java b/src/proguard/classfile/attribute/DeprecatedAttribute.java
index 4180950..f668063 100644
--- a/src/proguard/classfile/attribute/DeprecatedAttribute.java
+++ b/src/proguard/classfile/attribute/DeprecatedAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/EnclosingMethodAttribute.java b/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
index 9275b3a..1c2ecc4 100644
--- a/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
+++ b/src/proguard/classfile/attribute/EnclosingMethodAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/ExceptionInfo.java b/src/proguard/classfile/attribute/ExceptionInfo.java
index 082efab..31512e5 100644
--- a/src/proguard/classfile/attribute/ExceptionInfo.java
+++ b/src/proguard/classfile/attribute/ExceptionInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/ExceptionsAttribute.java b/src/proguard/classfile/attribute/ExceptionsAttribute.java
index d22c4a6..ff7b84a 100644
--- a/src/proguard/classfile/attribute/ExceptionsAttribute.java
+++ b/src/proguard/classfile/attribute/ExceptionsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -69,12 +69,12 @@ public class ExceptionsAttribute extends Attribute
* Applies the given constant pool visitor to all exception class pool info
* entries.
*/
- public void exceptionEntriesAccept(ProgramClass programClass, ConstantVisitor constantVisitor)
+ public void exceptionEntriesAccept(Clazz clazz, ConstantVisitor constantVisitor)
{
for (int index = 0; index < u2exceptionIndexTableLength; index++)
{
- programClass.constantPoolEntryAccept(u2exceptionIndexTable[index],
- constantVisitor);
+ clazz.constantPoolEntryAccept(u2exceptionIndexTable[index],
+ constantVisitor);
}
}
}
diff --git a/src/proguard/classfile/attribute/InnerClassesAttribute.java b/src/proguard/classfile/attribute/InnerClassesAttribute.java
index 2f7e310..b08d104 100644
--- a/src/proguard/classfile/attribute/InnerClassesAttribute.java
+++ b/src/proguard/classfile/attribute/InnerClassesAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/InnerClassesInfo.java b/src/proguard/classfile/attribute/InnerClassesInfo.java
index 1bdd6c3..87b9de4 100644
--- a/src/proguard/classfile/attribute/InnerClassesInfo.java
+++ b/src/proguard/classfile/attribute/InnerClassesInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -74,8 +74,7 @@ public class InnerClassesInfo implements VisitorAccepter
{
if (u2innerClassIndex != 0)
{
- clazz.constantPoolEntryAccept(u2innerClassIndex,
- constantVisitor);
+ clazz.constantPoolEntryAccept(u2innerClassIndex, constantVisitor);
}
}
@@ -88,8 +87,7 @@ public class InnerClassesInfo implements VisitorAccepter
{
if (u2outerClassIndex != 0)
{
- clazz.constantPoolEntryAccept(u2outerClassIndex,
- constantVisitor);
+ clazz.constantPoolEntryAccept(u2outerClassIndex, constantVisitor);
}
}
@@ -102,8 +100,7 @@ public class InnerClassesInfo implements VisitorAccepter
{
if (u2innerNameIndex != 0)
{
- clazz.constantPoolEntryAccept(u2innerNameIndex,
- constantVisitor);
+ clazz.constantPoolEntryAccept(u2innerNameIndex, constantVisitor);
}
}
diff --git a/src/proguard/classfile/attribute/LineNumberInfo.java b/src/proguard/classfile/attribute/LineNumberInfo.java
index f58083a..1bcacef 100644
--- a/src/proguard/classfile/attribute/LineNumberInfo.java
+++ b/src/proguard/classfile/attribute/LineNumberInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/LineNumberTableAttribute.java b/src/proguard/classfile/attribute/LineNumberTableAttribute.java
index 4d507d9..c217119 100644
--- a/src/proguard/classfile/attribute/LineNumberTableAttribute.java
+++ b/src/proguard/classfile/attribute/LineNumberTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -77,6 +77,56 @@ public class LineNumberTableAttribute extends Attribute
}
+ /**
+ * Returns the lowest line number, or 0 if there aren't any line numbers.
+ */
+ public int getLowestLineNumber()
+ {
+ if (u2lineNumberTableLength == 0)
+ {
+ return 0;
+ }
+
+ int lowestLineNumber = Integer.MAX_VALUE;
+
+ for (int index = 0; index < u2lineNumberTableLength; index++)
+ {
+ int lineNumber = lineNumberTable[index].u2lineNumber;
+ if (lineNumber < lowestLineNumber)
+ {
+ lowestLineNumber = lineNumber;
+ }
+ }
+
+ return lowestLineNumber;
+ }
+
+
+ /**
+ * Returns the highest line number, or 0 if there aren't any line numbers.
+ */
+ public int getHighestLineNumber()
+ {
+ if (u2lineNumberTableLength == 0)
+ {
+ return 0;
+ }
+
+ int highestLineNumber = Integer.MIN_VALUE;
+
+ for (int index = 0; index < u2lineNumberTableLength; index++)
+ {
+ int lineNumber = lineNumberTable[index].u2lineNumber;
+ if (lineNumber > highestLineNumber)
+ {
+ highestLineNumber = lineNumber;
+ }
+ }
+
+ return highestLineNumber;
+ }
+
+
// Implementations for Attribute.
public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, AttributeVisitor attributeVisitor)
diff --git a/src/proguard/classfile/attribute/LocalVariableInfo.java b/src/proguard/classfile/attribute/LocalVariableInfo.java
index 4e54c22..00bbd50 100644
--- a/src/proguard/classfile/attribute/LocalVariableInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
*/
package proguard.classfile.attribute;
-import proguard.classfile.Clazz;
+import proguard.classfile.*;
import proguard.classfile.visitor.ClassVisitor;
/**
@@ -28,7 +28,7 @@ import proguard.classfile.visitor.ClassVisitor;
*
* @author Eric Lafortune
*/
-public class LocalVariableInfo
+public class LocalVariableInfo implements VisitorAccepter, Comparable
{
public int u2startPC;
public int u2length;
@@ -44,6 +44,11 @@ public class LocalVariableInfo
*/
public Clazz referencedClass;
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
/**
* Creates an uninitialized LocalVariableInfo.
@@ -80,4 +85,33 @@ public class LocalVariableInfo
referencedClass.accept(classVisitor);
}
}
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+
+
+ // Implementations for Comparable.
+
+ public int compareTo(Object object)
+ {
+ LocalVariableInfo other = (LocalVariableInfo)object;
+
+ return
+ this.u2startPC < other.u2startPC ? -1 : this.u2startPC > other.u2startPC ? 1 :
+ this.u2index < other.u2index ? -1 : this.u2index > other.u2index ? 1 :
+ this.u2length < other.u2length ? -1 : this.u2length > other.u2length ? 1 :
+ this.u2descriptorIndex < other.u2descriptorIndex ? -1 : this.u2descriptorIndex > other.u2descriptorIndex ? 1 :
+ this.u2nameIndex < other.u2nameIndex ? -1 : this.u2nameIndex > other.u2nameIndex ? 1 :
+ 0;
+ }
}
diff --git a/src/proguard/classfile/attribute/LocalVariableTableAttribute.java b/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
index 9c3f115..9e081c0 100644
--- a/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
+++ b/src/proguard/classfile/attribute/LocalVariableTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
index 1b71f35..15b9d24 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
*/
package proguard.classfile.attribute;
-import proguard.classfile.Clazz;
+import proguard.classfile.*;
import proguard.classfile.visitor.ClassVisitor;
/**
@@ -28,7 +28,7 @@ import proguard.classfile.visitor.ClassVisitor;
*
* @author Eric Lafortune
*/
-public class LocalVariableTypeInfo
+public class LocalVariableTypeInfo implements VisitorAccepter, Comparable
{
public int u2startPC;
public int u2length;
@@ -45,6 +45,11 @@ public class LocalVariableTypeInfo
*/
public Clazz[] referencedClasses;
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
/**
* Creates an uninitialized LocalVariableTypeInfo.
@@ -88,4 +93,33 @@ public class LocalVariableTypeInfo
}
}
}
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+
+
+ // Implementations for Comparable.
+
+ public int compareTo(Object object)
+ {
+ LocalVariableTypeInfo other = (LocalVariableTypeInfo)object;
+
+ return
+ this.u2startPC < other.u2startPC ? -1 : this.u2startPC > other.u2startPC ? 1 :
+ this.u2length < other.u2length ? -1 : this.u2length > other.u2length ? 1 :
+ this.u2index < other.u2index ? -1 : this.u2index > other.u2index ? 1 :
+ this.u2signatureIndex < other.u2signatureIndex ? -1 : this.u2signatureIndex > other.u2signatureIndex ? 1 :
+ this.u2nameIndex < other.u2nameIndex ? -1 : this.u2nameIndex > other.u2nameIndex ? 1 :
+ 0;
+ }
}
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
index fd856fe..dda24fb 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
+++ b/src/proguard/classfile/attribute/LocalVariableTypeTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/SignatureAttribute.java b/src/proguard/classfile/attribute/SignatureAttribute.java
index c7585fe..86f95b8 100644
--- a/src/proguard/classfile/attribute/SignatureAttribute.java
+++ b/src/proguard/classfile/attribute/SignatureAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/SourceDirAttribute.java b/src/proguard/classfile/attribute/SourceDirAttribute.java
index a26e8b1..faa1c79 100644
--- a/src/proguard/classfile/attribute/SourceDirAttribute.java
+++ b/src/proguard/classfile/attribute/SourceDirAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/SourceFileAttribute.java b/src/proguard/classfile/attribute/SourceFileAttribute.java
index 24269b7..4abac17 100644
--- a/src/proguard/classfile/attribute/SourceFileAttribute.java
+++ b/src/proguard/classfile/attribute/SourceFileAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/SyntheticAttribute.java b/src/proguard/classfile/attribute/SyntheticAttribute.java
index 6ccb1b5..0135330 100644
--- a/src/proguard/classfile/attribute/SyntheticAttribute.java
+++ b/src/proguard/classfile/attribute/SyntheticAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/UnknownAttribute.java b/src/proguard/classfile/attribute/UnknownAttribute.java
index 2f138bd..182a9e8 100644
--- a/src/proguard/classfile/attribute/UnknownAttribute.java
+++ b/src/proguard/classfile/attribute/UnknownAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/Annotation.java b/src/proguard/classfile/attribute/annotation/Annotation.java
index 41bb8e3..b2f18d5 100644
--- a/src/proguard/classfile/attribute/annotation/Annotation.java
+++ b/src/proguard/classfile/attribute/annotation/Annotation.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
index b378cd2..b8f29cc 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
index 29129d0..8354f5d 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -64,7 +64,7 @@ public class AnnotationElementValue extends ElementValue
// Implementations for ElementValue.
- public int getTag()
+ public char getTag()
{
return ClassConstants.ELEMENT_VALUE_ANNOTATION;
}
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
index 8117077..a936ff4 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
index 25b8b9f..0aab49b 100644
--- a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -58,7 +58,7 @@ public class ArrayElementValue extends ElementValue
// Implementations for ElementValue.
- public int getTag()
+ public char getTag()
{
return ClassConstants.ELEMENT_VALUE_ARRAY;
}
diff --git a/src/proguard/classfile/attribute/annotation/ClassElementValue.java b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
index ba51641..ffeaf71 100644
--- a/src/proguard/classfile/attribute/annotation/ClassElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -83,7 +83,7 @@ public class ClassElementValue extends ElementValue
// Implementations for ElementValue.
- public int getTag()
+ public char getTag()
{
return ClassConstants.ELEMENT_VALUE_CLASS;
}
diff --git a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
index 3ebe5e5..8be4329 100644
--- a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -30,14 +30,14 @@ import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor;
*/
public class ConstantElementValue extends ElementValue
{
- public final int u1tag;
- public int u2constantValueIndex;
+ public final char u1tag;
+ public int u2constantValueIndex;
/**
* Creates an uninitialized ConstantElementValue.
*/
- public ConstantElementValue(int u1tag)
+ public ConstantElementValue(char u1tag)
{
this.u1tag = u1tag;
}
@@ -46,9 +46,9 @@ public class ConstantElementValue extends ElementValue
/**
* Creates an initialized ConstantElementValue.
*/
- public ConstantElementValue(int u1tag,
- int u2elementNameIndex,
- int u2constantValueIndex)
+ public ConstantElementValue(char u1tag,
+ int u2elementNameIndex,
+ int u2constantValueIndex)
{
super(u2elementNameIndex);
@@ -59,7 +59,7 @@ public class ConstantElementValue extends ElementValue
// Implementations for ElementValue.
- public int getTag()
+ public char getTag()
{
return u1tag;
}
diff --git a/src/proguard/classfile/attribute/annotation/ElementValue.java b/src/proguard/classfile/attribute/annotation/ElementValue.java
index 39f8953..19a7198 100644
--- a/src/proguard/classfile/attribute/annotation/ElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -90,7 +90,7 @@ public abstract class ElementValue implements VisitorAccepter
/**
* Returns the tag of this element value.
*/
- public abstract int getTag();
+ public abstract char getTag();
/**
diff --git a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
index d46bb7f..cd0f2f9 100644
--- a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,7 +22,7 @@ package proguard.classfile.attribute.annotation;
import proguard.classfile.*;
import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor;
-import proguard.classfile.visitor.ClassVisitor;
+import proguard.classfile.visitor.*;
/**
* This ElementValue represents an enumeration constant element value.
@@ -43,6 +43,14 @@ public class EnumConstantElementValue extends ElementValue
*/
public Clazz[] referencedClasses;
+ /**
+ * An extra field optionally pointing to the referenced enum Field object.
+ * This field is typically filled out by the {@link
+ * proguard.classfile.util.ClassReferenceInitializer
+ * ClassReferenceInitializer}
.
+ */
+ public Field referencedField;
+
/**
* Creates an uninitialized EnumConstantElementValue.
@@ -66,6 +74,24 @@ public class EnumConstantElementValue extends ElementValue
}
+ /**
+ * Returns the enumeration type name.
+ */
+ public String getTypeName(Clazz clazz)
+ {
+ return clazz.getString(u2typeNameIndex);
+ }
+
+
+ /**
+ * Returns the constant name.
+ */
+ public String getConstantName(Clazz clazz)
+ {
+ return clazz.getString(u2constantNameIndex);
+ }
+
+
/**
* Applies the given visitor to all referenced classes.
*/
@@ -85,9 +111,22 @@ public class EnumConstantElementValue extends ElementValue
}
+ /**
+ * Applies the given visitor to the referenced field.
+ */
+ public void referencedFieldAccept(MemberVisitor memberVisitor)
+ {
+ if (referencedField != null)
+ {
+ referencedField.accept(referencedClasses[0],
+ memberVisitor);
+ }
+ }
+
+
// Implementations for ElementValue.
- public int getTag()
+ public char getTag()
{
return ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT;
}
diff --git a/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
index 3c700c8..ddaa3a6 100644
--- a/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/ParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
index 9c8180c..deda8a5 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
index 7e41656..2fcae88 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
index 380c52e..da94f0c 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
index 626fbda..caa6830 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
index bce7170..0aadfe3 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/AllAnnotationVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -39,6 +39,11 @@ implements AttributeVisitor
private final AnnotationVisitor annotationVisitor;
+ /**
+ * Creates a new AllAnnotationVisitor.
+ * @param annotationVisitor the AnnotationVisitor to which visits will be
+ * delegated.
+ */
public AllAnnotationVisitor(AnnotationVisitor annotationVisitor)
{
this.annotationVisitor = annotationVisitor;
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
new file mode 100644
index 0000000..b728b8b
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/visitor/AllElementValueVisitor.java
@@ -0,0 +1,201 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.annotation.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.Attribute;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.*;
+
+/**
+ * This AttributeVisitor and AnnotationVisitor lets a given ElementValueVisitor
+ * visit all ElementValue objects of the attributes or annotations that it
+ * visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllElementValueVisitor
+extends SimplifiedVisitor
+implements AttributeVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ private final boolean deep;
+ private final ElementValueVisitor elementValueVisitor;
+
+
+ /**
+ * Creates a new AllElementValueVisitor.
+ * @param elementValueVisitor the AllElementValueVisitor to which visits
+ * will be delegated.
+ */
+ public AllElementValueVisitor(ElementValueVisitor elementValueVisitor)
+ {
+ this(false, elementValueVisitor);
+ }
+
+
+ /**
+ * Creates a new AllElementValueVisitor.
+ * @param deep specifies whether the element values
+ * further down the hierarchy should be
+ * visited too.
+ * @param elementValueVisitor the AllElementValueVisitor to which visits
+ * will be delegated.
+ */
+ public AllElementValueVisitor(boolean deep,
+ ElementValueVisitor elementValueVisitor)
+ {
+ this.deep = deep;
+ this.elementValueVisitor = elementValueVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, this);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, field, this);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, field, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
+ {
+ // Visit the annotations.
+ parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ // Visit the default element value.
+ annotationDefaultAttribute.defaultValueAccept(clazz, this);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(Clazz clazz, Annotation annotation)
+ {
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ public void visitAnnotation(Clazz clazz, Field field, Annotation annotation)
+ {
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ public void visitAnnotation(Clazz clazz, Method method, Annotation annotation)
+ {
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ public void visitAnnotation(Clazz clazz, Method method, int parameterIndex, Annotation annotation)
+ {
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ elementValueVisitor.visitConstantElementValue(clazz, annotation, constantElementValue);
+ }
+
+
+ public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ elementValueVisitor.visitEnumConstantElementValue(clazz, annotation, enumConstantElementValue);
+ }
+
+
+ public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
+ {
+ elementValueVisitor.visitClassElementValue(clazz, annotation, classElementValue);
+ }
+
+
+ public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ elementValueVisitor.visitAnnotationElementValue(clazz, annotation, annotationElementValue);
+
+ if (deep)
+ {
+ annotationElementValue.annotationAccept(clazz, this);
+ }
+ }
+
+
+ public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ elementValueVisitor.visitArrayElementValue(clazz, annotation, arrayElementValue);
+
+ if (deep)
+ {
+ arrayElementValue.elementValuesAccept(clazz, annotation, elementValueVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java
index 7a1d7c6..305928e 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/AnnotatedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java
index c206c16..7833f7e 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/AnnotationToMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java b/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
index d869fd2..d6ec3ca 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/AnnotationTypeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -33,7 +33,6 @@ import proguard.util.*;
* @author Eric Lafortune
*/
public class AnnotationTypeFilter
-extends SimplifiedVisitor
implements AnnotationVisitor
{
private final StringMatcher regularExpressionMatcher;
diff --git a/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
index 16b2a56..8d207af 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/AnnotationVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java b/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
index 112084a..2d3a20d 100644
--- a/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/visitor/ElementValueVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/DoubleType.java b/src/proguard/classfile/attribute/preverification/DoubleType.java
index d574dcb..1bc3e5d 100644
--- a/src/proguard/classfile/attribute/preverification/DoubleType.java
+++ b/src/proguard/classfile/attribute/preverification/DoubleType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/FloatType.java b/src/proguard/classfile/attribute/preverification/FloatType.java
index 2f24720..c58cd0a 100644
--- a/src/proguard/classfile/attribute/preverification/FloatType.java
+++ b/src/proguard/classfile/attribute/preverification/FloatType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/FullFrame.java b/src/proguard/classfile/attribute/preverification/FullFrame.java
index adf5684..4f0d72e 100644
--- a/src/proguard/classfile/attribute/preverification/FullFrame.java
+++ b/src/proguard/classfile/attribute/preverification/FullFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/IntegerType.java b/src/proguard/classfile/attribute/preverification/IntegerType.java
index 55e3abe..9c43cae 100644
--- a/src/proguard/classfile/attribute/preverification/IntegerType.java
+++ b/src/proguard/classfile/attribute/preverification/IntegerType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/LessZeroFrame.java b/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
index fcc8e0a..f722d73 100644
--- a/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
+++ b/src/proguard/classfile/attribute/preverification/LessZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/LongType.java b/src/proguard/classfile/attribute/preverification/LongType.java
index 9b14dd6..c986165 100644
--- a/src/proguard/classfile/attribute/preverification/LongType.java
+++ b/src/proguard/classfile/attribute/preverification/LongType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java b/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
index 881f188..be74df0 100644
--- a/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
+++ b/src/proguard/classfile/attribute/preverification/MoreZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/NullType.java b/src/proguard/classfile/attribute/preverification/NullType.java
index f35cefd..fe0d85f 100644
--- a/src/proguard/classfile/attribute/preverification/NullType.java
+++ b/src/proguard/classfile/attribute/preverification/NullType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/ObjectType.java b/src/proguard/classfile/attribute/preverification/ObjectType.java
index fbdeec7..4ea370a 100644
--- a/src/proguard/classfile/attribute/preverification/ObjectType.java
+++ b/src/proguard/classfile/attribute/preverification/ObjectType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/SameOneFrame.java b/src/proguard/classfile/attribute/preverification/SameOneFrame.java
index db6747b..4384aae 100644
--- a/src/proguard/classfile/attribute/preverification/SameOneFrame.java
+++ b/src/proguard/classfile/attribute/preverification/SameOneFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/SameZeroFrame.java b/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
index 64b17f5..a3bd824 100644
--- a/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
+++ b/src/proguard/classfile/attribute/preverification/SameZeroFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/StackMapAttribute.java b/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
index db53ff1..51e69fb 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
+++ b/src/proguard/classfile/attribute/preverification/StackMapAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/StackMapFrame.java b/src/proguard/classfile/attribute/preverification/StackMapFrame.java
index aa3e1f2..01890f3 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapFrame.java
+++ b/src/proguard/classfile/attribute/preverification/StackMapFrame.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java b/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
index 0cddf70..3de059f 100644
--- a/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
+++ b/src/proguard/classfile/attribute/preverification/StackMapTableAttribute.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/TopType.java b/src/proguard/classfile/attribute/preverification/TopType.java
index bde8dda..02dd1a2 100644
--- a/src/proguard/classfile/attribute/preverification/TopType.java
+++ b/src/proguard/classfile/attribute/preverification/TopType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/UninitializedThisType.java b/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
index dc4654f..7b2bfa9 100644
--- a/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
+++ b/src/proguard/classfile/attribute/preverification/UninitializedThisType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/UninitializedType.java b/src/proguard/classfile/attribute/preverification/UninitializedType.java
index a495f1f..7e4a0fd 100644
--- a/src/proguard/classfile/attribute/preverification/UninitializedType.java
+++ b/src/proguard/classfile/attribute/preverification/UninitializedType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/VerificationType.java b/src/proguard/classfile/attribute/preverification/VerificationType.java
index f33d511..02c3872 100644
--- a/src/proguard/classfile/attribute/preverification/VerificationType.java
+++ b/src/proguard/classfile/attribute/preverification/VerificationType.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java b/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
index f8ef7e0..ada9ce8 100644
--- a/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
+++ b/src/proguard/classfile/attribute/preverification/VerificationTypeFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java b/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
index 7db246c..5e4cf88 100644
--- a/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
+++ b/src/proguard/classfile/attribute/preverification/visitor/StackMapFrameVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java b/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
index e9931f8..2a3e9e7 100644
--- a/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
+++ b/src/proguard/classfile/attribute/preverification/visitor/VerificationTypeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java b/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
index 61b0f1a..9d8801c 100644
--- a/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/AllAttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java b/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
new file mode 100644
index 0000000..d70803c
--- /dev/null
+++ b/src/proguard/classfile/attribute/visitor/AllBootstrapMethodInfoVisitor.java
@@ -0,0 +1,55 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given BootstrapMethodInfoVisitor visit all
+ * bootstrap method objects of the BootstrapMethodsAttribute objects it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllBootstrapMethodInfoVisitor
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor;
+
+
+ public AllBootstrapMethodInfoVisitor(BootstrapMethodInfoVisitor bootstrapMethodInfoVisitor)
+ {
+ this.bootstrapMethodInfoVisitor = bootstrapMethodInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, bootstrapMethodInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java b/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
index 839e104..927bfd9 100644
--- a/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/AllExceptionInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java b/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
new file mode 100644
index 0000000..2422218
--- /dev/null
+++ b/src/proguard/classfile/attribute/visitor/AllInnerClassesInfoVisitor.java
@@ -0,0 +1,55 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given InnerClassesInfoVisitor visit all
+ * InnerClassessInfo objects of the InnerClassesAttribute objects it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllInnerClassesInfoVisitor
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final InnerClassesInfoVisitor innerClassesInfoVisitor;
+
+
+ public AllInnerClassesInfoVisitor(InnerClassesInfoVisitor innerClassesInfoVisitor)
+ {
+ this.innerClassesInfoVisitor = innerClassesInfoVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ innerClassesAttribute.innerClassEntriesAccept(clazz, innerClassesInfoVisitor);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java b/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
index aa81ce0..0db77d5 100644
--- a/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
+++ b/src/proguard/classfile/attribute/visitor/AttributeNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,34 +24,66 @@ import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.preverification.*;
-import proguard.util.StringMatcher;
+import proguard.util.*;
+
+import java.util.List;
/**
* This AttributeVisitor delegates its visits another AttributeVisitor, but
- * only when the visited attribute has a name that passes a given string
- * matcher.
+ * only when the visited attribute has a name that that matches a given regular
+ * expression.
*
* @author Eric Lafortune
*/
public class AttributeNameFilter
implements AttributeVisitor
{
- private final StringMatcher stringMatcher;
+ private final StringMatcher regularExpressionMatcher;
private final AttributeVisitor attributeVisitor;
/**
* Creates a new AttributeNameFilter.
- * @param stringMatcher the string matcher that will check the attribute
- * names.
- * @param attributeVisitor the AttributeVisitor
to which
- * visits will be delegated.
+ * @param regularExpression the regular expression against which attribute
+ * names will be matched.
+ * @param attributeVisitor the AttributeVisitor
to which
+ * visits will be delegated.
+ */
+ public AttributeNameFilter(String regularExpression,
+ AttributeVisitor attributeVisitor)
+ {
+ this(new ListParser(new NameParser()).parse(regularExpression),
+ attributeVisitor);
+ }
+
+
+ /**
+ * Creates a new AttributeNameFilter.
+ * @param regularExpression the regular expression against which attribute
+ * names will be matched.
+ * @param attributeVisitor the AttributeVisitor
to which
+ * visits will be delegated.
*/
- public AttributeNameFilter(StringMatcher stringMatcher,
+ public AttributeNameFilter(List regularExpression,
AttributeVisitor attributeVisitor)
{
- this.stringMatcher = stringMatcher;
- this.attributeVisitor = attributeVisitor;
+ this(new ListParser(new NameParser()).parse(regularExpression),
+ attributeVisitor);
+ }
+
+
+ /**
+ * Creates a new AttributeNameFilter.
+ * @param regularExpressionMatcher the string matcher against which
+ * attribute names will be matched.
+ * @param attributeVisitor the AttributeVisitor
to
+ * which visits will be delegated.
+ */
+ public AttributeNameFilter(StringMatcher regularExpressionMatcher,
+ AttributeVisitor attributeVisitor)
+ {
+ this.regularExpressionMatcher = regularExpressionMatcher;
+ this.attributeVisitor = attributeVisitor;
}
@@ -66,6 +98,15 @@ implements AttributeVisitor
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ if (accepted(clazz, bootstrapMethodsAttribute))
+ {
+ bootstrapMethodsAttribute.accept(clazz, attributeVisitor);
+ }
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
if (accepted(clazz, sourceFileAttribute))
@@ -340,6 +381,6 @@ implements AttributeVisitor
private boolean accepted(Clazz clazz, Attribute attribute)
{
- return stringMatcher.matches(attribute.getAttributeName(clazz));
+ return regularExpressionMatcher.matches(attribute.getAttributeName(clazz));
}
}
diff --git a/src/proguard/classfile/attribute/visitor/AttributeVisitor.java b/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
index e8f226b..76c1ab9 100644
--- a/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/AttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -35,11 +35,12 @@ public interface AttributeVisitor
{
// Attributes that are attached to classes.
- public void visitUnknownAttribute( Clazz clazz, UnknownAttribute unknownAttribute);
- 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 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.
diff --git a/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java b/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
new file mode 100755
index 0000000..9aab92e
--- /dev/null
+++ b/src/proguard/classfile/attribute/visitor/BootstrapMethodInfoVisitor.java
@@ -0,0 +1,40 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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 java.beans.MethodDescriptor;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * BootstrapMethodInfo
objects. Note that there is only a single
+ * implementation of BootstrapMethodInfo
, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface BootstrapMethodInfoVisitor
+{
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo);
+}
diff --git a/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java b/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
index 7c85e53..4a765f2 100644
--- a/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/ExceptionInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java b/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
index 91267b0..b373493 100644
--- a/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/InnerClassesInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java b/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
index e59ed7b..189b3d0 100644
--- a/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/LineNumberInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java b/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
index 8647cb3..c888d63 100644
--- a/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/LocalVariableInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java b/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
index 9ad38e0..f992e6d 100644
--- a/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/LocalVariableTypeInfoVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java b/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
index 870ba94..37c0639 100644
--- a/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
+++ b/src/proguard/classfile/attribute/visitor/MultiAttributeVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -85,6 +85,15 @@ public class MultiAttributeVisitor implements AttributeVisitor
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ for (int index = 0; index < attributeVisitors.length; index++)
+ {
+ attributeVisitors[index].visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute);
+ }
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
for (int index = 0; index < attributeVisitors.length; index++)
diff --git a/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java b/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
new file mode 100644
index 0000000..2ccc09c
--- /dev/null
+++ b/src/proguard/classfile/attribute/visitor/NonEmptyAttributeFilter.java
@@ -0,0 +1,293 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.preverification.*;
+import proguard.util.StringMatcher;
+
+/**
+ * This AttributeVisitor delegates its visits another AttributeVisitor, but
+ * only when the visited attribute is not empty. For instance, a local variable
+ * table without variables is empty.
+ *
+ * @author Eric Lafortune
+ */
+public class NonEmptyAttributeFilter
+implements AttributeVisitor
+{
+ private final AttributeVisitor attributeVisitor;
+
+
+ /**
+ * Creates a new NonEmptyAttributeFilter.
+ * @param attributeVisitor the AttributeVisitor
to which
+ * visits will be delegated.
+ */
+ public NonEmptyAttributeFilter(AttributeVisitor attributeVisitor)
+ {
+ this.attributeVisitor = attributeVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
+ {
+ unknownAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ if (bootstrapMethodsAttribute.u2bootstrapMethodsCount > 0)
+ {
+ bootstrapMethodsAttribute.accept(clazz, attributeVisitor);
+ }
+ }
+
+
+ public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
+ {
+ sourceFileAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
+ {
+ sourceDirAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ if (innerClassesAttribute.u2classesCount > 0)
+ {
+ innerClassesAttribute.accept(clazz, attributeVisitor);
+ }
+ }
+
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ enclosingMethodAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
+ {
+ deprecatedAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, Field field, DeprecatedAttribute deprecatedAttribute)
+ {
+ deprecatedAttribute.accept(clazz, field, attributeVisitor);
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, Method method, DeprecatedAttribute deprecatedAttribute)
+ {
+ deprecatedAttribute.accept(clazz, method, attributeVisitor);
+ }
+
+
+ public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
+ {
+ syntheticAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitSyntheticAttribute(Clazz clazz, Field field, SyntheticAttribute syntheticAttribute)
+ {
+ syntheticAttribute.accept(clazz, field, attributeVisitor);
+ }
+
+
+ public void visitSyntheticAttribute(Clazz clazz, Method method, SyntheticAttribute syntheticAttribute)
+ {
+ syntheticAttribute.accept(clazz, method, attributeVisitor);
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
+ {
+ signatureAttribute.accept(clazz, attributeVisitor);
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, Field field, SignatureAttribute signatureAttribute)
+ {
+ signatureAttribute.accept(clazz, field, attributeVisitor);
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
+ {
+ signatureAttribute.accept(clazz, method, attributeVisitor);
+ }
+
+
+ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
+ {
+ constantValueAttribute.accept(clazz, field, attributeVisitor);
+ }
+
+
+ public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
+ {
+ if (exceptionsAttribute.u2exceptionIndexTableLength > 0)
+ {
+ exceptionsAttribute.accept(clazz, method, attributeVisitor);
+ }
+ }
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttribute.accept(clazz, method, attributeVisitor);
+ }
+
+
+ public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
+ {
+ if (stackMapAttribute.u2stackMapFramesCount > 0)
+ {
+ stackMapAttribute.accept(clazz, method, codeAttribute, attributeVisitor);
+ }
+ }
+
+
+ public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
+ {
+ if (stackMapTableAttribute.u2stackMapFramesCount > 0)
+ {
+ stackMapTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor);
+ }
+ }
+
+
+ public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
+ {
+ if (lineNumberTableAttribute.u2lineNumberTableLength > 0)
+ {
+ lineNumberTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor);
+ }
+ }
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ if (localVariableTableAttribute.u2localVariableTableLength > 0)
+ {
+ localVariableTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor);
+ }
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ if (localVariableTypeTableAttribute.u2localVariableTypeTableLength > 0)
+ {
+ localVariableTypeTableAttribute.accept(clazz, method, codeAttribute, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeVisibleAnnotationsAttribute.accept(clazz, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeVisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
+ {
+ if (runtimeVisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeVisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeInvisibleAnnotationsAttribute.accept(clazz, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Field field, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeInvisibleAnnotationsAttribute.accept(clazz, field, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
+ {
+ if (runtimeInvisibleAnnotationsAttribute.u2annotationsCount > 0)
+ {
+ runtimeInvisibleAnnotationsAttribute.accept(clazz, method, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
+ {
+ if (runtimeVisibleParameterAnnotationsAttribute.u2parametersCount > 0)
+ {
+ runtimeVisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
+ {
+ if (runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount > 0)
+ {
+ runtimeInvisibleParameterAnnotationsAttribute.accept(clazz, method, attributeVisitor);
+ }
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ annotationDefaultAttribute.accept(clazz, method, attributeVisitor);
+ }
+}
diff --git a/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java b/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
index 92099f9..58e4e40 100644
--- a/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
+++ b/src/proguard/classfile/attribute/visitor/RequiredAttributeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,8 @@ import proguard.obfuscate.AttributeShrinker;
* AttributeVisitor instances, depending on whether the visited attribute
* is strictly required or not.
*
+ * Stack map attributes and stack map table attributes are treated as optional.
+ *
* @see AttributeShrinker
*
* @author Eric Lafortune
@@ -80,6 +82,15 @@ implements AttributeVisitor
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ if (requiredAttributeVisitor != null)
+ {
+ bootstrapMethodsAttribute.accept(clazz, requiredAttributeVisitor);
+ }
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
if (optionalAttributeVisitor != null)
@@ -235,9 +246,9 @@ implements AttributeVisitor
public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
{
- if (requiredAttributeVisitor != null)
+ if (optionalAttributeVisitor != null)
{
- stackMapTableAttribute.accept(clazz, method, codeAttribute, requiredAttributeVisitor);
+ stackMapTableAttribute.accept(clazz, method, codeAttribute, optionalAttributeVisitor);
}
}
diff --git a/src/proguard/classfile/attribute/visitor/StackSizeComputer.java b/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
index 401f188..b5e02e2 100644
--- a/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
+++ b/src/proguard/classfile/attribute/visitor/StackSizeComputer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,6 +27,8 @@ import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import java.util.Arrays;
+
/**
* This AttributeVisitor computes the stack sizes at all instruction offsets
* of the code attributes that it visits.
@@ -140,10 +142,7 @@ implements AttributeVisitor,
}
else
{
- for (int index = 0; index < codeLength; index++)
- {
- evaluated[index] = false;
- }
+ Arrays.fill(evaluated, 0, codeLength, false);
}
// The initial stack is always empty.
diff --git a/src/proguard/classfile/constant/ClassConstant.java b/src/proguard/classfile/constant/ClassConstant.java
index d217bf6..bbd9b31 100644
--- a/src/proguard/classfile/constant/ClassConstant.java
+++ b/src/proguard/classfile/constant/ClassConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/Constant.java b/src/proguard/classfile/constant/Constant.java
index 30ce5df..b4168ce 100644
--- a/src/proguard/classfile/constant/Constant.java
+++ b/src/proguard/classfile/constant/Constant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/DoubleConstant.java b/src/proguard/classfile/constant/DoubleConstant.java
index 61779b5..a4c64cf 100644
--- a/src/proguard/classfile/constant/DoubleConstant.java
+++ b/src/proguard/classfile/constant/DoubleConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/FieldrefConstant.java b/src/proguard/classfile/constant/FieldrefConstant.java
index d4afce5..d552d47 100644
--- a/src/proguard/classfile/constant/FieldrefConstant.java
+++ b/src/proguard/classfile/constant/FieldrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/FloatConstant.java b/src/proguard/classfile/constant/FloatConstant.java
index 578f567..1709fcb 100644
--- a/src/proguard/classfile/constant/FloatConstant.java
+++ b/src/proguard/classfile/constant/FloatConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/IntegerConstant.java b/src/proguard/classfile/constant/IntegerConstant.java
index 8a476c6..5f0d7f9 100644
--- a/src/proguard/classfile/constant/IntegerConstant.java
+++ b/src/proguard/classfile/constant/IntegerConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/InterfaceMethodrefConstant.java b/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
index ddee42f..52f1852 100644
--- a/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
+++ b/src/proguard/classfile/constant/InterfaceMethodrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/InvokeDynamicConstant.java b/src/proguard/classfile/constant/InvokeDynamicConstant.java
new file mode 100755
index 0000000..57474aa
--- /dev/null
+++ b/src/proguard/classfile/constant/InvokeDynamicConstant.java
@@ -0,0 +1,148 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This Constant represents an invoke dynamic constant in the constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class InvokeDynamicConstant extends Constant
+{
+ public int u2bootstrapMethodAttributeIndex;
+ public int u2nameAndTypeIndex;
+
+ /**
+ * An extra field pointing to the Clazz objects referenced in the
+ * descriptor string. This field is filled out by the {@link
+ * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}
.
+ * References to primitive types are ignored.
+ */
+ public Clazz[] referencedClasses;
+
+
+ /**
+ * Creates an uninitialized InvokeDynamicConstant.
+ */
+ public InvokeDynamicConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new InvokeDynamicConstant with the given bootstrap method
+ * and name-and-type indices.
+ * @param u2bootstrapMethodAttributeIndex the index of the bootstrap method
+ * entry in the bootstrap methods
+ * attribute.
+ * @param u2nameAndTypeIndex the index of the name and type
+ * entry in the constant pool.
+ * @param referencedClasses the classes referenced by the
+ * type.
+ */
+ public InvokeDynamicConstant(int u2bootstrapMethodAttributeIndex,
+ int u2nameAndTypeIndex,
+ Clazz[] referencedClasses)
+ {
+ this.u2bootstrapMethodAttributeIndex = u2bootstrapMethodAttributeIndex;
+ this.u2nameAndTypeIndex = u2nameAndTypeIndex;
+ this.referencedClasses = referencedClasses;
+ }
+
+
+ /**
+ * Returns the index of the bootstrap method in the bootstrap methods
+ * attribute of the class.
+ */
+ public int getBootstrapMethodAttributeIndex()
+ {
+ return u2bootstrapMethodAttributeIndex;
+ }
+
+ /**
+ * Returns the name-and-type index.
+ */
+ public int getNameAndTypeIndex()
+ {
+ return u2nameAndTypeIndex;
+ }
+
+ /**
+ * Returns the method name.
+ */
+ public String getName(Clazz clazz)
+ {
+ return clazz.getName(u2nameAndTypeIndex);
+ }
+
+ /**
+ * Returns the method type.
+ */
+ public String getType(Clazz clazz)
+ {
+ return clazz.getType(u2nameAndTypeIndex);
+ }
+
+
+ /**
+ * Lets the Clazz objects referenced in the descriptor string
+ * accept the given visitor.
+ */
+ public void referencedClassesAccept(ClassVisitor classVisitor)
+ {
+ if (referencedClasses != null)
+ {
+ for (int index = 0; index < referencedClasses.length; index++)
+ {
+ if (referencedClasses[index] != null)
+ {
+ referencedClasses[index].accept(classVisitor);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Lets the bootstrap method handle constant accept the given visitor.
+ */
+ public void bootstrapMethodHandleAccept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ new BootstrapMethodHandleTraveler(constantVisitor).visitInvokeDynamicConstant(clazz, this);
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_InvokeDynamic;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitInvokeDynamicConstant(clazz, this);
+ }
+}
diff --git a/src/proguard/classfile/constant/LongConstant.java b/src/proguard/classfile/constant/LongConstant.java
index ea66e07..2416f01 100644
--- a/src/proguard/classfile/constant/LongConstant.java
+++ b/src/proguard/classfile/constant/LongConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/MethodHandleConstant.java b/src/proguard/classfile/constant/MethodHandleConstant.java
new file mode 100755
index 0000000..6cffd9a
--- /dev/null
+++ b/src/proguard/classfile/constant/MethodHandleConstant.java
@@ -0,0 +1,124 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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 method handle constant in the constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodHandleConstant extends Constant
+{
+ public int u1referenceKind;
+ public int u2referenceIndex;
+
+
+ /**
+ * An extra field pointing to the java.lang.invoke.MethodHandle Clazz object.
+ * This field is typically filled out by the {@link
+ * proguard.classfile.util.ClassReferenceInitializer
+ * ClassReferenceInitializer}
..
+ */
+ public Clazz javaLangInvokeMethodHandleClass;
+
+
+ /**
+ * Creates an uninitialized MethodHandleConstant.
+ */
+ public MethodHandleConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new MethodHandleConstant with the given type and method ref
+ * index.
+ * @param u1referenceKind the reference kind.
+ * @param u2referenceIndex the index of the field ref constant, interface
+ * method ref constant, or method ref constant in
+ * the constant pool.
+ */
+ public MethodHandleConstant(int u1referenceKind, int u2referenceIndex)
+ {
+ this.u1referenceKind = u1referenceKind;
+ this.u2referenceIndex = u2referenceIndex;
+ }
+
+
+ /**
+ * Returns the kind of reference to which this constant is pointing.
+ * @return One of
+ * {@link ClassConstants#REF_getField },
+ * {@link ClassConstants#REF_getStatic },
+ * {@link ClassConstants#REF_putField },
+ * {@link ClassConstants#REF_putStatic },
+ * {@link ClassConstants#REF_invokeVirtual },
+ * {@link ClassConstants#REF_invokeStatic },
+ * {@link ClassConstants#REF_invokeSpecial },
+ * {@link ClassConstants#REF_newInvokeSpecial}, or
+ * {@link ClassConstants#REF_invokeInterface }.
+ */
+ public int getReferenceKind()
+ {
+ return u1referenceKind;
+ }
+
+ /**
+ * Returns the field ref, interface method ref, or method ref index.
+ */
+ public int getReferenceIndex()
+ {
+ return u2referenceIndex;
+ }
+
+
+ /**
+ * Returns the method/field name.
+ */
+ public String getName(Clazz clazz)
+ {
+ return clazz.getRefName(u2referenceIndex);
+ }
+
+ /**
+ * Returns the type.
+ */
+ public String getType(Clazz clazz)
+ {
+ return clazz.getRefType(u2referenceIndex);
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_MethodHandle;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitMethodHandleConstant(clazz, this);
+ }
+}
diff --git a/src/proguard/classfile/constant/MethodTypeConstant.java b/src/proguard/classfile/constant/MethodTypeConstant.java
new file mode 100644
index 0000000..96c136f
--- /dev/null
+++ b/src/proguard/classfile/constant/MethodTypeConstant.java
@@ -0,0 +1,93 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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 method handle constant in the constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodTypeConstant extends Constant
+{
+ public int u2descriptorIndex;
+
+
+ /**
+ * An extra field pointing to the java.lang.invoke.MethodType Clazz object.
+ * This field is typically filled out by the {@link
+ * proguard.classfile.util.ClassReferenceInitializer
+ * ClassReferenceInitializer}
..
+ */
+ public Clazz javaLangInvokeMethodTypeClass;
+
+
+ /**
+ * Creates an uninitialized MethodTypeConstant.
+ */
+ public MethodTypeConstant()
+ {
+ }
+
+
+ /**
+ * Creates a new MethodTypeConstant with the given descriptor index.
+ * @param u2descriptorIndex the index of the descriptor in the constant
+ * pool.
+ */
+ public MethodTypeConstant(int u2descriptorIndex)
+ {
+ this.u2descriptorIndex = u2descriptorIndex;
+ }
+
+
+ /**
+ * Returns the descriptor index.
+ */
+ public int getDescriptorIndex()
+ {
+ return u2descriptorIndex;
+ }
+
+
+ /**
+ * Returns the type.
+ */
+ public String getType(Clazz clazz)
+ {
+ return clazz.getString(u2descriptorIndex);
+ }
+
+
+ // Implementations for Constant.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_MethodType;
+ }
+
+ public void accept(Clazz clazz, ConstantVisitor constantVisitor)
+ {
+ constantVisitor.visitMethodTypeConstant(clazz, this);
+ }
+}
diff --git a/src/proguard/classfile/constant/MethodrefConstant.java b/src/proguard/classfile/constant/MethodrefConstant.java
index 858eec9..1ffa236 100644
--- a/src/proguard/classfile/constant/MethodrefConstant.java
+++ b/src/proguard/classfile/constant/MethodrefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/NameAndTypeConstant.java b/src/proguard/classfile/constant/NameAndTypeConstant.java
index e83d2f1..2a4dd66 100644
--- a/src/proguard/classfile/constant/NameAndTypeConstant.java
+++ b/src/proguard/classfile/constant/NameAndTypeConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/RefConstant.java b/src/proguard/classfile/constant/RefConstant.java
index 4e4d019..0a8fb78 100644
--- a/src/proguard/classfile/constant/RefConstant.java
+++ b/src/proguard/classfile/constant/RefConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/StringConstant.java b/src/proguard/classfile/constant/StringConstant.java
index 9a8d453..9b83745 100644
--- a/src/proguard/classfile/constant/StringConstant.java
+++ b/src/proguard/classfile/constant/StringConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/Utf8Constant.java b/src/proguard/classfile/constant/Utf8Constant.java
index ae419c9..3707ba9 100644
--- a/src/proguard/classfile/constant/Utf8Constant.java
+++ b/src/proguard/classfile/constant/Utf8Constant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/visitor/AllConstantVisitor.java b/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
index d2d3c2c..3c36609 100644
--- a/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
+++ b/src/proguard/classfile/constant/visitor/AllConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java b/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
new file mode 100644
index 0000000..6dce6c5
--- /dev/null
+++ b/src/proguard/classfile/constant/visitor/BootstrapMethodHandleTraveler.java
@@ -0,0 +1,100 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.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.optimize.info.MethodOptimizationInfo;
+
+/**
+ * This ConstantVisitor and BootstrapMethodInfoVisitor travels from any invoke
+ * dynamic constants or bootstrap method info entries that it visits to their
+ * bootstrap method handle constants, and applies a given constant visitor.
+ *
+ * @author Eric Lafortune
+ */
+public class BootstrapMethodHandleTraveler
+extends SimplifiedVisitor
+implements ConstantVisitor,
+ AttributeVisitor,
+ BootstrapMethodInfoVisitor
+{
+ private ConstantVisitor bootstrapMethodHandleVisitor;
+
+ // Field serving as a method argument.
+ int bootstrapMethodAttributeIndex;
+
+
+ /**
+ * Creates a new BootstrapMethodHandleVisitor that will delegate to the
+ * given constant visitor.
+ */
+ public BootstrapMethodHandleTraveler(ConstantVisitor bootstrapMethodHandleVisitor)
+ {
+ this.bootstrapMethodHandleVisitor = bootstrapMethodHandleVisitor;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // Pass the method index.
+ bootstrapMethodAttributeIndex =
+ invokeDynamicConstant.u2bootstrapMethodAttributeIndex;
+
+ // Delegate to the bootstrap method.
+ clazz.attributesAccept(this);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ // Check bootstrap methods.
+ bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz,
+ bootstrapMethodAttributeIndex,
+ this);
+ }
+
+
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ // Check bootstrap method.
+ clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex,
+ bootstrapMethodHandleVisitor);
+ }
+}
diff --git a/src/proguard/classfile/constant/visitor/ConstantTagFilter.java b/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
new file mode 100644
index 0000000..a3fcc8a
--- /dev/null
+++ b/src/proguard/classfile/constant/visitor/ConstantTagFilter.java
@@ -0,0 +1,86 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This ConstantVisitor
delegates its visits to one or more
+ * specified types of constants.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantTagFilter
+extends SimplifiedVisitor
+implements ConstantVisitor
+{
+ private final int constantTagMask;
+ private final ConstantVisitor constantVisitor;
+
+
+ /**
+ * Creates a new ConstantTagFilter.
+ * @param constantTag the type of constants for which visits will be
+ * delegated.
+ * @param constantVisitor the ConstantVisitor
to which visits
+ * will be delegated.
+ */
+ public ConstantTagFilter(int constantTag,
+ ConstantVisitor constantVisitor)
+ {
+ this.constantTagMask = 1 << constantTag;
+ this.constantVisitor = constantVisitor;
+ }
+
+
+ /**
+ * Creates a new ConstantTagFilter.
+ * @param constantTags the types of constants for which visits will be
+ * delegated.
+ * @param constantVisitor the ConstantVisitor
to which visits
+ * will be delegated.
+ */
+ public ConstantTagFilter(int[] constantTags,
+ ConstantVisitor constantVisitor)
+ {
+ int constantTagMask = 0;
+ for (int index = 0; index < constantTags.length; index++)
+ {
+ constantTagMask |= 1 << constantTags[index];
+ }
+
+ this.constantTagMask = constantTagMask;
+ this.constantVisitor = constantVisitor;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant)
+ {
+ if (((1 << constant.getTag()) & constantTagMask) != 0)
+ {
+ constant.accept(clazz, constantVisitor);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/constant/visitor/ConstantVisitor.java b/src/proguard/classfile/constant/visitor/ConstantVisitor.java
index 6cae352..362d54d 100644
--- a/src/proguard/classfile/constant/visitor/ConstantVisitor.java
+++ b/src/proguard/classfile/constant/visitor/ConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -38,9 +38,12 @@ public interface ConstantVisitor
public void visitDoubleConstant( Clazz clazz, DoubleConstant doubleConstant);
public void visitStringConstant( Clazz clazz, StringConstant stringConstant);
public void visitUtf8Constant( Clazz clazz, Utf8Constant utf8Constant);
+ public void visitInvokeDynamicConstant( Clazz clazz, InvokeDynamicConstant invokeDynamicConstant);
+ public void visitMethodHandleConstant( Clazz clazz, MethodHandleConstant methodHandleConstant);
public void visitFieldrefConstant( Clazz clazz, FieldrefConstant fieldrefConstant);
public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant);
public void visitMethodrefConstant( Clazz clazz, MethodrefConstant methodrefConstant);
public void visitClassConstant( Clazz clazz, ClassConstant classConstant);
+ public void visitMethodTypeConstant( Clazz clazz, MethodTypeConstant methodTypeConstant);
public void visitNameAndTypeConstant( Clazz clazz, NameAndTypeConstant nameAndTypeConstant);
}
diff --git a/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java b/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
index fbb3e52..bff4d1e 100644
--- a/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
+++ b/src/proguard/classfile/constant/visitor/ExceptClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -44,16 +44,16 @@ implements ConstantVisitor
/**
- * Creates a new ClassNameFilter.
+ * Creates a new ExceptClassConstantFilter.
* @param exceptClassName the name of the class that will not be visited.
* @param constantVisitor the ConstantVisitor
to which visits
* will be delegated.
*/
- public ExceptClassConstantFilter(String exceptClassName,
- ConstantVisitor constantVisitor)
+ public ExceptClassConstantFilter(String exceptClassName,
+ ConstantVisitor constantVisitor)
{
- this.exceptClassName = exceptClassName;
- this.constantVisitor = constantVisitor;
+ this.exceptClassName = exceptClassName;
+ this.constantVisitor = constantVisitor;
}
diff --git a/src/proguard/classfile/constant/visitor/MethodrefTraveler.java b/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
new file mode 100644
index 0000000..acd1bc8
--- /dev/null
+++ b/src/proguard/classfile/constant/visitor/MethodrefTraveler.java
@@ -0,0 +1,60 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.attribute.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This ConstantVisitor travels from any method handle constants that it visits
+ * to their methodref constants, and applies a given constant visitor.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodrefTraveler
+extends SimplifiedVisitor
+implements ConstantVisitor
+{
+ private ConstantVisitor methodrefConstantVisitor;
+
+
+ /**
+ * Creates a new v that will delegate to the given constant visitor.
+ */
+ public MethodrefTraveler(ConstantVisitor methodrefConstantVisitor)
+ {
+ this.methodrefConstantVisitor = methodrefConstantVisitor;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex,
+ methodrefConstantVisitor);
+ }
+}
diff --git a/src/proguard/classfile/editor/AccessFixer.java b/src/proguard/classfile/editor/AccessFixer.java
index 7d6274e..d770531 100644
--- a/src/proguard/classfile/editor/AccessFixer.java
+++ b/src/proguard/classfile/editor/AccessFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,8 @@
package proguard.classfile.editor;
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.util.*;
@@ -61,12 +63,26 @@ implements ConstantVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // Check the bootstrap method.
+ invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ // Check the method reference.
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
referencingClass = clazz;
// Remember the specified class, since it might be different from
- // the referenced class that acutally contains the class member.
+ // the referenced class that actually contains the class member.
clazz.constantPoolEntryAccept(refConstant.u2classIndex, referencedClassFinder);
// Make sure the access flags of the referenced class member are
@@ -91,8 +107,8 @@ implements ConstantVisitor,
public void visitProgramClass(ProgramClass programClass)
{
- int currentAccessFlags = programClass.getAccessFlags();
- int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
+ int currentAccessFlags = programClass.getAccessFlags();
+ int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
// Compute the required access level.
Clazz referencingClass = this.referencingClass;
@@ -117,8 +133,8 @@ implements ConstantVisitor,
public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
{
- int currentAccessFlags = programMember.getAccessFlags();
- int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
+ int currentAccessFlags = programMember.getAccessFlags();
+ int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
// Compute the required access level.
int requiredAccessLevel =
diff --git a/src/proguard/classfile/editor/AnnotationAdder.java b/src/proguard/classfile/editor/AnnotationAdder.java
index 359164a..0389ab1 100644
--- a/src/proguard/classfile/editor/AnnotationAdder.java
+++ b/src/proguard/classfile/editor/AnnotationAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/AnnotationsAttributeEditor.java b/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
index bf8852c..a175c33 100644
--- a/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
+++ b/src/proguard/classfile/editor/AnnotationsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/AttributeAdder.java b/src/proguard/classfile/editor/AttributeAdder.java
index 2b610b7..ad4ecc0 100644
--- a/src/proguard/classfile/editor/AttributeAdder.java
+++ b/src/proguard/classfile/editor/AttributeAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -138,16 +138,14 @@ implements AttributeVisitor
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
- // TODO: Implement method.
- // Note that the attribute may already be present.
-// // Create a copy of the attribute.
-// InnerClassesAttribute newInnerClassesAttribute =
-// new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex),
-// 0,
-// null);
-//
-// // Add it to the target class.
-// attributesEditor.addClassAttribute(newInnerClassesAttribute);
+ // Create a copy of the attribute.
+ InnerClassesAttribute newInnerClassesAttribute =
+ new InnerClassesAttribute(constantAdder.addConstant(clazz, innerClassesAttribute.u2attributeNameIndex),
+ 0,
+ null);
+
+ // Add it to the target class.
+ attributesEditor.addAttribute(newInnerClassesAttribute);
}
@@ -256,7 +254,7 @@ implements AttributeVisitor
CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
- codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength);
+ codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength + 32);
// Add the instructions.
codeAttribute.instructionsAccept(clazz,
diff --git a/src/proguard/classfile/editor/AttributeSorter.java b/src/proguard/classfile/editor/AttributeSorter.java
index d8e3367..23fe027 100644
--- a/src/proguard/classfile/editor/AttributeSorter.java
+++ b/src/proguard/classfile/editor/AttributeSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/AttributesEditor.java b/src/proguard/classfile/editor/AttributesEditor.java
index 10846cc..f50b8f1 100644
--- a/src/proguard/classfile/editor/AttributesEditor.java
+++ b/src/proguard/classfile/editor/AttributesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/BridgeMethodFixer.java b/src/proguard/classfile/editor/BridgeMethodFixer.java
new file mode 100644
index 0000000..2f1120d
--- /dev/null
+++ b/src/proguard/classfile/editor/BridgeMethodFixer.java
@@ -0,0 +1,117 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This MemberVisitor fixes all inappropriate bridge access flags of the
+ * program methods that it visits, checking whether the methods to which they
+ * bridge have the same name. Some compilers, like in Eclipse and in later
+ * versions of JDK 1.6, complain if they can't find the method with the same
+ * name.
+ *
+ * @author Eric Lafortune
+ */
+public class BridgeMethodFixer
+extends SimplifiedVisitor
+implements MemberVisitor,
+ AttributeVisitor,
+ InstructionVisitor,
+ ConstantVisitor
+{
+ private static final boolean DEBUG = false;
+
+
+ // Return values for the visitor methods.
+ private String bridgedMethodName;
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_BRIDGE) != 0)
+ {
+ programMethod.attributesAccept(programClass, this);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Go over the instructions of the bridge method.
+ codeAttribute.instructionsAccept(clazz, method, 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:
+ // Get the name of the bridged method.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+
+ // Check if the name is different.
+ if (!method.getName(clazz).equals(bridgedMethodName))
+ {
+ if (DEBUG)
+ {
+ System.out.println("BridgeMethodFixer: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] does not bridge to ["+bridgedMethodName+"]");
+ }
+
+ // Clear the bridge flag.
+ ((ProgramMethod)method).u2accessFlags &= ~ClassConstants.INTERNAL_ACC_BRIDGE;
+ }
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ bridgedMethodName = refConstant.getName(clazz);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/ClassEditor.java b/src/proguard/classfile/editor/ClassEditor.java
index e503ea3..7703c9d 100644
--- a/src/proguard/classfile/editor/ClassEditor.java
+++ b/src/proguard/classfile/editor/ClassEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ClassElementSorter.java b/src/proguard/classfile/editor/ClassElementSorter.java
index 3256c88..9875a29 100644
--- a/src/proguard/classfile/editor/ClassElementSorter.java
+++ b/src/proguard/classfile/editor/ClassElementSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ClassMemberSorter.java b/src/proguard/classfile/editor/ClassMemberSorter.java
index f31fcd0..ed0b5b1 100644
--- a/src/proguard/classfile/editor/ClassMemberSorter.java
+++ b/src/proguard/classfile/editor/ClassMemberSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ClassReferenceFixer.java b/src/proguard/classfile/editor/ClassReferenceFixer.java
index 9857903..1f8b396 100644
--- a/src/proguard/classfile/editor/ClassReferenceFixer.java
+++ b/src/proguard/classfile/editor/ClassReferenceFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/CodeAttributeComposer.java b/src/proguard/classfile/editor/CodeAttributeComposer.java
index e783203..c59b712 100644
--- a/src/proguard/classfile/editor/CodeAttributeComposer.java
+++ b/src/proguard/classfile/editor/CodeAttributeComposer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,9 @@ import proguard.classfile.attribute.visitor.*;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import proguard.util.ArrayUtil;
+
+import java.util.Arrays;
/**
* This AttributeVisitor accumulates instructions and exceptions, and then
@@ -49,7 +52,7 @@ implements AttributeVisitor,
//*
private static final boolean DEBUG = false;
/*/
- public static boolean DEBUG = true;
+ public static boolean DEBUG = false;
//*/
@@ -57,7 +60,8 @@ implements AttributeVisitor,
private static final int INVALID = -1;
- private boolean allowExternalExceptionHandlers;
+ private final boolean allowExternalExceptionHandlers;
+ private final boolean shrinkInstructions;
private int maximumCodeLength;
private int codeLength;
@@ -77,26 +81,34 @@ implements AttributeVisitor,
private final StackSizeUpdater stackSizeUpdater = new StackSizeUpdater();
private final VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater();
-// private final InstructionWriter instructionWriter = new InstructionWriter();
+ private final InstructionWriter instructionWriter = new InstructionWriter();
/**
* Creates a new CodeAttributeComposer that doesn't allow external exception
- * handlers.
+ * handlers and that automatically shrinks instructions.
*/
public CodeAttributeComposer()
{
- this(false);
+ this(false, true);
}
/**
- * Creates a new CodeAttributeComposer that optionally allows external
- * exception handlers.
+ * Creates a new CodeAttributeComposer.
+ * @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 CodeAttributeComposer(boolean allowExternalExceptionHandlers)
+ public CodeAttributeComposer(boolean allowExternalExceptionHandlers,
+ boolean shrinkInstructions)
{
this.allowExternalExceptionHandlers = allowExternalExceptionHandlers;
+ this.shrinkInstructions = shrinkInstructions;
}
@@ -109,6 +121,8 @@ implements AttributeVisitor,
codeLength = 0;
exceptionTableLength = 0;
level = -1;
+
+ instructionWriter.reset(ClassConstants.TYPICAL_CODE_LENGTH);
}
@@ -116,7 +130,10 @@ implements AttributeVisitor,
* 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.
+ * be added as part of this fragment (more
+ * precisely, the maximum old instruction
+ * offset or label that is specified, plus
+ * one).
*/
public void beginCodeFragment(int maximumCodeFragmentLength)
{
@@ -127,14 +144,9 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Maximum number of code fragment levels exceeded ["+level+"]");
}
-// // TODO: Figure out some length.
-// if (level == 0)
-// {
-// // Prepare for possible widening of instructions.
-// instructionWriter.reset(2 * maximumCodeFragmentLength);
-// }
-
// Make sure there is sufficient space for adding the code fragment.
+ // It's only a rough initial estimate for the code length, not even
+ // necessarily a length expressed in bytes.
maximumCodeLength += maximumCodeFragmentLength;
ensureCodeLength(maximumCodeLength);
@@ -159,6 +171,8 @@ implements AttributeVisitor,
/**
* 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.
@@ -167,12 +181,17 @@ implements AttributeVisitor,
public void appendInstruction(int oldInstructionOffset,
Instruction instruction)
{
+ if (shrinkInstructions)
+ {
+ instruction = instruction.shrink();
+ }
+
if (DEBUG)
{
println("["+codeLength+"] <- ", instruction.toString(oldInstructionOffset));
}
- // Make sure the code array is large enough.
+ // Make sure the code and offset arrays are large enough.
int newCodeLength = codeLength + instruction.length(codeLength);
ensureCodeLength(newCodeLength);
@@ -180,17 +199,18 @@ implements AttributeVisitor,
// Remember the old offset of the appended instruction.
oldInstructionOffsets[codeLength] = oldInstructionOffset;
- // Write the instruction.
-// instruction.accept(null,
-// null,
-// new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
-// codeLength,
-// instructionWriter);
- instruction.write(code, codeLength);
-
// Fill out the new offset of the appended instruction.
instructionOffsetMap[level][oldInstructionOffset] = codeLength;
+ // Write the instruction. The instruction writer may widen it later on,
+ // if necessary.
+ instruction.accept(null,
+ null,
+ new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
+ codeLength,
+ instructionWriter);
+ //instruction.write(code, codeLength);
+
// Continue appending at the next instruction offset.
codeLength = newCodeLength;
}
@@ -209,11 +229,69 @@ implements AttributeVisitor,
println("["+codeLength+"] <- ", "[" + oldInstructionOffset + "] (label)");
}
- // Fill out the new offset of the appended instruction.
+ // Make sure the code and offset arrays are large enough.
+ ensureCodeLength(codeLength + 1);
+
+ // Remember the old offset of the following instruction.
+ oldInstructionOffsets[codeLength] = oldInstructionOffset;
+
+ // Fill out the new offset of the following instruction.
instructionOffsetMap[level][oldInstructionOffset] = codeLength;
}
+ /**
+ * Appends the given instruction without defined offsets.
+ * @param instructions the instructions to be appended.
+ */
+ public void appendInstructions(Instruction[] instructions)
+ {
+ for (int index = 0; index < instructions.length; index++)
+ {
+ appendInstruction(instructions[index]);
+ }
+ }
+
+
+ /**
+ * 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 void appendInstruction(Instruction instruction)
+ {
+ if (shrinkInstructions)
+ {
+ instruction = instruction.shrink();
+ }
+
+ if (DEBUG)
+ {
+ println("["+codeLength+"] <- ", instruction.toString());
+ }
+
+ // Make sure the code array is large enough.
+ int newCodeLength = codeLength + instruction.length(codeLength);
+
+ ensureCodeLength(newCodeLength);
+
+ // Write the instruction. The instruction writer may widen it later on,
+ // if necessary.
+ instruction.accept(null,
+ null,
+ new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
+ codeLength,
+ instructionWriter);
+ //instruction.write(code, codeLength);
+
+ // Continue appending at the next instruction offset.
+ codeLength = newCodeLength;
+ }
+
+
/**
* Appends the given exception to the exception table.
* @param exceptionInfo the exception to be appended.
@@ -244,16 +322,11 @@ implements AttributeVisitor,
return;
}
- // Make sure there is sufficient space in the exception table.
- if (exceptionTable.length <= exceptionTableLength)
- {
- ExceptionInfo[] newExceptionTable = new ExceptionInfo[exceptionTableLength+1];
- System.arraycopy(exceptionTable, 0, newExceptionTable, 0, exceptionTableLength);
- exceptionTable = newExceptionTable;
- }
-
// Add the exception.
- exceptionTable[exceptionTableLength++] = exceptionInfo;
+ exceptionTable =
+ (ExceptionInfo[])ArrayUtil.add(exceptionTable,
+ exceptionTableLength++,
+ exceptionInfo);
}
@@ -281,13 +354,14 @@ implements AttributeVisitor,
// Adapt the instruction for its new offset.
instruction.accept(null, null, null, instructionOffset, this);
- // Write the instruction back.
-// instruction.accept(null,
-// null,
-// new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
-// instructionOffset,
-// instructionWriter);
- instruction.write(code, instructionOffset);
+ // Write the instruction back. The instruction writer may still
+ // widen it later on, if necessary.
+ instruction.accept(null,
+ null,
+ new CodeAttribute(0, 0, 0, 0, code, 0, null, 0, null),
+ instructionOffset,
+ instructionWriter);
+ //instruction.write(code, codeLength);
// Don't remap this instruction again.
oldInstructionOffsets[instructionOffset] = -1;
@@ -313,9 +387,9 @@ implements AttributeVisitor,
int handlerPC = -exceptionInfo.u2handlerPC;
if (handlerPC > 0)
{
- if (remappableInstructionOffset(handlerPC))
+ if (remappableExceptionHandler(handlerPC))
{
- exceptionInfo.u2handlerPC = remapInstructionOffset(handlerPC);
+ exceptionInfo.u2handlerPC = newInstructionOffset(handlerPC);
}
else if (level == 0)
{
@@ -381,7 +455,7 @@ implements AttributeVisitor,
// Remap the line number table and the local variable table.
codeAttribute.attributesAccept(clazz, method, this);
- // Remap the exception table.
+ // Remap the exception table (done before).
//codeAttribute.exceptionsAccept(clazz, method, this);
// Remove exceptions with empty code blocks (done before).
@@ -389,8 +463,8 @@ implements AttributeVisitor,
// removeEmptyExceptions(codeAttribute.exceptionTable,
// codeAttribute.u2exceptionTableLength);
-// // Make sure instructions are widened if necessary.
-// instructionWriter.visitCodeAttribute(clazz, method, codeAttribute);
+ // Make sure instructions are widened if necessary.
+ instructionWriter.visitCodeAttribute(clazz, method, codeAttribute);
level--;
}
@@ -459,20 +533,20 @@ implements AttributeVisitor,
public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
{
// Adjust the branch offset.
- branchInstruction.branchOffset = remapBranchOffset(offset,
- branchInstruction.branchOffset);
+ branchInstruction.branchOffset = newBranchOffset(offset,
+ branchInstruction.branchOffset);
}
public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
{
// Adjust the default jump offset.
- switchInstruction.defaultOffset = remapBranchOffset(offset,
- switchInstruction.defaultOffset);
+ switchInstruction.defaultOffset = newBranchOffset(offset,
+ switchInstruction.defaultOffset);
// Adjust the jump offsets.
- remapJumpOffsets(offset,
- switchInstruction.jumpOffsets);
+ updateJumpOffsets(offset,
+ switchInstruction.jumpOffsets);
}
@@ -482,16 +556,16 @@ implements AttributeVisitor,
{
// Remap the code offsets. Note that the instruction offset map also has
// an entry for the first offset after the code, for u2endPC.
- exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC);
- exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC);
+ exceptionInfo.u2startPC = newInstructionOffset(exceptionInfo.u2startPC);
+ exceptionInfo.u2endPC = newInstructionOffset(exceptionInfo.u2endPC);
// See if we can remap the handler right away. Unmapped exception
// handlers are negated, in order to mark them as external.
int handlerPC = exceptionInfo.u2handlerPC;
exceptionInfo.u2handlerPC =
!allowExternalExceptionHandlers ||
- remappableInstructionOffset(handlerPC) ?
- remapInstructionOffset(handlerPC) :
+ remappableExceptionHandler(handlerPC) ?
+ newInstructionOffset(handlerPC) :
-handlerPC;
}
@@ -501,7 +575,7 @@ implements AttributeVisitor,
public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame)
{
// Remap the stack map frame offset.
- int stackMapFrameOffset = remapInstructionOffset(offset);
+ int stackMapFrameOffset = newInstructionOffset(offset);
int offsetDelta = stackMapFrameOffset;
@@ -557,7 +631,7 @@ implements AttributeVisitor,
public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
{
// Remap the offset of the 'new' instruction.
- uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset);
+ uninitializedType.u2newInstructionOffset = newInstructionOffset(uninitializedType.u2newInstructionOffset);
}
@@ -566,7 +640,7 @@ implements AttributeVisitor,
public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
{
// Remap the code offset.
- lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC);
+ lineNumberInfo.u2startPC = newInstructionOffset(lineNumberInfo.u2startPC);
}
@@ -576,8 +650,9 @@ implements AttributeVisitor,
{
// Remap the code offset and length.
// TODO: The local variable frame might not be strictly preserved.
- int startPC = remapInstructionOffset(localVariableInfo.u2startPC);
- int endPC = remapInstructionOffset(localVariableInfo.u2startPC + localVariableInfo.u2length);
+ int startPC = newInstructionOffset(localVariableInfo.u2startPC);
+ int endPC = newInstructionOffset(localVariableInfo.u2startPC +
+ localVariableInfo.u2length);
localVariableInfo.u2startPC = startPC;
localVariableInfo.u2length = endPC - startPC;
@@ -589,8 +664,9 @@ implements AttributeVisitor,
{
// Remap the code offset and length.
// TODO: The local variable frame might not be strictly preserved.
- int startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC);
- int endPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length);
+ int startPC = newInstructionOffset(localVariableTypeInfo.u2startPC);
+ int endPC = newInstructionOffset(localVariableTypeInfo.u2startPC +
+ localVariableTypeInfo.u2length);
localVariableTypeInfo.u2startPC = startPC;
localVariableTypeInfo.u2length = endPC - startPC;
@@ -609,13 +685,10 @@ implements AttributeVisitor,
// Add 20% to avoid extending the arrays too often.
newCodeLength = newCodeLength * 6 / 5;
- byte[] newCode = new byte[newCodeLength];
- System.arraycopy(code, 0, newCode, 0, codeLength);
- code = newCode;
+ code = ArrayUtil.extendArray(code, newCodeLength);
+ oldInstructionOffsets = ArrayUtil.extendArray(oldInstructionOffsets, newCodeLength);
- int[] newOldInstructionOffsets = new int[newCodeLength];
- System.arraycopy(oldInstructionOffsets, 0, newOldInstructionOffsets, 0, codeLength);
- oldInstructionOffsets = newOldInstructionOffsets;
+ instructionWriter.extend(newCodeLength);
}
}
@@ -623,11 +696,11 @@ implements AttributeVisitor,
/**
* Adjusts the given jump offsets for the instruction at the given offset.
*/
- private void remapJumpOffsets(int offset, int[] jumpOffsets)
+ private void updateJumpOffsets(int offset, int[] jumpOffsets)
{
for (int index = 0; index < jumpOffsets.length; index++)
{
- jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]);
+ jumpOffsets[index] = newBranchOffset(offset, jumpOffsets[index]);
}
}
@@ -636,7 +709,7 @@ implements AttributeVisitor,
* Computes the new branch offset for the instruction at the given new offset
* with the given old branch offset.
*/
- private int remapBranchOffset(int newInstructionOffset, int branchOffset)
+ private int newBranchOffset(int newInstructionOffset, int oldBranchOffset)
{
if (newInstructionOffset < 0 ||
newInstructionOffset > codeLength)
@@ -646,8 +719,8 @@ implements AttributeVisitor,
int oldInstructionOffset = oldInstructionOffsets[newInstructionOffset];
- return remapInstructionOffset(oldInstructionOffset + branchOffset) -
- remapInstructionOffset(oldInstructionOffset);
+ return newInstructionOffset(oldInstructionOffset + oldBranchOffset) -
+ newInstructionOffset(oldInstructionOffset);
}
@@ -655,7 +728,7 @@ implements AttributeVisitor,
* Computes the new instruction offset for the instruction at the given old
* offset.
*/
- private int remapInstructionOffset(int oldInstructionOffset)
+ private int newInstructionOffset(int oldInstructionOffset)
{
if (oldInstructionOffset < 0 ||
oldInstructionOffset > codeFragmentLengths[level])
@@ -674,13 +747,25 @@ implements AttributeVisitor,
/**
- * Returns whether the given old instruction offset can be remapped at the
+ * Returns whether the given old exception handler can be remapped in the
+ * current code fragment.
*/
- private boolean remappableInstructionOffset(int oldInstructionOffset)
+ private boolean remappableExceptionHandler(int oldInstructionOffset)
{
- return
- oldInstructionOffset <= codeFragmentLengths[level] &&
- instructionOffsetMap[level][oldInstructionOffset] > INVALID;
+ // Can we index in the array?
+ if (oldInstructionOffset > codeFragmentLengths[level])
+ {
+ return false;
+ }
+
+ // Do we have a valid new instruction offset, but not yet right after
+ // the code? That offset is only labeled for mapping try blocks, not
+ // for mapping handlers.
+ int newInstructionOffset =
+ instructionOffsetMap[level][oldInstructionOffset];
+
+ return newInstructionOffset > INVALID &&
+ newInstructionOffset < codeLength;
}
@@ -703,10 +788,7 @@ implements AttributeVisitor,
}
// Clear the unused array entries.
- for (int index = newIndex; index < exceptionInfoCount; index++)
- {
- exceptionInfos[index] = null;
- }
+ Arrays.fill(exceptionInfos, newIndex, exceptionInfoCount, null);
return newIndex;
}
@@ -734,10 +816,7 @@ implements AttributeVisitor,
}
// Clear the unused array entries.
- for (int index = newIndex; index < lineNumberInfoCount; index++)
- {
- lineNumberInfos[index] = null;
- }
+ Arrays.fill(lineNumberInfos, newIndex, lineNumberInfoCount, null);
return newIndex;
}
@@ -764,10 +843,7 @@ implements AttributeVisitor,
}
// Clear the unused array entries.
- for (int index = newIndex; index < localVariableInfoCount; index++)
- {
- localVariableInfos[index] = null;
- }
+ Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null);
return newIndex;
}
@@ -794,10 +870,7 @@ implements AttributeVisitor,
}
// Clear the unused array entries.
- for (int index = newIndex; index < localVariableTypeInfoCount; index++)
- {
- localVariableTypeInfos[index] = null;
- }
+ Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null);
return newIndex;
}
diff --git a/src/proguard/classfile/editor/CodeAttributeEditor.java b/src/proguard/classfile/editor/CodeAttributeEditor.java
index 9658c98..337e0d4 100644
--- a/src/proguard/classfile/editor/CodeAttributeEditor.java
+++ b/src/proguard/classfile/editor/CodeAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,9 @@ import proguard.classfile.attribute.visitor.*;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.ClassPrinter;
+import proguard.util.ArrayUtil;
+
+import java.util.Arrays;
/**
* This AttributeVisitor accumulates specified changes to code, and then applies
@@ -50,10 +52,12 @@ implements AttributeVisitor,
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = true;
+ public static boolean DEBUG = false;
//*/
- private boolean updateFrameSizes;
+
+ private final boolean updateFrameSizes;
+ private final boolean shrinkInstructions;
private int codeLength;
private boolean modified;
@@ -64,7 +68,7 @@ implements AttributeVisitor,
/*private*/public Instruction[] postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
/*private*/public boolean[] deleted = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
- private int[] instructionOffsetMap = new int[ClassConstants.TYPICAL_CODE_LENGTH];
+ private int[] newInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private int newOffset;
private boolean lengthIncreased;
@@ -75,15 +79,28 @@ implements AttributeVisitor,
private final InstructionWriter instructionWriter = new InstructionWriter();
+ /**
+ * Creates a new CodeAttributeEditor that automatically updates frame
+ * sizes and shrinks instructions.
+ */
public CodeAttributeEditor()
{
- this(true);
+ this(true, true);
}
- public CodeAttributeEditor(boolean updateFrameSizes)
+ /**
+ * Creates a new CodeAttributeEditor.
+ * @param updateFrameSizes specifies whether frame sizes of edited code
+ * should be updated.
+ * @param shrinkInstructions specifies whether added instructions should
+ * automatically be shrunk before being written.
+ */
+ public CodeAttributeEditor(boolean updateFrameSizes,
+ boolean shrinkInstructions)
{
- this.updateFrameSizes = updateFrameSizes;
+ this.updateFrameSizes = updateFrameSizes;
+ this.shrinkInstructions = shrinkInstructions;
}
@@ -93,8 +110,6 @@ implements AttributeVisitor,
*/
public void reset(int codeLength)
{
- this.codeLength = codeLength;
-
// Try to reuse the previous arrays.
if (preInsertions.length < codeLength)
{
@@ -105,18 +120,42 @@ implements AttributeVisitor,
}
else
{
- for (int index = 0; index < codeLength; index++)
- {
- preInsertions[index] = null;
- replacements[index] = null;
- postInsertions[index] = null;
- deleted[index] = false;
- }
+ 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;
+
modified = false;
simple = true;
+ }
+
+
+ /**
+ * Extends the size of the accumulated code changes.
+ * @param codeLength the length of the code that will be edited next.
+ */
+ 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);
+ }
+ 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);
+ }
+ this.codeLength = codeLength;
}
@@ -134,7 +173,9 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- preInsertions[instructionOffset] = instruction;
+ preInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
simple = false;
@@ -156,7 +197,12 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- preInsertions[instructionOffset] = new CompositeInstruction(instructions);
+ CompositeInstruction instruction =
+ new CompositeInstruction(instructions);
+
+ preInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
simple = false;
@@ -178,7 +224,9 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- replacements[instructionOffset] = instruction;
+ replacements[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
}
@@ -198,7 +246,12 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- replacements[instructionOffset] = new CompositeInstruction(instructions);
+ CompositeInstruction instruction =
+ new CompositeInstruction(instructions);
+
+ replacements[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
}
@@ -218,7 +271,9 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- postInsertions[instructionOffset] = instruction;
+ postInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
simple = false;
@@ -239,7 +294,12 @@ implements AttributeVisitor,
throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
}
- postInsertions[instructionOffset] = new CompositeInstruction(instructions);
+ CompositeInstruction instruction =
+ new CompositeInstruction(instructions);
+
+ postInsertions[instructionOffset] = shrinkInstructions ?
+ instruction.shrink() :
+ instruction;
modified = true;
simple = false;
@@ -281,6 +341,34 @@ implements AttributeVisitor,
}
+ /**
+ * Clears all modifications of the instruction at the given offset.
+ * @param instructionOffset the offset of the instruction to be deleted.
+ */
+ public void clearModifications(int instructionOffset)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ preInsertions[instructionOffset] = null;
+ replacements[instructionOffset] = null;
+ postInsertions[instructionOffset] = null;
+ deleted[instructionOffset] = false;
+ }
+
+
+ /**
+ * Returns whether the code has been modified in any way.
+ */
+ public boolean isModified()
+ {
+ return modified;
+ }
+
+
/**
* Returns whether the instruction at the given offset has been modified
* in any way.
@@ -326,54 +414,53 @@ implements AttributeVisitor,
public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
- if (DEBUG)
- {
- System.out.println("CodeAttributeEditor: ["+clazz.getName()+"."+method.getName(clazz)+"]");
- }
-
- // Avoid doing any work if nothing is changing anyway.
- if (!modified)
+ // Do we have to update the code?
+ if (modified)
{
- return;
- }
+ if (DEBUG)
+ {
+ System.out.println("CodeAttributeEditor: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ }
- // Check if we can perform a faster simple replacement of instructions.
- if (canPerformSimpleReplacements(codeAttribute))
- {
- // Simply overwrite the instructions.
- performSimpleReplacements(codeAttribute);
+ // Can we perform a faster simple replacement of instructions?
+ if (canPerformSimpleReplacements(codeAttribute))
+ {
+ if (DEBUG)
+ {
+ System.out.println(" Simple editing");
+ }
- // Update the maximum stack size and local variable frame size.
- updateFrameSizes(clazz, method, codeAttribute);
- }
- else
- {
- // Move and remap the instructions.
- codeAttribute.u4codeLength =
- updateInstructions(clazz, method, codeAttribute);
+ // Simply overwrite the instructions.
+ performSimpleReplacements(codeAttribute);
+ }
+ else
+ {
+ if (DEBUG)
+ {
+ System.out.println(" Full editing");
+ }
- // Remap the exception table.
- codeAttribute.exceptionsAccept(clazz, method, this);
+ // Move and remap the instructions.
+ codeAttribute.u4codeLength =
+ updateInstructions(clazz, method, codeAttribute);
- // Remove exceptions with empty code blocks.
- codeAttribute.u2exceptionTableLength =
- removeEmptyExceptions(codeAttribute.exceptionTable,
- codeAttribute.u2exceptionTableLength);
+ // Update the exception table.
+ codeAttribute.exceptionsAccept(clazz, method, this);
- // Update the maximum stack size and local variable frame size.
- updateFrameSizes(clazz, method, codeAttribute);
+ // Remove exceptions with empty code blocks.
+ codeAttribute.u2exceptionTableLength =
+ removeEmptyExceptions(codeAttribute.exceptionTable,
+ codeAttribute.u2exceptionTableLength);
- // Remap the line number table and the local variable table.
- codeAttribute.attributesAccept(clazz, method, this);
+ // Update the line number table and the local variable tables.
+ codeAttribute.attributesAccept(clazz, method, this);
+ }
// Make sure instructions are widened if necessary.
instructionWriter.visitCodeAttribute(clazz, method, codeAttribute);
}
- }
-
- private void updateFrameSizes(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
+ // Update the maximum stack size and local variable frame size.
if (updateFrameSizes)
{
stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
@@ -384,7 +471,7 @@ implements AttributeVisitor,
public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
{
- // Remap all stack map entries.
+ // Update all stack map entries.
expectedStackMapFrameOffset = -1;
stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
}
@@ -392,7 +479,7 @@ implements AttributeVisitor,
public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
{
- // Remap all stack map table entries.
+ // Update all stack map table entries.
expectedStackMapFrameOffset = 0;
stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
}
@@ -400,7 +487,7 @@ implements AttributeVisitor,
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
{
- // Remap all line number table entries.
+ // Update all line number table entries.
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
// Remove line numbers with empty code blocks.
@@ -413,27 +500,15 @@ implements AttributeVisitor,
public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
{
- // Remap all local variable table entries.
+ // Update all local variable table entries.
localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
-
- // Remove local variables with empty code blocks.
- localVariableTableAttribute.u2localVariableTableLength =
- removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable,
- localVariableTableAttribute.u2localVariableTableLength,
- codeAttribute.u2maxLocals);
}
public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
{
- // Remap all local variable table entries.
+ // Update all local variable table entries.
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
-
- // Remove local variables with empty code blocks.
- localVariableTypeTableAttribute.u2localVariableTypeTableLength =
- removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
- localVariableTypeTableAttribute.u2localVariableTypeTableLength,
- codeAttribute.u2maxLocals);
}
@@ -491,7 +566,7 @@ implements AttributeVisitor,
if (DEBUG)
{
- System.out.println(" Replaced "+replacementInstruction.toString(newOffset));
+ System.out.println(" Replaced "+replacementInstruction.toString(offset));
}
}
}
@@ -513,9 +588,9 @@ implements AttributeVisitor,
int oldLength = codeAttribute.u4codeLength;
// Make sure there is a sufficiently large instruction offset map.
- if (instructionOffsetMap.length < oldLength + 1)
+ if (newInstructionOffsets.length < oldLength + 1)
{
- instructionOffsetMap = new int[oldLength + 1];
+ newInstructionOffsets = new int[oldLength + 1];
}
// Fill out the instruction offset map.
@@ -574,7 +649,7 @@ implements AttributeVisitor,
while (oldOffset < oldLength);
// Also add an entry for the first offset after the code.
- instructionOffsetMap[oldOffset] = newOffset;
+ newInstructionOffsets[oldOffset] = newOffset;
return newOffset;
}
@@ -588,7 +663,7 @@ implements AttributeVisitor,
private void mapInstruction(int oldOffset,
Instruction instruction)
{
- instructionOffsetMap[oldOffset] = newOffset;
+ newInstructionOffsets[oldOffset] = newOffset;
// Account for the pre-inserted instruction, if any.
Instruction preInstruction = preInsertions[oldOffset];
@@ -670,52 +745,53 @@ implements AttributeVisitor,
int oldOffset,
Instruction instruction)
{
- // Remap and insert the pre-inserted instruction, if any.
+ // Update and insert the pre-inserted instruction, if any.
Instruction preInstruction = preInsertions[oldOffset];
if (preInstruction != null)
{
if (DEBUG)
{
- System.out.println(" Pre-inserted "+preInstruction.toString(newOffset));
+ System.out.println(" Pre-inserted ["+oldOffset+"] -> "+preInstruction.toString(newOffset));
}
- // Remap the instruction.
+ // Update the instruction.
preInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
}
- // Remap and insert the replacement instruction, or the current
+ // Update and insert the replacement instruction, or the current
// instruction, if it shouldn't be deleted.
Instruction replacementInstruction = replacements[oldOffset];
if (replacementInstruction != null)
{
if (DEBUG)
{
- System.out.println(" Replaced "+replacementInstruction.toString(newOffset));
+ System.out.println(" Replaced ["+oldOffset+"] -> "+replacementInstruction.toString(newOffset));
}
- // Remap the instruction.
+
+ // Update the instruction.
replacementInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
}
else if (!deleted[oldOffset])
{
if (DEBUG)
{
- System.out.println(" Copied "+instruction.toString(newOffset));
+ System.out.println(" Copied ["+oldOffset+"] -> "+instruction.toString(newOffset));
}
- // Remap the instruction.
+ // Update the instruction.
instruction.accept(clazz, method, codeAttribute, oldOffset, this);
}
- // Remap and insert the post-inserted instruction, if any.
+ // Update and insert the post-inserted instruction, if any.
Instruction postInstruction = postInsertions[oldOffset];
if (postInstruction != null)
{
if (DEBUG)
{
- System.out.println(" Post-inserted "+postInstruction.toString(newOffset));
+ System.out.println(" Post-inserted ["+oldOffset+"] -> "+postInstruction.toString(newOffset));
}
- // Remap the instruction.
+ // Update the instruction.
postInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
}
}
@@ -765,8 +841,8 @@ implements AttributeVisitor,
public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
{
// Adjust the branch offset.
- branchInstruction.branchOffset = remapBranchOffset(offset,
- branchInstruction.branchOffset);
+ branchInstruction.branchOffset = newBranchOffset(offset,
+ branchInstruction.branchOffset);
// Write out the instruction.
instructionWriter.visitBranchInstruction(clazz,
@@ -782,11 +858,11 @@ implements AttributeVisitor,
public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
{
// Adjust the default jump offset.
- tableSwitchInstruction.defaultOffset = remapBranchOffset(offset,
- tableSwitchInstruction.defaultOffset);
+ tableSwitchInstruction.defaultOffset = newBranchOffset(offset,
+ tableSwitchInstruction.defaultOffset);
// Adjust the jump offsets.
- remapJumpOffsets(offset,
+ newJumpOffsets(offset,
tableSwitchInstruction.jumpOffsets);
// Write out the instruction.
@@ -803,11 +879,11 @@ implements AttributeVisitor,
public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
{
// Adjust the default jump offset.
- lookUpSwitchInstruction.defaultOffset = remapBranchOffset(offset,
- lookUpSwitchInstruction.defaultOffset);
+ lookUpSwitchInstruction.defaultOffset = newBranchOffset(offset,
+ lookUpSwitchInstruction.defaultOffset);
// Adjust the jump offsets.
- remapJumpOffsets(offset,
+ newJumpOffsets(offset,
lookUpSwitchInstruction.jumpOffsets);
// Write out the instruction.
@@ -825,11 +901,11 @@ implements AttributeVisitor,
public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
{
- // Remap the code offsets. Note that the instruction offset map also has
+ // Update the code offsets. Note that the instruction offset map also has
// an entry for the first offset after the code, for u2endPC.
- exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC);
- exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC);
- exceptionInfo.u2handlerPC = remapInstructionOffset(exceptionInfo.u2handlerPC);
+ exceptionInfo.u2startPC = newInstructionOffset(exceptionInfo.u2startPC);
+ exceptionInfo.u2endPC = newInstructionOffset(exceptionInfo.u2endPC);
+ exceptionInfo.u2handlerPC = newInstructionOffset(exceptionInfo.u2handlerPC);
}
@@ -837,8 +913,8 @@ implements AttributeVisitor,
public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame)
{
- // Remap the stack map frame offset.
- int stackMapFrameOffset = remapInstructionOffset(offset);
+ // Update the stack map frame offset.
+ int stackMapFrameOffset = newInstructionOffset(offset);
int offsetDelta = stackMapFrameOffset;
@@ -857,30 +933,30 @@ implements AttributeVisitor,
public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
{
- // Remap the stack map frame offset.
+ // Update the stack map frame offset.
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame);
- // Remap the verification type offset.
+ // Update the verification type offset.
sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
}
public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
{
- // Remap the stack map frame offset.
+ // Update the stack map frame offset.
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame);
- // Remap the verification type offsets.
+ // Update the verification type offsets.
moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
}
public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
{
- // Remap the stack map frame offset.
+ // Update the stack map frame offset.
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame);
- // Remap the verification type offsets.
+ // Update the verification type offsets.
fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
}
@@ -893,8 +969,8 @@ implements AttributeVisitor,
public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
{
- // Remap the offset of the 'new' instruction.
- uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset);
+ // Update the offset of the 'new' instruction.
+ uninitializedType.u2newInstructionOffset = newInstructionOffset(uninitializedType.u2newInstructionOffset);
}
@@ -902,8 +978,8 @@ implements AttributeVisitor,
public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
{
- // Remap the code offset.
- lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC);
+ // Update the code offset.
+ lineNumberInfo.u2startPC = newInstructionOffset(lineNumberInfo.u2startPC);
}
@@ -911,11 +987,13 @@ implements AttributeVisitor,
public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
{
- // Remap the code offset and length.
- // TODO: The local variable frame might not be strictly preserved.
- localVariableInfo.u2length = remapBranchOffset(localVariableInfo.u2startPC,
- localVariableInfo.u2length);
- localVariableInfo.u2startPC = remapInstructionOffset(localVariableInfo.u2startPC);
+ // Update the code offset and length.
+ int newStartPC = newInstructionOffset(localVariableInfo.u2startPC);
+ int newEndPC = newInstructionOffset(localVariableInfo.u2startPC +
+ localVariableInfo.u2length);
+
+ localVariableInfo.u2length = newEndPC - newStartPC;
+ localVariableInfo.u2startPC = newStartPC;
}
@@ -923,11 +1001,13 @@ implements AttributeVisitor,
public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
{
- // Remap the code offset and length.
- // TODO: The local variable frame might not be strictly preserved.
- localVariableTypeInfo.u2length = remapBranchOffset(localVariableTypeInfo.u2startPC,
- localVariableTypeInfo.u2length);
- localVariableTypeInfo.u2startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC);
+ // Update the code offset and length.
+ int newStartPC = newInstructionOffset(localVariableTypeInfo.u2startPC);
+ int newEndPC = newInstructionOffset(localVariableTypeInfo.u2startPC +
+ localVariableTypeInfo.u2length);
+
+ localVariableTypeInfo.u2length = newEndPC - newStartPC;
+ localVariableTypeInfo.u2startPC = newStartPC;
}
@@ -936,11 +1016,11 @@ implements AttributeVisitor,
/**
* Adjusts the given jump offsets for the instruction at the given offset.
*/
- private void remapJumpOffsets(int offset, int[] jumpOffsets)
+ private void newJumpOffsets(int oldInstructionOffset, int[] oldJumpOffsets)
{
- for (int index = 0; index < jumpOffsets.length; index++)
+ for (int index = 0; index < oldJumpOffsets.length; index++)
{
- jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]);
+ oldJumpOffsets[index] = newBranchOffset(oldInstructionOffset, oldJumpOffsets[index]);
}
}
@@ -949,24 +1029,24 @@ implements AttributeVisitor,
* Computes the new branch offset for the instruction at the given offset
* with the given branch offset.
*/
- private int remapBranchOffset(int offset, int branchOffset)
+ private int newBranchOffset(int oldInstructionOffset, int oldBranchOffset)
{
- return remapInstructionOffset(offset + branchOffset) - newOffset;
+ return newInstructionOffset(oldInstructionOffset + oldBranchOffset) - newOffset;
}
/**
* Computes the new instruction offset for the instruction at the given offset.
*/
- private int remapInstructionOffset(int offset)
+ private int newInstructionOffset(int oldInstructionOffset)
{
- if (offset < 0 ||
- offset > codeLength)
+ if (oldInstructionOffset < 0 ||
+ oldInstructionOffset > codeLength)
{
- throw new IllegalArgumentException("Invalid instruction offset ["+offset+"] in code with length ["+codeLength+"]");
+ throw new IllegalArgumentException("Invalid instruction offset ["+oldInstructionOffset+"] in code with length ["+codeLength+"]");
}
- return instructionOffsetMap[offset];
+ return newInstructionOffsets[oldInstructionOffset];
}
@@ -1018,53 +1098,9 @@ implements AttributeVisitor,
/**
- * Returns the given list of local variables, without the ones that have empty
- * code blocks or that exceed the actual number of local variables.
+ * This instruction is a composite of other instructions, for local use
+ * inside the editor class only.
*/
- private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
- int localVariableInfoCount,
- int maxLocals)
- {
- // Overwrite all empty local variable entries.
- int newIndex = 0;
- for (int index = 0; index < localVariableInfoCount; index++)
- {
- LocalVariableInfo localVariableInfo = localVariableInfos[index];
- if (localVariableInfo.u2length > 0 &&
- localVariableInfo.u2index < maxLocals)
- {
- localVariableInfos[newIndex++] = localVariableInfo;
- }
- }
-
- return newIndex;
- }
-
-
- /**
- * Returns the given list of local variable types, without the ones that
- * have empty code blocks or that exceed the actual number of local variables.
- */
- private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
- int localVariableTypeInfoCount,
- int maxLocals)
- {
- // Overwrite all empty local variable type entries.
- int newIndex = 0;
- for (int index = 0; index < localVariableTypeInfoCount; index++)
- {
- LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
- if (localVariableTypeInfo.u2length > 0 &&
- localVariableTypeInfo.u2index < maxLocals)
- {
- localVariableTypeInfos[newIndex++] = localVariableTypeInfo;
- }
- }
-
- return newIndex;
- }
-
-
private class CompositeInstruction
extends Instruction
{
diff --git a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java b/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
index 9962ea5..8f767c7 100644
--- a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
+++ b/src/proguard/classfile/editor/CodeAttributeEditorResetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ComparableConstant.java b/src/proguard/classfile/editor/ComparableConstant.java
index bb81221..476edd6 100644
--- a/src/proguard/classfile/editor/ComparableConstant.java
+++ b/src/proguard/classfile/editor/ComparableConstant.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -39,7 +39,7 @@ class ComparableConstant
extends SimplifiedVisitor
implements Comparable, ConstantVisitor
{
- private static final int[] PRIORITIES = new int[13];
+ private static final int[] PRIORITIES = new int[19];
static
{
PRIORITIES[ClassConstants.CONSTANT_Integer] = 0; // Possibly byte index (ldc).
@@ -47,12 +47,15 @@ implements Comparable, ConstantVisitor
PRIORITIES[ClassConstants.CONSTANT_String] = 2;
PRIORITIES[ClassConstants.CONSTANT_Class] = 3;
PRIORITIES[ClassConstants.CONSTANT_Long] = 4; // Always wide index (ldc2_w).
- PRIORITIES[ClassConstants.CONSTANT_Double] = 5;
- PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index.
- PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7;
- PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8;
- PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 9;
- PRIORITIES[ClassConstants.CONSTANT_Utf8] = 10;
+ PRIORITIES[ClassConstants.CONSTANT_Double] = 5; // Always wide index (ldc2_w).
+ PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index (getfield,...).
+ PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7; // Always wide index (invokespecial,...).
+ PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; // Always wide index (invokeinterface).
+ PRIORITIES[ClassConstants.CONSTANT_InvokeDynamic] = 9; // Always wide index (invokedynamic).
+ PRIORITIES[ClassConstants.CONSTANT_MethodHandle] = 10;
+ PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 11;
+ PRIORITIES[ClassConstants.CONSTANT_MethodType] = 12;
+ PRIORITIES[ClassConstants.CONSTANT_Utf8] = 13;
}
private final Clazz clazz;
@@ -122,26 +125,32 @@ implements Comparable, ConstantVisitor
public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
{
- // In JDK 1.4, we can use Integer.compare(a,b).
- result = new Integer(integerConstant.getValue()).compareTo(new Integer(((IntegerConstant)otherConstant).getValue()));
+ int value = integerConstant.getValue();
+ int otherValue = ((IntegerConstant)otherConstant).getValue();
+ result = value < otherValue ? -1 :
+ value == otherValue ? 0 :
+ 1;
}
public void visitLongConstant(Clazz clazz, LongConstant longConstant)
{
- // In JDK 1.4, we can use Long.compare(a,b).
- result = new Long(longConstant.getValue()).compareTo(new Long(((LongConstant)otherConstant).getValue()));
+ long value = longConstant.getValue();
+ long otherValue = ((LongConstant)otherConstant).getValue();
+ result = value < otherValue ? -1 :
+ value == otherValue ? 0 :
+ 1;
}
public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
{
- // In JDK 1.4, we can use Float.compare(a,b).
- result = new Float(floatConstant.getValue()).compareTo(new Float(((FloatConstant)otherConstant).getValue()));
+ result = Float.compare(floatConstant.getValue(),
+ ((FloatConstant)otherConstant).getValue());
}
public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
- {
- // In JDK 1.4, we can use Double.compare(a,b).
- result = new Double(doubleConstant.getValue()).compareTo(new Double(((DoubleConstant)otherConstant).getValue()));
+ {
+ result = Double.compare(doubleConstant.getValue(),
+ ((DoubleConstant)otherConstant).getValue());
}
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
@@ -154,6 +163,38 @@ implements Comparable, ConstantVisitor
result = utf8Constant.getString().compareTo(((Utf8Constant)otherConstant).getString());
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ InvokeDynamicConstant otherInvokeDynamicConstant = (InvokeDynamicConstant)otherConstant;
+
+ int index = invokeDynamicConstant.getBootstrapMethodAttributeIndex();
+ int otherIndex = otherInvokeDynamicConstant.getBootstrapMethodAttributeIndex();
+
+ result = index < otherIndex ? -1 :
+ index > otherIndex ? 1 :
+ (invokeDynamicConstant.getName(clazz) + ' ' +
+ invokeDynamicConstant.getType(clazz))
+ .compareTo
+ (otherInvokeDynamicConstant.getName(clazz) + ' ' +
+ otherInvokeDynamicConstant.getType(clazz));
+ }
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ MethodHandleConstant otherMethodHandleConstant = (MethodHandleConstant)otherConstant;
+
+ int kind = methodHandleConstant.getReferenceKind();
+ int otherKind = methodHandleConstant.getReferenceKind();
+
+ result = kind < otherKind ? -1 :
+ kind > otherKind ? 1 :
+ (methodHandleConstant.getName(clazz) + ' ' +
+ methodHandleConstant.getType(clazz))
+ .compareTo
+ (otherMethodHandleConstant.getName(clazz) + ' ' +
+ otherMethodHandleConstant.getType(clazz));
+ }
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
RefConstant otherRefConstant = (RefConstant)otherConstant;
@@ -171,6 +212,14 @@ implements Comparable, ConstantVisitor
result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz));
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant MethodTypeConstant)
+ {
+ MethodTypeConstant otherMethodTypeConstant = (MethodTypeConstant)otherConstant;
+ result = MethodTypeConstant.getType(clazz)
+ .compareTo
+ (otherMethodTypeConstant.getType(clazz));
+ }
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant;
diff --git a/src/proguard/classfile/editor/ConstantAdder.java b/src/proguard/classfile/editor/ConstantAdder.java
index 2b74f5f..9d20199 100644
--- a/src/proguard/classfile/editor/ConstantAdder.java
+++ b/src/proguard/classfile/editor/ConstantAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,6 +23,7 @@ package proguard.classfile.editor;
import proguard.classfile.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.util.ListUtil;
/**
* This ConstantVisitor adds all constants that it visits to the constant pool
@@ -128,6 +129,43 @@ implements ConstantVisitor
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // First add the name and type constant.
+ clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this);
+
+ // Copy the referenced classes.
+ Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses;
+ Clazz[] referencedClassesCopy = null;
+ if (referencedClasses != null)
+ {
+ referencedClassesCopy = new Clazz[referencedClasses.length];
+ System.arraycopy(referencedClasses, 0,
+ referencedClassesCopy, 0,
+ referencedClasses.length);
+ }
+
+ // Then add the actual invoke dynamic constant.
+ constantIndex =
+ constantPoolEditor.addInvokeDynamicConstant(invokeDynamicConstant.getBootstrapMethodAttributeIndex(),
+ constantIndex,
+ referencedClassesCopy);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ // First add the field ref, interface method ref, or method ref
+ // constant.
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
+
+ // Then add the actual method handle constant.
+ constantIndex =
+ constantPoolEditor.addMethodHandleConstant(methodHandleConstant.getReferenceKind(),
+ constantIndex);
+ }
+
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
// First add the referenced class constant, with its own referenced class.
@@ -185,6 +223,13 @@ implements ConstantVisitor
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ constantIndex =
+ constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz));
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
constantIndex =
diff --git a/src/proguard/classfile/editor/ConstantPoolEditor.java b/src/proguard/classfile/editor/ConstantPoolEditor.java
index 8663dee..7adbc44 100644
--- a/src/proguard/classfile/editor/ConstantPoolEditor.java
+++ b/src/proguard/classfile/editor/ConstantPoolEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -198,6 +198,93 @@ public class ConstantPoolEditor
}
+ /**
+ * Finds or creates a InvokeDynamicConstant constant pool entry with the
+ * given bootstrap method constant pool entry index, method name, and
+ * descriptor.
+ * @return the constant pool index of the InvokeDynamicConstant.
+ */
+ public int addInvokeDynamicConstant(int bootstrapMethodIndex,
+ String name,
+ String descriptor,
+ Clazz[] referencedClasses)
+ {
+ return addInvokeDynamicConstant(bootstrapMethodIndex,
+ addNameAndTypeConstant(name, descriptor),
+ referencedClasses);
+ }
+
+
+ /**
+ * Finds or creates a InvokeDynamicConstant constant pool entry with the given
+ * class constant pool entry index and name and type constant pool entry
+ * index.
+ * @return the constant pool index of the InvokeDynamicConstant.
+ */
+ public int addInvokeDynamicConstant(int bootstrapMethodIndex,
+ int nameAndTypeIndex,
+ Clazz[] referencedClasses)
+ {
+ 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_InvokeDynamic)
+ {
+ InvokeDynamicConstant invokeDynamicConstant = (InvokeDynamicConstant)constant;
+ if (invokeDynamicConstant.u2bootstrapMethodAttributeIndex == bootstrapMethodIndex &&
+ invokeDynamicConstant.u2nameAndTypeIndex == nameAndTypeIndex)
+ {
+ return index;
+ }
+ }
+ }
+
+ return addConstant(new InvokeDynamicConstant(bootstrapMethodIndex,
+ nameAndTypeIndex,
+ referencedClasses));
+ }
+
+
+ /**
+ * Finds or creates a MethodHandleConstant constant pool entry of the
+ * specified kind and with the given field ref, interface method ref,
+ * or method ref constant pool entry index.
+ * @return the constant pool index of the MethodHandleConstant.
+ */
+ public int addMethodHandleConstant(int referenceKind,
+ int referenceIndex)
+ {
+ 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_MethodHandle)
+ {
+ MethodHandleConstant methodHandleConstant = (MethodHandleConstant)constant;
+ if (methodHandleConstant.u1referenceKind == referenceKind &&
+ methodHandleConstant.u2referenceIndex == referenceIndex)
+ {
+ return index;
+ }
+ }
+ }
+
+ return addConstant(new MethodHandleConstant(referenceKind,
+ referenceIndex));
+ }
+
+
/**
* Finds or creates a FieldrefConstant constant pool entry for the given
* class and field.
@@ -562,6 +649,36 @@ public class ConstantPoolEditor
}
+ /**
+ * Finds or creates a MethodTypeConstant constant pool entry with the given
+ * type.
+ * @return the constant pool index of the MethodTypeConstant.
+ */
+ public int addMethodTypeConstant(String type)
+ {
+ 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_MethodType)
+ {
+ MethodTypeConstant methodTypeConstant = (MethodTypeConstant)constant;
+ if (methodTypeConstant.getType(targetClass).equals(type))
+ {
+ return index;
+ }
+ }
+ }
+
+ return addConstant(new MethodTypeConstant(addUtf8Constant(type)));
+ }
+
+
/**
* Finds or creates a NameAndTypeConstant constant pool entry with the given
* name and type.
diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/src/proguard/classfile/editor/ConstantPoolRemapper.java
index 7430d3d..eaf7653 100644
--- a/src/proguard/classfile/editor/ConstantPoolRemapper.java
+++ b/src/proguard/classfile/editor/ConstantPoolRemapper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -47,9 +47,10 @@ implements ClassVisitor,
ConstantVisitor,
MemberVisitor,
AttributeVisitor,
- InstructionVisitor,
+ BootstrapMethodInfoVisitor,
InnerClassesInfoVisitor,
ExceptionInfoVisitor,
+ InstructionVisitor,
StackMapFrameVisitor,
VerificationTypeVisitor,
LocalVariableInfoVisitor,
@@ -57,7 +58,7 @@ implements ClassVisitor,
AnnotationVisitor,
ElementValueVisitor
{
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, true);
private int[] constantIndexMap;
@@ -100,40 +101,66 @@ implements ClassVisitor,
// Implementations for ConstantVisitor.
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
{
- classConstant.u2nameIndex =
- remapConstantIndex(classConstant.u2nameIndex);
+ // Nothing to do.
}
- public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
+ public void visitLongConstant(Clazz clazz, LongConstant longConstant)
{
// Nothing to do.
}
- public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
{
- fieldrefConstant.u2classIndex =
- remapConstantIndex(fieldrefConstant.u2classIndex);
- fieldrefConstant.u2nameAndTypeIndex =
- remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex);
+ // Nothing to do.
}
- public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
+ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
{
// Nothing to do.
}
- public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ stringConstant.u2stringIndex =
+ remapConstantIndex(stringConstant.u2stringIndex);
+ }
+
+
+ public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
{
// Nothing to do.
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ invokeDynamicConstant.u2nameAndTypeIndex =
+ remapConstantIndex(invokeDynamicConstant.u2nameAndTypeIndex);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ methodHandleConstant.u2referenceIndex =
+ remapConstantIndex(methodHandleConstant.u2referenceIndex);
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ fieldrefConstant.u2classIndex =
+ remapConstantIndex(fieldrefConstant.u2classIndex);
+ fieldrefConstant.u2nameAndTypeIndex =
+ remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex);
+ }
+
+
public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
{
interfaceMethodrefConstant.u2classIndex =
@@ -143,12 +170,6 @@ implements ClassVisitor,
}
- public void visitLongConstant(Clazz clazz, LongConstant longConstant)
- {
- // Nothing to do.
- }
-
-
public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
{
methodrefConstant.u2classIndex =
@@ -158,25 +179,26 @@ implements ClassVisitor,
}
- public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
- nameAndTypeConstant.u2nameIndex =
- remapConstantIndex(nameAndTypeConstant.u2nameIndex);
- nameAndTypeConstant.u2descriptorIndex =
- remapConstantIndex(nameAndTypeConstant.u2descriptorIndex);
+ classConstant.u2nameIndex =
+ remapConstantIndex(classConstant.u2nameIndex);
}
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
{
- stringConstant.u2stringIndex =
- remapConstantIndex(stringConstant.u2stringIndex);
+ methodTypeConstant.u2descriptorIndex =
+ remapConstantIndex(methodTypeConstant.u2descriptorIndex);
}
- public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
+ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
- // Nothing to do.
+ nameAndTypeConstant.u2nameIndex =
+ remapConstantIndex(nameAndTypeConstant.u2nameIndex);
+ nameAndTypeConstant.u2descriptorIndex =
+ remapConstantIndex(nameAndTypeConstant.u2descriptorIndex);
}
@@ -230,6 +252,16 @@ implements ClassVisitor,
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ bootstrapMethodsAttribute.u2attributeNameIndex =
+ remapConstantIndex(bootstrapMethodsAttribute.u2attributeNameIndex);
+
+ // Remap the constant pool references of the bootstrap method entries.
+ bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
sourceFileAttribute.u2attributeNameIndex =
@@ -410,6 +442,19 @@ implements ClassVisitor,
}
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ bootstrapMethodInfo.u2methodHandleIndex =
+ remapConstantIndex(bootstrapMethodInfo.u2methodHandleIndex);
+
+ // Remap the constant pool references of the bootstrap methods..
+ remapConstantIndexArray(bootstrapMethodInfo.u2methodArguments,
+ bootstrapMethodInfo.u2methodArgumentCount);
+ }
+
+
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
@@ -461,7 +506,7 @@ implements ClassVisitor,
Instruction replacementInstruction =
new ConstantInstruction(constantInstruction.opcode,
newConstantIndex,
- constantInstruction.constant).shrink();
+ constantInstruction.constant);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
}
diff --git a/src/proguard/classfile/editor/ConstantPoolShrinker.java b/src/proguard/classfile/editor/ConstantPoolShrinker.java
new file mode 100644
index 0000000..ee309a0
--- /dev/null
+++ b/src/proguard/classfile/editor/ConstantPoolShrinker.java
@@ -0,0 +1,578 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+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.*;
+
+import java.util.Arrays;
+
+/**
+ * This ClassVisitor removes all unused entries from the constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantPoolShrinker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor,
+ ConstantVisitor,
+ AttributeVisitor,
+ BootstrapMethodInfoVisitor,
+ InnerClassesInfoVisitor,
+ ExceptionInfoVisitor,
+ StackMapFrameVisitor,
+ VerificationTypeVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor,
+ InstructionVisitor
+{
+ // A visitor info flag to indicate the constant is being used.
+ private static final Object USED = new Object();
+
+ private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE];
+ private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Mark this class's name.
+ markConstant(programClass, programClass.u2thisClass);
+
+ // Mark the superclass class constant.
+ programClass.superClassConstantAccept(this);
+
+ // Mark the interface class constants.
+ programClass.interfaceConstantsAccept(this);
+
+ // Mark the constants referenced by the class members.
+ programClass.fieldsAccept(this);
+ programClass.methodsAccept(this);
+
+ // Mark the attributes.
+ programClass.attributesAccept(this);
+
+ // Shift the used constant pool entries together, filling out the
+ // index map.
+ int newConstantPoolCount =
+ shrinkConstantPool(programClass.constantPool,
+ programClass.u2constantPoolCount);
+
+ // Remap the references to the constant pool if it has shrunk.
+ if (newConstantPoolCount < programClass.u2constantPoolCount)
+ {
+ programClass.u2constantPoolCount = newConstantPoolCount;
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setConstantIndexMap(constantIndexMap);
+ constantPoolRemapper.visitProgramClass(programClass);
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
+ {
+ // Mark the name and descriptor.
+ markConstant(programClass, programMember.u2nameIndex);
+ markConstant(programClass, programMember.u2descriptorIndex);
+
+ // Mark the attributes.
+ programMember.attributesAccept(programClass, this);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant)
+ {
+ markAsUsed(constant);
+ }
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ markAsUsed(stringConstant);
+
+ markConstant(clazz, stringConstant.u2stringIndex);
+ }
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ markAsUsed(invokeDynamicConstant);
+
+ markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex);
+
+ // Mark the bootstrap methods attribute.
+ clazz.attributesAccept(this);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ markAsUsed(methodHandleConstant);
+
+ markConstant(clazz, methodHandleConstant.u2referenceIndex);
+ }
+
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ markAsUsed(refConstant);
+
+ markConstant(clazz, refConstant.u2classIndex);
+ markConstant(clazz, refConstant.u2nameAndTypeIndex);
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ markAsUsed(classConstant);
+
+ markConstant(clazz, classConstant.u2nameIndex);
+ }
+
+
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ markAsUsed(methodTypeConstant);
+
+ markConstant(clazz, methodTypeConstant.u2descriptorIndex);
+ }
+
+
+ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
+ {
+ markAsUsed(nameAndTypeConstant);
+
+ markConstant(clazz, nameAndTypeConstant.u2nameIndex);
+ markConstant(clazz, nameAndTypeConstant.u2descriptorIndex);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute)
+ {
+ markConstant(clazz, attribute.u2attributeNameIndex);
+ }
+
+
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex);
+
+ // Mark the bootstrap method entries.
+ bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
+ }
+
+
+ public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
+ {
+ markConstant(clazz, sourceFileAttribute.u2attributeNameIndex);
+ markConstant(clazz, sourceFileAttribute.u2sourceFileIndex);
+ }
+
+
+ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
+ {
+ markConstant(clazz, sourceDirAttribute.u2attributeNameIndex);
+ markConstant(clazz, sourceDirAttribute.u2sourceDirIndex);
+ }
+
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ markConstant(clazz, innerClassesAttribute.u2attributeNameIndex);
+
+ // Mark the outer class entries.
+ innerClassesAttribute.innerClassEntriesAccept(clazz, this);
+ }
+
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ markConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex);
+ markConstant(clazz, enclosingMethodAttribute.u2classIndex);
+
+ if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
+ {
+ markConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex);
+ }
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
+ {
+ markConstant(clazz, signatureAttribute.u2attributeNameIndex);
+ markConstant(clazz, signatureAttribute.u2signatureIndex);
+ }
+
+
+ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
+ {
+ markConstant(clazz, constantValueAttribute.u2attributeNameIndex);
+ markConstant(clazz, constantValueAttribute.u2constantValueIndex);
+ }
+
+
+ public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
+ {
+ markConstant(clazz, exceptionsAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the exceptions.
+ exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this);
+ }
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ markConstant(clazz, codeAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the instructions,
+ // by the exceptions, and by the attributes.
+ codeAttribute.instructionsAccept(clazz, method, this);
+ codeAttribute.exceptionsAccept(clazz, method, this);
+ codeAttribute.attributesAccept(clazz, method, this);
+ }
+
+
+ public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
+ {
+ markConstant(clazz, stackMapAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the stack map frames.
+ stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
+ {
+ markConstant(clazz, stackMapTableAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the stack map frames.
+ stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the local variables.
+ localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the local variable types.
+ localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
+ {
+ markConstant(clazz, annotationsAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ annotationsAttribute.annotationsAccept(clazz, this);
+ }
+
+
+ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
+ {
+ markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex);
+
+ // Mark the constant pool entries referenced by the element value.
+ annotationDefaultAttribute.defaultValueAccept(clazz, this);
+ }
+
+
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex);
+
+ // Mark the constant pool entries referenced by the arguments.
+ bootstrapMethodInfo.methodArgumentsAccept(clazz, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
+ {
+ innerClassesInfo.innerClassConstantAccept(clazz, this);
+ innerClassesInfo.outerClassConstantAccept(clazz, this);
+ innerClassesInfo.innerNameConstantAccept(clazz, this);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
+ {
+ if (exceptionInfo.u2catchType != 0)
+ {
+ markConstant(clazz, exceptionInfo.u2catchType);
+ }
+ }
+
+
+ // Implementations for StackMapFrameVisitor.
+
+ public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {}
+
+
+ public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
+ {
+ // Mark the constant pool entries referenced by the verification types.
+ sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
+ {
+ // Mark the constant pool entries referenced by the verification types.
+ moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
+ {
+ // Mark the constant pool entries referenced by the verification types.
+ fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
+ fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ // Implementations for VerificationTypeVisitor.
+
+ public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {}
+
+
+ public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType)
+ {
+ markConstant(clazz, objectType.u2classIndex);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
+ {
+ markConstant(clazz, localVariableInfo.u2nameIndex);
+ markConstant(clazz, localVariableInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ markConstant(clazz, localVariableTypeInfo.u2nameIndex);
+ markConstant(clazz, localVariableTypeInfo.u2signatureIndex);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(Clazz clazz, Annotation annotation)
+ {
+ markConstant(clazz, annotation.u2typeIndex);
+
+ // Mark the constant pool entries referenced by the element values.
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ if (constantElementValue.u2elementNameIndex != 0)
+ {
+ markConstant(clazz, constantElementValue.u2elementNameIndex);
+ }
+
+ markConstant(clazz, constantElementValue.u2constantValueIndex);
+ }
+
+
+ public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ if (enumConstantElementValue.u2elementNameIndex != 0)
+ {
+ markConstant(clazz, enumConstantElementValue.u2elementNameIndex);
+ }
+
+ markConstant(clazz, enumConstantElementValue.u2typeNameIndex);
+ markConstant(clazz, enumConstantElementValue.u2constantNameIndex);
+ }
+
+
+ public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
+ {
+ if (classElementValue.u2elementNameIndex != 0)
+ {
+ markConstant(clazz, classElementValue.u2elementNameIndex);
+ }
+
+ markConstant(clazz, classElementValue.u2classInfoIndex);
+ }
+
+
+ public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ if (annotationElementValue.u2elementNameIndex != 0)
+ {
+ markConstant(clazz, annotationElementValue.u2elementNameIndex);
+ }
+
+ // Mark the constant pool entries referenced by the annotation.
+ annotationElementValue.annotationAccept(clazz, this);
+ }
+
+
+ public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ if (arrayElementValue.u2elementNameIndex != 0)
+ {
+ markConstant(clazz, arrayElementValue.u2elementNameIndex);
+ }
+
+ // Mark the constant pool entries referenced by the element values.
+ arrayElementValue.elementValuesAccept(clazz, annotation, 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)
+ {
+ markConstant(clazz, constantInstruction.constantIndex);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given constant pool entry of the given class. This includes
+ * visiting any referenced objects.
+ */
+ private void markConstant(Clazz clazz, int index)
+ {
+ clazz.constantPoolEntryAccept(index, this);
+ }
+
+
+ /**
+ * Marks the given visitor accepter as being used.
+ */
+ private void markAsUsed(Constant constant)
+ {
+ constant.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 constants that are not marked as being used from the given
+ * constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(Constant[] constantPool, int length)
+ {
+ // Create a new index map, if necessary.
+ if (constantIndexMap.length < length)
+ {
+ constantIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ constantIndexMap[index] = counter;
+
+ Constant constant = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (constant != null)
+ {
+ isUsed = isUsed(constant);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = constant;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ Arrays.fill(constantPool, counter, length, null);
+
+ return counter;
+ }
+}
diff --git a/src/proguard/classfile/editor/ConstantPoolSorter.java b/src/proguard/classfile/editor/ConstantPoolSorter.java
index faae318..b578624 100644
--- a/src/proguard/classfile/editor/ConstantPoolSorter.java
+++ b/src/proguard/classfile/editor/ConstantPoolSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -112,10 +112,7 @@ implements ClassVisitor
System.arraycopy(newConstantPool, 0, programClass.constantPool, 0, newLength);
// Clear any remaining entries.
- for (int index = newLength; index < constantPoolCount; index++)
- {
- programClass.constantPool[index] = null;
- }
+ Arrays.fill(programClass.constantPool, newLength, constantPoolCount, null);
programClass.u2constantPoolCount = newLength;
diff --git a/src/proguard/classfile/editor/ElementValueAdder.java b/src/proguard/classfile/editor/ElementValueAdder.java
index 8cbd11d..9c8b3f9 100644
--- a/src/proguard/classfile/editor/ElementValueAdder.java
+++ b/src/proguard/classfile/editor/ElementValueAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ElementValuesEditor.java b/src/proguard/classfile/editor/ElementValuesEditor.java
index bfc4e9f..57671e6 100644
--- a/src/proguard/classfile/editor/ElementValuesEditor.java
+++ b/src/proguard/classfile/editor/ElementValuesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ExceptionAdder.java b/src/proguard/classfile/editor/ExceptionAdder.java
index 1ccb1a6..152a065 100644
--- a/src/proguard/classfile/editor/ExceptionAdder.java
+++ b/src/proguard/classfile/editor/ExceptionAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ExceptionInfoAdder.java b/src/proguard/classfile/editor/ExceptionInfoAdder.java
index e0cc9c5..c1c20fa 100644
--- a/src/proguard/classfile/editor/ExceptionInfoAdder.java
+++ b/src/proguard/classfile/editor/ExceptionInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ExceptionsAttributeEditor.java b/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
index 4509a9a..98bb79e 100644
--- a/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
+++ b/src/proguard/classfile/editor/ExceptionsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/InnerClassesAccessFixer.java b/src/proguard/classfile/editor/InnerClassesAccessFixer.java
new file mode 100644
index 0000000..5a5e8a5
--- /dev/null
+++ b/src/proguard/classfile/editor/InnerClassesAccessFixer.java
@@ -0,0 +1,83 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.visitor.InnerClassesInfoVisitor;
+import proguard.classfile.attribute.InnerClassesInfo;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InnerClassesInfoVisitor fixes the inner class access flags of the
+ * inner classes information that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class InnerClassesAccessFixer
+extends SimplifiedVisitor
+implements InnerClassesInfoVisitor,
+ ConstantVisitor,
+ ClassVisitor
+{
+ private int innerClassAccessFlags;
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
+ {
+ // The current access flags are the default.
+ innerClassAccessFlags = innerClassesInfo.u2innerClassAccessFlags;
+
+ // See if we can find new access flags.
+ innerClassesInfo.innerClassConstantAccept(clazz, this);
+
+ // Update the access flags.
+ innerClassesInfo.u2innerClassAccessFlags = innerClassAccessFlags;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ classConstant.referencedClassAccept(this);
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitLibraryClass(LibraryClass libraryClass) {}
+
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ innerClassAccessFlags =
+ AccessUtil.replaceAccessFlags(innerClassAccessFlags,
+ programClass.u2accessFlags);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/InstructionAdder.java b/src/proguard/classfile/editor/InstructionAdder.java
index 60fde6d..422a348 100644
--- a/src/proguard/classfile/editor/InstructionAdder.java
+++ b/src/proguard/classfile/editor/InstructionAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -68,7 +68,7 @@ implements InstructionVisitor
Instruction newConstantInstruction =
new ConstantInstruction(constantInstruction.opcode,
constantAdder.addConstant(clazz, constantInstruction.constantIndex),
- constantInstruction.constant).shrink();
+ constantInstruction.constant);
// Add the instruction.
codeAttributeComposer.appendInstruction(offset, newConstantInstruction);
diff --git a/src/proguard/classfile/editor/InstructionWriter.java b/src/proguard/classfile/editor/InstructionWriter.java
index d842358..c4a9b09 100644
--- a/src/proguard/classfile/editor/InstructionWriter.java
+++ b/src/proguard/classfile/editor/InstructionWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,7 +31,7 @@ import proguard.classfile.util.SimplifiedVisitor;
* This InstructionVisitor writes out the instructions that it visits,
* collecting instructions that have to be widened. As an AttributeVisitor,
* it then applies the collected changes. The process will be repeated
- * recursively, if necessary.
+ * recursively, if necessary. The caller still has to update the frame sizes.
*
* @author Eric Lafortune
*/
@@ -40,20 +40,26 @@ extends SimplifiedVisitor
implements InstructionVisitor,
AttributeVisitor
{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ public static boolean DEBUG = false;
+ //*/
+
+
private int codeLength;
private CodeAttributeEditor codeAttributeEditor;
/**
- * Resets the accumulated code changes.
+ * Resets the accumulated code.
* @param codeLength the length of the code that will be edited next.
*/
public void reset(int codeLength)
{
this.codeLength = codeLength;
- // The code attribute editor has to be created lazily.
if (codeAttributeEditor != null)
{
codeAttributeEditor.reset(codeLength);
@@ -61,6 +67,21 @@ implements InstructionVisitor,
}
+ /**
+ * Extends the size of the accumulated code.
+ * @param codeLength the length of the code that will be edited next.
+ */
+ public void extend(int codeLength)
+ {
+ this.codeLength = codeLength;
+
+ if (codeAttributeEditor != null)
+ {
+ codeAttributeEditor.extend(codeLength);
+ }
+ }
+
+
// Implementations for InstructionVisitor.
public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
@@ -84,7 +105,12 @@ implements InstructionVisitor,
Instruction replacementInstruction =
new ConstantInstruction(constantInstruction.opcode,
constantInstruction.constantIndex,
- constantInstruction.constant).shrink();
+ constantInstruction.constant);
+
+ if (DEBUG)
+ {
+ System.out.println(" "+constantInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
+ }
replaceInstruction(offset, replacementInstruction);
@@ -109,10 +135,15 @@ implements InstructionVisitor,
Instruction replacementInstruction =
new VariableInstruction(variableInstruction.opcode,
variableInstruction.variableIndex,
- variableInstruction.constant).shrink();
+ variableInstruction.constant);
replaceInstruction(offset, replacementInstruction);
+ if (DEBUG)
+ {
+ System.out.println(" "+variableInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
+ }
+
// Write out a dummy variable instruction for now.
variableInstruction.variableIndex = 0;
variableInstruction.constant = 0;
@@ -143,7 +174,7 @@ implements InstructionVisitor,
// Create a new branch instruction that will fit.
replacementInstruction =
new BranchInstruction(branchInstruction.opcode,
- branchInstruction.branchOffset).shrink();
+ branchInstruction.branchOffset);
break;
}
@@ -190,6 +221,11 @@ implements InstructionVisitor,
}
}
+ if (DEBUG)
+ {
+ System.out.println(" "+branchInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
+ }
+
replaceInstruction(offset, replacementInstruction);
// Write out a dummy branch instruction for now.
@@ -214,10 +250,16 @@ implements InstructionVisitor,
// Avoid doing any work if nothing is changing anyway.
if (codeAttributeEditor != null)
{
+ if (DEBUG)
+ {
+ System.out.println("InstructionWriter: widening instructions in "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ }
+
// Apply the collected expansions.
codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- // Clear the modifications for the next run.
+ // Don't keep the editor around. We're assuming it won't be needed
+ // very often, so we don't want to be resetting it all the time.
codeAttributeEditor = null;
}
}
@@ -271,7 +313,7 @@ implements InstructionVisitor,
{
if (codeAttributeEditor == null)
{
- codeAttributeEditor = new CodeAttributeEditor();
+ codeAttributeEditor = new CodeAttributeEditor(false, true);
codeAttributeEditor.reset(codeLength);
}
}
diff --git a/src/proguard/classfile/editor/InterfaceAdder.java b/src/proguard/classfile/editor/InterfaceAdder.java
index e095af6..1ad67dc 100644
--- a/src/proguard/classfile/editor/InterfaceAdder.java
+++ b/src/proguard/classfile/editor/InterfaceAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/InterfaceSorter.java b/src/proguard/classfile/editor/InterfaceSorter.java
index 6521369..0d1f28c 100644
--- a/src/proguard/classfile/editor/InterfaceSorter.java
+++ b/src/proguard/classfile/editor/InterfaceSorter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,10 +21,14 @@
package proguard.classfile.editor;
import proguard.classfile.*;
-import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.*;
import proguard.classfile.visitor.ClassVisitor;
-import java.util.Arrays;
+import java.util.*;
/**
* This ClassVisitor sorts the interfaces of the program classes that it visits.
@@ -33,7 +37,8 @@ import java.util.Arrays;
*/
public class InterfaceSorter
extends SimplifiedVisitor
-implements ClassVisitor
+implements ClassVisitor,
+ AttributeVisitor
{
// Implementations for ClassVisitor.
@@ -42,26 +47,106 @@ implements ClassVisitor
int[] interfaces = programClass.u2interfaces;
int interfacesCount = programClass.u2interfacesCount;
- // Sort the interfaces.
- Arrays.sort(interfaces, 0, interfacesCount);
+ if (interfacesCount > 1)
+ {
+ // Sort the interfaces.
+ Arrays.sort(interfaces, 0, interfacesCount);
+
+ // Remove any duplicate entries.
+ int newInterfacesCount = 0;
+ int previousInterfaceIndex = 0;
+ for (int index = 0; index < interfacesCount; index++)
+ {
+ int interfaceIndex = interfaces[index];
+
+ // Isn't this a duplicate of the previous interface?
+ if (interfaceIndex != previousInterfaceIndex)
+ {
+ interfaces[newInterfacesCount++] = interfaceIndex;
+
+ // Remember the interface.
+ previousInterfaceIndex = interfaceIndex;
+ }
+ }
+
+ programClass.u2interfacesCount = newInterfacesCount;
+
+ // Update the signature, if any
+ programClass.attributesAccept(this);
+ }
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
+ {
+ // Process the generic definitions, superclass, and implemented
+ // interfaces.
+ String signature = clazz.getString(signatureAttribute.u2signatureIndex);
+
+ // Count the signature types.
+ InternalTypeEnumeration internalTypeEnumeration =
+ new InternalTypeEnumeration(signature);
- // Remove any duplicate entries.
- int newInterfacesCount = 0;
- int previousInterfaceIndex = 0;
- for (int index = 0; index < interfacesCount; index++)
+ int count = 0;
+ int interfacesCount = -1;
+ while (internalTypeEnumeration.hasMoreTypes())
{
- int interfaceIndex = interfaces[index];
+ String internalType = internalTypeEnumeration.nextType();
- // Isn't this a duplicate of the previous interface?
- if (interfaceIndex != previousInterfaceIndex)
+ count++;
+
+ if (ClassUtil.isInternalClassType(internalType))
{
- interfaces[newInterfacesCount++] = interfaceIndex;
+ interfacesCount++;
+ }
+ }
+
+ // Put the signature types in an array.
+ internalTypeEnumeration =
+ new InternalTypeEnumeration(signature);
+
+ String[] internalTypes = new String[count];
+
+ for (int index = 0; index < count; index++)
+ {
+ String internalType = internalTypeEnumeration.nextType();
+
+ internalTypes[index] = internalType;
+ }
- // Remember the interface.
- previousInterfaceIndex = interfaceIndex;
+ // Sort the interface types in the array.
+ Arrays.sort(internalTypes, count - interfacesCount, count);
+
+ // Recompose the signature types in a string.
+ StringBuffer newSignatureBuffer = new StringBuffer();
+
+ for (int index = 0; index < count; index++)
+ {
+ // Is this not an interface type, or an interface type that isn't
+ // a duplicate of the previous interface type?
+ if (index < count - interfacesCount ||
+ !internalTypes[index].equals(internalTypes[index-1]))
+ {
+ newSignatureBuffer.append(internalTypes[index]);
}
}
- programClass.u2interfacesCount = newInterfacesCount;
+ String newSignature = newSignatureBuffer.toString();
+
+ // Did the signature change?
+ if (!newSignature.equals(signature))
+ {
+ // Update the signature.
+ ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString());
+
+ // Clear the referenced classes.
+ // TODO: Properly update the referenced classes.
+ signatureAttribute.referencedClasses = null;
+ }
}
}
diff --git a/src/proguard/classfile/editor/InterfacesEditor.java b/src/proguard/classfile/editor/InterfacesEditor.java
index d3170e1..8765e36 100644
--- a/src/proguard/classfile/editor/InterfacesEditor.java
+++ b/src/proguard/classfile/editor/InterfacesEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LineNumberInfoAdder.java b/src/proguard/classfile/editor/LineNumberInfoAdder.java
index aa8c0c4..e1bd14a 100644
--- a/src/proguard/classfile/editor/LineNumberInfoAdder.java
+++ b/src/proguard/classfile/editor/LineNumberInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java b/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
index ab96b38..f712d46 100644
--- a/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
+++ b/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LocalVariableInfoAdder.java b/src/proguard/classfile/editor/LocalVariableInfoAdder.java
index f285e4f..a270fcf 100644
--- a/src/proguard/classfile/editor/LocalVariableInfoAdder.java
+++ b/src/proguard/classfile/editor/LocalVariableInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java b/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
index 053b628..b9e601f 100644
--- a/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
+++ b/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java b/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
index ca50f3f..bed1366 100644
--- a/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
+++ b/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java b/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
index fe5a64d..00f7ef3 100644
--- a/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
+++ b/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/MemberAdder.java b/src/proguard/classfile/editor/MemberAdder.java
index 5f939bb..811acae 100644
--- a/src/proguard/classfile/editor/MemberAdder.java
+++ b/src/proguard/classfile/editor/MemberAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -26,8 +26,9 @@ import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.MemberVisitor;
/**
- * This ConstantVisitor adds all class members that it visits to the given
- * target class.
+ * This MemberVisitor copies all class members that it visits to the given
+ * target class. Their visitor info is set to the class members from which they
+ * were copied.
*
* @author Eric Lafortune
*/
@@ -45,8 +46,9 @@ implements MemberVisitor
private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0];
- private final ProgramClass targetClass;
-// private final boolean addFields;
+ private final ProgramClass targetClass;
+// private final boolean addFields;
+ private final MemberVisitor extraMemberVisitor;
private final ConstantAdder constantAdder;
private final ClassEditor classEditor;
@@ -59,13 +61,30 @@ implements MemberVisitor
* @param targetClass the class to which all visited class members will be
* added.
*/
+ public MemberAdder(ProgramClass targetClass)
+ {
+ this(targetClass, null);
+ }
+
+
+ /**
+ * 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 extraMemberVisitor an optional member visitor that visits each
+ * 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)
+ public MemberAdder(ProgramClass targetClass,
+// boolean addFields,
+ MemberVisitor extraMemberVisitor)
{
- this.targetClass = targetClass;
-// this.addFields = addFields;
+ this.targetClass = targetClass;
+// this.addFields = addFields;
+ this.extraMemberVisitor = extraMemberVisitor;
constantAdder = new ConstantAdder(targetClass);
classEditor = new ClassEditor(targetClass);
@@ -77,51 +96,54 @@ implements MemberVisitor
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();
- // Does the target class already have such a field?
- ProgramField targetField = (ProgramField)targetClass.findField(name, descriptor);
- if (targetField != null)
- {
- // Is the field private or static?
- int targetAccessFlags = targetField.getAccessFlags();
- if ((targetAccessFlags &
- (ClassConstants.INTERNAL_ACC_PRIVATE |
- ClassConstants.INTERNAL_ACC_STATIC)) != 0)
- {
- if (DEBUG)
- {
- System.out.println("MemberAdder: renaming field ["+targetClass+"."+targetField.getName(targetClass)+" "+targetField.getDescriptor(targetClass)+"]");
- }
-
- // Rename the private or static field.
- targetField.u2nameIndex =
- constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, targetClass.getName()));
- }
-// else
-// {
-// // Keep the non-private and non-static field, but update its
-// // contents, in order to keep any references to it valid.
-// if (DEBUG)
-// {
-// System.out.println("MemberAdder: updating field ["+programClass+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]");
-// }
-//
-// // Combine the access flags.
-// targetField.u2accessFlags = accessFlags | targetAccessFlags;
-//
-// // Add and replace any attributes.
-// programField.attributesAccept(programClass,
-// new AttributeAdder(targetClass,
-// targetField,
-// true));
-//
-// // Don't add a new field.
-// return;
-// }
- }
+ // 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.
+ //// Does the target class already have such a field?
+ //ProgramField targetField = (ProgramField)targetClass.findField(name, descriptor);
+ //if (targetField != null)
+ //{
+ // // Is the field private or static?
+ // int targetAccessFlags = targetField.getAccessFlags();
+ // if ((targetAccessFlags &
+ // (ClassConstants.INTERNAL_ACC_PRIVATE |
+ // ClassConstants.INTERNAL_ACC_STATIC)) != 0)
+ // {
+ // if (DEBUG)
+ // {
+ // System.out.println("MemberAdder: renaming field ["+targetClass+"."+targetField.getName(targetClass)+" "+targetField.getDescriptor(targetClass)+"]");
+ // }
+ //
+ // // Rename the private or static field.
+ // targetField.u2nameIndex =
+ // constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, targetClass.getName()));
+ // }
+ // else
+ // {
+ // // Keep the non-private and non-static field, but update its
+ // // contents, in order to keep any references to it valid.
+ // if (DEBUG)
+ // {
+ // System.out.println("MemberAdder: updating field ["+programClass+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass)+"] into ["+targetClass.getName()+"]");
+ // }
+ //
+ // // Combine the access flags.
+ // targetField.u2accessFlags = accessFlags | targetAccessFlags;
+ //
+ // // Add and replace any attributes.
+ // programField.attributesAccept(programClass,
+ // new AttributeAdder(targetClass,
+ // targetField,
+ // true));
+ //
+ // // Don't add a new field.
+ // return;
+ // }
+ //}
if (DEBUG)
{
@@ -150,6 +172,12 @@ implements MemberVisitor
// Add the completed field.
classEditor.addField(newProgramField);
+
+ // Visit the newly added field, if necessary.
+ if (extraMemberVisitor != null)
+ {
+ extraMemberVisitor.visitProgramField(targetClass, newProgramField);
+ }
}
@@ -206,9 +234,12 @@ implements MemberVisitor
System.out.println("MemberAdder: renaming method ["+targetClass.getName()+"."+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]");
}
- // Rename the private (non-abstract) or static method.
- targetMethod.u2nameIndex =
- constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, descriptor));
+ // TODO: Handle non-abstract method with the same name and descriptor in the target class.
+ // We currently avoid this case, since renaming the identical method
+ // still causes confused method references.
+ //// Rename the private (non-abstract) or static method.
+ //targetMethod.u2nameIndex =
+ // constantPoolEditor.addUtf8Constant(newUniqueMemberName(name, descriptor));
}
if (DEBUG)
@@ -240,6 +271,12 @@ implements MemberVisitor
// Add the completed method.
classEditor.addMethod(newProgramMethod);
+
+ // Visit the newly added method, if necessary.
+ if (extraMemberVisitor != null)
+ {
+ extraMemberVisitor.visitProgramMethod(targetClass, newProgramMethod);
+ }
}
diff --git a/src/proguard/classfile/editor/MemberReferenceFixer.java b/src/proguard/classfile/editor/MemberReferenceFixer.java
index 4bd8af5..b623047 100644
--- a/src/proguard/classfile/editor/MemberReferenceFixer.java
+++ b/src/proguard/classfile/editor/MemberReferenceFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -298,22 +298,17 @@ implements ClassVisitor,
{
Clazz referencedClass = enclosingMethodAttribute.referencedClass;
- // Does it have a new class?
- if (!enclosingMethodAttribute.getClassName(clazz).equals(referencedClass.getName()))
- {
- // Update the class index.
- enclosingMethodAttribute.u2classIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addClassConstant(referencedClass);
- }
-
// Does it have a new name or type?
- if (!enclosingMethodAttribute.getName(clazz).equals(referencedMember.getName(referencedClass)) ||
- !enclosingMethodAttribute.getType(clazz).equals(referencedMember.getDescriptor(referencedClass)))
+ String newName = referencedMember.getName(referencedClass);
+ String newType = referencedMember.getDescriptor(referencedClass);
+
+ if (!enclosingMethodAttribute.getName(clazz).equals(newName) ||
+ !enclosingMethodAttribute.getType(clazz).equals(newType))
{
// Update the name and type index.
enclosingMethodAttribute.u2nameAndTypeIndex =
- new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(referencedMember.getName(referencedClass),
- referencedMember.getDescriptor(referencedClass));
+ new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName,
+ newType);
}
}
}
@@ -324,7 +319,7 @@ implements ClassVisitor,
// Recompute the maximum stack size if necessary.
if (stackSizesMayHaveChanged)
{
- stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
+ stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
}
// Fix the nested attributes.
@@ -433,10 +428,9 @@ implements ClassVisitor,
Member referencedMember)
{
System.out.println("MemberReferenceFixer:");
- System.out.println(" Class file = "+clazz.getName());
- System.out.println(" Ref class = "+referencedClass.getName());
- System.out.println(" Ref member name = "+stringConstant.getString(clazz));
- System.out.println(" -> "+referencedMember.getName(referencedClass));
+ System.out.println(" ["+clazz.getName()+"]: String ["+
+ stringConstant.getString(clazz)+"] -> ["+
+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]");
}
@@ -446,11 +440,8 @@ implements ClassVisitor,
Member referencedMember)
{
System.out.println("MemberReferenceFixer:");
- System.out.println(" Class file = "+clazz.getName());
- System.out.println(" Ref class = "+referencedClass.getName());
- System.out.println(" Ref member name = "+refConstant.getName(clazz));
- System.out.println(" -> "+referencedMember.getName(referencedClass));
- System.out.println(" Ref descriptor = "+refConstant.getType(clazz));
- System.out.println(" -> "+referencedMember.getDescriptor(referencedClass));
+ System.out.println(" ["+clazz.getName()+"]: ["+
+ refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+" "+refConstant.getType(clazz)+"] -> ["+
+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]");
}
}
diff --git a/src/proguard/classfile/editor/MethodInvocationFixer.java b/src/proguard/classfile/editor/MethodInvocationFixer.java
index ef76012..e457e63 100644
--- a/src/proguard/classfile/editor/MethodInvocationFixer.java
+++ b/src/proguard/classfile/editor/MethodInvocationFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,6 @@ import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
-import proguard.classfile.visitor.*;
/**
* This AttributeVisitor fixes all inappropriate special/virtual/static/interface
@@ -40,9 +39,7 @@ public class MethodInvocationFixer
extends SimplifiedVisitor
implements AttributeVisitor,
InstructionVisitor,
- ConstantVisitor,
- ClassVisitor,
- MemberVisitor
+ ConstantVisitor
{
private static final boolean DEBUG = false;
@@ -88,7 +85,8 @@ implements AttributeVisitor,
clazz.constantPoolEntryAccept(constantIndex, this);
// Did we find the called class and method?
- if (referencedMethod != null)
+ if (referencedClass != null &&
+ referencedMethod != null)
{
// Do we need to update the opcode?
byte opcode = constantInstruction.opcode;
@@ -102,7 +100,7 @@ implements AttributeVisitor,
// Replace the invocation by an invokestatic instruction.
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
- constantIndex).shrink();
+ constantIndex);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
@@ -123,7 +121,7 @@ implements AttributeVisitor,
// Replace the invocation by an invokespecial instruction.
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL,
- constantIndex).shrink();
+ constantIndex);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
@@ -149,7 +147,7 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE,
constantIndex,
- invokeinterfaceConstant).shrink();
+ invokeinterfaceConstant);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
@@ -168,12 +166,13 @@ implements AttributeVisitor,
// but not a super call)?
if (opcode != InstructionConstants.OP_INVOKEVIRTUAL &&
(opcode != InstructionConstants.OP_INVOKESPECIAL ||
+ clazz.equals(referencedClass) ||
!clazz.extends_(referencedClass)))
{
// Replace the invocation by an invokevirtual instruction.
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL,
- constantIndex).shrink();
+ constantIndex);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
@@ -194,40 +193,30 @@ implements AttributeVisitor,
public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
{
- // Check if this is an interface method. Note that we're interested in
- // the class of the method reference, not in the class in which the
- // method was actually found.
- //refConstant.referencedClassAccept(this);
- clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
-
- // Get the referenced access flags and names.
- refConstant.referencedMemberAccept(this);
- }
-
+ // Remember the referenced class. Note that we're interested in the
+ // class of the method reference, not in the class in which the
+ // method 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
+ {
+ clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
+ }
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
- {
- // Check if this is an interface class.
- classConstant.referencedClassAccept(this);
+ // Remember the referenced method.
+ referencedMethodClass = refConstant.referencedClass;
+ referencedMethod = refConstant.referencedMember;
}
- // Implementations for ClassVisitor.
-
- public void visitAnyClass(Clazz clazz)
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
// Remember the referenced class.
- referencedClass = clazz;
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitAnyMember(Clazz clazz, Member member)
- {
- // Remember the referenced method.
- referencedMethodClass = clazz;
- referencedMethod = member;
+ referencedClass = classConstant.referencedClass;
}
diff --git a/src/proguard/classfile/editor/NameAndTypeShrinker.java b/src/proguard/classfile/editor/NameAndTypeShrinker.java
new file mode 100644
index 0000000..650f9ba
--- /dev/null
+++ b/src/proguard/classfile/editor/NameAndTypeShrinker.java
@@ -0,0 +1,188 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.ConstantPoolRemapper;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.ClassVisitor;
+
+import java.util.Arrays;
+
+
+/**
+ * This ClassVisitor removes NameAndType constant pool entries that are not
+ * used.
+ *
+ * @author Eric Lafortune
+ */
+public class NameAndTypeShrinker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ ConstantVisitor,
+ AttributeVisitor
+{
+ // A visitor info flag to indicate the NameAndType constant pool entry is being used.
+ private static final Object USED = new Object();
+
+ private int[] constantIndexMap;
+ private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Mark the NameAndType entries referenced by all other constant pool
+ // entries.
+ programClass.constantPoolEntriesAccept(this);
+
+ // Mark the NameAndType entries referenced by all EnclosingMethod
+ // attributes.
+ programClass.attributesAccept(this);
+
+ // Shift the used constant pool entries together, filling out the
+ // index map.
+ int newConstantPoolCount =
+ shrinkConstantPool(programClass.constantPool,
+ programClass.u2constantPoolCount);
+
+ // Remap the references to the constant pool if it has shrunk.
+ if (newConstantPoolCount < programClass.u2constantPoolCount)
+ {
+ programClass.u2constantPoolCount = newConstantPoolCount;
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setConstantIndexMap(constantIndexMap);
+ constantPoolRemapper.visitProgramClass(programClass);
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ markNameAndTypeConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex);
+ }
+
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
+ {
+ markNameAndTypeConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given UTF-8 constant pool entry of the given class.
+ */
+ private void markNameAndTypeConstant(Clazz clazz, int index)
+ {
+ markAsUsed((NameAndTypeConstant)((ProgramClass)clazz).getConstant(index));
+ }
+
+
+ /**
+ * Marks the given VisitorAccepter as being used.
+ * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
+ */
+ private void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given VisitorAccepter has been marked as being used.
+ * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
+ */
+ private boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+
+
+ /**
+ * Removes all NameAndType entries that are not marked as being used
+ * from the given constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(Constant[] constantPool, int length)
+ {
+ // Create a new index map, if necessary.
+ if (constantIndexMap == null ||
+ constantIndexMap.length < length)
+ {
+ constantIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ constantIndexMap[index] = counter;
+
+ Constant constant = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (constant != null)
+ {
+ isUsed = constant.getTag() != ClassConstants.CONSTANT_NameAndType ||
+ isUsed(constant);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = constant;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ Arrays.fill(constantPool, counter, length, null);
+
+ return counter;
+ }
+}
diff --git a/src/proguard/classfile/editor/NamedAttributeDeleter.java b/src/proguard/classfile/editor/NamedAttributeDeleter.java
index 0c4d339..6aa5cdf 100644
--- a/src/proguard/classfile/editor/NamedAttributeDeleter.java
+++ b/src/proguard/classfile/editor/NamedAttributeDeleter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java b/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
index 4cad6b8..232747f 100644
--- a/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
+++ b/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/StackSizeUpdater.java b/src/proguard/classfile/editor/StackSizeUpdater.java
index 94e0519..d90b3d0 100644
--- a/src/proguard/classfile/editor/StackSizeUpdater.java
+++ b/src/proguard/classfile/editor/StackSizeUpdater.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/SubclassAdder.java b/src/proguard/classfile/editor/SubclassAdder.java
index 6b9fd64..717bb1c 100644
--- a/src/proguard/classfile/editor/SubclassAdder.java
+++ b/src/proguard/classfile/editor/SubclassAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/SubclassToAdder.java b/src/proguard/classfile/editor/SubclassToAdder.java
index deb242f..109152b 100644
--- a/src/proguard/classfile/editor/SubclassToAdder.java
+++ b/src/proguard/classfile/editor/SubclassToAdder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/Utf8Shrinker.java b/src/proguard/classfile/editor/Utf8Shrinker.java
new file mode 100644
index 0000000..eda5826
--- /dev/null
+++ b/src/proguard/classfile/editor/Utf8Shrinker.java
@@ -0,0 +1,455 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.attribute.preverification.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.ConstantPoolRemapper;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+
+import java.util.Arrays;
+
+
+/**
+ * This ClassVisitor removes UTF-8 constant pool entries that are not used.
+ *
+ * @author Eric Lafortune
+ */
+public class Utf8Shrinker
+extends SimplifiedVisitor
+implements ClassVisitor,
+ MemberVisitor,
+ ConstantVisitor,
+ AttributeVisitor,
+ InnerClassesInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ // A visitor info flag to indicate the UTF-8 constant pool entry is being used.
+ private static final Object USED = new Object();
+
+ private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE];
+ private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ // Mark the UTF-8 entries referenced by the other constant pool entries.
+ programClass.constantPoolEntriesAccept(this);
+
+ // Mark the UTF-8 entries referenced by the fields and methods.
+ programClass.fieldsAccept(this);
+ programClass.methodsAccept(this);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ programClass.attributesAccept(this);
+
+ // Shift the used constant pool entries together, filling out the
+ // index map.
+ int newConstantPoolCount =
+ shrinkConstantPool(programClass.constantPool,
+ programClass.u2constantPoolCount);
+
+ // Remap the references to the constant pool if it has shrunk.
+ if (newConstantPoolCount < programClass.u2constantPoolCount)
+ {
+ programClass.u2constantPoolCount = newConstantPoolCount;
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setConstantIndexMap(constantIndexMap);
+ constantPoolRemapper.visitProgramClass(programClass);
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
+ {
+ // Mark the name and descriptor UTF-8 entries.
+ markCpUtf8Entry(programClass, programMember.u2nameIndex);
+ markCpUtf8Entry(programClass, programMember.u2descriptorIndex);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ programMember.attributesAccept(programClass, this);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ markCpUtf8Entry(clazz, stringConstant.u2stringIndex);
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ markCpUtf8Entry(clazz, classConstant.u2nameIndex);
+ }
+
+
+ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
+ {
+ markCpUtf8Entry(clazz, nameAndTypeConstant.u2nameIndex);
+ markCpUtf8Entry(clazz, nameAndTypeConstant.u2descriptorIndex);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
+ {
+ // This is the best we can do for unknown attributes.
+ markCpUtf8Entry(clazz, unknownAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
+ {
+ markCpUtf8Entry(clazz, sourceFileAttribute.u2attributeNameIndex);
+
+ markCpUtf8Entry(clazz, sourceFileAttribute.u2sourceFileIndex);
+ }
+
+
+ public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
+ {
+ markCpUtf8Entry(clazz, sourceDirAttribute.u2attributeNameIndex);
+
+ markCpUtf8Entry(clazz, sourceDirAttribute.u2sourceDirIndex);
+ }
+
+
+ public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
+ {
+ markCpUtf8Entry(clazz, innerClassesAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the inner classes.
+ innerClassesAttribute.innerClassEntriesAccept(clazz, this);
+ }
+
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ markCpUtf8Entry(clazz, enclosingMethodAttribute.u2attributeNameIndex);
+
+ // These entries have already been marked in the constant pool.
+ //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2classIndex);
+ //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2nameAndTypeIndex);
+ }
+
+
+ public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
+ {
+ markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
+ {
+ markCpUtf8Entry(clazz, syntheticAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
+ {
+ markCpUtf8Entry(clazz, signatureAttribute.u2attributeNameIndex);
+
+ markCpUtf8Entry(clazz, signatureAttribute.u2signatureIndex);
+ }
+
+
+ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
+ {
+ markCpUtf8Entry(clazz, constantValueAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
+ {
+ markCpUtf8Entry(clazz, exceptionsAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ markCpUtf8Entry(clazz, codeAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ codeAttribute.attributesAccept(clazz, method, this);
+ }
+
+
+ public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
+ {
+ markCpUtf8Entry(clazz, stackMapAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
+ {
+ markCpUtf8Entry(clazz, stackMapTableAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
+ {
+ markCpUtf8Entry(clazz, lineNumberTableAttribute.u2attributeNameIndex);
+ }
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ markCpUtf8Entry(clazz, localVariableTableAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the local variables.
+ localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ markCpUtf8Entry(clazz, localVariableTypeTableAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the local variable types.
+ localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
+ {
+ markCpUtf8Entry(clazz, annotationsAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ annotationsAttribute.annotationsAccept(clazz, this);
+ }
+
+
+ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
+ {
+ markCpUtf8Entry(clazz, parameterAnnotationsAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ markCpUtf8Entry(clazz, annotationDefaultAttribute.u2attributeNameIndex);
+
+ // Mark the UTF-8 entries referenced by the element value.
+ annotationDefaultAttribute.defaultValueAccept(clazz, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
+ {
+ if (innerClassesInfo.u2innerNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, innerClassesInfo.u2innerNameIndex);
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
+ {
+ markCpUtf8Entry(clazz, localVariableInfo.u2nameIndex);
+ markCpUtf8Entry(clazz, localVariableInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ markCpUtf8Entry(clazz, localVariableTypeInfo.u2nameIndex);
+ markCpUtf8Entry(clazz, localVariableTypeInfo.u2signatureIndex);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(Clazz clazz, Annotation annotation)
+ {
+ markCpUtf8Entry(clazz, annotation.u2typeIndex);
+
+ // Mark the UTF-8 entries referenced by the element values.
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ if (constantElementValue.u2elementNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, constantElementValue.u2elementNameIndex);
+ }
+
+ // Only the string constant element value refers to a UTF-8 entry.
+ if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT)
+ {
+ markCpUtf8Entry(clazz, constantElementValue.u2constantValueIndex);
+ }
+ }
+
+
+ public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ if (enumConstantElementValue.u2elementNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, enumConstantElementValue.u2elementNameIndex);
+ }
+
+ markCpUtf8Entry(clazz, enumConstantElementValue.u2typeNameIndex);
+ markCpUtf8Entry(clazz, enumConstantElementValue.u2constantNameIndex);
+ }
+
+
+ public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
+ {
+ if (classElementValue.u2elementNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, classElementValue.u2elementNameIndex);
+ }
+
+ markCpUtf8Entry(clazz, classElementValue.u2classInfoIndex);
+ }
+
+
+ public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ if (annotationElementValue.u2elementNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, annotationElementValue.u2elementNameIndex);
+ }
+
+ // Mark the UTF-8 entries referenced by the annotation.
+ annotationElementValue.annotationAccept(clazz, this);
+ }
+
+
+ public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ if (arrayElementValue.u2elementNameIndex != 0)
+ {
+ markCpUtf8Entry(clazz, arrayElementValue.u2elementNameIndex);
+ }
+
+ // Mark the UTF-8 entries referenced by the element values.
+ arrayElementValue.elementValuesAccept(clazz, annotation, this);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given UTF-8 constant pool entry of the given class.
+ */
+ private void markCpUtf8Entry(Clazz clazz, int index)
+ {
+ markAsUsed((Utf8Constant)((ProgramClass)clazz).getConstant(index));
+ }
+
+
+ /**
+ * Marks the given VisitorAccepter as being used.
+ * In this context, the VisitorAccepter will be a Utf8Constant object.
+ */
+ private void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given VisitorAccepter has been marked as being used.
+ * In this context, the VisitorAccepter will be a Utf8Constant object.
+ */
+ private boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+
+
+ /**
+ * Removes all UTF-8 entries that are not marked as being used
+ * from the given constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(Constant[] constantPool, int length)
+ {
+ // Create a new index map, if necessary.
+ if (constantIndexMap.length < length)
+ {
+ constantIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ constantIndexMap[index] = counter;
+
+ Constant constant = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (constant != null)
+ {
+ isUsed = constant.getTag() != ClassConstants.CONSTANT_Utf8 ||
+ isUsed(constant);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = constant;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ Arrays.fill(constantPool, counter, length, null);
+
+ return counter;
+ }
+}
diff --git a/src/proguard/classfile/editor/VariableCleaner.java b/src/proguard/classfile/editor/VariableCleaner.java
index 1e93c15..63b7d4a 100644
--- a/src/proguard/classfile/editor/VariableCleaner.java
+++ b/src/proguard/classfile/editor/VariableCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,15 +22,15 @@ package proguard.classfile.editor;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.optimize.info.VariableUsageMarker;
+
+import java.util.Arrays;
/**
- * This AttributeVisitor cleans up unused variables in all attributes that it
- * visits.
+ * This AttributeVisitor cleans up variable tables in all code attributes that
+ * it visits. It trims overlapping local variables. It removes empty local
+ * variables and empty local variable tables.
*
* @author Eric Lafortune
*/
@@ -38,7 +38,8 @@ public class VariableCleaner
extends SimplifiedVisitor
implements AttributeVisitor
{
- private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker();
+ private boolean deleteLocalVariableTableAttribute;
+ private boolean deleteLocalVariableTypeTableAttribute;
// Implementations for AttributeVisitor.
@@ -48,11 +49,35 @@ implements AttributeVisitor
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
- // Figure out the local variables that are used by the code.
- variableUsageMarker.visitCodeAttribute(clazz, method, codeAttribute);
+ deleteLocalVariableTableAttribute = false;
+ deleteLocalVariableTypeTableAttribute = false;
- // Clean up the variables of the attributes.
+ // Trim the local variable table and the local variable type table.
codeAttribute.attributesAccept(clazz, method, this);
+
+ // Delete the local variable table if it ended up empty.
+ if (deleteLocalVariableTableAttribute)
+ {
+ AttributesEditor editor =
+ new AttributesEditor((ProgramClass)clazz,
+ (ProgramMember)method,
+ codeAttribute,
+ true);
+
+ editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTable);
+ }
+
+ // Delete the local variable type table if it ended up empty.
+ if (deleteLocalVariableTypeTableAttribute)
+ {
+ AttributesEditor editor =
+ new AttributesEditor((ProgramClass)clazz,
+ (ProgramMember)method,
+ codeAttribute,
+ true);
+
+ editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTypeTable);
+ }
}
@@ -60,9 +85,20 @@ implements AttributeVisitor
{
// Clean up local variables that aren't used.
localVariableTableAttribute.u2localVariableTableLength =
- removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable,
- localVariableTableAttribute.u2localVariableTableLength,
- codeAttribute.u2maxLocals);
+ removeUnusedLocalVariables(localVariableTableAttribute.localVariableTable,
+ localVariableTableAttribute.u2localVariableTableLength,
+ codeAttribute.u2maxLocals);
+
+ // Trim the code blocks of the local variables.
+ trimLocalVariables(localVariableTableAttribute.localVariableTable,
+ localVariableTableAttribute.u2localVariableTableLength,
+ codeAttribute.u2maxLocals);
+
+ // Delete the attribute in a moment, if it is empty.
+ if (localVariableTableAttribute.u2localVariableTableLength == 0)
+ {
+ deleteLocalVariableTableAttribute = true;
+ }
}
@@ -70,9 +106,20 @@ implements AttributeVisitor
{
// Clean up local variables that aren't used.
localVariableTypeTableAttribute.u2localVariableTypeTableLength =
- removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
- localVariableTypeTableAttribute.u2localVariableTypeTableLength,
- codeAttribute.u2maxLocals);
+ removeUnusedLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
+ localVariableTypeTableAttribute.u2localVariableTypeTableLength,
+ codeAttribute.u2maxLocals);
+
+ // Trim the code blocks of the local variables.
+ trimLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
+ localVariableTypeTableAttribute.u2localVariableTypeTableLength,
+ codeAttribute.u2maxLocals);
+
+ // Delete the attribute in a moment, if it is empty.
+ if (localVariableTypeTableAttribute.u2localVariableTypeTableLength == 0)
+ {
+ deleteLocalVariableTypeTableAttribute = true;
+ }
}
@@ -80,27 +127,30 @@ implements AttributeVisitor
/**
* Returns the given list of local variables, without the ones that aren't
- * used
+ * used.
*/
- private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
- int localVariableInfoCount,
- int maxLocals)
+ private int removeUnusedLocalVariables(LocalVariableInfo[] localVariableInfos,
+ int localVariableInfoCount,
+ int maxLocals)
{
// Overwrite all empty local variable entries.
+ // Do keep parameter entries.
int newIndex = 0;
- for (int index = 0; index < localVariableInfoCount && index < maxLocals; index++)
+ for (int index = 0; index < localVariableInfoCount; index++)
{
- if (variableUsageMarker.isVariableUsed(index))
+ LocalVariableInfo localVariableInfo = localVariableInfos[index];
+
+ if (localVariableInfo.u2index >= 0 &&
+ localVariableInfo.u2index < maxLocals &&
+ (localVariableInfo.u2startPC == 0 ||
+ localVariableInfo.u2length > 0))
{
localVariableInfos[newIndex++] = localVariableInfos[index];
}
}
// Clean up any remaining array elements.
- for (int index = newIndex; index < localVariableInfoCount; index++)
- {
- localVariableInfos[index] = null;
- }
+ Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null);
return newIndex;
}
@@ -108,28 +158,114 @@ implements AttributeVisitor
/**
* Returns the given list of local variable types, without the ones that
- * aren't used
+ * aren't used.
*/
- private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
- int localVariableTypeInfoCount,
- int maxLocals)
+ private int removeUnusedLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
+ int localVariableTypeInfoCount,
+ int maxLocals)
{
// Overwrite all empty local variable type entries.
+ // Do keep parameter entries.
int newIndex = 0;
- for (int index = 0; index < localVariableTypeInfoCount && index < maxLocals; index++)
+ for (int index = 0; index < localVariableTypeInfoCount; index++)
{
- if (variableUsageMarker.isVariableUsed(index))
+ LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
+
+ if (localVariableTypeInfo.u2index >= 0 &&
+ localVariableTypeInfo.u2index < maxLocals &&
+ (localVariableTypeInfo.u2startPC == 0 ||
+ localVariableTypeInfo.u2length > 0))
{
localVariableTypeInfos[newIndex++] = localVariableTypeInfos[index];
}
}
// Clean up any remaining array elements.
- for (int index = newIndex; index < localVariableTypeInfoCount; index++)
+ Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null);
+
+ return newIndex;
+ }
+
+
+ /**
+ * Sorts the given list of local variables and trims their code blocks
+ * when necessary. The block is trimmed at the end, which is a bit
+ * arbitrary.
+ */
+ private void trimLocalVariables(LocalVariableInfo[] localVariableInfos,
+ int localVariableInfoCount,
+ int maxLocals)
+ {
+ // Sort the local variable entries.
+ Arrays.sort(localVariableInfos, 0, localVariableInfoCount);
+
+ int[] startPCs = createMaxArray(maxLocals);
+
+ // Trim the local variable entries, starting at the last one.
+ for (int index = localVariableInfoCount-1; index >= 0; index--)
{
- localVariableTypeInfos[index] = null;
+ LocalVariableInfo localVariableInfo = localVariableInfos[index];
+
+ // Make sure the variable's code block doesn't overlap with the
+ // next one for the same variable.
+ int maxLength = startPCs[localVariableInfo.u2index] -
+ localVariableInfo.u2startPC;
+
+ if (localVariableInfo.u2length > maxLength)
+ {
+ localVariableInfo.u2length = maxLength;
+ }
+
+ startPCs[localVariableInfo.u2index] = localVariableInfo.u2startPC;
}
+ }
- return newIndex;
+
+ /**
+ * Sorts the given list of local variable types and trims their code blocks
+ * when necessary. The block is trimmed at the end, which is a bit
+ * arbitrary.
+ */
+ private void trimLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
+ int localVariableTypeInfoCount,
+ int maxLocals)
+ {
+ // Sort the local variable entries.
+ Arrays.sort(localVariableTypeInfos, 0, localVariableTypeInfoCount);
+
+ int[] startPCs = createMaxArray(maxLocals);
+
+ // Trim the local variable entries, starting at the last one.
+ for (int index = localVariableTypeInfoCount-1; index >= 0; index--)
+ {
+ LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
+
+ // Make sure the variable's code block doesn't overlap with the
+ // next one for the same variable.
+ int maxLength = startPCs[localVariableTypeInfo.u2index] -
+ localVariableTypeInfo.u2startPC;
+
+ if (localVariableTypeInfo.u2length > maxLength)
+ {
+ localVariableTypeInfo.u2length = maxLength;
+ }
+
+ startPCs[localVariableTypeInfo.u2index] = localVariableTypeInfo.u2startPC;
+ }
+ }
+
+
+ /**
+ * Creates an integer array of the given length, initialized with
+ * Integer.MAX_VALUE.
+ */
+ private int[] createMaxArray(int length)
+ {
+ int[] startPCs = new int[length];
+ for (int index = 0; index < length; index++)
+ {
+ startPCs[index] = Integer.MAX_VALUE;
+ }
+ return startPCs;
}
}
\ No newline at end of file
diff --git a/src/proguard/classfile/editor/VariableEditor.java b/src/proguard/classfile/editor/VariableEditor.java
index a583b49..b5143b5 100644
--- a/src/proguard/classfile/editor/VariableEditor.java
+++ b/src/proguard/classfile/editor/VariableEditor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -25,6 +25,8 @@ import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import java.util.Arrays;
+
/**
* This AttributeVisitor accumulates specified changes to local variables, and
* then applies these accumulated changes to the code attributes that it visits.
@@ -53,14 +55,13 @@ implements AttributeVisitor
// Try to reuse the previous array.
if (deleted.length < maxLocals)
{
+ // Create a new array.
deleted = new boolean[maxLocals];
}
else
{
- for (int index = 0; index < maxLocals; index++)
- {
- deleted[index] = false;
- }
+ // Reset the array.
+ Arrays.fill(deleted, 0, maxLocals, false);
}
modified = false;
diff --git a/src/proguard/classfile/editor/VariableRemapper.java b/src/proguard/classfile/editor/VariableRemapper.java
index 590cd4e..ca9d88a 100644
--- a/src/proguard/classfile/editor/VariableRemapper.java
+++ b/src/proguard/classfile/editor/VariableRemapper.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -40,6 +40,9 @@ implements AttributeVisitor,
LocalVariableInfoVisitor,
LocalVariableTypeInfoVisitor
{
+ private static final boolean DEBUG = false;
+
+
private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
private int[] variableMap;
@@ -62,6 +65,19 @@ implements AttributeVisitor,
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
+ if (DEBUG)
+ {
+ System.out.println("VariableRemapper: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ for (int index= 0; index < codeAttribute.u2maxLocals; index++)
+ {
+ System.out.println(" v"+index+" -> "+variableMap[index]);
+ }
+ }
+
+ // Remap the variables of the attributes, before editing the code and
+ // cleaning up its local variable frame.
+ codeAttribute.attributesAccept(clazz, method, this);
+
// Initially, the code attribute editor doesn't contain any changes.
codeAttributeEditor.reset(codeAttribute.u4codeLength);
@@ -70,9 +86,6 @@ implements AttributeVisitor,
// Apply the code atribute editor.
codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
-
- // Remap the variables of the attributes.
- codeAttribute.attributesAccept(clazz, method, this);
}
@@ -80,11 +93,6 @@ implements AttributeVisitor,
{
// Remap the variable references of the local variables.
localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
-
- // Remove local variables that haven't been mapped.
- localVariableTableAttribute.u2localVariableTableLength =
- removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable,
- localVariableTableAttribute.u2localVariableTableLength);
}
@@ -92,11 +100,6 @@ implements AttributeVisitor,
{
// Remap the variable references of the local variables.
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
-
- // Remove local variables that haven't been mapped.
- localVariableTypeTableAttribute.u2localVariableTypeTableLength =
- removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
- localVariableTypeTableAttribute.u2localVariableTypeTableLength);
}
@@ -134,7 +137,7 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new VariableInstruction(variableInstruction.opcode,
newVariableIndex,
- variableInstruction.constant).shrink();
+ variableInstruction.constant);
codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
}
@@ -150,48 +153,4 @@ implements AttributeVisitor,
{
return variableMap[variableIndex];
}
-
-
- /**
- * Returns the given list of local variables, without the ones that have
- * been removed.
- */
- private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
- int localVariableInfoCount)
- {
- // Overwrite all empty local variable entries.
- int newIndex = 0;
- for (int index = 0; index < localVariableInfoCount; index++)
- {
- LocalVariableInfo localVariableInfo = localVariableInfos[index];
- if (localVariableInfo.u2index >= 0)
- {
- localVariableInfos[newIndex++] = localVariableInfo;
- }
- }
-
- return newIndex;
- }
-
-
- /**
- * Returns the given list of local variable types, without the ones that
- * have been removed.
- */
- private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
- int localVariableTypeInfoCount)
- {
- // Overwrite all empty local variable type entries.
- int newIndex = 0;
- for (int index = 0; index < localVariableTypeInfoCount; index++)
- {
- LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
- if (localVariableTypeInfo.u2index >= 0)
- {
- localVariableTypeInfos[newIndex++] = localVariableTypeInfo;
- }
- }
-
- return newIndex;
- }
}
diff --git a/src/proguard/classfile/editor/VariableSizeUpdater.java b/src/proguard/classfile/editor/VariableSizeUpdater.java
index 18958c5..2feaa9d 100644
--- a/src/proguard/classfile/editor/VariableSizeUpdater.java
+++ b/src/proguard/classfile/editor/VariableSizeUpdater.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,7 +29,8 @@ import proguard.classfile.util.*;
/**
* This AttributeVisitor computes and updates the maximum local variable frame
- * size of the code attributes that it visits.
+ * size of the code attributes that it visits. It also cleans up the local
+ * variable tables.
*
* @author Eric Lafortune
*/
@@ -45,6 +46,9 @@ implements AttributeVisitor,
//*/
+ private VariableCleaner variableCleaner = new VariableCleaner();
+
+
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
@@ -69,6 +73,9 @@ implements AttributeVisitor,
// Go over all instructions.
codeAttribute.instructionsAccept(clazz, method, this);
+
+ // Remove the unused variables of the attributes.
+ variableCleaner.visitCodeAttribute(clazz, method, codeAttribute);
}
@@ -91,7 +98,7 @@ implements AttributeVisitor,
if (DEBUG)
{
- System.out.println("Max locals: "+codeAttribute.u2maxLocals+" <- "+variableInstruction.toString(offset));
+ System.out.println(" Max locals: "+codeAttribute.u2maxLocals+" <- "+variableInstruction.toString(offset));
}
}
}
diff --git a/src/proguard/classfile/instruction/BranchInstruction.java b/src/proguard/classfile/instruction/BranchInstruction.java
index 2baa917..f3a7080 100644
--- a/src/proguard/classfile/instruction/BranchInstruction.java
+++ b/src/proguard/classfile/instruction/BranchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -174,7 +174,6 @@ public class BranchInstruction extends Instruction
*/
private int requiredBranchOffsetSize()
{
- return branchOffset << 16 >> 16 == branchOffset ? 2 :
- 4;
+ return (short)branchOffset == branchOffset ? 2 : 4;
}
}
diff --git a/src/proguard/classfile/instruction/ConstantInstruction.java b/src/proguard/classfile/instruction/ConstantInstruction.java
index 6c2d1a3..42d1523 100644
--- a/src/proguard/classfile/instruction/ConstantInstruction.java
+++ b/src/proguard/classfile/instruction/ConstantInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -93,13 +93,9 @@ implements ConstantVisitor
public byte canonicalOpcode()
{
// Remove the _w extension, if any.
- switch (opcode)
- {
- case InstructionConstants.OP_LDC_W:
- case InstructionConstants.OP_LDC2_W: return InstructionConstants.OP_LDC;
-
- default: return opcode;
- }
+ return
+ opcode == InstructionConstants.OP_LDC_W ? InstructionConstants.OP_LDC :
+ opcode;
}
public Instruction shrink()
@@ -185,7 +181,8 @@ implements ConstantVisitor
case InstructionConstants.OP_INVOKESPECIAL:
case InstructionConstants.OP_INVOKESTATIC:
case InstructionConstants.OP_INVOKEINTERFACE:
- // The some parameters may be popped from the stack.
+ case InstructionConstants.OP_INVOKEDYNAMIC:
+ // Some parameters may be popped from the stack.
clazz.constantPoolEntryAccept(constantIndex, this);
stackPopCount += parameterStackDelta;
break;
@@ -208,6 +205,7 @@ implements ConstantVisitor
case InstructionConstants.OP_INVOKESPECIAL:
case InstructionConstants.OP_INVOKESTATIC:
case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
// The field value or a return value may be pushed onto the stack.
clazz.constantPoolEntryAccept(constantIndex, this);
stackPushCount += typeStackDelta;
@@ -226,8 +224,9 @@ implements ConstantVisitor
public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {}
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 visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) {}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) {}
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
@@ -238,21 +237,27 @@ implements ConstantVisitor
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this);
+ }
+
+
public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
{
- visitRefConstant(clazz, interfaceMethodrefConstant);
+ clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2nameAndTypeIndex, this);
}
public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
{
- visitRefConstant(clazz, methodrefConstant);
+ clazz.constantPoolEntryAccept(methodrefConstant.u2nameAndTypeIndex, this);
}
- private void visitRefConstant(Clazz clazz, RefConstant methodrefConstant)
+ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
- String type = methodrefConstant.getType(clazz);
+ String type = nameAndTypeConstant.getType(clazz);
parameterStackDelta = ClassUtil.internalMethodParameterSize(type);
typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
@@ -263,7 +268,7 @@ implements ConstantVisitor
public String toString()
{
- return getName()+" #"+constantIndex;
+ return getName()+" #"+constantIndex+(constantSize() == 0 ? "" : ", "+constant);
}
@@ -285,6 +290,7 @@ implements ConstantVisitor
private int constantSize()
{
return opcode == InstructionConstants.OP_MULTIANEWARRAY ? 1 :
+ opcode == InstructionConstants.OP_INVOKEDYNAMIC ||
opcode == InstructionConstants.OP_INVOKEINTERFACE ? 2 :
0;
}
diff --git a/src/proguard/classfile/instruction/Instruction.java b/src/proguard/classfile/instruction/Instruction.java
index 8437495..33e705d 100644
--- a/src/proguard/classfile/instruction/Instruction.java
+++ b/src/proguard/classfile/instruction/Instruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -220,7 +220,7 @@ public abstract class Instruction
false, // invokespecial
false, // invokestatic
false, // invokeinterface
- false, // unused
+ false, // invokedynamic
false, // new
false, // newarray
false, // anewarray
@@ -429,7 +429,7 @@ public abstract class Instruction
1, // invokespecial
0, // invokestatic
1, // invokeinterface
- 0, // unused
+ 0, // invokedynamic
0, // new
1, // newarray
1, // anewarray
@@ -638,7 +638,7 @@ public abstract class Instruction
0, // invokespecial
0, // invokestatic
0, // invokeinterface
- 0, // unused
+ 0, // invokedynamic
1, // new
1, // newarray
1, // anewarray
@@ -887,7 +887,7 @@ public abstract class Instruction
protected static void writeSignedByte(byte[] code, int offset, int value)
{
- if (value << 24 >> 24 != value)
+ if ((byte)value != value)
{
throw new IllegalArgumentException("Signed byte value out of range ["+value+"]");
}
@@ -897,7 +897,7 @@ public abstract class Instruction
protected static void writeSignedShort(byte[] code, int offset, int value)
{
- if (value << 16 >> 16 != value)
+ if ((short)value != value)
{
throw new IllegalArgumentException("Signed short value out of range ["+value+"]");
}
diff --git a/src/proguard/classfile/instruction/InstructionConstants.java b/src/proguard/classfile/instruction/InstructionConstants.java
index 78730b3..d8cbd98 100644
--- a/src/proguard/classfile/instruction/InstructionConstants.java
+++ b/src/proguard/classfile/instruction/InstructionConstants.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -213,22 +213,22 @@ public interface InstructionConstants
public static final byte OP_INVOKESPECIAL = -73;
public static final byte OP_INVOKESTATIC = -72;
public static final byte OP_INVOKEINTERFACE = -71;
-// public static final byte OP_UNUSED = -70;
- public static final byte OP_NEW = -69;
- public static final byte OP_NEWARRAY = -68;
- public static final byte OP_ANEWARRAY = -67;
- public static final byte OP_ARRAYLENGTH = -66;
- public static final byte OP_ATHROW = -65;
- public static final byte OP_CHECKCAST = -64;
- public static final byte OP_INSTANCEOF = -63;
- public static final byte OP_MONITORENTER = -62;
- public static final byte OP_MONITOREXIT = -61;
- public static final byte OP_WIDE = -60;
- public static final byte OP_MULTIANEWARRAY = -59;
- public static final byte OP_IFNULL = -58;
- public static final byte OP_IFNONNULL = -57;
- public static final byte OP_GOTO_W = -56;
- public static final byte OP_JSR_W = -55;
+ public static final byte OP_INVOKEDYNAMIC = -70;
+ public static final byte OP_NEW = -69;
+ public static final byte OP_NEWARRAY = -68;
+ public static final byte OP_ANEWARRAY = -67;
+ public static final byte OP_ARRAYLENGTH = -66;
+ public static final byte OP_ATHROW = -65;
+ public static final byte OP_CHECKCAST = -64;
+ public static final byte OP_INSTANCEOF = -63;
+ public static final byte OP_MONITORENTER = -62;
+ public static final byte OP_MONITOREXIT = -61;
+ public static final byte OP_WIDE = -60;
+ public static final byte OP_MULTIANEWARRAY = -59;
+ public static final byte OP_IFNULL = -58;
+ public static final byte OP_IFNONNULL = -57;
+ public static final byte OP_GOTO_W = -56;
+ public static final byte OP_JSR_W = -55;
public static final String[] NAMES =
@@ -419,7 +419,7 @@ public interface InstructionConstants
"invokespecial",
"invokestatic",
"invokeinterface",
- "unused",
+ "invokedynamic",
"new",
"newarray",
"anewarray",
diff --git a/src/proguard/classfile/instruction/InstructionFactory.java b/src/proguard/classfile/instruction/InstructionFactory.java
index f898471..89d498c 100644
--- a/src/proguard/classfile/instruction/InstructionFactory.java
+++ b/src/proguard/classfile/instruction/InstructionFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -182,6 +182,7 @@ public class InstructionFactory
case InstructionConstants.OP_INVOKESPECIAL:
case InstructionConstants.OP_INVOKESTATIC:
case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
case InstructionConstants.OP_NEW:
case InstructionConstants.OP_ANEWARRAY:
diff --git a/src/proguard/classfile/instruction/InstructionUtil.java b/src/proguard/classfile/instruction/InstructionUtil.java
index a3a328a..c6ae99b 100644
--- a/src/proguard/classfile/instruction/InstructionUtil.java
+++ b/src/proguard/classfile/instruction/InstructionUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
index 178cce5..807c0cc 100644
--- a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
+++ b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/SimpleInstruction.java b/src/proguard/classfile/instruction/SimpleInstruction.java
index 84e6344..c9a2957 100644
--- a/src/proguard/classfile/instruction/SimpleInstruction.java
+++ b/src/proguard/classfile/instruction/SimpleInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -248,8 +248,8 @@ public class SimpleInstruction extends Instruction
private int requiredConstantSize()
{
return constant >= -1 && constant <= 5 ? 0 :
- constant << 24 >> 24 == constant ? 1 :
- constant << 16 >> 16 == constant ? 2 :
+ (byte)constant == constant ? 1 :
+ (short)constant == constant ? 2 :
4;
}
}
diff --git a/src/proguard/classfile/instruction/SwitchInstruction.java b/src/proguard/classfile/instruction/SwitchInstruction.java
index b98c2fb..3706ba0 100644
--- a/src/proguard/classfile/instruction/SwitchInstruction.java
+++ b/src/proguard/classfile/instruction/SwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/TableSwitchInstruction.java b/src/proguard/classfile/instruction/TableSwitchInstruction.java
index ee81af5..45490e5 100644
--- a/src/proguard/classfile/instruction/TableSwitchInstruction.java
+++ b/src/proguard/classfile/instruction/TableSwitchInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/VariableInstruction.java b/src/proguard/classfile/instruction/VariableInstruction.java
index 309f802..6390e0a 100644
--- a/src/proguard/classfile/instruction/VariableInstruction.java
+++ b/src/proguard/classfile/instruction/VariableInstruction.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -365,8 +365,8 @@ public class VariableInstruction extends Instruction
private int requiredConstantSize()
{
return opcode != InstructionConstants.OP_IINC ? 0 :
- constant << 24 >> 24 == constant ? 1 :
- constant << 16 >> 16 == constant ? 2 :
+ (byte)constant == constant ? 1 :
+ (short)constant == constant ? 2 :
4;
}
}
diff --git a/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java b/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
index 71b2cde..4d739c2 100644
--- a/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
+++ b/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java b/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
new file mode 100644
index 0000000..6b24e98
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/InstructionConstantVisitor.java
@@ -0,0 +1,65 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.instruction.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.ClassConstant;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given ConstantVisitor visit all constants
+ * of the instructions it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionConstantVisitor
+extends SimplifiedVisitor
+implements InstructionVisitor
+{
+ private final ConstantVisitor constantVisitor;
+
+
+ /**
+ * Creates a new InstructionConstantVisitor.
+ * @param constantVisitor the ConstantVisitor to which visits will be
+ * delegated.
+ */
+ public InstructionConstantVisitor(ConstantVisitor constantVisitor)
+ {
+ this.constantVisitor = constantVisitor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex,
+ constantVisitor);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/instruction/visitor/InstructionCounter.java b/src/proguard/classfile/instruction/visitor/InstructionCounter.java
index 1d10980..5623498 100644
--- a/src/proguard/classfile/instruction/visitor/InstructionCounter.java
+++ b/src/proguard/classfile/instruction/visitor/InstructionCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/visitor/InstructionVisitor.java b/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
index 11af131..cffb15e 100644
--- a/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
+++ b/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java b/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
index aada455..444fd57 100644
--- a/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
+++ b/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/io/LibraryClassReader.java b/src/proguard/classfile/io/LibraryClassReader.java
index f14471c..d1eab3e 100644
--- a/src/proguard/classfile/io/LibraryClassReader.java
+++ b/src/proguard/classfile/io/LibraryClassReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -277,6 +277,18 @@ implements ClassVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ dataInput.skipBytes(4);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ dataInput.skipBytes(3);
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
dataInput.skipBytes(4);
@@ -289,6 +301,12 @@ implements ClassVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ dataInput.skipBytes(2);
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
dataInput.skipBytes(4);
@@ -325,16 +343,19 @@ implements ClassVisitor,
switch (u1tag)
{
- case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
case ClassConstants.CONSTANT_Integer: return new IntegerConstant();
case ClassConstants.CONSTANT_Float: return new FloatConstant();
case ClassConstants.CONSTANT_Long: return new LongConstant();
case ClassConstants.CONSTANT_Double: return new DoubleConstant();
case ClassConstants.CONSTANT_String: return new StringConstant();
+ case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
+ case ClassConstants.CONSTANT_InvokeDynamic: return new InvokeDynamicConstant();
+ case ClassConstants.CONSTANT_MethodHandle: return new MethodHandleConstant();
case ClassConstants.CONSTANT_Fieldref: return new FieldrefConstant();
case ClassConstants.CONSTANT_Methodref: return new MethodrefConstant();
case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant();
case ClassConstants.CONSTANT_Class: return new ClassConstant();
+ case ClassConstants.CONSTANT_MethodType : return new MethodTypeConstant();
case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant();
default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
diff --git a/src/proguard/classfile/io/ProgramClassReader.java b/src/proguard/classfile/io/ProgramClassReader.java
index 476a346..80a38f7 100644
--- a/src/proguard/classfile/io/ProgramClassReader.java
+++ b/src/proguard/classfile/io/ProgramClassReader.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -46,6 +46,7 @@ implements ClassVisitor,
MemberVisitor,
ConstantVisitor,
AttributeVisitor,
+ BootstrapMethodInfoVisitor,
InnerClassesInfoVisitor,
ExceptionInfoVisitor,
StackMapFrameVisitor,
@@ -250,6 +251,20 @@ implements ClassVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ invokeDynamicConstant.u2bootstrapMethodAttributeIndex = dataInput.readUnsignedShort();
+ invokeDynamicConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort();
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ methodHandleConstant.u1referenceKind = dataInput.readUnsignedByte();
+ methodHandleConstant.u2referenceIndex = dataInput.readUnsignedShort();
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
refConstant.u2classIndex = dataInput.readUnsignedShort();
@@ -263,6 +278,12 @@ implements ClassVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ methodTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort();
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
nameAndTypeConstant.u2nameIndex = dataInput.readUnsignedShort();
@@ -281,6 +302,21 @@ implements ClassVisitor,
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ // Read the bootstrap methods.
+ bootstrapMethodsAttribute.u2bootstrapMethodsCount = dataInput.readUnsignedShort();
+
+ bootstrapMethodsAttribute.bootstrapMethods = new BootstrapMethodInfo[bootstrapMethodsAttribute.u2bootstrapMethodsCount];
+ for (int index = 0; index < bootstrapMethodsAttribute.u2bootstrapMethodsCount; index++)
+ {
+ BootstrapMethodInfo bootstrapMethodInfo = new BootstrapMethodInfo();
+ visitBootstrapMethodInfo(clazz, bootstrapMethodInfo);
+ bootstrapMethodsAttribute.bootstrapMethods[index] = bootstrapMethodInfo;
+ }
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
sourceFileAttribute.u2sourceFileIndex = dataInput.readUnsignedShort();
@@ -302,7 +338,7 @@ implements ClassVisitor,
for (int index = 0; index < innerClassesAttribute.u2classesCount; index++)
{
InnerClassesInfo innerClassesInfo = new InnerClassesInfo();
- this.visitInnerClassesInfo(clazz, innerClassesInfo);
+ visitInnerClassesInfo(clazz, innerClassesInfo);
innerClassesAttribute.classes[index] = innerClassesInfo;
}
}
@@ -372,7 +408,7 @@ implements ClassVisitor,
for (int index = 0; index < codeAttribute.u2exceptionTableLength; index++)
{
ExceptionInfo exceptionInfo = new ExceptionInfo();
- this.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
+ visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
codeAttribute.exceptionTable[index] = exceptionInfo;
}
@@ -398,7 +434,7 @@ implements ClassVisitor,
for (int index = 0; index < stackMapAttribute.u2stackMapFramesCount; index++)
{
FullFrame stackMapFrame = new FullFrame();
- this.visitFullFrame(clazz, method, codeAttribute, index, stackMapFrame);
+ visitFullFrame(clazz, method, codeAttribute, index, stackMapFrame);
stackMapAttribute.stackMapFrames[index] = stackMapFrame;
}
}
@@ -428,7 +464,7 @@ implements ClassVisitor,
for (int index = 0; index < lineNumberTableAttribute.u2lineNumberTableLength; index++)
{
LineNumberInfo lineNumberInfo = new LineNumberInfo();
- this.visitLineNumberInfo(clazz, method, codeAttribute, lineNumberInfo);
+ visitLineNumberInfo(clazz, method, codeAttribute, lineNumberInfo);
lineNumberTableAttribute.lineNumberTable[index] = lineNumberInfo;
}
}
@@ -443,7 +479,7 @@ implements ClassVisitor,
for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++)
{
LocalVariableInfo localVariableInfo = new LocalVariableInfo();
- this.visitLocalVariableInfo(clazz, method, codeAttribute, localVariableInfo);
+ visitLocalVariableInfo(clazz, method, codeAttribute, localVariableInfo);
localVariableTableAttribute.localVariableTable[index] = localVariableInfo;
}
}
@@ -458,7 +494,7 @@ implements ClassVisitor,
for (int index = 0; index < localVariableTypeTableAttribute.u2localVariableTypeTableLength; index++)
{
LocalVariableTypeInfo localVariableTypeInfo = new LocalVariableTypeInfo();
- this.visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeInfo);
+ visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeInfo);
localVariableTypeTableAttribute.localVariableTypeTable[index] = localVariableTypeInfo;
}
}
@@ -473,7 +509,7 @@ implements ClassVisitor,
for (int index = 0; index < annotationsAttribute.u2annotationsCount; index++)
{
Annotation annotation = new Annotation();
- this.visitAnnotation(clazz, annotation);
+ visitAnnotation(clazz, annotation);
annotationsAttribute.annotations[index] = annotation;
}
}
@@ -508,7 +544,7 @@ implements ClassVisitor,
for (int index = 0; index < u2annotationsCount; index++)
{
Annotation annotation = new Annotation();
- this.visitAnnotation(clazz, annotation);
+ visitAnnotation(clazz, annotation);
annotations[index] = annotation;
}
@@ -527,6 +563,22 @@ implements ClassVisitor,
}
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ bootstrapMethodInfo.u2methodHandleIndex = dataInput.readUnsignedShort();
+
+ // Read the bootstrap method arguments.
+ bootstrapMethodInfo.u2methodArgumentCount = dataInput.readUnsignedShort();
+ bootstrapMethodInfo.u2methodArguments = new int[bootstrapMethodInfo.u2methodArgumentCount];
+ for (int index = 0; index < bootstrapMethodInfo.u2methodArgumentCount; index++)
+ {
+ bootstrapMethodInfo.u2methodArguments[index] = dataInput.readUnsignedShort();
+ }
+ }
+
+
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
@@ -721,7 +773,7 @@ implements ClassVisitor,
{
// Read the annotation.
Annotation annotationValue = new Annotation();
- this.visitAnnotation(clazz, annotationValue);
+ visitAnnotation(clazz, annotationValue);
annotationElementValue.annotationValue = annotationValue;
}
@@ -749,16 +801,19 @@ implements ClassVisitor,
switch (u1tag)
{
- case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
case ClassConstants.CONSTANT_Integer: return new IntegerConstant();
case ClassConstants.CONSTANT_Float: return new FloatConstant();
case ClassConstants.CONSTANT_Long: return new LongConstant();
case ClassConstants.CONSTANT_Double: return new DoubleConstant();
case ClassConstants.CONSTANT_String: return new StringConstant();
+ case ClassConstants.CONSTANT_Utf8: return new Utf8Constant();
+ case ClassConstants.CONSTANT_InvokeDynamic: return new InvokeDynamicConstant();
+ case ClassConstants.CONSTANT_MethodHandle: return new MethodHandleConstant();
case ClassConstants.CONSTANT_Fieldref: return new FieldrefConstant();
case ClassConstants.CONSTANT_Methodref: return new MethodrefConstant();
case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant();
case ClassConstants.CONSTANT_Class: return new ClassConstant();
+ case ClassConstants.CONSTANT_MethodType : return new MethodTypeConstant();
case ClassConstants.CONSTANT_NameAndType: return new NameAndTypeConstant();
default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
@@ -771,7 +826,9 @@ implements ClassVisitor,
int u2attributeNameIndex = dataInput.readUnsignedShort();
int u4attributeLength = dataInput.readInt();
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():
@@ -849,7 +906,7 @@ implements ClassVisitor,
case ClassConstants.INTERNAL_TYPE_FLOAT:
case ClassConstants.INTERNAL_TYPE_LONG:
case ClassConstants.INTERNAL_TYPE_DOUBLE:
- case ClassConstants.ELEMENT_VALUE_STRING_CONSTANT: return new ConstantElementValue(u1tag);
+ case ClassConstants.ELEMENT_VALUE_STRING_CONSTANT: return new ConstantElementValue((char)u1tag);
case ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT: return new EnumConstantElementValue();
case ClassConstants.ELEMENT_VALUE_CLASS: return new ClassElementValue();
diff --git a/src/proguard/classfile/io/ProgramClassWriter.java b/src/proguard/classfile/io/ProgramClassWriter.java
index e56f08a..dbf1de3 100644
--- a/src/proguard/classfile/io/ProgramClassWriter.java
+++ b/src/proguard/classfile/io/ProgramClassWriter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -57,7 +57,7 @@ implements ClassVisitor,
/**
- * Creates a new ProgramClassWriter for reading from the given DataOutput.
+ * Creates a new ProgramClassWriter for writing to the given DataOutput.
*/
public ProgramClassWriter(DataOutput dataOutput)
{
@@ -208,6 +208,20 @@ implements ClassVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ dataOutput.writeShort(invokeDynamicConstant.u2bootstrapMethodAttributeIndex);
+ dataOutput.writeShort(invokeDynamicConstant.u2nameAndTypeIndex);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ dataOutput.writeByte(methodHandleConstant.u1referenceKind);
+ dataOutput.writeShort(methodHandleConstant.u2referenceIndex);
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
dataOutput.writeShort(refConstant.u2classIndex);
@@ -221,6 +235,12 @@ implements ClassVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ dataOutput.writeShort(methodTypeConstant.u2descriptorIndex);
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
dataOutput.writeShort(nameAndTypeConstant.u2nameIndex);
@@ -263,6 +283,7 @@ implements ClassVisitor,
private class AttributeBodyWriter
extends SimplifiedVisitor
implements AttributeVisitor,
+ BootstrapMethodInfoVisitor,
InnerClassesInfoVisitor,
ExceptionInfoVisitor,
StackMapFrameVisitor,
@@ -282,6 +303,15 @@ implements ClassVisitor,
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ // Write the bootstrap methods.
+ dataOutput.writeShort(bootstrapMethodsAttribute.u2bootstrapMethodsCount);
+
+ bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
dataOutput.writeShort(sourceFileAttribute.u2sourceFileIndex);
@@ -438,8 +468,7 @@ implements ClassVisitor,
for (int index = 0; index < u2annotationsCount; index++)
{
- Annotation annotation = annotations[index];
- this.visitAnnotation(clazz, annotation);
+ visitAnnotation(clazz, annotations[index]);
}
}
@@ -453,6 +482,22 @@ implements ClassVisitor,
}
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ dataOutput.writeShort(bootstrapMethodInfo.u2methodHandleIndex);
+
+ // Write the bootstrap method arguments.
+ dataOutput.writeShort(bootstrapMethodInfo.u2methodArgumentCount);
+
+ for (int index = 0; index < bootstrapMethodInfo.u2methodArgumentCount; index++)
+ {
+ dataOutput.writeShort(bootstrapMethodInfo.u2methodArguments[index]);
+ }
+ }
+
+
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
diff --git a/src/proguard/classfile/io/RuntimeDataInput.java b/src/proguard/classfile/io/RuntimeDataInput.java
index 104b7c9..ce2d1a5 100644
--- a/src/proguard/classfile/io/RuntimeDataInput.java
+++ b/src/proguard/classfile/io/RuntimeDataInput.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/io/RuntimeDataOutput.java b/src/proguard/classfile/io/RuntimeDataOutput.java
index ffde3af..44acc70 100644
--- a/src/proguard/classfile/io/RuntimeDataOutput.java
+++ b/src/proguard/classfile/io/RuntimeDataOutput.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/AccessUtil.java b/src/proguard/classfile/util/AccessUtil.java
index 3ad6961..d16f576 100644
--- a/src/proguard/classfile/util/AccessUtil.java
+++ b/src/proguard/classfile/util/AccessUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/ClassReferenceInitializer.java b/src/proguard/classfile/util/ClassReferenceInitializer.java
index b1f2c27..a5748ee 100644
--- a/src/proguard/classfile/util/ClassReferenceInitializer.java
+++ b/src/proguard/classfile/util/ClassReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -64,7 +64,8 @@ implements ClassVisitor,
private final ClassPool programClassPool;
private final ClassPool libraryClassPool;
private final WarningPrinter missingClassWarningPrinter;
- private final WarningPrinter missingMemberWarningPrinter;
+ private final WarningPrinter missingProgramMemberWarningPrinter;
+ private final WarningPrinter missingLibraryMemberWarningPrinter;
private final WarningPrinter dependencyWarningPrinter;
private final MemberFinder memberFinder = new MemberFinder();
@@ -78,14 +79,16 @@ implements ClassVisitor,
public ClassReferenceInitializer(ClassPool programClassPool,
ClassPool libraryClassPool,
WarningPrinter missingClassWarningPrinter,
- WarningPrinter missingMemberWarningPrinter,
+ WarningPrinter missingProgramMemberWarningPrinter,
+ WarningPrinter missingLibraryMemberWarningPrinter,
WarningPrinter dependencyWarningPrinter)
{
- this.programClassPool = programClassPool;
- this.libraryClassPool = libraryClassPool;
- this.missingClassWarningPrinter = missingClassWarningPrinter;
- this.missingMemberWarningPrinter = missingMemberWarningPrinter;
- this.dependencyWarningPrinter = dependencyWarningPrinter;
+ this.programClassPool = programClassPool;
+ this.libraryClassPool = libraryClassPool;
+ this.missingClassWarningPrinter = missingClassWarningPrinter;
+ this.missingProgramMemberWarningPrinter = missingProgramMemberWarningPrinter;
+ this.missingLibraryMemberWarningPrinter = missingLibraryMemberWarningPrinter;
+ this.dependencyWarningPrinter = dependencyWarningPrinter;
}
@@ -166,17 +169,30 @@ implements ClassVisitor,
}
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ // Fill out the MethodHandle class.
+ methodHandleConstant.javaLangInvokeMethodHandleClass =
+ findClass(clazz.getName(), ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE);
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
String className = refConstant.getClassName(clazz);
+ // Methods for array types should be found in the Object class.
+ if (ClassUtil.isInternalArrayType(className))
+ {
+ className = ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT;
+ }
+
// See if we can find the referenced class.
// Unresolved references are assumed to refer to library classes
// that will not change anyway.
Clazz referencedClass = findClass(clazz.getName(), className);
- if (referencedClass != null &&
- !ClassUtil.isInternalArrayType(className))
+ if (referencedClass != null)
{
String name = refConstant.getName(clazz);
String type = refConstant.getType(clazz);
@@ -194,7 +210,13 @@ implements ClassVisitor,
if (refConstant.referencedMember == null)
{
- // We've haven't found the class member anywhere in the hierarchy.
+ // We haven't found the class member anywhere in the hierarchy.
+ boolean isProgramClass = referencedClass instanceof ProgramClass;
+
+ WarningPrinter missingMemberWarningPrinter = isProgramClass ?
+ missingProgramMemberWarningPrinter :
+ missingLibraryMemberWarningPrinter;
+
missingMemberWarningPrinter.print(clazz.getName(),
className,
"Warning: " +
@@ -203,7 +225,11 @@ implements ClassVisitor,
(isFieldRef ?
"field '" + ClassUtil.externalFullFieldDescription(0, name, type) :
"method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) +
- "' in class " +
+ "' in " +
+ (isProgramClass ?
+ "program" :
+ "library") +
+ " class " +
ClassUtil.externalClassName(className));
}
}
@@ -216,7 +242,7 @@ implements ClassVisitor,
// Fill out the referenced class.
classConstant.referencedClass =
- findClass(className, classConstant.getName(clazz));
+ findClass(className, ClassUtil.internalClassNameFromClassType(classConstant.getName(clazz)));
// Fill out the Class class.
classConstant.javaLangClassClass =
@@ -224,6 +250,14 @@ implements ClassVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ // Fill out the MethodType class.
+ methodTypeConstant.javaLangInvokeMethodTypeClass =
+ findClass(clazz.getName(), ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE);
+ }
+
+
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
@@ -235,49 +269,36 @@ implements ClassVisitor,
String enclosingClassName = enclosingMethodAttribute.getClassName(clazz);
// See if we can find the referenced class.
- Clazz referencedClass = findClass(className, enclosingClassName);
+ enclosingMethodAttribute.referencedClass =
+ findClass(className, enclosingClassName);
- if (referencedClass == null)
+ if (enclosingMethodAttribute.referencedClass != null)
{
- // We couldn't find the enclosing class.
- missingClassWarningPrinter.print(className,
- enclosingClassName,
- "Warning: " +
- ClassUtil.externalClassName(className) +
- ": can't find enclosing class " +
- ClassUtil.externalClassName(enclosingClassName));
- return;
- }
-
- // Make sure there is actually an enclosed method.
- if (enclosingMethodAttribute.u2nameAndTypeIndex == 0)
- {
- return;
- }
-
- String name = enclosingMethodAttribute.getName(clazz);
- String type = enclosingMethodAttribute.getType(clazz);
+ // Is there an enclosing method? Otherwise it's just initialization
+ // code outside of the constructors.
+ if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
+ {
+ String name = enclosingMethodAttribute.getName(clazz);
+ String type = enclosingMethodAttribute.getType(clazz);
- // See if we can find the method in the referenced class.
- Method referencedMethod = referencedClass.findMethod(name, type);
+ // See if we can find the method in the referenced class.
+ enclosingMethodAttribute.referencedMethod =
+ enclosingMethodAttribute.referencedClass.findMethod(name, type);
- if (referencedMethod == null)
- {
- // We couldn't find the enclosing method.
- missingMemberWarningPrinter.print(className,
- enclosingClassName,
- "Warning: " +
- ClassUtil.externalClassName(className) +
- ": can't find enclosing method '" +
- ClassUtil.externalFullMethodDescription(enclosingClassName, 0, name, type) +
- "' in class " +
- ClassUtil.externalClassName(enclosingClassName));
- return;
+ if (enclosingMethodAttribute.referencedMethod == null)
+ {
+ // We couldn't find the enclosing method.
+ missingProgramMemberWarningPrinter.print(className,
+ enclosingClassName,
+ "Warning: " +
+ ClassUtil.externalClassName(className) +
+ ": can't find enclosing method '" +
+ ClassUtil.externalFullMethodDescription(enclosingClassName, 0, name, type) +
+ "' in program class " +
+ ClassUtil.externalClassName(enclosingClassName));
+ }
+ }
}
-
- // Save the references.
- enclosingMethodAttribute.referencedClass = referencedClass;
- enclosingMethodAttribute.referencedMethod = referencedMethod;
}
@@ -501,11 +522,17 @@ implements ClassVisitor,
*/
private Clazz findClass(String referencingClassName, String name)
{
- // Ignore any primitive array types.
- if (ClassUtil.isInternalArrayType(name) &&
- !ClassUtil.isInternalClassType(name))
+ // Is it an array type?
+ if (ClassUtil.isInternalArrayType(name))
{
- return null;
+ // Ignore any primitive array types.
+ if (!ClassUtil.isInternalClassType(name))
+ {
+ return null;
+ }
+
+ // Strip the array part.
+ name = ClassUtil.internalClassNameFromClassType(name);
}
// First look for the class in the program class pool.
diff --git a/src/proguard/classfile/util/ClassSubHierarchyInitializer.java b/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
index 30fd526..993a559 100644
--- a/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
+++ b/src/proguard/classfile/util/ClassSubHierarchyInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java b/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
index af2a209..fb431b8 100644
--- a/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
+++ b/src/proguard/classfile/util/ClassSuperHierarchyInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -106,11 +106,6 @@ implements ClassVisitor,
libraryClass.interfaceClasses = interfaceClasses;
}
-
- // Discard the name Strings. From now on, we'll use the object
- // references.
- libraryClass.superClassName = null;
- libraryClass.interfaceNames = null;
}
diff --git a/src/proguard/classfile/util/ClassUtil.java b/src/proguard/classfile/util/ClassUtil.java
index 5f25f01..fb38616 100644
--- a/src/proguard/classfile/util/ClassUtil.java
+++ b/src/proguard/classfile/util/ClassUtil.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -100,6 +100,8 @@ public class ClassUtil
classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_5) ? ClassConstants.INTERNAL_CLASS_VERSION_1_5 :
classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6_ALIAS) ||
classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6) ? ClassConstants.INTERNAL_CLASS_VERSION_1_6 :
+ classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7_ALIAS) ||
+ classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7) ? ClassConstants.INTERNAL_CLASS_VERSION_1_7 :
0;
}
@@ -119,6 +121,7 @@ public class ClassUtil
case ClassConstants.INTERNAL_CLASS_VERSION_1_4: return ClassConstants.EXTERNAL_CLASS_VERSION_1_4;
case ClassConstants.INTERNAL_CLASS_VERSION_1_5: return ClassConstants.EXTERNAL_CLASS_VERSION_1_5;
case ClassConstants.INTERNAL_CLASS_VERSION_1_6: return ClassConstants.EXTERNAL_CLASS_VERSION_1_6;
+ case ClassConstants.INTERNAL_CLASS_VERSION_1_7: return ClassConstants.EXTERNAL_CLASS_VERSION_1_7;
default: return null;
}
}
@@ -132,11 +135,14 @@ public class ClassUtil
public static void checkVersionNumbers(int classVersion) throws UnsupportedOperationException
{
if (classVersion < ClassConstants.INTERNAL_CLASS_VERSION_1_0 ||
- classVersion > ClassConstants.INTERNAL_CLASS_VERSION_1_6)
+ classVersion > ClassConstants.INTERNAL_CLASS_VERSION_1_7)
{
- throw new UnsupportedOperationException("Unsupported version number ["+
+ throw new UnsupportedOperationException("Unsupported class version number ["+
internalMajorClassVersion(classVersion)+"."+
- internalMinorClassVersion(classVersion)+"] for class format");
+ internalMinorClassVersion(classVersion)+"] (maximum "+
+ ClassConstants.INTERNAL_CLASS_VERSION_1_7_MAJOR+"."+
+ ClassConstants.INTERNAL_CLASS_VERSION_1_7_MINOR+", Java "+
+ ClassConstants.EXTERNAL_CLASS_VERSION_1_7+")");
}
}
@@ -189,8 +195,25 @@ public class ClassUtil
/**
- * Converts an internal class name into an external short class name, without
- * package specification.
+ * Returns the external base type of an external array type, dropping any
+ * array brackets.
+ * @param externalArrayType the external array type,
+ * e.g. "java.lang.Object[][]
"
+ * @return the external base type,
+ * e.g. "java.lang.Object
".
+ */
+ public static String externalBaseType(String externalArrayType)
+ {
+ int index = externalArrayType.indexOf(ClassConstants.EXTERNAL_TYPE_ARRAY);
+ return index >= 0 ?
+ externalArrayType.substring(0, index) :
+ externalArrayType;
+ }
+
+
+ /**
+ * Returns the external short class name of an external class name, dropping
+ * the package specification.
* @param externalClassName the external class name,
* e.g. "java.lang.Object
"
* @return the external short class name,
@@ -409,6 +432,21 @@ public class ClassUtil
}
+ /**
+ * Returns whether the given method name refers to a class initializer or
+ * an instance initializer.
+ * @param internalMethodName the internal method name,
+ * e.g. "<clinit>
".
+ * @return whether the method name refers to an initializer,
+ * e.g. true
.
+ */
+ public static boolean isInitializer(String internalMethodName)
+ {
+ return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+ internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+ }
+
+
/**
* Returns the internal type of the given internal method descriptor.
* @param internalMethodDescriptor the internal method descriptor,
@@ -869,6 +907,21 @@ public class ClassUtil
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' ');
}
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0)
+ {
+ // Only in InnerClasses attributes.
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' ');
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0)
+ {
+ // Only in InnerClasses attributes.
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' ');
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
+ {
+ // Only in InnerClasses attributes.
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' ');
+ }
if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0)
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' ');
@@ -889,6 +942,10 @@ public class ClassUtil
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(' ');
}
+ else if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' ');
+ }
return string.toString();
}
@@ -950,6 +1007,10 @@ public class ClassUtil
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_TRANSIENT).append(' ');
}
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' ');
+ }
return string.toString();
}
@@ -1007,6 +1068,14 @@ public class ClassUtil
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED).append(' ');
}
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_BRIDGE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_BRIDGE).append(' ');
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_VARARGS) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VARARGS).append(' ');
+ }
if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0)
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_NATIVE).append(' ');
@@ -1019,6 +1088,10 @@ public class ClassUtil
{
string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STRICT).append(' ');
}
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' ');
+ }
return string.toString();
}
diff --git a/src/proguard/classfile/util/DescriptorClassEnumeration.java b/src/proguard/classfile/util/DescriptorClassEnumeration.java
index 0bee2d5..81590fa 100644
--- a/src/proguard/classfile/util/DescriptorClassEnumeration.java
+++ b/src/proguard/classfile/util/DescriptorClassEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/DynamicClassReferenceInitializer.java b/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
index 09ffdd0..865e094 100644
--- a/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
+++ b/src/proguard/classfile/util/DynamicClassReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -301,7 +301,8 @@ implements InstructionVisitor,
{
// Save a reference to the corresponding class.
String externalClassName = stringConstant.getString(clazz);
- String internalClassName = ClassUtil.internalClassName(externalClassName);
+ String internalClassName = ClassUtil.internalClassName(
+ ClassUtil.externalBaseType(externalClassName));
stringConstant.referencedClass = findClass(clazz.getName(), internalClassName);
}
@@ -350,7 +351,7 @@ implements InstructionVisitor,
return;
}
- String className = methodrefConstant.getClassName(clazz);
+ String className = methodrefConstant.getClassName(clazz);
// Note that we look for the class by name, since the referenced
// class has not been initialized yet.
@@ -434,11 +435,17 @@ implements InstructionVisitor,
*/
private Clazz findClass(String referencingClassName, String name)
{
- // Ignore any primitive array types.
- if (ClassUtil.isInternalArrayType(name) &&
- !ClassUtil.isInternalClassType(name))
+ // Is it an array type?
+ if (ClassUtil.isInternalArrayType(name))
{
- return null;
+ // Ignore any primitive array types.
+ if (!ClassUtil.isInternalClassType(name))
+ {
+ return null;
+ }
+
+ // Strip the array part.
+ name = ClassUtil.internalClassNameFromClassType(name);
}
// First look for the class in the program class pool.
diff --git a/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java b/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java
index 1f57708..23c8d40 100644
--- a/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java
+++ b/src/proguard/classfile/util/DynamicMemberReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -52,17 +52,22 @@ public class DynamicMemberReferenceInitializer
extends SimplifiedVisitor
implements InstructionVisitor,
ConstantVisitor,
- AttributeVisitor,
MemberVisitor
{
- public static final int X = InstructionSequenceMatcher.X;
- public static final int Y = InstructionSequenceMatcher.Y;
- public static final int Z = InstructionSequenceMatcher.Z;
+ /*
+ private static boolean DEBUG = true;
+ /*/
+ private static final boolean DEBUG = false;
+ //*/
- public static final int A = InstructionSequenceMatcher.A;
- public static final int B = InstructionSequenceMatcher.B;
- public static final int C = InstructionSequenceMatcher.C;
- public static final int D = InstructionSequenceMatcher.D;
+ public static final int CLASS_INDEX = InstructionSequenceMatcher.X;
+ public static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.Y;
+ public static final int TYPE_CLASS_INDEX = InstructionSequenceMatcher.Z;
+
+ public static final int PARAMETER0_CLASS_INDEX = InstructionSequenceMatcher.A;
+ public static final int PARAMETER1_CLASS_INDEX = InstructionSequenceMatcher.B;
+ public static final int PARAMETER2_CLASS_INDEX = InstructionSequenceMatcher.C;
+ public static final int PARAMETER3_CLASS_INDEX = InstructionSequenceMatcher.D;
private final Constant[] GET_FIELD_CONSTANTS = new Constant[]
@@ -85,6 +90,26 @@ implements InstructionVisitor,
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
};
+ private final Constant[] GET_CONSTRUCTOR_CONSTANTS = new Constant[]
+ {
+ new MethodrefConstant(1, 2, null, null),
+ new ClassConstant(3, null),
+ new NameAndTypeConstant(4, 5),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
+ new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR),
+ new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR),
+ };
+
+ private final Constant[] GET_DECLARED_CONSTRUCTOR_CONSTANTS = new Constant[]
+ {
+ new MethodrefConstant(1, 2, null, null),
+ new ClassConstant(3, null),
+ new NameAndTypeConstant(4, 5),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
+ new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR),
+ new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR),
+ };
+
private final Constant[] GET_METHOD_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
@@ -105,19 +130,88 @@ implements InstructionVisitor,
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
};
+ private final Constant[] NEW_INTEGER_UPDATER_CONSTANTS = new Constant[]
+ {
+ new MethodrefConstant(1, 2, null, null),
+ new ClassConstant(3, null),
+ new NameAndTypeConstant(4, 5),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER),
+ };
+
+ private final Constant[] NEW_LONG_UPDATER_CONSTANTS = new Constant[]
+ {
+ new MethodrefConstant(1, 2, null, null),
+ new ClassConstant(3, null),
+ new NameAndTypeConstant(4, 5),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER),
+ };
+
+ private final Constant[] NEW_REFERENCE_UPDATER_CONSTANTS = new Constant[]
+ {
+ new MethodrefConstant(1, 2, null, null),
+ new ClassConstant(3, null),
+ new NameAndTypeConstant(4, 5),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER),
+ };
+
// SomeClass.class.get[Declared]Field("someField").
private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, X),
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
+// // SomeClass.class.get[Declared]Constructor(new Class[] {}).
+// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
+// {
+// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+// };
+//
+// // SomeClass.class.get[Declared]Constructor(new Class[] { A.class }).
+// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
+// {
+// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+// new SimpleInstruction(InstructionConstants.OP_DUP),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_AASTORE),
+// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+// };
+//
+// // SomeClass.class.get[Declared]Constructor(new Class[] { A.class, B.class }).
+// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
+// {
+// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_2),
+// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+// new SimpleInstruction(InstructionConstants.OP_DUP),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_AASTORE),
+// new SimpleInstruction(InstructionConstants.OP_DUP),
+// new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
+// new SimpleInstruction(InstructionConstants.OP_AASTORE),
+// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+// };
+
// SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, X),
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
@@ -126,13 +220,13 @@ implements InstructionVisitor,
// SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, X),
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
- new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
@@ -140,32 +234,86 @@ implements InstructionVisitor,
// SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, X),
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_2),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
- new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
- new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
+ // AtomicIntegerFieldUpdater.newUpdater(A.class, "someField").
+ // AtomicLongFieldUpdater.newUpdater(A.class, "someField").
+ private final Instruction[] CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
+ };
+
+ // AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField").
+ private final Instruction[] CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, TYPE_CLASS_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
+ };
+
// get[Declared]Field("someField").
private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+ };
+
+// // get[Declared]Constructor(new Class[] {}).
+// private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
+// {
+// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+// };
+
+ // get[Declared]Constructor(new Class[] { A.class }).
+ private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
+ new SimpleInstruction(InstructionConstants.OP_AASTORE),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
+ };
+
+ // get[Declared]Constructor(new Class[] { A.class, B.class }).
+ private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_2),
+ new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
+ new SimpleInstruction(InstructionConstants.OP_AASTORE),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
+ new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// get[Declared]Method("someMethod", new Class[] {}).
private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
@@ -174,12 +322,12 @@ implements InstructionVisitor,
// get[Declared]Method("someMethod", new Class[] { A.class }).
private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
- new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
@@ -187,20 +335,29 @@ implements InstructionVisitor,
// get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
{
- new ConstantInstruction(InstructionConstants.OP_LDC, Y),
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_2),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
- new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
- new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
+ // AtomicIntegerFieldUpdater.newUpdater(..., "someField").
+ // AtomicLongFieldUpdater.newUpdater(..., "someField").
+ // AtomicReferenceFieldUpdater.newUpdater(..., "someField").
+ private final Instruction[] NEW_UPDATER_INSTRUCTIONS = new Instruction[]
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
+ };
+
private final ClassPool programClassPool;
private final ClassPool libraryClassPool;
@@ -217,6 +374,30 @@ implements InstructionVisitor,
new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
CONSTANT_GET_FIELD_INSTRUCTIONS);
+// private final InstructionSequenceMatcher constantGetConstructorMatcher0 =
+// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
+//
+// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher0 =
+// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
+//
+// private final InstructionSequenceMatcher constantGetConstructorMatcher1 =
+// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
+//
+// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher1 =
+// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
+//
+// private final InstructionSequenceMatcher constantGetConstructorMatcher2 =
+// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
+//
+// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher2 =
+// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
+
private final InstructionSequenceMatcher constantGetMethodMatcher0 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS0);
@@ -241,6 +422,18 @@ implements InstructionVisitor,
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS2);
+ private final InstructionSequenceMatcher constantGetIntegerUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
+ CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
+
+ private final InstructionSequenceMatcher constantGetLongUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
+ CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
+
+ private final InstructionSequenceMatcher constantGetReferenceUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
+ CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS);
+
private final InstructionSequenceMatcher getFieldMatcher =
new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
GET_FIELD_INSTRUCTIONS);
@@ -249,6 +442,30 @@ implements InstructionVisitor,
new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
GET_FIELD_INSTRUCTIONS);
+// private final InstructionSequenceMatcher getConstructorMatcher0 =
+// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+// GET_CONSTRUCTOR_INSTRUCTIONS0);
+//
+// private final InstructionSequenceMatcher getDeclaredConstructorMatcher0 =
+// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+// GET_CONSTRUCTOR_INSTRUCTIONS0);
+
+ private final InstructionSequenceMatcher getConstructorMatcher1 =
+ new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+ GET_CONSTRUCTOR_INSTRUCTIONS1);
+
+ private final InstructionSequenceMatcher getDeclaredConstructorMatcher1 =
+ new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+ GET_CONSTRUCTOR_INSTRUCTIONS1);
+
+ private final InstructionSequenceMatcher getConstructorMatcher2 =
+ new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
+ GET_CONSTRUCTOR_INSTRUCTIONS2);
+
+ private final InstructionSequenceMatcher getDeclaredConstructorMatcher2 =
+ new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
+ GET_CONSTRUCTOR_INSTRUCTIONS2);
+
private final InstructionSequenceMatcher getMethodMatcher0 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS0);
@@ -273,11 +490,24 @@ implements InstructionVisitor,
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS2);
+ private final InstructionSequenceMatcher getIntegerUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
+ NEW_UPDATER_INSTRUCTIONS);
+
+ private final InstructionSequenceMatcher getLongUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
+ NEW_UPDATER_INSTRUCTIONS);
+
+ private final InstructionSequenceMatcher getReferenceUpdaterMatcher =
+ new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
+ NEW_UPDATER_INSTRUCTIONS);
+
private final MemberFinder memberFinder = new MemberFinder();
// Fields acting as parameters for the visitors.
private Clazz referencedClass;
+ private String descriptor;
private boolean isDeclared;
private boolean isField;
@@ -307,48 +537,110 @@ implements InstructionVisitor,
// Try to match the SomeClass.class.getField("someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetFieldMatcher,
- getFieldMatcher, true, false);
+ getFieldMatcher, true, false, null, null);
// Try to match the SomeClass.class.getDeclaredField("someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredFieldMatcher,
- getDeclaredFieldMatcher, true, true);
+ getDeclaredFieldMatcher, true, true, null, null);
+
+// // Try to match the SomeClass.class.getConstructor(new Class[]
+// // {}) construct.
+// matchGetMember(clazz, method, codeAttribute, offset, instruction,
+// cnull, //onstantGetConstructorMatcher0,
+// getConstructorMatcher0, false, false,
+// ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
+//
+// // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
+// // {}) construct.
+// matchGetMember(clazz, method, codeAttribute, offset, instruction,
+// null, //constantGetDeclaredConstructorMatcher0,
+// getDeclaredConstructorMatcher0, false, true,
+// ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
+
+ // Try to match the SomeClass.class.getConstructor(new Class[]
+ // { A.class }) construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ null, //constantGetConstructorMatcher1,
+ getConstructorMatcher1, false, false,
+ ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
+
+ // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
+ // { A.class }) construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ null, //constantGetDeclaredConstructorMatcher1,
+ getDeclaredConstructorMatcher1, false, true,
+ ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
+
+ // Try to match the SomeClass.class.getConstructor(new Class[]
+ // { A.class, B.class }) construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ null, //constantGetConstructorMatcher2,
+ getConstructorMatcher2, false, false,
+ ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
+
+ // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
+ // { A.class, B.class }) construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ null, //constantGetDeclaredConstructorMatcher2,
+ getDeclaredConstructorMatcher2, false, true,
+ ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// {}) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher0,
- getMethodMatcher0, false, false);
+ getMethodMatcher0, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
- // new Class[] {}) construct.
+ // new Class[] {}) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher0,
- getDeclaredMethodMatcher0, false, true);
+ getDeclaredMethodMatcher0, false, true, null, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher1,
- getMethodMatcher1, false, false);
+ getMethodMatcher1, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
// new Class[] { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher1,
- getDeclaredMethodMatcher1, false, true);
+ getDeclaredMethodMatcher1, false, true, null, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher2,
- getMethodMatcher2, false, false);
+ getMethodMatcher2, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
- // new Class[] { A.class, B.class }) construct.
+ // new Class[] { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher2,
- getDeclaredMethodMatcher2, false, true);
+ getDeclaredMethodMatcher2, false, true, null, null);
+
+ // Try to match the AtomicIntegerFieldUpdater.newUpdater(
+ // SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ constantGetIntegerUpdaterMatcher,
+ getIntegerUpdaterMatcher, true, false, null,
+ "" + ClassConstants.INTERNAL_TYPE_INT);
+
+ // Try to match the AtomicLongFieldUpdater.newUpdater(
+ // SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ constantGetLongUpdaterMatcher,
+ getLongUpdaterMatcher, true, false, null,
+ "" + ClassConstants.INTERNAL_TYPE_LONG);
+
+ // Try to match the AtomicReferenceFieldUpdater.newUpdater(
+ // SomeClass.class, SomeClass.class, "someField") construct.
+ matchGetMember(clazz, method, codeAttribute, offset, instruction,
+ constantGetReferenceUpdaterMatcher,
+ getReferenceUpdaterMatcher, true, false, null, null);
}
@@ -364,26 +656,28 @@ implements InstructionVisitor,
InstructionSequenceMatcher constantSequenceMatcher,
InstructionSequenceMatcher variableSequenceMatcher,
boolean isField,
- boolean isDeclared)
+ boolean isDeclared,
+ String defaultName,
+ String defaultDescriptor)
{
- // 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())
+ if (constantSequenceMatcher != null)
{
- this.isField = isField;
- this.isDeclared = isDeclared;
-
- // Get the member's class.
- clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(X), this);
-
- // Fill out the matched string constant.
- clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(Y), this);
+ // Try to match the next instruction in the constant sequence.
+ instruction.accept(clazz, method, codeAttribute, offset,
+ constantSequenceMatcher);
- // Don't look for the dynamic construct.
- variableSequenceMatcher.reset();
+ // Did we find a match to fill out the string constant?
+ if (constantSequenceMatcher.isMatching())
+ {
+ initializeStringReference(clazz,
+ constantSequenceMatcher,
+ isField,
+ isDeclared,
+ defaultDescriptor);
+
+ // Don't look for the dynamic construct.
+ variableSequenceMatcher.reset();
+ }
}
// Try to match the next instruction in the variable sequence.
@@ -397,11 +691,41 @@ implements InstructionVisitor,
printDynamicInvocationNote(clazz,
variableSequenceMatcher,
isField,
- isDeclared);
+ isDeclared,
+ defaultName,
+ defaultDescriptor);
}
}
+ /**
+ * Initializes the reference of the matched string constant to the
+ * referenced class member and its class.
+ */
+ private void initializeStringReference(Clazz clazz,
+ InstructionSequenceMatcher constantSequenceMatcher,
+ boolean isField,
+ boolean isDeclared,
+ String defaultDescriptor)
+ {
+ this.isField = isField;
+ this.isDeclared = isDeclared;
+
+ // Get the member's class.
+ int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX);
+ clazz.constantPoolEntryAccept(classIndex, this);
+
+ // Get the field's reference type, if applicable.
+ int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(TYPE_CLASS_INDEX);
+ descriptor = typeClassIndex <= 0 ? defaultDescriptor :
+ ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex));
+
+ // Fill out the matched string constant.
+ int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
+ clazz.constantPoolEntryAccept(memberNameIndex, this);
+ }
+
+
// Implementations for ConstantVisitor.
/**
@@ -409,6 +733,11 @@ implements InstructionVisitor,
*/
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
+ if (DEBUG)
+ {
+ System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched class ["+classConstant.getName(clazz)+"]");
+ }
+
// Remember the referenced class.
referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
null :
@@ -425,15 +754,20 @@ implements InstructionVisitor,
{
String name = stringConstant.getString(clazz);
+ if (DEBUG)
+ {
+ System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+name+"]");
+ }
+
// See if we can find the referenced class member locally, or
// somewhere in the hierarchy.
Member referencedMember = isDeclared ? isField ?
- (Member)referencedClass.findField(name, null) :
- (Member)referencedClass.findMethod(name, null) :
+ (Member)referencedClass.findField(name, descriptor) :
+ (Member)referencedClass.findMethod(name, descriptor) :
(Member)memberFinder.findMember(clazz,
referencedClass,
name,
- null,
+ descriptor,
isField);
if (referencedMember != null)
{
@@ -454,7 +788,9 @@ implements InstructionVisitor,
private void printDynamicInvocationNote(Clazz clazz,
InstructionSequenceMatcher noteSequenceMatcher,
boolean isField,
- boolean isDeclared)
+ boolean isDeclared,
+ String defaultName,
+ String defaultDescriptor)
{
// Print out a note about the dynamic invocation.
if (notePrinter != null &&
@@ -465,8 +801,9 @@ implements InstructionVisitor,
noteFieldExceptionMatcher :
noteMethodExceptionMatcher;
- int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(Y);
- String memberName = clazz.getStringString(memberNameIndex);
+ int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
+ String memberName = memberNameIndex <= 0 ? defaultName :
+ clazz.getStringString(memberNameIndex);
if (noteExceptionMatcher == null ||
!noteExceptionMatcher.matches(memberName))
@@ -479,7 +816,8 @@ implements InstructionVisitor,
externalMemberDescription += '(';
for (int count = 0; count < 2; count++)
{
- int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count);
+ int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(
+ PARAMETER0_CLASS_INDEX + count);
if (memberArgumentIndex > 0)
{
if (count > 0)
@@ -501,7 +839,9 @@ implements InstructionVisitor,
ClassUtil.externalClassName(clazz.getName()) +
" accesses a " +
(isDeclared ? "declared " : "") +
- (isField ? "field" : "method") +
+ (isField ? "field" :
+ memberName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ?
+ "constructor" : "method") +
" '" +
externalMemberDescription +
"' dynamically");
@@ -511,9 +851,12 @@ implements InstructionVisitor,
if (isField)
{
- classVisitor =
+ classVisitor = defaultDescriptor == null ?
+ new AllFieldVisitor(
+ new MemberNameFilter(memberName, this)) :
new AllFieldVisitor(
- new MemberNameFilter(memberName, this));
+ new MemberNameFilter(memberName,
+ new MemberDescriptorFilter(defaultDescriptor, this)));
}
else
{
@@ -521,20 +864,16 @@ implements InstructionVisitor,
String methodDescriptor = "(";
for (int count = 0; count < 2; count++)
{
- int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count);
+ int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(PARAMETER0_CLASS_INDEX + count);
if (memberArgumentIndex > 0)
{
- if (count > 0)
- {
- methodDescriptor += ',';
- }
String className = clazz.getClassName(memberArgumentIndex);
methodDescriptor += ClassUtil.isInternalArrayType(className) ?
className :
ClassUtil.internalTypeFromClassName(className);
}
}
- methodDescriptor += ")L///;";
+ methodDescriptor += ")L***;";
classVisitor =
new AllMethodVisitor(
@@ -571,7 +910,7 @@ implements InstructionVisitor,
System.out.println(" Maybe this is program method '" +
ClassUtil.externalFullClassDescription(0, programClass.getName()) +
" { " +
- ClassUtil.externalFullMethodDescription(null, 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
+ ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
"; }'");
}
}
@@ -597,7 +936,7 @@ implements InstructionVisitor,
System.out.println(" Maybe this is library method '" +
ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
" { " +
- ClassUtil.externalFullMethodDescription(null, 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
+ ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
"; }'");
}
}
diff --git a/src/proguard/classfile/util/EnumFieldReferenceInitializer.java b/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
new file mode 100644
index 0000000..dae6db2
--- /dev/null
+++ b/src/proguard/classfile/util/EnumFieldReferenceInitializer.java
@@ -0,0 +1,150 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.attribute.annotation.*;
+import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.*;
+import proguard.classfile.visitor.*;
+import proguard.util.StringMatcher;
+
+/**
+ * This ElementValueVisitor initializes the field references of the
+ * EnumConstantElementValue instances that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class EnumFieldReferenceInitializer
+extends SimplifiedVisitor
+implements ElementValueVisitor,
+ InstructionVisitor,
+ ConstantVisitor
+{
+ /*
+ private static boolean DEBUG = true;
+ /*/
+ private static final boolean DEBUG = false;
+ //*/
+
+ private MemberVisitor enumFieldFinder = new AllAttributeVisitor(
+ new AllInstructionVisitor(this));
+
+ // Fields acting as parameters and return values for the visitors.
+ private String enumTypeName;
+ private String enumConstantName;
+ private boolean enumConstantNameFound;
+ private Clazz referencedEnumClass;
+ private Field referencedEnumField;
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) {}
+
+
+ public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+
+ if (enumConstantElementValue.referencedClasses != null &&
+ enumConstantElementValue.referencedClasses.length > 0)
+ {
+ referencedEnumClass = enumConstantElementValue.referencedClasses[0];
+ if (referencedEnumClass != null)
+ {
+ // Try to find the enum field through the static enum
+ // initialization code (at least for program classes).
+ enumTypeName = enumConstantElementValue.getTypeName(clazz);
+ enumConstantName = enumConstantElementValue.getConstantName(clazz);
+ referencedEnumField = null;
+ referencedEnumClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+ ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+ enumFieldFinder);
+
+ // Otherwise try to find the enum field through its name.
+ // The constant name could be different from the field name, if
+ // the latter is already obfuscated.
+ if (referencedEnumField == null)
+ {
+ referencedEnumField =
+ referencedEnumClass.findField(enumConstantName,
+ enumTypeName);
+ }
+
+ if (DEBUG)
+ {
+ System.out.println("EnumFieldReferenceInitializer: ["+referencedEnumClass.getName()+"."+enumConstantName+"] -> "+referencedEnumField);
+ }
+
+ enumConstantElementValue.referencedField = referencedEnumField;
+ }
+ }
+ }
+
+
+ // 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_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_PUTSTATIC:
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ enumConstantNameFound =
+ enumConstantName.equals(stringConstant.getString(clazz));
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ if (enumConstantNameFound)
+ {
+ if (enumTypeName.equals(fieldrefConstant.getType(clazz)))
+ {
+ referencedEnumField = (Field)fieldrefConstant.referencedMember;
+ }
+
+ enumConstantNameFound = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/util/ExternalTypeEnumeration.java b/src/proguard/classfile/util/ExternalTypeEnumeration.java
index 6371888..e5b7067 100644
--- a/src/proguard/classfile/util/ExternalTypeEnumeration.java
+++ b/src/proguard/classfile/util/ExternalTypeEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/InstructionSequenceMatcher.java b/src/proguard/classfile/util/InstructionSequenceMatcher.java
index 8a689d5..8c529a9 100644
--- a/src/proguard/classfile/util/InstructionSequenceMatcher.java
+++ b/src/proguard/classfile/util/InstructionSequenceMatcher.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,6 +27,8 @@ import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
+import java.util.Arrays;
+
/**
* This InstructionVisitor checks whether a given pattern instruction sequence
* occurs in the instructions that are visited. The arguments of the
@@ -40,8 +42,8 @@ implements InstructionVisitor,
ConstantVisitor
{
/*
- private static boolean DEBUG = false;
- public static boolean DEBUG_MORE = false;
+ public static boolean DEBUG = true;
+ public static boolean DEBUG_MORE = true;
/*/
private static final boolean DEBUG = false;
private static final boolean DEBUG_MORE = false;
@@ -60,14 +62,15 @@ implements InstructionVisitor,
private final Constant[] patternConstants;
private final Instruction[] patternInstructions;
- private boolean matching;
- private boolean matchingAnyWildCards;
- private int patternInstructionIndex;
- private final int[] matchedInstructionOffsets;
- private int matchedArgumentFlags;
- private final int[] matchedArguments = new int[7];
- private long matchedConstantFlags;
- private final int[] matchedConstantIndices;
+ private boolean matching;
+ private int patternInstructionIndex;
+ private final int[] matchedInstructionOffsets;
+ private int matchedArgumentFlags;
+ private final int[] matchedArguments = new int[7];
+ 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;
@@ -87,6 +90,7 @@ implements InstructionVisitor,
this.patternInstructions = patternInstructions;
matchedInstructionOffsets = new int[patternInstructions.length];
+ matchedConstantFlags = new long[(patternConstants.length + 63) / 64];
matchedConstantIndices = new int[patternConstants.length];
}
@@ -98,34 +102,55 @@ implements InstructionVisitor,
{
patternInstructionIndex = 0;
matchedArgumentFlags = 0;
- matchedConstantFlags = 0L;
- }
+ Arrays.fill(matchedConstantFlags, 0L);
- public boolean isMatching()
- {
- return matching;
+ previousConstantFlags = constantFlags;
+ constantFlags = 0;
}
- public boolean isMatchingAnyWildcards()
+ /**
+ * Returns whether the complete pattern sequence has been matched.
+ */
+ public boolean isMatching()
{
- return matchingAnyWildCards;
+ return matching;
}
+ /**
+ * Returns the number of instructions in the pattern sequence.
+ */
public int instructionCount()
{
return patternInstructions.length;
}
+ /**
+ * Returns the matched instruction offset of the specified pattern
+ * instruction.
+ */
public int matchedInstructionOffset(int index)
{
return matchedInstructionOffsets[index];
}
+ /**
+ * Returns whether the specified wildcard argument was a constant from
+ * the constant pool in the most recent match.
+ */
+ public boolean wasConstant(int argument)
+ {
+ return (previousConstantFlags & (1 << (argument - X))) != 0;
+ }
+
+
+ /**
+ * Returns the value of the specified matched argument (wildcard or not).
+ */
public int matchedArgument(int argument)
{
int argumentIndex = argument - X;
@@ -135,6 +160,9 @@ implements InstructionVisitor,
}
+ /**
+ * Returns the values of the specified matched arguments (wildcard or not).
+ */
public int[] matchedArguments(int[] arguments)
{
int[] matchedArguments = new int[arguments.length];
@@ -148,6 +176,9 @@ implements InstructionVisitor,
}
+ /**
+ * Returns the index of the specified matched constant (wildcard or not).
+ */
public int matchedConstantIndex(int constantIndex)
{
int argumentIndex = constantIndex - X;
@@ -157,6 +188,10 @@ implements InstructionVisitor,
}
+ /**
+ * Returns the value of the specified matched branch offset (wildcard or
+ * not).
+ */
public int matchedBranchOffset(int offset, int branchOffset)
{
int argumentIndex = branchOffset - X;
@@ -166,6 +201,10 @@ implements InstructionVisitor,
}
+ /**
+ * Returns the values of the specified matched jump offsets (wildcard or
+ * not).
+ */
public int[] matchedJumpOffsets(int offset, int[] jumpOffsets)
{
int[] matchedJumpOffsets = new int[jumpOffsets.length];
@@ -387,6 +426,35 @@ implements InstructionVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ InvokeDynamicConstant invokeDynamicPatternConstant = (InvokeDynamicConstant)patternConstant;
+
+ // Check the bootstrap method and the name and type.
+ matchingConstant =
+ matchingConstantIndices(clazz,
+ invokeDynamicConstant.getBootstrapMethodAttributeIndex(),
+ invokeDynamicPatternConstant.getBootstrapMethodAttributeIndex()) &&
+ matchingConstantIndices(clazz,
+ invokeDynamicConstant.getNameAndTypeIndex(),
+ invokeDynamicPatternConstant.getNameAndTypeIndex());
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ MethodHandleConstant methodHandlePatternConstant = (MethodHandleConstant)patternConstant;
+
+ // Check the handle type and the name and type.
+ matchingConstant =
+ matchingArguments(methodHandleConstant.getReferenceKind(),
+ methodHandlePatternConstant.getReferenceKind()) &&
+ matchingConstantIndices(clazz,
+ methodHandleConstant.getReferenceIndex(),
+ methodHandlePatternConstant.getReferenceIndex());
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
RefConstant refPatternConstant = (RefConstant)patternConstant;
@@ -414,6 +482,18 @@ implements InstructionVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ MethodTypeConstant typePatternConstant = (MethodTypeConstant)patternConstant;
+
+ // Check the descriptor.
+ matchingConstant =
+ matchingConstantIndices(clazz,
+ methodTypeConstant.u2descriptorIndex,
+ typePatternConstant.u2descriptorIndex);
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
NameAndTypeConstant typePatternConstant = (NameAndTypeConstant)patternConstant;
@@ -449,11 +529,10 @@ implements InstructionVisitor,
// Check the literal argument.
return argument1 == argument2;
}
- else if ((matchedArgumentFlags & (1 << argumentIndex)) == 0)
+ else if (!isMatchingArgumentIndex(argumentIndex))
{
- // Store a wildcard argument.
- matchedArguments[argumentIndex] = argument1;
- matchedArgumentFlags |= 1 << argumentIndex;
+ // Store the wildcard argument.
+ setMatchingArgument(argumentIndex, argument1);
return true;
}
@@ -465,6 +544,28 @@ implements InstructionVisitor,
}
+ /**
+ * Marks the specified argument (by index) as matching the specified
+ * argument value.
+ */
+ private void setMatchingArgument(int argumentIndex,
+ int argument)
+ {
+ matchedArguments[argumentIndex] = argument;
+ matchedArgumentFlags |= 1 << argumentIndex;
+ }
+
+
+ /**
+ * Returns whether the specified wildcard argument (by index) has been
+ * matched.
+ */
+ private boolean isMatchingArgumentIndex(int argumentIndex)
+ {
+ return (matchedArgumentFlags & (1 << argumentIndex)) != 0;
+ }
+
+
private boolean matchingArguments(int[] arguments1,
int[] arguments2)
{
@@ -491,10 +592,13 @@ implements InstructionVisitor,
{
if (constantIndex2 >= X)
{
+ // Remember that we are trying to match a constant.
+ constantFlags |= 1 << (constantIndex2 - X);
+
// Check the constant index.
return matchingArguments(constantIndex1, constantIndex2);
}
- else if ((matchedConstantFlags & (1L << constantIndex2)) == 0)
+ else if (!isMatchingConstantIndex(constantIndex2))
{
// Check the actual constant.
matchingConstant = false;
@@ -507,8 +611,7 @@ implements InstructionVisitor,
if (matchingConstant)
{
// Store the constant index.
- matchedConstantIndices[constantIndex2] = constantIndex1;
- matchedConstantFlags |= 1L << constantIndex2;
+ setMatchingConstant(constantIndex2, constantIndex1);
}
}
@@ -522,6 +625,27 @@ implements InstructionVisitor,
}
+ /**
+ * Marks the specified constant (by index) as matching the specified
+ * constant index value.
+ */
+ private void setMatchingConstant(int constantIndex,
+ int constantIndex1)
+ {
+ matchedConstantIndices[constantIndex] = constantIndex1;
+ matchedConstantFlags[constantIndex / 64] |= 1L << constantIndex;
+ }
+
+
+ /**
+ * Returns whether the specified wildcard constant has been matched.
+ */
+ private boolean isMatchingConstantIndex(int constantIndex)
+ {
+ return (matchedConstantFlags[constantIndex / 64] & (1L << constantIndex)) != 0;
+ }
+
+
private boolean matchingBranchOffsets(int offset,
int branchOffset1,
int branchOffset2)
@@ -532,11 +656,10 @@ implements InstructionVisitor,
// Check the literal argument.
return branchOffset1 == branchOffset2;
}
- else if ((matchedArgumentFlags & (1 << argumentIndex)) == 0)
+ else if (!isMatchingArgumentIndex(argumentIndex))
{
// Store a wildcard argument.
- matchedArguments[argumentIndex] = offset + branchOffset1;
- matchedArgumentFlags |= 1 << argumentIndex;
+ setMatchingArgument(argumentIndex, offset + branchOffset1);
return true;
}
@@ -595,9 +718,6 @@ implements InstructionVisitor,
// Did we match all instructions in the sequence?
matching = patternInstructionIndex == patternInstructions.length;
- // Did we match any wildcards along the way?
- matchingAnyWildCards = matchedArgumentFlags != 0;
-
if (matching)
{
if (DEBUG)
diff --git a/src/proguard/classfile/util/InternalTypeEnumeration.java b/src/proguard/classfile/util/InternalTypeEnumeration.java
index 76f7e84..9c63ad9 100644
--- a/src/proguard/classfile/util/InternalTypeEnumeration.java
+++ b/src/proguard/classfile/util/InternalTypeEnumeration.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,7 +27,7 @@ import proguard.classfile.ClassConstants;
* An InternalTypeEnumeration
provides an enumeration of all
* parameter types listed in a given internal method descriptor or signature.
* The signature can also be a class signature. The return type of a method
- * descriptor can retrieved separately.
+ * descriptor can be retrieved separately.
*
* @author Eric Lafortune
*/
diff --git a/src/proguard/classfile/util/MemberFinder.java b/src/proguard/classfile/util/MemberFinder.java
index 0fdeec0..36c0003 100644
--- a/src/proguard/classfile/util/MemberFinder.java
+++ b/src/proguard/classfile/util/MemberFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/MethodLinker.java b/src/proguard/classfile/util/MethodLinker.java
index 5f2ea6f..56b6723 100644
--- a/src/proguard/classfile/util/MethodLinker.java
+++ b/src/proguard/classfile/util/MethodLinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -26,16 +26,11 @@ import proguard.classfile.visitor.*;
import java.util.*;
/**
- * This ClassVisitor links all corresponding non-private methods in the class
- * hierarchies of all visited classes. Visited classes are typically all class
- * files that are not being subclassed. Chains of links that have been created
- * in previous invocations are merged with new chains of links, in order to
- * create a consistent set of chains.
- * - * As a MemberVisitor, it links all corresponding class members that it visits, - * including fields and private class members. - *
- * Class initialization methods and constructors are always ignored.
+ * This ClassVisitor links all corresponding non-private, non-static,
+ * non-initializer methods in the class hierarchies of all visited classes.
+ * Visited classes are typically all class files that are not being subclassed.
+ * Chains of links that have been created in previous invocations are merged
+ * with new chains of links, in order to create a consistent set of chains.
*
* @author Eric Lafortune
*/
@@ -56,7 +51,7 @@ implements ClassVisitor,
// Collect all non-private members in this class hierarchy.
clazz.hierarchyAccept(true, true, true, false,
new AllMethodVisitor(
- new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC,
this)));
// Clean up for the next class hierarchy.
diff --git a/src/proguard/classfile/util/SimplifiedVisitor.java b/src/proguard/classfile/util/SimplifiedVisitor.java
index 87b7fe4..aed46eb 100644
--- a/src/proguard/classfile/util/SimplifiedVisitor.java
+++ b/src/proguard/classfile/util/SimplifiedVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -42,7 +42,7 @@ public abstract class SimplifiedVisitor
/**
* Visits any type of class member of the given class.
*/
- public void visitAnyClass(Clazz Clazz)
+ public void visitAnyClass(Clazz clazz)
{
throw new UnsupportedOperationException("Method must be overridden in ["+this.getClass().getName()+"] if ever called");
}
@@ -157,6 +157,18 @@ public abstract class SimplifiedVisitor
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ visitAnyConstant(clazz, invokeDynamicConstant);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ visitAnyConstant(clazz, methodHandleConstant);
+ }
+
+
/**
* Visits any type of RefConstant of the given class.
*/
@@ -199,6 +211,12 @@ public abstract class SimplifiedVisitor
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ visitAnyConstant(clazz, methodTypeConstant);
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
visitAnyConstant(clazz, nameAndTypeConstant);
@@ -222,6 +240,12 @@ public abstract class SimplifiedVisitor
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ visitAnyAttribute(clazz, bootstrapMethodsAttribute);
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
visitAnyAttribute(clazz, sourceFileAttribute);
diff --git a/src/proguard/classfile/util/StringReferenceInitializer.java b/src/proguard/classfile/util/StringReferenceInitializer.java
index 3884a04..f00f0d3 100644
--- a/src/proguard/classfile/util/StringReferenceInitializer.java
+++ b/src/proguard/classfile/util/StringReferenceInitializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -62,7 +62,8 @@ implements ConstantVisitor
{
// See if we can find the referenced class.
stringConstant.referencedClass =
- findClass(ClassUtil.internalClassName(stringConstant.getString(clazz)));
+ findClass(ClassUtil.internalClassName(
+ ClassUtil.externalBaseType(stringConstant.getString(clazz))));
}
}
diff --git a/src/proguard/classfile/util/StringSharer.java b/src/proguard/classfile/util/StringSharer.java
index 56de7c5..dacb2d1 100644
--- a/src/proguard/classfile/util/StringSharer.java
+++ b/src/proguard/classfile/util/StringSharer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -64,6 +64,23 @@ implements ClassVisitor,
{
libraryClass.superClassName = superClass.getName();
}
+
+ // Replace the interface name strings by the shared name strings.
+ if (libraryClass.interfaceNames != null)
+ {
+ String[] interfaceNames = libraryClass.interfaceNames;
+ Clazz[] interfaceClasses = new Clazz[interfaceNames.length];
+
+ for (int index = 0; index < interfaceNames.length; index++)
+ {
+ // Keep a reference to the interface class.
+ Clazz interfaceClass = interfaceClasses[index];
+ if (interfaceClass != null)
+ {
+ interfaceNames[index] = interfaceClass.getName();
+ }
+ }
+ }
}
@@ -73,7 +90,7 @@ implements ClassVisitor,
public void visitAnyConstant(Clazz clazz, Constant constant) {}
- public void visitAnyStringConstant(Clazz clazz, StringConstant stringConstant)
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
Member referencedMember = stringConstant.referencedMember;
if (referencedMember != null)
diff --git a/src/proguard/classfile/util/WarningPrinter.java b/src/proguard/classfile/util/WarningPrinter.java
index 87d8978..39172dd 100644
--- a/src/proguard/classfile/util/WarningPrinter.java
+++ b/src/proguard/classfile/util/WarningPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllClassVisitor.java b/src/proguard/classfile/visitor/AllClassVisitor.java
index 06aca2c..5c6f3de 100644
--- a/src/proguard/classfile/visitor/AllClassVisitor.java
+++ b/src/proguard/classfile/visitor/AllClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllFieldVisitor.java b/src/proguard/classfile/visitor/AllFieldVisitor.java
index 8bff7d4..92c4b05 100644
--- a/src/proguard/classfile/visitor/AllFieldVisitor.java
+++ b/src/proguard/classfile/visitor/AllFieldVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllMemberVisitor.java b/src/proguard/classfile/visitor/AllMemberVisitor.java
index 448470e..ab26bf3 100644
--- a/src/proguard/classfile/visitor/AllMemberVisitor.java
+++ b/src/proguard/classfile/visitor/AllMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllMethodVisitor.java b/src/proguard/classfile/visitor/AllMethodVisitor.java
index 75b919d..5d8e6a3 100644
--- a/src/proguard/classfile/visitor/AllMethodVisitor.java
+++ b/src/proguard/classfile/visitor/AllMethodVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/BottomClassFilter.java b/src/proguard/classfile/visitor/BottomClassFilter.java
index 8f5bdd1..e094ce3 100644
--- a/src/proguard/classfile/visitor/BottomClassFilter.java
+++ b/src/proguard/classfile/visitor/BottomClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassAccessFilter.java b/src/proguard/classfile/visitor/ClassAccessFilter.java
index a8815b6..1855662 100644
--- a/src/proguard/classfile/visitor/ClassAccessFilter.java
+++ b/src/proguard/classfile/visitor/ClassAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassCleaner.java b/src/proguard/classfile/visitor/ClassCleaner.java
index 36165ef..a7ad1f6 100644
--- a/src/proguard/classfile/visitor/ClassCleaner.java
+++ b/src/proguard/classfile/visitor/ClassCleaner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassCollector.java b/src/proguard/classfile/visitor/ClassCollector.java
index a69fe76..a24bb0b 100644
--- a/src/proguard/classfile/visitor/ClassCollector.java
+++ b/src/proguard/classfile/visitor/ClassCollector.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassCounter.java b/src/proguard/classfile/visitor/ClassCounter.java
index c58c090..b6deef2 100644
--- a/src/proguard/classfile/visitor/ClassCounter.java
+++ b/src/proguard/classfile/visitor/ClassCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassForNameClassVisitor.java b/src/proguard/classfile/visitor/ClassForNameClassVisitor.java
deleted file mode 100644
index ee028f8..0000000
--- a/src/proguard/classfile/visitor/ClassForNameClassVisitor.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.classfile.visitor;
-
-import proguard.classfile.Clazz;
-import proguard.classfile.constant.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
-
-
-/**
- * This ConstantVisitor lets a given ClassVisitor
visit all
- * constant classes involved in any Class.forName
constructs that
- * it visits.
- *
- * @see DotClassClassVisitor
- *
- * @author Eric Lafortune
- */
-public class ClassForNameClassVisitor
-extends SimplifiedVisitor
-implements ConstantVisitor
-{
- private final ClassVisitor classVisitor;
-
-
- /**
- * Creates a new ClassHierarchyTraveler.
- * @param classVisitor the ClassVisitor
to which visits will
- * be delegated.
- */
- public ClassForNameClassVisitor(ClassVisitor classVisitor)
- {
- this.classVisitor = classVisitor;
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyConstant(Clazz clazz, Constant constant) {}
-
-
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
- {
- // Visit the referenced class from the Class.forName construct, if any.
- stringConstant.referencedClassAccept(classVisitor);
- }
-}
diff --git a/src/proguard/classfile/visitor/ClassHierarchyTraveler.java b/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
index 2e1755e..38ba3d6 100644
--- a/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
+++ b/src/proguard/classfile/visitor/ClassHierarchyTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassNameFilter.java b/src/proguard/classfile/visitor/ClassNameFilter.java
index c016a34..bd66eb1 100644
--- a/src/proguard/classfile/visitor/ClassNameFilter.java
+++ b/src/proguard/classfile/visitor/ClassNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -70,7 +70,7 @@ public class ClassNameFilter implements ClassVisitor
/**
* Creates a new ClassNameFilter.
- * @param regularExpressionMatcher the regular expression against which
+ * @param regularExpressionMatcher the string matcher against which
* class names will be matched.
* @param classVisitor the ClassVisitor
to which
* visits will be delegated.
diff --git a/src/proguard/classfile/visitor/ClassPoolFiller.java b/src/proguard/classfile/visitor/ClassPoolFiller.java
index e1773de..ae234be 100644
--- a/src/proguard/classfile/visitor/ClassPoolFiller.java
+++ b/src/proguard/classfile/visitor/ClassPoolFiller.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassPoolVisitor.java b/src/proguard/classfile/visitor/ClassPoolVisitor.java
index 0b659dc..821304a 100644
--- a/src/proguard/classfile/visitor/ClassPoolVisitor.java
+++ b/src/proguard/classfile/visitor/ClassPoolVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassPresenceFilter.java b/src/proguard/classfile/visitor/ClassPresenceFilter.java
index 429c340..0c55d1d 100644
--- a/src/proguard/classfile/visitor/ClassPresenceFilter.java
+++ b/src/proguard/classfile/visitor/ClassPresenceFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassPrinter.java b/src/proguard/classfile/visitor/ClassPrinter.java
index 1da7d16..3121e58 100644
--- a/src/proguard/classfile/visitor/ClassPrinter.java
+++ b/src/proguard/classfile/visitor/ClassPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -48,8 +48,9 @@ implements ClassVisitor,
ConstantVisitor,
MemberVisitor,
AttributeVisitor,
- ExceptionInfoVisitor,
+ BootstrapMethodInfoVisitor,
InnerClassesInfoVisitor,
+ ExceptionInfoVisitor,
StackMapFrameVisitor,
VerificationTypeVisitor,
LineNumberInfoVisitor,
@@ -62,7 +63,8 @@ implements ClassVisitor,
private static final String INDENTATION = " ";
private final PrintStream ps;
- private int indentation;
+
+ private int indentation;
/**
@@ -95,6 +97,7 @@ implements ClassVisitor,
println("Superclass: " + programClass.getSuperName());
println("Major version: 0x" + Integer.toHexString(ClassUtil.internalMajorClassVersion(programClass.u4version)));
println("Minor version: 0x" + Integer.toHexString(ClassUtil.internalMinorClassVersion(programClass.u4version)));
+ println(" = target " + ClassUtil.externalClassVersion(programClass.u4version));
println("Access flags: 0x" + Integer.toHexString(programClass.u2accessFlags));
println(" = " +
((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0 ? "@ " : "") +
@@ -222,10 +225,30 @@ implements ClassVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ println(visitorInfo(invokeDynamicConstant) + " InvokeDynamic [bootstrap method index = " + invokeDynamicConstant.u2bootstrapMethodAttributeIndex + "]:");
+
+ indent();
+ clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this);
+ outdent();
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ println(visitorInfo(methodHandleConstant) + " MethodHandle [kind = " + methodHandleConstant.u1referenceKind + "]:");
+
+ indent();
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
+ outdent();
+ }
+
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
println(visitorInfo(fieldrefConstant) + " Fieldref [" +
- clazz.getClassName(fieldrefConstant.u2classIndex) + "." +
+ clazz.getClassName(fieldrefConstant.u2classIndex) + "." +
clazz.getName(fieldrefConstant.u2nameAndTypeIndex) + " " +
clazz.getType(fieldrefConstant.u2nameAndTypeIndex) + "]");
}
@@ -256,6 +279,13 @@ implements ClassVisitor,
}
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ println(visitorInfo(methodTypeConstant) + " MethodType [" +
+ clazz.getString(methodTypeConstant.u2descriptorIndex) + "]");
+ }
+
+
public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
{
println(visitorInfo(nameAndTypeConstant) + " NameAndType [" +
@@ -361,6 +391,17 @@ implements ClassVisitor,
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ println(visitorInfo(bootstrapMethodsAttribute) +
+ " Bootstrap methods attribute (count = " + bootstrapMethodsAttribute.u2bootstrapMethodsCount + "):");
+
+ indent();
+ bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this);
+ outdent();
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
println(visitorInfo(sourceFileAttribute) +
@@ -595,6 +636,21 @@ implements ClassVisitor,
}
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ println(visitorInfo(bootstrapMethodInfo) +
+ " BootstrapMethodInfo (argument count = " +
+ bootstrapMethodInfo.u2methodArgumentCount+ "):");
+
+ indent();
+ clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, this);
+ bootstrapMethodInfo.methodArgumentsAccept(clazz, this);
+ outdent();
+ }
+
+
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
@@ -603,6 +659,8 @@ implements ClassVisitor,
" InnerClassesInfo:");
indent();
+ println("Access flags: 0x" + Integer.toHexString(innerClassesInfo.u2innerClassAccessFlags) + " = " +
+ ClassUtil.externalClassAccessFlags(innerClassesInfo.u2innerClassAccessFlags));
innerClassesInfo.innerClassConstantAccept(clazz, this);
innerClassesInfo.outerClassConstantAccept(clazz, this);
innerClassesInfo.innerNameConstantAccept(clazz, this);
@@ -816,7 +874,7 @@ implements ClassVisitor,
public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
{
- println("#" + localVariableInfo.u2index + ": " +
+ println("v" + localVariableInfo.u2index + ": " +
localVariableInfo.u2startPC + " -> " +
(localVariableInfo.u2startPC + localVariableInfo.u2length) + " [" +
clazz.getString(localVariableInfo.u2descriptorIndex) + " " +
@@ -828,7 +886,7 @@ implements ClassVisitor,
public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
{
- println("#" + localVariableTypeInfo.u2index + ": " +
+ println("v" + localVariableTypeInfo.u2index + ": " +
localVariableTypeInfo.u2startPC + " -> " +
(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length) + " [" +
clazz.getString(localVariableTypeInfo.u2signatureIndex) + " " +
diff --git a/src/proguard/classfile/visitor/ClassVersionFilter.java b/src/proguard/classfile/visitor/ClassVersionFilter.java
index 578cabf..73bcc6a 100644
--- a/src/proguard/classfile/visitor/ClassVersionFilter.java
+++ b/src/proguard/classfile/visitor/ClassVersionFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -36,6 +36,19 @@ public class ClassVersionFilter implements ClassVisitor
private final ClassVisitor classVisitor;
+ /**
+ * Creates a new ClassVersionFilter.
+ * @param minimumClassVersion the minimum class version number.
+ * @param classVisitor the ClassVisitor
to which visits
+ * will be delegated.
+ */
+ public ClassVersionFilter(int minimumClassVersion,
+ ClassVisitor classVisitor)
+ {
+ this(minimumClassVersion, Integer.MAX_VALUE, classVisitor);
+ }
+
+
/**
* Creates a new ClassVersionFilter.
* @param minimumClassVersion the minimum class version number.
diff --git a/src/proguard/classfile/visitor/ClassVersionSetter.java b/src/proguard/classfile/visitor/ClassVersionSetter.java
index 34dfbc1..d3f0183 100644
--- a/src/proguard/classfile/visitor/ClassVersionSetter.java
+++ b/src/proguard/classfile/visitor/ClassVersionSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassVisitor.java b/src/proguard/classfile/visitor/ClassVisitor.java
index fdba2df..c423446 100644
--- a/src/proguard/classfile/visitor/ClassVisitor.java
+++ b/src/proguard/classfile/visitor/ClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java b/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
index ec3fe68..0b971f0 100644
--- a/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
+++ b/src/proguard/classfile/visitor/ConcreteClassDownTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/DotClassClassVisitor.java b/src/proguard/classfile/visitor/DotClassClassVisitor.java
index 263dbd5..979f846 100644
--- a/src/proguard/classfile/visitor/DotClassClassVisitor.java
+++ b/src/proguard/classfile/visitor/DotClassClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -36,8 +36,6 @@ import proguard.classfile.util.SimplifiedVisitor;
* Note that before JDK 1.5, .class
constructs are actually
* compiled differently, using Class.forName
constructs.
*
- * @see ClassForNameClassVisitor
- *
* @author Eric Lafortune
*/
public class DotClassClassVisitor
diff --git a/src/proguard/classfile/visitor/ExceptClassFilter.java b/src/proguard/classfile/visitor/ExceptClassFilter.java
index 924485e..25c6e68 100644
--- a/src/proguard/classfile/visitor/ExceptClassFilter.java
+++ b/src/proguard/classfile/visitor/ExceptClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptClassesFilter.java b/src/proguard/classfile/visitor/ExceptClassesFilter.java
index 7380c40..bdf72bd 100644
--- a/src/proguard/classfile/visitor/ExceptClassesFilter.java
+++ b/src/proguard/classfile/visitor/ExceptClassesFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionCounter.java b/src/proguard/classfile/visitor/ExceptionCounter.java
index c324129..5c476b6 100644
--- a/src/proguard/classfile/visitor/ExceptionCounter.java
+++ b/src/proguard/classfile/visitor/ExceptionCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java b/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
index 3911e39..2fd18ae 100644
--- a/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
+++ b/src/proguard/classfile/visitor/ExceptionExcludedOffsetFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java b/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
index e0fdec3..de7139b 100644
--- a/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
+++ b/src/proguard/classfile/visitor/ExceptionHandlerConstantVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionHandlerFilter.java b/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
index a90fb56..36ead5e 100644
--- a/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
+++ b/src/proguard/classfile/visitor/ExceptionHandlerFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionOffsetFilter.java b/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
index e2a4fc9..c84473a 100644
--- a/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
+++ b/src/proguard/classfile/visitor/ExceptionOffsetFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ExceptionRangeFilter.java b/src/proguard/classfile/visitor/ExceptionRangeFilter.java
index c541b1f..626a32e 100644
--- a/src/proguard/classfile/visitor/ExceptionRangeFilter.java
+++ b/src/proguard/classfile/visitor/ExceptionRangeFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java b/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
index 6fe2e7d..334b85f 100644
--- a/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
+++ b/src/proguard/classfile/visitor/ImplementedClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ImplementedClassFilter.java b/src/proguard/classfile/visitor/ImplementedClassFilter.java
index 955a74e..abbacfb 100644
--- a/src/proguard/classfile/visitor/ImplementedClassFilter.java
+++ b/src/proguard/classfile/visitor/ImplementedClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java b/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
index 9e9cea3..8e7010d 100644
--- a/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
+++ b/src/proguard/classfile/visitor/ImplementingClassConstantFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/LibraryClassFilter.java b/src/proguard/classfile/visitor/LibraryClassFilter.java
index 0e40f2f..7437ed3 100644
--- a/src/proguard/classfile/visitor/LibraryClassFilter.java
+++ b/src/proguard/classfile/visitor/LibraryClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/LibraryMemberFilter.java b/src/proguard/classfile/visitor/LibraryMemberFilter.java
index 0ee80e5..eae0698 100644
--- a/src/proguard/classfile/visitor/LibraryMemberFilter.java
+++ b/src/proguard/classfile/visitor/LibraryMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberAccessFilter.java b/src/proguard/classfile/visitor/MemberAccessFilter.java
index 6fd32e3..6bdc152 100644
--- a/src/proguard/classfile/visitor/MemberAccessFilter.java
+++ b/src/proguard/classfile/visitor/MemberAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberClassAccessFilter.java b/src/proguard/classfile/visitor/MemberClassAccessFilter.java
index 85272ff..3605407 100644
--- a/src/proguard/classfile/visitor/MemberClassAccessFilter.java
+++ b/src/proguard/classfile/visitor/MemberClassAccessFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberCollector.java b/src/proguard/classfile/visitor/MemberCollector.java
index ec68b2d..46665f8 100644
--- a/src/proguard/classfile/visitor/MemberCollector.java
+++ b/src/proguard/classfile/visitor/MemberCollector.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberCounter.java b/src/proguard/classfile/visitor/MemberCounter.java
index c2da72e..58df4a7 100644
--- a/src/proguard/classfile/visitor/MemberCounter.java
+++ b/src/proguard/classfile/visitor/MemberCounter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberDescriptorFilter.java b/src/proguard/classfile/visitor/MemberDescriptorFilter.java
index bd69304..cce515a 100644
--- a/src/proguard/classfile/visitor/MemberDescriptorFilter.java
+++ b/src/proguard/classfile/visitor/MemberDescriptorFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberNameFilter.java b/src/proguard/classfile/visitor/MemberNameFilter.java
index 0fe450e..9996a4e 100644
--- a/src/proguard/classfile/visitor/MemberNameFilter.java
+++ b/src/proguard/classfile/visitor/MemberNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -47,7 +47,8 @@ public class MemberNameFilter implements MemberVisitor
public MemberNameFilter(String regularExpression,
MemberVisitor memberVisitor)
{
- this(new NameParser().parse(regularExpression), memberVisitor);
+ this(new ListParser(new NameParser()).parse(regularExpression),
+ memberVisitor);
}
diff --git a/src/proguard/classfile/visitor/MemberToClassVisitor.java b/src/proguard/classfile/visitor/MemberToClassVisitor.java
index a405cfc..e82e52f 100644
--- a/src/proguard/classfile/visitor/MemberToClassVisitor.java
+++ b/src/proguard/classfile/visitor/MemberToClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberVisitor.java b/src/proguard/classfile/visitor/MemberVisitor.java
index 01fdf71..7b45662 100644
--- a/src/proguard/classfile/visitor/MemberVisitor.java
+++ b/src/proguard/classfile/visitor/MemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MethodImplementationFilter.java b/src/proguard/classfile/visitor/MethodImplementationFilter.java
index 57d923a..893a699 100644
--- a/src/proguard/classfile/visitor/MethodImplementationFilter.java
+++ b/src/proguard/classfile/visitor/MethodImplementationFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MethodImplementationTraveler.java b/src/proguard/classfile/visitor/MethodImplementationTraveler.java
index dc0ea36..c9f942e 100644
--- a/src/proguard/classfile/visitor/MethodImplementationTraveler.java
+++ b/src/proguard/classfile/visitor/MethodImplementationTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MultiClassPoolVisitor.java b/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
index 044d55a..0e96cf1 100644
--- a/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
+++ b/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MultiClassVisitor.java b/src/proguard/classfile/visitor/MultiClassVisitor.java
index d34d91e..059e9b7 100644
--- a/src/proguard/classfile/visitor/MultiClassVisitor.java
+++ b/src/proguard/classfile/visitor/MultiClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MultiMemberVisitor.java b/src/proguard/classfile/visitor/MultiMemberVisitor.java
index cc4629c..800d65f 100644
--- a/src/proguard/classfile/visitor/MultiMemberVisitor.java
+++ b/src/proguard/classfile/visitor/MultiMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedClassVisitor.java b/src/proguard/classfile/visitor/NamedClassVisitor.java
index a14d04a..79e14c9 100644
--- a/src/proguard/classfile/visitor/NamedClassVisitor.java
+++ b/src/proguard/classfile/visitor/NamedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedFieldVisitor.java b/src/proguard/classfile/visitor/NamedFieldVisitor.java
index 76b66c6..685f62d 100644
--- a/src/proguard/classfile/visitor/NamedFieldVisitor.java
+++ b/src/proguard/classfile/visitor/NamedFieldVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedMethodVisitor.java b/src/proguard/classfile/visitor/NamedMethodVisitor.java
index d4611c1..c2baf19 100644
--- a/src/proguard/classfile/visitor/NamedMethodVisitor.java
+++ b/src/proguard/classfile/visitor/NamedMethodVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ProgramClassFilter.java b/src/proguard/classfile/visitor/ProgramClassFilter.java
index fba3b21..976658c 100644
--- a/src/proguard/classfile/visitor/ProgramClassFilter.java
+++ b/src/proguard/classfile/visitor/ProgramClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ProgramMemberFilter.java b/src/proguard/classfile/visitor/ProgramMemberFilter.java
index 048a1e6..cf187fb 100644
--- a/src/proguard/classfile/visitor/ProgramMemberFilter.java
+++ b/src/proguard/classfile/visitor/ProgramMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ReferencedClassVisitor.java b/src/proguard/classfile/visitor/ReferencedClassVisitor.java
index 986c3f9..e7fe855 100644
--- a/src/proguard/classfile/visitor/ReferencedClassVisitor.java
+++ b/src/proguard/classfile/visitor/ReferencedClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -123,6 +123,13 @@ implements ClassVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // Let the visitor visit the class referenced in the reference constant.
+ invokeDynamicConstant.referencedClassesAccept(classVisitor);
+ }
+
+
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
// Let the visitor visit the class referenced in the class constant.
diff --git a/src/proguard/classfile/visitor/ReferencedMemberVisitor.java b/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
index c4d34b8..3c59075 100644
--- a/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
+++ b/src/proguard/classfile/visitor/ReferencedMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/SimilarMemberVisitor.java b/src/proguard/classfile/visitor/SimilarMemberVisitor.java
index 6dc06af..5087f48 100644
--- a/src/proguard/classfile/visitor/SimilarMemberVisitor.java
+++ b/src/proguard/classfile/visitor/SimilarMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/SimpleClassPrinter.java b/src/proguard/classfile/visitor/SimpleClassPrinter.java
index a661110..df630c7 100644
--- a/src/proguard/classfile/visitor/SimpleClassPrinter.java
+++ b/src/proguard/classfile/visitor/SimpleClassPrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/SubclassFilter.java b/src/proguard/classfile/visitor/SubclassFilter.java
index 69ea1a1..6b6f84b 100644
--- a/src/proguard/classfile/visitor/SubclassFilter.java
+++ b/src/proguard/classfile/visitor/SubclassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/SubclassTraveler.java b/src/proguard/classfile/visitor/SubclassTraveler.java
index 4170341..32dccb7 100644
--- a/src/proguard/classfile/visitor/SubclassTraveler.java
+++ b/src/proguard/classfile/visitor/SubclassTraveler.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/VariableClassVisitor.java b/src/proguard/classfile/visitor/VariableClassVisitor.java
index 2f575c4..17a5522 100644
--- a/src/proguard/classfile/visitor/VariableClassVisitor.java
+++ b/src/proguard/classfile/visitor/VariableClassVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/VariableMemberVisitor.java b/src/proguard/classfile/visitor/VariableMemberVisitor.java
index c58cff3..34c39f3 100644
--- a/src/proguard/classfile/visitor/VariableMemberVisitor.java
+++ b/src/proguard/classfile/visitor/VariableMemberVisitor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/BasicBranchUnit.java b/src/proguard/evaluation/BasicBranchUnit.java
index 3a2db76..127e922 100644
--- a/src/proguard/evaluation/BasicBranchUnit.java
+++ b/src/proguard/evaluation/BasicBranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/BasicInvocationUnit.java b/src/proguard/evaluation/BasicInvocationUnit.java
index bccd866..474556c 100644
--- a/src/proguard/evaluation/BasicInvocationUnit.java
+++ b/src/proguard/evaluation/BasicInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -162,6 +162,7 @@ implements InvocationUnit,
break;
case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
isStatic = true;
break;
@@ -230,6 +231,31 @@ implements InvocationUnit,
}
}
+ 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.INTERNAL_TYPE_VOID)
+ {
+ stack.push(getMethodReturnValue(clazz, invokeDynamicConstant, returnType));
+ }
+ }
+
/**
* Sets the class through which the specified field is accessed.
@@ -340,6 +366,25 @@ implements InvocationUnit,
}
+ /**
+ * Returns the return value of the specified method.
+ */
+ protected Value getMethodReturnValue(Clazz clazz,
+ InvokeDynamicConstant invokeDynamicConstant,
+ String type)
+ {
+ // Try to figure out the class of the return type.
+ Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses;
+
+ Clazz returnTypeClass = referencedClasses == null ? null :
+ referencedClasses[referencedClasses.length - 1];
+
+ return valueFactory.createValue(type,
+ returnTypeClass,
+ true);
+ }
+
+
// Implementations for MemberVisitor.
public void visitProgramField(ProgramClass programClass, ProgramField programField)
diff --git a/src/proguard/evaluation/BranchUnit.java b/src/proguard/evaluation/BranchUnit.java
index b709807..a381da7 100644
--- a/src/proguard/evaluation/BranchUnit.java
+++ b/src/proguard/evaluation/BranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/ClassConstantValueFactory.java b/src/proguard/evaluation/ClassConstantValueFactory.java
new file mode 100644
index 0000000..1c418c2
--- /dev/null
+++ b/src/proguard/evaluation/ClassConstantValueFactory.java
@@ -0,0 +1,53 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This class creates java.lang.Class ReferenceValue instances that correspond
+ * to specified constant pool entries.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassConstantValueFactory
+extends ConstantValueFactory
+{
+ public ClassConstantValueFactory(ValueFactory valueFactory)
+ {
+ super(valueFactory);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Create a Class reference instead of a reference to the class.
+ value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS,
+ classConstant.javaLangClassClass,
+ false);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/ConstantValueFactory.java b/src/proguard/evaluation/ConstantValueFactory.java
new file mode 100644
index 0000000..0afb20c
--- /dev/null
+++ b/src/proguard/evaluation/ConstantValueFactory.java
@@ -0,0 +1,113 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This class creates Value instance that correspond to specified constant pool
+ * entries.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantValueFactory
+extends SimplifiedVisitor
+implements ConstantVisitor
+{
+ protected final ValueFactory valueFactory;
+
+ // Field acting as a parameter for the ConstantVisitor methods.
+ protected Value value;
+
+
+ public ConstantValueFactory(ValueFactory valueFactory)
+ {
+ this.valueFactory = valueFactory;
+ }
+
+
+ /**
+ * Returns the Value of the constant pool element at the given index.
+ */
+ public Value constantValue(Clazz clazz,
+ int constantIndex)
+ {
+ // Visit the constant pool entry to get its return value.
+ clazz.constantPoolEntryAccept(constantIndex, this);
+
+ return value;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
+ {
+ value = valueFactory.createIntegerValue(integerConstant.getValue());
+ }
+
+ public void visitLongConstant(Clazz clazz, LongConstant longConstant)
+ {
+ value = valueFactory.createLongValue(longConstant.getValue());
+ }
+
+ public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
+ {
+ value = valueFactory.createFloatValue(floatConstant.getValue());
+ }
+
+ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
+ {
+ value = valueFactory.createDoubleValue(doubleConstant.getValue());
+ }
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING,
+ stringConstant.javaLangStringClass,
+ false);
+ }
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE,
+ methodHandleConstant.javaLangInvokeMethodHandleClass,
+ false);
+ }
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ value = valueFactory.createReferenceValue(classConstant.getName(clazz),
+ classConstant.referencedClass,
+ false);
+ }
+
+ public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
+ {
+ value = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE,
+ methodTypeConstant.javaLangInvokeMethodTypeClass,
+ false);
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/evaluation/InvocationUnit.java b/src/proguard/evaluation/InvocationUnit.java
index cb4d3c5..e526b35 100644
--- a/src/proguard/evaluation/InvocationUnit.java
+++ b/src/proguard/evaluation/InvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/Processor.java b/src/proguard/evaluation/Processor.java
index 74afd0b..3bfc5f3 100644
--- a/src/proguard/evaluation/Processor.java
+++ b/src/proguard/evaluation/Processor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,11 +22,8 @@ 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.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
import proguard.evaluation.value.*;
/**
@@ -36,9 +33,7 @@ import proguard.evaluation.value.*;
* @author Eric Lafortune
*/
public class Processor
-extends SimplifiedVisitor
-implements InstructionVisitor,
- ConstantVisitor
+implements InstructionVisitor
{
private final Variables variables;
private final Stack stack;
@@ -46,9 +41,8 @@ implements InstructionVisitor,
private final BranchUnit branchUnit;
private final InvocationUnit invocationUnit;
- // Fields acting as parameters for the ConstantVisitor methods.
- private boolean handleClassConstantAsClassValue;
- private Value cpValue;
+ private final ConstantValueFactory constantValueFactory;
+ private final ClassConstantValueFactory classConstantValueFactory;
/**
@@ -69,6 +63,9 @@ implements InstructionVisitor,
this.valueFactory = valueFactory;
this.branchUnit = branchUnit;
this.invocationUnit = invocationUnit;
+
+ constantValueFactory = new ConstantValueFactory(valueFactory);
+ classConstantValueFactory = new ClassConstantValueFactory(valueFactory);
}
@@ -561,7 +558,7 @@ implements InstructionVisitor,
case InstructionConstants.OP_LDC:
case InstructionConstants.OP_LDC_W:
case InstructionConstants.OP_LDC2_W:
- stack.push(cpValue(clazz, constantIndex, true));
+ stack.push(classConstantValueFactory.constantValue(clazz, constantIndex));
break;
case InstructionConstants.OP_GETSTATIC:
@@ -572,16 +569,17 @@ implements InstructionVisitor,
case InstructionConstants.OP_INVOKESPECIAL:
case InstructionConstants.OP_INVOKESTATIC:
case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack);
break;
case InstructionConstants.OP_NEW:
- stack.push(cpValue(clazz, constantIndex).referenceValue());
+ stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
break;
case InstructionConstants.OP_ANEWARRAY:
{
- ReferenceValue referenceValue = cpValue(clazz, constantIndex).referenceValue();
+ ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(),
referenceValue.getReferencedClass(),
@@ -594,14 +592,14 @@ implements InstructionVisitor,
ReferenceValue castValue = stack.apop();
ReferenceValue castResultValue =
castValue.isNull() == Value.ALWAYS ? castValue :
- castValue.isNull() == Value.NEVER ? cpValue(clazz, constantIndex).referenceValue() :
- cpValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
+ castValue.isNull() == Value.NEVER ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() :
+ constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
stack.push(castResultValue);
break;
case InstructionConstants.OP_INSTANCEOF:
{
- ReferenceValue referenceValue = cpValue(clazz, constantIndex).referenceValue();
+ ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
int instanceOf = stack.apop().instanceOf(referenceValue.getType(),
referenceValue.getReferencedClass());
@@ -621,7 +619,7 @@ implements InstructionVisitor,
IntegerValue arrayLength = stack.ipop();
}
- stack.push(cpValue(clazz, constantIndex).referenceValue());
+ stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
break;
}
@@ -907,73 +905,4 @@ implements InstructionVisitor,
}
}
}
-
-
- // Implementations for ConstantVisitor.
-
- public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
- {
- cpValue = valueFactory.createIntegerValue(integerConstant.getValue());
- }
-
- public void visitLongConstant(Clazz clazz, LongConstant longConstant)
- {
- cpValue = valueFactory.createLongValue(longConstant.getValue());
- }
-
- public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
- {
- cpValue = valueFactory.createFloatValue(floatConstant.getValue());
- }
-
- public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
- {
- cpValue = valueFactory.createDoubleValue(doubleConstant.getValue());
- }
-
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
- {
- cpValue = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING,
- stringConstant.javaLangStringClass,
- false);
- }
-
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
- {
- cpValue = handleClassConstantAsClassValue ?
- valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS,
- classConstant.javaLangClassClass,
- false) :
- valueFactory.createReferenceValue(classConstant.getName(clazz),
- classConstant.referencedClass,
- false);
- }
-
-
- // Small utility methods.
-
- /**
- * Returns the Value of the constant pool element at the given index.
- */
- private Value cpValue(Clazz clazz,
- int constantIndex)
- {
- return cpValue(clazz, constantIndex, false);
- }
-
-
- /**
- * Returns the Value of the constant pool element at the given index.
- */
- private Value cpValue(Clazz clazz,
- int constantIndex,
- boolean handleClassConstantAsClassValue)
- {
- this.handleClassConstantAsClassValue = handleClassConstantAsClassValue;
-
- // Visit the constant pool entry to get its return value.
- clazz.constantPoolEntryAccept(constantIndex, this);
-
- return cpValue;
- }
}
diff --git a/src/proguard/evaluation/Stack.java b/src/proguard/evaluation/Stack.java
index 2808e62..c449e86 100644
--- a/src/proguard/evaluation/Stack.java
+++ b/src/proguard/evaluation/Stack.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,6 +22,8 @@ package proguard.evaluation;
import proguard.evaluation.value.*;
+import java.util.Arrays;
+
/**
* This class represents an operand stack that contains Value
* objects.
@@ -163,10 +165,7 @@ public class Stack
public void clear()
{
// Clear the stack contents.
- for (int index = 0; index < currentSize; index++)
- {
- values[index] = null;
- }
+ Arrays.fill(values, 0, currentSize, null);
currentSize = 0;
}
diff --git a/src/proguard/evaluation/TracedStack.java b/src/proguard/evaluation/TracedStack.java
index c24f783..08778a1 100644
--- a/src/proguard/evaluation/TracedStack.java
+++ b/src/proguard/evaluation/TracedStack.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/TracedVariables.java b/src/proguard/evaluation/TracedVariables.java
index 1ae6ba6..fef54e1 100644
--- a/src/proguard/evaluation/TracedVariables.java
+++ b/src/proguard/evaluation/TracedVariables.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -30,9 +30,6 @@ import proguard.evaluation.value.Value;
* stores. It then generalizes a given collected Value with the producer Value
* of each Value it loads. The producer Value and the initial collected Value
* can be set; the generalized collected Value can be retrieved.
- *
- * In addition, an initialization index can be reset and retrieved, pointing
- * to the most recent variable that has been initialized by a store operation.
*
* @author Eric Lafortune
*/
@@ -43,7 +40,6 @@ public class TracedVariables extends Variables
private Value producerValue;
private Variables producerVariables;
- private int initializationIndex;
/**
@@ -77,24 +73,6 @@ public class TracedVariables extends Variables
}
- /**
- * Resets the initialization index.
- */
- public void resetInitialization()
- {
- initializationIndex = NONE;
- }
-
-
- /**
- * Returns the most recent initialization index since it has been reset.
- */
- public int getInitializationIndex()
- {
- return initializationIndex;
- }
-
-
/**
* Gets the producer Value for the specified variable, without disturbing it.
* @param index the variable index.
@@ -164,14 +142,6 @@ public class TracedVariables extends Variables
public void store(int index, Value value)
{
- // Is this store operation an initialization of the variable?
- Value previousValue = super.load(index);
- if (previousValue == null ||
- previousValue.computationalType() != value.computationalType())
- {
- initializationIndex = index;
- }
-
// Store the value itself in the variable.
super.store(index, value);
diff --git a/src/proguard/evaluation/Variables.java b/src/proguard/evaluation/Variables.java
index 4496aaa..16b39e7 100644
--- a/src/proguard/evaluation/Variables.java
+++ b/src/proguard/evaluation/Variables.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,6 +22,8 @@ package proguard.evaluation;
import proguard.evaluation.value.*;
+import java.util.Arrays;
+
/**
* This class represents a local variable frame that contains \
+ With this GUI, you can create, load, modify, and save ProGuard configurations.\
+ \
With the ReTrace part of this GUI you can de-obfuscate your stack traces.\
- \n\n\
+ \
ProGuard and ReTrace are written and maintained by Eric Lafortune.\
- \n\n\
+ \
+ Official site at Sourceforge: \
+ http://proguard.sourceforge.net/\
+ \
Distributed under the GNU General Public License.\
- \n\
- Copyright (c) 2002-2009.
+ Value
* objects. Values are generalizations of all values that have been stored in
@@ -75,10 +77,7 @@ public class Variables
else
{
// Clear the variables.
- for (int index = 0; index < values.length; index++)
- {
- values[index] = null;
- }
+ Arrays.fill(values, null);
}
this.size = size;
diff --git a/src/proguard/evaluation/value/Category1Value.java b/src/proguard/evaluation/value/Category1Value.java
index b8c5db2..a5ebf86 100644
--- a/src/proguard/evaluation/value/Category1Value.java
+++ b/src/proguard/evaluation/value/Category1Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/Category2Value.java b/src/proguard/evaluation/value/Category2Value.java
index 65916c7..2be6e71 100644
--- a/src/proguard/evaluation/value/Category2Value.java
+++ b/src/proguard/evaluation/value/Category2Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ComparisonValue.java b/src/proguard/evaluation/value/ComparisonValue.java
index e4e2e02..abbf31c 100644
--- a/src/proguard/evaluation/value/ComparisonValue.java
+++ b/src/proguard/evaluation/value/ComparisonValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -35,11 +35,11 @@ final class ComparisonValue extends SpecificIntegerValue
/**
* Creates a new comparison integer value of the two given scalar values.
*/
- public ComparisonValue(Value integerValue1,
- Value integerValue2)
+ public ComparisonValue(Value value1,
+ Value value2)
{
- this.value1 = integerValue1;
- this.value2 = integerValue2;
+ this.value1 = value1;
+ this.value2 = value2;
}
diff --git a/src/proguard/evaluation/value/CompositeDoubleValue.java b/src/proguard/evaluation/value/CompositeDoubleValue.java
index a6d48ef..be739ed 100644
--- a/src/proguard/evaluation/value/CompositeDoubleValue.java
+++ b/src/proguard/evaluation/value/CompositeDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/CompositeFloatValue.java b/src/proguard/evaluation/value/CompositeFloatValue.java
index 4df890a..0961068 100644
--- a/src/proguard/evaluation/value/CompositeFloatValue.java
+++ b/src/proguard/evaluation/value/CompositeFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -36,7 +36,7 @@ final class CompositeFloatValue extends SpecificFloatValue
private final FloatValue floatValue1;
- private final byte operation;
+ private final byte operation;
private final FloatValue floatValue2;
@@ -45,11 +45,11 @@ final class CompositeFloatValue extends SpecificFloatValue
* and the given operation.
*/
public CompositeFloatValue(FloatValue floatValue1,
- byte operation,
- FloatValue floatValue2)
+ byte operation,
+ FloatValue floatValue2)
{
this.floatValue1 = floatValue1;
- this.operation = operation;
+ this.operation = operation;
this.floatValue2 = floatValue2;
}
diff --git a/src/proguard/evaluation/value/CompositeIntegerValue.java b/src/proguard/evaluation/value/CompositeIntegerValue.java
index 6d4f59c..97caa2f 100644
--- a/src/proguard/evaluation/value/CompositeIntegerValue.java
+++ b/src/proguard/evaluation/value/CompositeIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/CompositeLongValue.java b/src/proguard/evaluation/value/CompositeLongValue.java
index 7f63211..3b8a97f 100644
--- a/src/proguard/evaluation/value/CompositeLongValue.java
+++ b/src/proguard/evaluation/value/CompositeLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedByteValue.java b/src/proguard/evaluation/value/ConvertedByteValue.java
index 7ab5d0a..eb1a350 100644
--- a/src/proguard/evaluation/value/ConvertedByteValue.java
+++ b/src/proguard/evaluation/value/ConvertedByteValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedCharacterValue.java b/src/proguard/evaluation/value/ConvertedCharacterValue.java
index 76568d1..a491bed 100644
--- a/src/proguard/evaluation/value/ConvertedCharacterValue.java
+++ b/src/proguard/evaluation/value/ConvertedCharacterValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedDoubleValue.java b/src/proguard/evaluation/value/ConvertedDoubleValue.java
index a6afe34..65fab84 100644
--- a/src/proguard/evaluation/value/ConvertedDoubleValue.java
+++ b/src/proguard/evaluation/value/ConvertedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedFloatValue.java b/src/proguard/evaluation/value/ConvertedFloatValue.java
index 33683b7..e74ec8d 100644
--- a/src/proguard/evaluation/value/ConvertedFloatValue.java
+++ b/src/proguard/evaluation/value/ConvertedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedIntegerValue.java b/src/proguard/evaluation/value/ConvertedIntegerValue.java
index aecb533..273b5a1 100644
--- a/src/proguard/evaluation/value/ConvertedIntegerValue.java
+++ b/src/proguard/evaluation/value/ConvertedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedLongValue.java b/src/proguard/evaluation/value/ConvertedLongValue.java
index ec97008..5cb9104 100644
--- a/src/proguard/evaluation/value/ConvertedLongValue.java
+++ b/src/proguard/evaluation/value/ConvertedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ConvertedShortValue.java b/src/proguard/evaluation/value/ConvertedShortValue.java
index ab79b49..cef2a20 100644
--- a/src/proguard/evaluation/value/ConvertedShortValue.java
+++ b/src/proguard/evaluation/value/ConvertedShortValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/DoubleValue.java b/src/proguard/evaluation/value/DoubleValue.java
index e39ee5c..6630b2f 100644
--- a/src/proguard/evaluation/value/DoubleValue.java
+++ b/src/proguard/evaluation/value/DoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -342,11 +342,6 @@ public abstract class DoubleValue extends Category2Value
return this;
}
- public Value refresh()
- {
- return this;
- }
-
public final Value generalize(Value other)
{
return this.generalize(other.doubleValue());
diff --git a/src/proguard/evaluation/value/FloatValue.java b/src/proguard/evaluation/value/FloatValue.java
index b30e395..6dc8bee 100644
--- a/src/proguard/evaluation/value/FloatValue.java
+++ b/src/proguard/evaluation/value/FloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IdentifiedDoubleValue.java b/src/proguard/evaluation/value/IdentifiedDoubleValue.java
index 4009c6e..4ff2466 100644
--- a/src/proguard/evaluation/value/IdentifiedDoubleValue.java
+++ b/src/proguard/evaluation/value/IdentifiedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IdentifiedFloatValue.java b/src/proguard/evaluation/value/IdentifiedFloatValue.java
index 87bed64..c8349bc 100644
--- a/src/proguard/evaluation/value/IdentifiedFloatValue.java
+++ b/src/proguard/evaluation/value/IdentifiedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IdentifiedIntegerValue.java b/src/proguard/evaluation/value/IdentifiedIntegerValue.java
index 66e88ee..6c3ee5d 100644
--- a/src/proguard/evaluation/value/IdentifiedIntegerValue.java
+++ b/src/proguard/evaluation/value/IdentifiedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IdentifiedLongValue.java b/src/proguard/evaluation/value/IdentifiedLongValue.java
index eea1816..e0b68f2 100644
--- a/src/proguard/evaluation/value/IdentifiedLongValue.java
+++ b/src/proguard/evaluation/value/IdentifiedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IdentifiedReferenceValue.java b/src/proguard/evaluation/value/IdentifiedReferenceValue.java
index cb5efc1..5cfbd60 100644
--- a/src/proguard/evaluation/value/IdentifiedReferenceValue.java
+++ b/src/proguard/evaluation/value/IdentifiedReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -57,6 +57,17 @@ final class IdentifiedReferenceValue extends ReferenceValue
}
+ // Implementations of binary methods of ReferenceValue.
+
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ // Remove the ID if both values don't share the same ID.
+ return this.equals(other) ?
+ this :
+ new ReferenceValue(type, referencedClass, mayBeNull).generalize(other);
+ }
+
+
// Implementations for Value.
public boolean isSpecific()
diff --git a/src/proguard/evaluation/value/IdentifiedValueFactory.java b/src/proguard/evaluation/value/IdentifiedValueFactory.java
index 2b14e72..be5c885 100644
--- a/src/proguard/evaluation/value/IdentifiedValueFactory.java
+++ b/src/proguard/evaluation/value/IdentifiedValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/InstructionOffsetValue.java b/src/proguard/evaluation/value/InstructionOffsetValue.java
index 10b5a6f..07a44ee 100644
--- a/src/proguard/evaluation/value/InstructionOffsetValue.java
+++ b/src/proguard/evaluation/value/InstructionOffsetValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/IntegerValue.java b/src/proguard/evaluation/value/IntegerValue.java
index 508c5f5..b1824c6 100644
--- a/src/proguard/evaluation/value/IntegerValue.java
+++ b/src/proguard/evaluation/value/IntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/LongValue.java b/src/proguard/evaluation/value/LongValue.java
index f7ba162..e23c13c 100644
--- a/src/proguard/evaluation/value/LongValue.java
+++ b/src/proguard/evaluation/value/LongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/NegatedDoubleValue.java b/src/proguard/evaluation/value/NegatedDoubleValue.java
index 2bc9423..7619be7 100644
--- a/src/proguard/evaluation/value/NegatedDoubleValue.java
+++ b/src/proguard/evaluation/value/NegatedDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/NegatedFloatValue.java b/src/proguard/evaluation/value/NegatedFloatValue.java
index 0ddf4ab..51b5074 100644
--- a/src/proguard/evaluation/value/NegatedFloatValue.java
+++ b/src/proguard/evaluation/value/NegatedFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/NegatedIntegerValue.java b/src/proguard/evaluation/value/NegatedIntegerValue.java
index a89a2d9..1729083 100644
--- a/src/proguard/evaluation/value/NegatedIntegerValue.java
+++ b/src/proguard/evaluation/value/NegatedIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/NegatedLongValue.java b/src/proguard/evaluation/value/NegatedLongValue.java
index c3b22bb..7510524 100644
--- a/src/proguard/evaluation/value/NegatedLongValue.java
+++ b/src/proguard/evaluation/value/NegatedLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ParticularDoubleValue.java b/src/proguard/evaluation/value/ParticularDoubleValue.java
index 05bc559..e8c5aa7 100644
--- a/src/proguard/evaluation/value/ParticularDoubleValue.java
+++ b/src/proguard/evaluation/value/ParticularDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -79,17 +79,23 @@ final class ParticularDoubleValue extends SpecificDoubleValue
public DoubleValue add(DoubleValue other)
{
- return value == 0.0 ? other : other.add(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other : other.add(this);
+ return other.add(this);
}
public DoubleValue subtract(DoubleValue other)
{
- return value == 0.0 ? other.negate() : other.subtractFrom(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other.negate() : other.subtractFrom(this);
+ return other.subtractFrom(this);
}
public DoubleValue subtractFrom(DoubleValue other)
{
- return value == 0.0 ? other : other.subtract(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other : other.subtract(this);
+ return other.subtract(this);
}
public DoubleValue multiply(DoubleValue other)
@@ -128,7 +134,10 @@ final class ParticularDoubleValue extends SpecificDoubleValue
public DoubleValue generalize(ParticularDoubleValue other)
{
- return this.value == other.value ? this : ValueFactory.DOUBLE_VALUE;
+ // Also handle NaN and Infinity.
+ return Double.doubleToRawLongBits(this.value) ==
+ Double.doubleToRawLongBits(other.value) ?
+ this : ValueFactory.DOUBLE_VALUE;
}
public DoubleValue add(ParticularDoubleValue other)
@@ -191,8 +200,10 @@ final class ParticularDoubleValue extends SpecificDoubleValue
public boolean equals(Object object)
{
- return super.equals(object) &&
- this.value == ((ParticularDoubleValue)object).value;
+ // Also handle NaN and Infinity.
+ return super.equals(object) &&
+ Double.doubleToLongBits(this.value) ==
+ Double.doubleToLongBits(((ParticularDoubleValue)object).value);
}
diff --git a/src/proguard/evaluation/value/ParticularFloatValue.java b/src/proguard/evaluation/value/ParticularFloatValue.java
index 59e4357..cbdde31 100644
--- a/src/proguard/evaluation/value/ParticularFloatValue.java
+++ b/src/proguard/evaluation/value/ParticularFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -79,17 +79,23 @@ final class ParticularFloatValue extends SpecificFloatValue
public FloatValue add(FloatValue other)
{
- return value == 0.0 ? other : other.add(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other : other.add(this);
+ return other.add(this);
}
public FloatValue subtract(FloatValue other)
{
- return value == 0.0 ? other.negate() : other.subtractFrom(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other.negate() : other.subtractFrom(this);
+ return other.subtractFrom(this);
}
public FloatValue subtractFrom(FloatValue other)
{
- return value == 0.0 ? other : other.subtract(this);
+ // Careful: -0.0 + 0.0 == 0.0
+ //return value == 0.0 ? other : other.subtract(this);
+ return other.subtract(this);
}
public FloatValue multiply(FloatValue other)
@@ -128,7 +134,10 @@ final class ParticularFloatValue extends SpecificFloatValue
public FloatValue generalize(ParticularFloatValue other)
{
- return this.value == other.value ? this : ValueFactory.FLOAT_VALUE;
+ // Also handle NaN and Infinity.
+ return Float.floatToRawIntBits(this.value) ==
+ Float.floatToRawIntBits(other.value) ?
+ this : ValueFactory.FLOAT_VALUE;
}
public FloatValue add(ParticularFloatValue other)
@@ -191,8 +200,10 @@ final class ParticularFloatValue extends SpecificFloatValue
public boolean equals(Object object)
{
+ // Also handle NaN and Infinity.
return super.equals(object) &&
- this.value == ((ParticularFloatValue)object).value;
+ Float.floatToIntBits(this.value) ==
+ Float.floatToIntBits(((ParticularFloatValue)object).value);
}
diff --git a/src/proguard/evaluation/value/ParticularIntegerValue.java b/src/proguard/evaluation/value/ParticularIntegerValue.java
index 8a4ac1d..609e95f 100644
--- a/src/proguard/evaluation/value/ParticularIntegerValue.java
+++ b/src/proguard/evaluation/value/ParticularIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ParticularLongValue.java b/src/proguard/evaluation/value/ParticularLongValue.java
index 61d2e04..1903235 100644
--- a/src/proguard/evaluation/value/ParticularLongValue.java
+++ b/src/proguard/evaluation/value/ParticularLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ReferenceValue.java b/src/proguard/evaluation/value/ReferenceValue.java
index 418c6f8..4a52e82 100644
--- a/src/proguard/evaluation/value/ReferenceValue.java
+++ b/src/proguard/evaluation/value/ReferenceValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -280,11 +280,25 @@ public class ReferenceValue extends Category1Value
thisReferencedClass.hierarchyAccept(false, true, true, false,
new ClassCollector(thisSuperClasses));
+ int thisSuperClassesCount = thisSuperClasses.size();
+ if (thisSuperClassesCount == 0 &&
+ thisReferencedClass.getSuperName() != null)
+ {
+ throw new IllegalArgumentException("Can't find any super classes of ["+thisType+"] (not even immediate super class ["+thisReferencedClass.getSuperName()+"])");
+ }
+
// Collect the superclasses and interfaces of the other class.
Set otherSuperClasses = new HashSet();
otherReferencedClass.hierarchyAccept(false, true, true, false,
new ClassCollector(otherSuperClasses));
+ int otherSuperClassesCount = otherSuperClasses.size();
+ if (otherSuperClassesCount == 0 &&
+ otherReferencedClass.getSuperName() != null)
+ {
+ throw new IllegalArgumentException("Can't find any super classes of ["+otherType+"] (not even immediate super class ["+otherReferencedClass.getSuperName()+"])");
+ }
+
if (DEBUG)
{
System.out.println("ReferenceValue.generalize this ["+thisReferencedClass.getName()+"] with other ["+otherReferencedClass.getName()+"]");
@@ -302,7 +316,7 @@ public class ReferenceValue extends Category1Value
// Find a class that is a subclass of all common superclasses,
// or that at least has the maximum number of common superclasses.
- Clazz commonClazz = null;
+ Clazz commonClass = null;
int maximumSuperClassCount = -1;
@@ -317,31 +331,33 @@ public class ReferenceValue extends Category1Value
int superClassCount = superClassCount(commonSuperClass, thisSuperClasses);
if (maximumSuperClassCount < superClassCount ||
(maximumSuperClassCount == superClassCount &&
- commonClazz != null &&
- commonClazz.getName().compareTo(commonSuperClass.getName()) > 0))
+ commonClass != null &&
+ commonClass.getName().compareTo(commonSuperClass.getName()) > 0))
{
- commonClazz = commonSuperClass;
+ commonClass = commonSuperClass;
maximumSuperClassCount = superClassCount;
}
}
- if (commonClazz == null)
+ if (commonClass == null)
{
- throw new IllegalArgumentException("Can't find common super class of ["+thisType+"] and ["+otherType+"]");
+ throw new IllegalArgumentException("Can't find common super class of ["+
+ thisType +"] (with "+thisSuperClassesCount +" known super classes) and ["+
+ otherType+"] (with "+otherSuperClassesCount+" known super classes)");
}
if (DEBUG)
{
- System.out.println(" Best common class: ["+commonClazz.getName()+"]");
+ System.out.println(" Best common class: ["+commonClass.getName()+"]");
}
// TODO: Handle more difficult cases, with multiple global subclasses.
return new ReferenceValue(commonDimensionCount == 0 ?
- commonClazz.getName() :
- ClassUtil.internalArrayTypeFromClassName(commonClazz.getName(),
+ commonClass.getName() :
+ ClassUtil.internalArrayTypeFromClassName(commonClass.getName(),
commonDimensionCount),
- commonClazz,
+ commonClass,
mayBeNull);
}
}
@@ -402,8 +418,6 @@ public class ReferenceValue extends Category1Value
}
}
- //System.out.println("ReferenceValue.superClassCount: ["+subClass.getName()+"]: "+count);
-
return count;
}
diff --git a/src/proguard/evaluation/value/SpecificDoubleValue.java b/src/proguard/evaluation/value/SpecificDoubleValue.java
index 572d891..644f553 100644
--- a/src/proguard/evaluation/value/SpecificDoubleValue.java
+++ b/src/proguard/evaluation/value/SpecificDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -153,9 +153,12 @@ abstract class SpecificDoubleValue extends DoubleValue
public IntegerValue compare(SpecificDoubleValue other)
{
- return this.equals(other) ?
- SpecificValueFactory.INTEGER_VALUE_0 :
- new ComparisonValue(this, other);
+ return ValueFactory.INTEGER_VALUE;
+
+ // Not handling NaN properly.
+ //return this.equals(other) ?
+ // SpecificValueFactory.INTEGER_VALUE_0 :
+ // new ComparisonValue(this, other);
}
diff --git a/src/proguard/evaluation/value/SpecificFloatValue.java b/src/proguard/evaluation/value/SpecificFloatValue.java
index 3bc3679..d88baa3 100644
--- a/src/proguard/evaluation/value/SpecificFloatValue.java
+++ b/src/proguard/evaluation/value/SpecificFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -153,9 +153,12 @@ abstract class SpecificFloatValue extends FloatValue
public IntegerValue compare(SpecificFloatValue other)
{
- return this.equals(other) ?
- SpecificValueFactory.INTEGER_VALUE_0 :
- new ComparisonValue(this, other);
+ return ValueFactory.INTEGER_VALUE;
+
+ // Not handling NaN properly.
+ //return this.equals(other) ?
+ // SpecificValueFactory.INTEGER_VALUE_0 :
+ // new ComparisonValue(this, other);
}
diff --git a/src/proguard/evaluation/value/SpecificIntegerValue.java b/src/proguard/evaluation/value/SpecificIntegerValue.java
index 57c48b1..81f8646 100644
--- a/src/proguard/evaluation/value/SpecificIntegerValue.java
+++ b/src/proguard/evaluation/value/SpecificIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/SpecificLongValue.java b/src/proguard/evaluation/value/SpecificLongValue.java
index 5e12bde..15138b4 100644
--- a/src/proguard/evaluation/value/SpecificLongValue.java
+++ b/src/proguard/evaluation/value/SpecificLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/SpecificValueFactory.java b/src/proguard/evaluation/value/SpecificValueFactory.java
index 72dd1d3..f761938 100644
--- a/src/proguard/evaluation/value/SpecificValueFactory.java
+++ b/src/proguard/evaluation/value/SpecificValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -45,6 +45,10 @@ extends ValueFactory
static final DoubleValue DOUBLE_VALUE_1 = new ParticularDoubleValue(1.0);
+ private static int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f);
+ private static long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0);
+
+
// Implementations for ValueFactory.
public IntegerValue createIntegerValue(int value)
@@ -73,7 +77,9 @@ extends ValueFactory
public FloatValue createFloatValue(float value)
{
- return value == 0.0f ? FLOAT_VALUE_0 :
+ // Make sure to distinguish between +0.0 and -0.0.
+ return value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS
+ ? FLOAT_VALUE_0 :
value == 1.0f ? FLOAT_VALUE_1 :
value == 2.0f ? FLOAT_VALUE_2 :
new ParticularFloatValue(value);
@@ -82,7 +88,9 @@ extends ValueFactory
public DoubleValue createDoubleValue(double value)
{
- return value == 0.0 ? DOUBLE_VALUE_0 :
+ // Make sure to distinguish between +0.0 and -0.0.
+ return value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS
+ ? DOUBLE_VALUE_0 :
value == 1.0 ? DOUBLE_VALUE_1 :
new ParticularDoubleValue(value);
}
diff --git a/src/proguard/evaluation/value/TopValue.java b/src/proguard/evaluation/value/TopValue.java
index 048a1ff..c7320fa 100644
--- a/src/proguard/evaluation/value/TopValue.java
+++ b/src/proguard/evaluation/value/TopValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/UnknownDoubleValue.java b/src/proguard/evaluation/value/UnknownDoubleValue.java
index 79cc4de..f8bad9a 100644
--- a/src/proguard/evaluation/value/UnknownDoubleValue.java
+++ b/src/proguard/evaluation/value/UnknownDoubleValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/UnknownFloatValue.java b/src/proguard/evaluation/value/UnknownFloatValue.java
index 3f9622a..464ceed 100644
--- a/src/proguard/evaluation/value/UnknownFloatValue.java
+++ b/src/proguard/evaluation/value/UnknownFloatValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -120,6 +120,6 @@ public class UnknownFloatValue extends FloatValue
public String toString()
{
- return "d";
+ return "f";
}
}
\ No newline at end of file
diff --git a/src/proguard/evaluation/value/UnknownIntegerValue.java b/src/proguard/evaluation/value/UnknownIntegerValue.java
index be5e79d..b273b12 100644
--- a/src/proguard/evaluation/value/UnknownIntegerValue.java
+++ b/src/proguard/evaluation/value/UnknownIntegerValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/UnknownLongValue.java b/src/proguard/evaluation/value/UnknownLongValue.java
index 83a75dc..ee315be 100644
--- a/src/proguard/evaluation/value/UnknownLongValue.java
+++ b/src/proguard/evaluation/value/UnknownLongValue.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/Value.java b/src/proguard/evaluation/value/Value.java
index e24ece1..f8d9327 100644
--- a/src/proguard/evaluation/value/Value.java
+++ b/src/proguard/evaluation/value/Value.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/evaluation/value/ValueFactory.java b/src/proguard/evaluation/value/ValueFactory.java
index 8415381..c94ac65 100644
--- a/src/proguard/evaluation/value/ValueFactory.java
+++ b/src/proguard/evaluation/value/ValueFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gradle/ProGuardTask.java b/src/proguard/gradle/ProGuardTask.java
new file mode 100644
index 0000000..f5f96e8
--- /dev/null
+++ b/src/proguard/gradle/ProGuardTask.java
@@ -0,0 +1,1532 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.gradle;
+
+import groovy.lang.Closure;
+import org.gradle.api.*;
+import org.gradle.api.file.*;
+import org.gradle.api.logging.*;
+import org.gradle.api.tasks.*;
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.util.ListUtil;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This Task allows to configure and run ProGuard from Gradle.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuardTask extends DefaultTask
+{
+ // Accumulated input and output, for the sake of Gradle's lazy file
+ // resolution and lazy task execution.
+ private final List inJarFiles = new ArrayList();
+ private final List inJarFilters = new ArrayList();
+ private final List outJarFiles = new ArrayList();
+ private final List outJarFilters = new ArrayList();
+ private final List inJarCounts = new ArrayList();
+ private final List libraryJarFiles = new ArrayList();
+ private final List libraryJarFilters = new ArrayList();
+ private final List configurationFiles = new ArrayList();
+
+ // Accumulated configuration.
+ private final Configuration configuration = new Configuration();
+
+ // Field acting as a parameter for the class member specification methods.
+ private ClassSpecification classSpecification;
+
+
+ // Gradle task inputs and outputs, because annotations on the List fields
+ // (private or not) don't seem to work. Private methods don't work either,
+ // but package visible or protected methods are ok.
+
+ @InputFiles
+ protected FileCollection getInJarFiles() throws ParseException
+ {
+ return getProject().files(inJarFiles);
+ }
+
+ @Optional @OutputFiles
+ protected FileCollection getOutJarFiles() throws ParseException
+ {
+ return getProject().files(outJarFiles);
+ }
+
+ @InputFiles
+ protected FileCollection getLibraryJarFiles() throws ParseException
+ {
+ return getProject().files(libraryJarFiles);
+ }
+
+ @InputFiles
+ protected FileCollection getConfigurationFiles() throws ParseException
+ {
+ return getProject().files(configurationFiles);
+ }
+
+
+ // Gradle task settings corresponding to all ProGuard options.
+
+ public void configuration(Object configurationFiles)
+ throws ParseException, IOException
+ {
+ // Just collect the arguments, so they can be resolved lazily.
+ this.configurationFiles.add(configurationFiles);
+ }
+
+ public void injars(Object inJarFiles)
+ throws ParseException
+ {
+ injars(null, inJarFiles);
+ }
+
+ public void injars(Map filterArgs, Object inJarFiles)
+ throws ParseException
+ {
+ // Just collect the arguments, so they can be resolved lazily.
+ this.inJarFiles.add(inJarFiles);
+ this.inJarFilters.add(filterArgs);
+ }
+
+ public void outjars(Object outJarFiles)
+ throws ParseException
+ {
+ outjars(null, outJarFiles);
+ }
+
+ public void outjars(Map filterArgs, Object outJarFiles)
+ throws ParseException
+ {
+ // Just collect the arguments, so they can be resolved lazily.
+ this.outJarFiles.add(getProject().file(outJarFiles));
+ this.outJarFilters.add(filterArgs);
+ this.inJarCounts.add(Integer.valueOf(inJarFiles.size()));
+ }
+
+ public void libraryjars(Object libraryJarFiles)
+ throws ParseException
+ {
+ libraryjars(null, libraryJarFiles);
+ }
+
+ public void libraryjars(Map filterArgs, Object libraryJarFiles)
+ throws ParseException
+ {
+ // Just collect the arguments, so they can be resolved lazily.
+ this.libraryJarFiles.add(libraryJarFiles);
+ this.libraryJarFilters.add(filterArgs);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getskipnonpubliclibraryclasses()
+ {
+ skipnonpubliclibraryclasses();
+ return null;
+ }
+
+ public void skipnonpubliclibraryclasses()
+ {
+ configuration.skipNonPublicLibraryClasses = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontskipnonpubliclibraryclassmembers()
+ {
+ dontskipnonpubliclibraryclassmembers();
+ return null;
+ }
+
+ public void dontskipnonpubliclibraryclassmembers()
+ {
+ configuration.skipNonPublicLibraryClassMembers = false;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getkeepdirectories()
+ {
+ keepdirectories();
+ return null;
+ }
+
+ public void keepdirectories()
+ {
+ keepdirectories(null);
+ }
+
+ public void keepdirectories(String filter)
+ {
+ configuration.keepDirectories =
+ extendFilter(configuration.keepDirectories, filter);
+ }
+
+ public void target(String targetClassVersion)
+ {
+ configuration.targetClassVersion =
+ ClassUtil.internalClassVersion(targetClassVersion);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getforceprocessing()
+ {
+ forceprocessing();
+ return null;
+ }
+
+ public void forceprocessing()
+ {
+ configuration.lastModified = Long.MAX_VALUE;
+ }
+
+ public void keep(String classSpecificationString)
+ throws ParseException
+ {
+ keep(null, classSpecificationString);
+ }
+
+ public void keep(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ true,
+ false,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keep(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keep(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keep(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ true,
+ false,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ public void keepclassmembers(String classSpecificationString)
+ throws ParseException
+ {
+ keepclassmembers(null, classSpecificationString);
+ }
+
+ public void keepclassmembers(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ false,
+ false,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keepclassmembers(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keepclassmembers(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keepclassmembers(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ false,
+ false,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ public void keepclasseswithmembers(String classSpecificationString)
+ throws ParseException
+ {
+ keepclasseswithmembers(null, classSpecificationString);
+ }
+
+ public void keepclasseswithmembers(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ false,
+ true,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keepclasseswithmembers(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keepclasseswithmembers(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keepclasseswithmembers(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(false,
+ false,
+ true,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ public void keepnames(String classSpecificationString)
+ throws ParseException
+ {
+ keepnames(null, classSpecificationString);
+ }
+
+ public void keepnames(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ true,
+ false,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keepnames(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keepnames(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keepnames(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ true,
+ false,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ public void keepclassmembernames(String classSpecificationString)
+ throws ParseException
+ {
+ keepclassmembernames(null, classSpecificationString);
+ }
+
+ public void keepclassmembernames(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ false,
+ false,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keepclassmembernames(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keepclassmembernames(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keepclassmembernames(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ false,
+ false,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ public void keepclasseswithmembernames(String classSpecificationString)
+ throws ParseException
+ {
+ keepclasseswithmembernames(null, classSpecificationString);
+ }
+
+ public void keepclasseswithmembernames(Map keepArgs,
+ String classSpecificationString)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ false,
+ true,
+ keepArgs,
+ classSpecificationString));
+ }
+
+ public void keepclasseswithmembernames(Map keepClassSpecificationArgs)
+ throws ParseException
+ {
+ keepclasseswithmembernames(keepClassSpecificationArgs, (Closure)null);
+ }
+
+ public void keepclasseswithmembernames(Map keepClassSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.keep =
+ extendClassSpecifications(configuration.keep,
+ createKeepClassSpecification(true,
+ false,
+ true,
+ keepClassSpecificationArgs,
+ classMembersClosure));
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getprintseeds()
+ {
+ printseeds();
+ return null;
+ }
+
+ public void printseeds()
+ {
+ configuration.printSeeds = Configuration.STD_OUT;
+ }
+
+ public void printseeds(Object printSeeds)
+ throws ParseException
+ {
+ configuration.printSeeds = getProject().file(printSeeds);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontshrink()
+ {
+ dontshrink();
+ return null;
+ }
+
+ public void dontshrink()
+ {
+ configuration.shrink = false;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getprintusage()
+ {
+ printusage();
+ return null;
+ }
+
+ public void printusage()
+ {
+ configuration.printUsage = Configuration.STD_OUT;
+ }
+
+ public void printusage(Object printUsage)
+ throws ParseException
+ {
+ configuration.printUsage = getProject().file(printUsage);
+ }
+
+ public void whyareyoukeeping(String classSpecificationString)
+ throws ParseException
+ {
+ configuration.whyAreYouKeeping =
+ extendClassSpecifications(configuration.whyAreYouKeeping,
+ createClassSpecification(classSpecificationString));
+ }
+
+ public void whyareyoukeeping(Map classSpecificationArgs)
+ throws ParseException
+ {
+ whyareyoukeeping(classSpecificationArgs, null);
+ }
+
+ public void whyareyoukeeping(Map classSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.whyAreYouKeeping =
+ extendClassSpecifications(configuration.whyAreYouKeeping,
+ createClassSpecification(classSpecificationArgs,
+ classMembersClosure));
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontoptimize()
+ {
+ dontoptimize();
+ return null;
+ }
+
+ public void dontoptimize()
+ {
+ configuration.optimize = false;
+ }
+
+ public void optimizations(String filter)
+ {
+ configuration.optimizations =
+ extendFilter(configuration.optimizations, filter);
+ }
+
+
+ public void optimizationpasses(int optimizationPasses)
+ {
+ configuration.optimizationPasses = optimizationPasses;
+ }
+
+ public void assumenosideeffects(String classSpecificationString)
+ throws ParseException
+ {
+ configuration.assumeNoSideEffects =
+ extendClassSpecifications(configuration.assumeNoSideEffects,
+ createClassSpecification(classSpecificationString));
+ }
+
+ public void assumenosideeffects(Map classSpecificationArgs,
+ Closure classMembersClosure)
+ throws ParseException
+ {
+ configuration.assumeNoSideEffects =
+ extendClassSpecifications(configuration.assumeNoSideEffects,
+ createClassSpecification(classSpecificationArgs,
+ classMembersClosure));
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getallowaccessmodification()
+ {
+ allowaccessmodification();
+ return null;
+ }
+
+ public void allowaccessmodification()
+ {
+ configuration.allowAccessModification = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getmergeinterfacesaggressively()
+ {
+ mergeinterfacesaggressively();
+ return null;
+ }
+
+ public void mergeinterfacesaggressively()
+ {
+ configuration.mergeInterfacesAggressively = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontobfuscate()
+ {
+ dontobfuscate();
+ return null;
+ }
+
+ public void dontobfuscate()
+ {
+ configuration.obfuscate = false;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getprintmapping()
+ {
+ printmapping();
+ return null;
+ }
+
+ public void printmapping()
+ {
+ configuration.printMapping = Configuration.STD_OUT;
+ }
+
+ public void printmapping(Object printMapping)
+ throws ParseException
+ {
+ configuration.printMapping = getProject().file(printMapping);
+ }
+
+ public void applymapping(Object applyMapping)
+ throws ParseException
+ {
+ configuration.applyMapping = getProject().file(applyMapping);
+ }
+
+ public void obfuscationdictionary(Object obfuscationDictionary)
+ throws ParseException
+ {
+ configuration.obfuscationDictionary =
+ getProject().file(obfuscationDictionary);
+ }
+
+ public void classobfuscationdictionary(Object classObfuscationDictionary)
+ throws ParseException
+ {
+ configuration.classObfuscationDictionary =
+ getProject().file(classObfuscationDictionary);
+ }
+
+ public void packageobfuscationdictionary(Object packageObfuscationDictionary)
+ throws ParseException
+ {
+ configuration.packageObfuscationDictionary =
+ getProject().file(packageObfuscationDictionary);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getoverloadaggressively()
+ {
+ overloadaggressively();
+ return null;
+ }
+
+ public void overloadaggressively()
+ {
+ configuration.overloadAggressively = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getuseuniqueclassmembernames()
+ {
+ useuniqueclassmembernames();
+ return null;
+ }
+
+ public void useuniqueclassmembernames()
+ {
+ configuration.useUniqueClassMemberNames = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontusemixedcaseclassnames()
+ {
+ dontusemixedcaseclassnames();
+ return null;
+ }
+
+ public void dontusemixedcaseclassnames()
+ {
+ configuration.useMixedCaseClassNames = false;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getkeeppackagenames()
+ {
+ keeppackagenames();
+ return null;
+ }
+
+ public void keeppackagenames()
+ {
+ keeppackagenames(null);
+ }
+
+ public void keeppackagenames(String filter)
+ {
+ configuration.keepPackageNames =
+ extendFilter(configuration.keepPackageNames, filter, true);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getflattenpackagehierarchy()
+ {
+ flattenpackagehierarchy();
+ return null;
+ }
+
+ public void flattenpackagehierarchy()
+ {
+ flattenpackagehierarchy("");
+ }
+
+ public void flattenpackagehierarchy(String flattenPackageHierarchy)
+ {
+ configuration.flattenPackageHierarchy =
+ ClassUtil.internalClassName(flattenPackageHierarchy);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getrepackageclasses()
+ {
+ repackageclasses();
+ return null;
+ }
+
+ public void repackageclasses()
+ {
+ repackageclasses("");
+ }
+
+ public void repackageclasses(String repackageClasses)
+ {
+ configuration.repackageClasses =
+ ClassUtil.internalClassName(repackageClasses);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getkeepattributes()
+ {
+ keepattributes();
+ return null;
+ }
+
+ public void keepattributes()
+ {
+ keepattributes(null);
+ }
+
+ public void keepattributes(String filter)
+ {
+ configuration.keepAttributes =
+ extendFilter(configuration.keepAttributes, filter);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getkeepparameternames()
+ {
+ keepparameternames();
+ return null;
+ }
+
+ public void keepparameternames()
+ {
+ configuration.keepParameterNames = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getrenamesourcefileattribute()
+ {
+ renamesourcefileattribute();
+ return null;
+ }
+
+ public void renamesourcefileattribute()
+ {
+ renamesourcefileattribute("");
+ }
+
+ public void renamesourcefileattribute(String newSourceFileAttribute)
+ {
+ configuration.newSourceFileAttribute = newSourceFileAttribute;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getadaptclassstrings()
+ {
+ adaptclassstrings();
+ return null;
+ }
+
+ public void adaptclassstrings()
+ {
+ adaptclassstrings(null);
+ }
+
+ public void adaptclassstrings(String filter)
+ {
+ configuration.adaptClassStrings =
+ extendFilter(configuration.adaptClassStrings, filter, true);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getadaptresourcefilenames()
+ {
+ adaptresourcefilenames();
+ return null;
+ }
+
+ public void adaptresourcefilenames()
+ {
+ adaptresourcefilenames(null);
+ }
+
+ public void adaptresourcefilenames(String filter)
+ {
+ configuration.adaptResourceFileNames =
+ extendFilter(configuration.adaptResourceFileNames, filter);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getadaptresourcefilecontents()
+ {
+ adaptresourcefilecontents();
+ return null;
+ }
+
+ public void adaptresourcefilecontents()
+ {
+ adaptresourcefilecontents(null);
+ }
+
+ public void adaptresourcefilecontents(String filter)
+ {
+ configuration.adaptResourceFileContents =
+ extendFilter(configuration.adaptResourceFileContents, filter);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontpreverify()
+ {
+ dontpreverify();
+ return null;
+ }
+
+ public void dontpreverify()
+ {
+ configuration.preverify = false;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getmicroedition()
+ {
+ microedition();
+ return null;
+ }
+
+ public void microedition()
+ {
+ configuration.microEdition = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getverbose()
+ {
+ verbose();
+ return null;
+ }
+
+ public void verbose()
+ {
+ configuration.verbose = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontnote()
+ {
+ dontnote();
+ return null;
+ }
+
+ public void dontnote()
+ {
+ dontnote(null);
+ }
+
+ public void dontnote(String filter)
+ {
+ configuration.note = extendFilter(configuration.note, filter, true);
+ }
+
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdontwarn()
+ {
+ dontwarn();
+ return null;
+ }
+
+ public void dontwarn()
+ {
+ dontwarn(null);
+ }
+
+ public void dontwarn(String filter)
+ {
+ configuration.warn = extendFilter(configuration.warn, filter, true);
+ }
+
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getignorewarnings()
+ {
+ ignorewarnings();
+ return null;
+ }
+
+ public void ignorewarnings()
+ {
+ configuration.ignoreWarnings = true;
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getprintconfiguration()
+ {
+ printconfiguration();
+ return null;
+ }
+
+ public void printconfiguration()
+ {
+ configuration.printConfiguration = Configuration.STD_OUT;
+ }
+
+ public void printconfiguration(Object printConfiguration)
+ throws ParseException
+ {
+ configuration.printConfiguration =
+ getProject().file(printConfiguration);
+ }
+
+ // Hack: support the keyword without parentheses in Groovy.
+ public Object getdump()
+ {
+ dump();
+ return null;
+ }
+
+ public void dump()
+ {
+ configuration.dump = Configuration.STD_OUT;
+ }
+
+ public void dump(Object dump)
+ throws ParseException
+ {
+ configuration.dump = getProject().file(dump);
+ }
+
+
+ // Class member methods.
+
+ public void field(Map memberSpecificationArgs)
+ throws ParseException
+ {
+ if (classSpecification == null)
+ {
+ throw new IllegalArgumentException("The 'field' method can only be used nested inside a class specification.");
+ }
+
+ classSpecification.addField(createMemberSpecification(false,
+ false,
+ memberSpecificationArgs));
+ }
+
+
+ public void constructor(Map memberSpecificationArgs)
+ throws ParseException
+ {
+ if (classSpecification == null)
+ {
+ throw new IllegalArgumentException("The 'constructor' method can only be used nested inside a class specification.");
+ }
+
+ classSpecification.addMethod(createMemberSpecification(true,
+ true,
+ memberSpecificationArgs));
+ }
+
+
+ public void method(Map memberSpecificationArgs)
+ throws ParseException
+ {
+ if (classSpecification == null)
+ {
+ throw new IllegalArgumentException("The 'method' method can only be used nested inside a class specification.");
+ }
+
+ classSpecification.addMethod(createMemberSpecification(true,
+ false,
+ memberSpecificationArgs));
+ }
+
+
+ // Gradle task execution.
+
+ @TaskAction
+ public void proguard()
+ throws ParseException, IOException
+ {
+ // Weave the input jars and the output jars into a single class path,
+ // with lazy resolution of the files.
+ configuration.programJars = new ClassPath();
+
+ int outJarIndex = 0;
+
+ int inJarCount = inJarCounts.size() == 0 ? -1 :
+ ((Integer)inJarCounts.get(0)).intValue();
+
+ for (int inJarIndex = 0; inJarIndex < inJarFiles.size(); inJarIndex++)
+ {
+ configuration.programJars =
+ extendClassPath(configuration.programJars,
+ inJarFiles.get(inJarIndex),
+ (Map)inJarFilters.get(inJarIndex),
+ false);
+
+ while (inJarIndex == inJarCount - 1)
+ {
+ configuration.programJars =
+ extendClassPath(configuration.programJars,
+ outJarFiles.get(outJarIndex),
+ (Map)outJarFilters.get(outJarIndex),
+ true);
+
+ outJarIndex++;
+
+ inJarCount = inJarCounts.size() == outJarIndex ? -1 :
+ ((Integer)inJarCounts.get(outJarIndex)).intValue();
+ }
+ }
+
+ // Copy the library jars into a single class path, with lazy resolution
+ // of the files.
+ configuration.libraryJars = new ClassPath();
+
+ for (int libraryJarIndex = 0; libraryJarIndex < libraryJarFiles.size(); libraryJarIndex++)
+ {
+ configuration.libraryJars =
+ extendClassPath(configuration.libraryJars,
+ libraryJarFiles.get(libraryJarIndex),
+ (Map)libraryJarFilters.get(libraryJarIndex),
+ false);
+ }
+
+ // Lazily apply the external configuration files.
+ ConfigurableFileCollection fileCollection =
+ getProject().files(configurationFiles);
+
+ Iterator
\
You can then process your code right away, or you can run ProGuard from the \
- command line using your saved configuration. \
- \n\n\
+ command line using your saved configuration.\
+
\
+ Professional support by Saikoa: \
+ http://www.saikoa.com/\
+
\
+ Copyright © 2002-2013.
processingInfo = \
You can now start processing your code, \
@@ -105,6 +111,7 @@ flattenPackageHierarchy = Flatten package hierarchy
repackageClasses = Repackage classes
useMixedCaseClassNames = Use mixed-case class names
keepAttributes = Keep attributes
+keepParameterNames = Keep parameter names
renameSourceFileAttribute = Rename SourceFile attribute
adaptClassStrings = Adapt class strings
adaptResourceFileNames = Adapt resource file names
@@ -115,14 +122,14 @@ microEdition = Micro Edition
verbose = Verbose
note = Note potential mistakes in the configuration
-warn = Warn about possibly erronous input
-ignoreWarnings = Ignore warnings about possibly erronous input
+warn = Warn about possibly erroneous input
+ignoreWarnings = Ignore warnings about possibly erroneous input
skipNonPublicLibraryClasses = Skip non-public library classes
skipNonPublicLibraryClassMembers = Skip non-public library class members
keepDirectories = Keep directories
forceProcessing = Force processing
target = Target
-targets = 1.0,1.1,1.2,1.3,1.4,1.5,1.6
+targets = 1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7
printSeeds = Print seeds
printConfiguration = Print configuration
dump = Print class files
@@ -209,6 +216,9 @@ attributesTip = \
*
and the negator !
are allowed.
+keepParameterNamesTip = \
+ Keep parameter names and types in "LocalVariable*Table" attributesMemberVisitor
delegates its visits to another given
+ * MemberVisitor
, but only when the visited member has a new name.
+ * Constructors are judged based on the class name.
+ *
+ * @see ClassObfuscator
+ * @see MemberObfuscator
+ *
+ * @author Eric Lafortune
+ */
+public class MemberNameFilter implements MemberVisitor
+{
+ private final MemberVisitor memberVisitor;
+
+
+ /**
+ * Creates a new MemberNameFilter.
+ * @param memberVisitor the MemberVisitor
to which
+ * visits will be delegated.
+ */
+ public MemberNameFilter(MemberVisitor memberVisitor)
+ {
+ this.memberVisitor = memberVisitor;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ if (hasName(programField))
+ {
+ memberVisitor.visitProgramField(programClass, programField);
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (hasName(programClass, programMethod))
+ {
+ memberVisitor.visitProgramMethod(programClass, programMethod);
+ }
+ }
+
+
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
+ {
+ if (hasName(libraryField))
+ {
+ memberVisitor.visitLibraryField(libraryClass, libraryField);
+ }
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ if (hasName(libraryClass, libraryMethod))
+ {
+ memberVisitor.visitLibraryMethod(libraryClass, libraryMethod);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether the given class has a new name.
+ */
+ private boolean hasName(Clazz clazz)
+ {
+ return ClassObfuscator.newClassName(clazz) != null;
+ }
+
+
+ /**
+ * Returns whether the given method has a new name.
+ */
+ private boolean hasName(Clazz clazz, Method method)
+ {
+ return
+ hasName(method) ||
+ (hasName(clazz) &&
+ method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT));
+ }
+
+
+ /**
+ * Returns whether the given class member has a new name.
+ */
+ private boolean hasName(Member member)
+ {
+ return MemberObfuscator.newMemberName(member) != null;
+ }
+}
diff --git a/src/proguard/obfuscate/MemberObfuscator.java b/src/proguard/obfuscate/MemberObfuscator.java
index 332b849..adf590c 100644
--- a/src/proguard/obfuscate/MemberObfuscator.java
+++ b/src/proguard/obfuscate/MemberObfuscator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/MemberSpecialNameFilter.java b/src/proguard/obfuscate/MemberSpecialNameFilter.java
index f83374b..0eb4d2d 100644
--- a/src/proguard/obfuscate/MemberSpecialNameFilter.java
+++ b/src/proguard/obfuscate/MemberSpecialNameFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -54,7 +54,7 @@ public class MemberSpecialNameFilter implements MemberVisitor
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- if (isSpecialName(programField))
+ if (hasSpecialName(programField))
{
memberVisitor.visitProgramField(programClass, programField);
}
@@ -63,7 +63,7 @@ public class MemberSpecialNameFilter implements MemberVisitor
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- if (isSpecialName(programMethod))
+ if (hasSpecialName(programMethod))
{
memberVisitor.visitProgramMethod(programClass, programMethod);
}
@@ -72,7 +72,7 @@ public class MemberSpecialNameFilter implements MemberVisitor
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
- if (isSpecialName(libraryField))
+ if (hasSpecialName(libraryField))
{
memberVisitor.visitLibraryField(libraryClass, libraryField);
}
@@ -81,7 +81,7 @@ public class MemberSpecialNameFilter implements MemberVisitor
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
- if (isSpecialName(libraryMethod))
+ if (hasSpecialName(libraryMethod))
{
memberVisitor.visitLibraryMethod(libraryClass, libraryMethod);
}
@@ -94,7 +94,7 @@ public class MemberSpecialNameFilter implements MemberVisitor
* Returns whether the given class member has a special new name.
* @param member the class member.
*/
- private static boolean isSpecialName(Member member)
+ private static boolean hasSpecialName(Member member)
{
return SpecialNameFactory.isSpecialName(MemberObfuscator.newMemberName(member));
}
diff --git a/src/proguard/obfuscate/MultiMappingProcessor.java b/src/proguard/obfuscate/MultiMappingProcessor.java
index 4074ff8..051260f 100644
--- a/src/proguard/obfuscate/MultiMappingProcessor.java
+++ b/src/proguard/obfuscate/MultiMappingProcessor.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameAndTypeShrinker.java b/src/proguard/obfuscate/NameAndTypeShrinker.java
deleted file mode 100644
index 1284c82..0000000
--- a/src/proguard/obfuscate/NameAndTypeShrinker.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.obfuscate;
-
-import proguard.classfile.*;
-import proguard.classfile.constant.Constant;
-import proguard.classfile.editor.ConstantPoolRemapper;
-import proguard.classfile.visitor.ClassVisitor;
-
-
-/**
- * This ClassVisitor removes NameAndType constant pool entries
- * that are not marked as being used.
- *
- * @see NameAndTypeUsageMarker
- *
- * @author Eric Lafortune
- */
-public class NameAndTypeShrinker implements ClassVisitor
-{
- private int[] constantIndexMap;
- private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Shift the used constant pool entries together, filling out the
- // index map.
- programClass.u2constantPoolCount =
- shrinkConstantPool(programClass.constantPool,
- programClass.u2constantPoolCount);
-
-
- // Remap all constant pool references.
- constantPoolRemapper.setConstantIndexMap(constantIndexMap);
- constantPoolRemapper.visitProgramClass(programClass);
- }
-
-
- public void visitLibraryClass(LibraryClass libraryClass)
- {
- }
-
-
- // Small utility methods.
-
- /**
- * Removes all NameAndType entries that are not marked as being used
- * from the given constant pool.
- * @return the new number of entries.
- */
- private int shrinkConstantPool(Constant[] constantPool, int length)
- {
- // Create a new index map, if necessary.
- if (constantIndexMap == null ||
- constantIndexMap.length < length)
- {
- constantIndexMap = new int[length];
- }
-
- int counter = 1;
- boolean isUsed = false;
-
- // Shift the used constant pool entries together.
- for (int index = 1; index < length; index++)
- {
- constantIndexMap[index] = counter;
-
- Constant constant = constantPool[index];
-
- // Don't update the flag if this is the second half of a long entry.
- if (constant != null)
- {
- isUsed = constant.getTag() != ClassConstants.CONSTANT_NameAndType ||
- NameAndTypeUsageMarker.isUsed(constant);
- }
-
- if (isUsed)
- {
- constantPool[counter++] = constant;
- }
- }
-
- // Clear the remaining constant pool elements.
- for (int index = counter; index < length; index++)
- {
- constantPool[index] = null;
- }
-
- return counter;
- }
-}
diff --git a/src/proguard/obfuscate/NameAndTypeUsageMarker.java b/src/proguard/obfuscate/NameAndTypeUsageMarker.java
deleted file mode 100644
index cc779f0..0000000
--- a/src/proguard/obfuscate/NameAndTypeUsageMarker.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.obfuscate;
-
-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.util.SimplifiedVisitor;
-import proguard.classfile.visitor.ClassVisitor;
-
-/**
- * This ClassVisitor marks all NameAndType constant pool entries that are
- * being used in the program classes it visits.
- *
- * @see NameAndTypeShrinker
- *
- * @author Eric Lafortune
- */
-public class NameAndTypeUsageMarker
-extends SimplifiedVisitor
-implements ClassVisitor,
- ConstantVisitor,
- AttributeVisitor
-{
- // A visitor info flag to indicate the NameAndType constant pool entry is being used.
- private static final Object USED = new Object();
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Mark the NameAndType entries referenced by all other constant pool
- // entries.
- programClass.constantPoolEntriesAccept(this);
-
- // Mark the NameAndType entries referenced by all EnclosingMethod
- // attributes.
- programClass.attributesAccept(this);
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyConstant(Clazz clazz, Constant constant) {}
-
-
- public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
- {
- visitRefConstant(clazz, fieldrefConstant);
- }
-
-
- public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
- {
- visitRefConstant(clazz, interfaceMethodrefConstant);
- }
-
-
- public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
- {
- visitRefConstant(clazz, methodrefConstant);
- }
-
-
- private void visitRefConstant(Clazz clazz, RefConstant refConstant)
- {
- markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex);
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
- {
- if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
- {
- markNameAndTypeConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex);
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Marks the given UTF-8 constant pool entry of the given class.
- */
- private void markNameAndTypeConstant(Clazz clazz, int index)
- {
- markAsUsed((NameAndTypeConstant)((ProgramClass)clazz).getConstant(index));
- }
-
-
- /**
- * Marks the given VisitorAccepter as being used.
- * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
- */
- private static void markAsUsed(VisitorAccepter visitorAccepter)
- {
- visitorAccepter.setVisitorInfo(USED);
- }
-
-
- /**
- * Returns whether the given VisitorAccepter has been marked as being used.
- * In this context, the VisitorAccepter will be a NameAndTypeConstant object.
- */
- static boolean isUsed(VisitorAccepter visitorAccepter)
- {
- return visitorAccepter.getVisitorInfo() == USED;
- }
-}
diff --git a/src/proguard/obfuscate/NameFactory.java b/src/proguard/obfuscate/NameFactory.java
index c64d1ad..97ebe5a 100644
--- a/src/proguard/obfuscate/NameFactory.java
+++ b/src/proguard/obfuscate/NameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameFactoryResetter.java b/src/proguard/obfuscate/NameFactoryResetter.java
index b6ba6ad..b04d12e 100644
--- a/src/proguard/obfuscate/NameFactoryResetter.java
+++ b/src/proguard/obfuscate/NameFactoryResetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameMarker.java b/src/proguard/obfuscate/NameMarker.java
index 2ce0ee9..5283ef3 100644
--- a/src/proguard/obfuscate/NameMarker.java
+++ b/src/proguard/obfuscate/NameMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NumericNameFactory.java b/src/proguard/obfuscate/NumericNameFactory.java
index cc21c4b..b1e38b1 100644
--- a/src/proguard/obfuscate/NumericNameFactory.java
+++ b/src/proguard/obfuscate/NumericNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/Obfuscator.java b/src/proguard/obfuscate/Obfuscator.java
index dce563a..cc79b0d 100644
--- a/src/proguard/obfuscate/Obfuscator.java
+++ b/src/proguard/obfuscate/Obfuscator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -99,19 +99,30 @@ public class Obfuscator
libraryClassPool.classesAccept(new AllMemberVisitor(nameMarker));
// Mark attributes that have to be kept.
- AttributeUsageMarker requiredAttributeUsageMarker =
- new AttributeUsageMarker();
+ AttributeVisitor attributeUsageMarker =
+ new NonEmptyAttributeFilter(
+ new AttributeUsageMarker());
AttributeVisitor optionalAttributeUsageMarker =
configuration.keepAttributes == null ? null :
new AttributeNameFilter(new ListParser(new NameParser()).parse(configuration.keepAttributes),
- requiredAttributeUsageMarker);
+ attributeUsageMarker);
programClassPool.classesAccept(
new AllAttributeVisitor(true,
- new RequiredAttributeFilter(requiredAttributeUsageMarker,
+ new RequiredAttributeFilter(attributeUsageMarker,
optionalAttributeUsageMarker)));
+ // Keep parameter names and types if specified.
+ if (configuration.keepParameterNames)
+ {
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new MemberNameFilter(
+ new AllAttributeVisitor(true,
+ new ParameterNameMarker(attributeUsageMarker)))));
+ }
+
// Remove the attributes that can be discarded. Note that the attributes
// may only be discarded after the seeds have been marked, since the
// configuration may rely on annotations.
@@ -135,17 +146,23 @@ public class Obfuscator
reader.pump(keeper);
// Print out a summary of the warnings if necessary.
- int mappingWarningCount = warningPrinter.getWarningCount();
- if (mappingWarningCount > 0)
+ int warningCount = warningPrinter.getWarningCount();
+ if (warningCount > 0)
{
- System.err.println("Warning: there were " + mappingWarningCount +
- " kept classes and class members that were remapped anyway.");
+ System.err.println("Warning: there were " + warningCount +
+ " kept classes and class members that were remapped anyway.");
System.err.println(" You should adapt your configuration or edit the mapping file.");
if (!configuration.ignoreWarnings)
{
- System.err.println(" If you are sure this remapping won't hurt,");
- System.err.println(" you could try your luck using the '-ignorewarnings' option.");
+ System.err.println(" If you are sure this remapping won't hurt, you could try your luck");
+ System.err.println(" using the '-ignorewarnings' option.");
+ }
+
+ System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#mappingconflict1)");
+
+ if (!configuration.ignoreWarnings)
+ {
throw new IOException("Please correct the above warnings first.");
}
}
@@ -248,6 +265,19 @@ public class Obfuscator
new MemberNameCollector(configuration.overloadAggressively,
descriptorMap)))),
+ // Collect all member names from interfaces of abstract
+ // classes down the hierarchy.
+ // Due to an error in the JLS/JVMS, virtual invocations
+ // may end up at a private method otherwise (Sun/Oracle
+ // bugs #6691741 and #6684387, ProGuard bug #3471941,
+ // and ProGuard test #1180).
+ new ClassHierarchyTraveler(false, false, false, true,
+ new ClassAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0,
+ new ClassHierarchyTraveler(false, false, true, false,
+ new AllMemberVisitor(
+ new MemberNameCollector(configuration.overloadAggressively,
+ descriptorMap))))),
+
// Assign new names to all private members in this class.
new AllMemberVisitor(
new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0,
@@ -361,6 +391,12 @@ public class Obfuscator
{
System.err.println(" If you are sure the conflicts are harmless,");
System.err.println(" you could try your luck using the '-ignorewarnings' option.");
+ }
+
+ System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#mappingconflict2)");
+
+ if (!configuration.ignoreWarnings)
+ {
throw new IOException("Please correct the above warnings first.");
}
}
@@ -368,14 +404,20 @@ public class Obfuscator
// Print out the mapping, if requested.
if (configuration.printMapping != null)
{
- PrintStream ps = isFile(configuration.printMapping) ?
- new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) :
- System.out;
+ PrintStream ps =
+ configuration.printMapping == Configuration.STD_OUT ? System.out :
+ new PrintStream(
+ new BufferedOutputStream(
+ new FileOutputStream(configuration.printMapping)));
// Print out items that will be removed.
programClassPool.classesAcceptAlphabetically(new MappingPrinter(ps));
- if (ps != System.out)
+ if (ps == System.out)
+ {
+ ps.flush();
+ }
+ else
{
ps.close();
}
@@ -398,32 +440,27 @@ public class Obfuscator
programClassPool.classesAccept(
new AllConstantVisitor(
new AccessFixer()));
+
+ // Fix the access flags of the inner classes information.
+ programClassPool.classesAccept(
+ new AllAttributeVisitor(
+ new AllInnerClassesInfoVisitor(
+ new InnerClassesAccessFixer())));
}
+ // Fix the bridge method flags.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new BridgeMethodFixer()));
+
// Rename the source file attributes, if requested.
if (configuration.newSourceFileAttribute != null)
{
programClassPool.classesAccept(new SourceFileRenamer(configuration.newSourceFileAttribute));
}
- // Mark NameAndType constant pool entries that have to be kept
- // and remove the other ones.
- programClassPool.classesAccept(new NameAndTypeUsageMarker());
- programClassPool.classesAccept(new NameAndTypeShrinker());
-
- // Mark Utf8 constant pool entries that have to be kept
- // and remove the other ones.
- programClassPool.classesAccept(new Utf8UsageMarker());
- programClassPool.classesAccept(new Utf8Shrinker());
- }
-
-
- /**
- * Returns whether the given file is actually a file, or just a placeholder
- * for the standard output.
- */
- private boolean isFile(File file)
- {
- return file.getPath().length() > 0;
+ // Remove unused constants.
+ programClassPool.classesAccept(
+ new ConstantPoolShrinker());
}
}
diff --git a/src/proguard/obfuscate/ParameterNameMarker.java b/src/proguard/obfuscate/ParameterNameMarker.java
new file mode 100644
index 0000000..22af125
--- /dev/null
+++ b/src/proguard/obfuscate/ParameterNameMarker.java
@@ -0,0 +1,128 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.*;
+
+/**
+ * This AttributeVisitor trims and marks all local variable (type) table
+ * attributes that it visits. It keeps parameter names and types and removes
+ * the ordinary local variable names and types.
+ *
+ * @author Eric Lafortune
+ */
+public class ParameterNameMarker
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final AttributeVisitor attributeUsageMarker;
+
+
+ /**
+ * Constructs a new ParameterNameMarker.
+ * @param attributeUsageMarker the marker that will be used to mark
+ * attributes containing local variable info.
+ */
+ public ParameterNameMarker(AttributeVisitor attributeUsageMarker)
+ {
+ this.attributeUsageMarker = attributeUsageMarker;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ if (!AttributeUsageMarker.isUsed(localVariableTableAttribute) &&
+ hasParameters(clazz, method))
+ {
+ // Shift the entries that start at offset 0 to the front.
+ int newIndex = 0;
+
+ for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++)
+ {
+ LocalVariableInfo localVariableInfo =
+ localVariableTableAttribute.localVariableTable[index];
+
+ if (localVariableInfo.u2startPC == 0)
+ {
+ localVariableTableAttribute.localVariableTable[newIndex++] =
+ localVariableInfo;
+ }
+ }
+
+ // Trim the table.
+ localVariableTableAttribute.u2localVariableTableLength = newIndex;
+
+ // Mark the table if there are any entries.
+ if (newIndex > 0)
+ {
+ attributeUsageMarker.visitLocalVariableTableAttribute(clazz, method, codeAttribute, localVariableTableAttribute);
+ }
+ }
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ if (!AttributeUsageMarker.isUsed(localVariableTypeTableAttribute) &&
+ hasParameters(clazz, method))
+ {
+ // Shift the entries that start at offset 0 to the front.
+ int newIndex = 0;
+
+ for (int index = 0; index < localVariableTypeTableAttribute.u2localVariableTypeTableLength; index++)
+ {
+ LocalVariableTypeInfo localVariableTypeInfo =
+ localVariableTypeTableAttribute.localVariableTypeTable[index];
+
+ if (localVariableTypeInfo.u2startPC == 0)
+ {
+ localVariableTypeTableAttribute.localVariableTypeTable[newIndex++] =
+ localVariableTypeInfo;
+ }
+ }
+
+ // Trim the table.
+ localVariableTypeTableAttribute.u2localVariableTypeTableLength = newIndex;
+
+ // Mark the table if there are any entries.
+ if (newIndex > 0)
+ {
+ attributeUsageMarker.visitLocalVariableTypeTableAttribute(clazz, method, codeAttribute, localVariableTypeTableAttribute);
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean hasParameters(Clazz clazz, Method method)
+ {
+ return method.getDescriptor(clazz).charAt(1) != ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE;
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/obfuscate/SimpleNameFactory.java b/src/proguard/obfuscate/SimpleNameFactory.java
index bce22de..0473852 100644
--- a/src/proguard/obfuscate/SimpleNameFactory.java
+++ b/src/proguard/obfuscate/SimpleNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/SourceFileRenamer.java b/src/proguard/obfuscate/SourceFileRenamer.java
index cbf1b63..248d18f 100644
--- a/src/proguard/obfuscate/SourceFileRenamer.java
+++ b/src/proguard/obfuscate/SourceFileRenamer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/SpecialNameFactory.java b/src/proguard/obfuscate/SpecialNameFactory.java
index a5431ca..596f919 100644
--- a/src/proguard/obfuscate/SpecialNameFactory.java
+++ b/src/proguard/obfuscate/SpecialNameFactory.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/Utf8Shrinker.java b/src/proguard/obfuscate/Utf8Shrinker.java
deleted file mode 100644
index 87ada80..0000000
--- a/src/proguard/obfuscate/Utf8Shrinker.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.obfuscate;
-
-import proguard.classfile.*;
-import proguard.classfile.constant.Constant;
-import proguard.classfile.editor.ConstantPoolRemapper;
-import proguard.classfile.visitor.ClassVisitor;
-
-
-/**
- * This ClassVisitor removes UTF-8 constant pool entries that are not marked
- * as being used.
- *
- * @see Utf8UsageMarker
- *
- * @author Eric Lafortune
- */
-public class Utf8Shrinker implements ClassVisitor
-{
- private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE];
- private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper();
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Shift the used constant pool entries together, filling out the
- // index map.
- programClass.u2constantPoolCount =
- shrinkConstantPool(programClass.constantPool,
- programClass.u2constantPoolCount);
-
- // Remap all constant pool references.
- constantPoolRemapper.setConstantIndexMap(constantIndexMap);
- constantPoolRemapper.visitProgramClass(programClass);
- }
-
-
- public void visitLibraryClass(LibraryClass libraryClass)
- {
- }
-
-
- // Small utility methods.
-
- /**
- * Removes all UTF-8 entries that are not marked as being used
- * from the given constant pool.
- * @return the new number of entries.
- */
- private int shrinkConstantPool(Constant[] constantPool, int length)
- {
- // Create a new index map, if necessary.
- if (constantIndexMap.length < length)
- {
- constantIndexMap = new int[length];
- }
-
- int counter = 1;
- boolean isUsed = false;
-
- // Shift the used constant pool entries together.
- for (int index = 1; index < length; index++)
- {
- constantIndexMap[index] = counter;
-
- Constant constant = constantPool[index];
-
- // Don't update the flag if this is the second half of a long entry.
- if (constant != null)
- {
- isUsed = constant.getTag() != ClassConstants.CONSTANT_Utf8 ||
- Utf8UsageMarker.isUsed(constant);
- }
-
- if (isUsed)
- {
- constantPool[counter++] = constant;
- }
- }
-
- // Clear the remaining constant pool elements.
- for (int index = counter; index < length; index++)
- {
- constantPool[index] = null;
- }
-
- return counter;
- }
-}
diff --git a/src/proguard/obfuscate/Utf8UsageMarker.java b/src/proguard/obfuscate/Utf8UsageMarker.java
deleted file mode 100644
index c59ebb8..0000000
--- a/src/proguard/obfuscate/Utf8UsageMarker.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.obfuscate;
-
-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.visitor.*;
-import proguard.classfile.constant.*;
-import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.*;
-
-/**
- * This ClassVisitor marks all UTF-8 constant pool entries that are
- * being used in the program classes it visits.
- *
- * @see Utf8Shrinker
- *
- * @author Eric Lafortune
- */
-public class Utf8UsageMarker
-extends SimplifiedVisitor
-implements ClassVisitor,
- MemberVisitor,
- ConstantVisitor,
- AttributeVisitor,
- InnerClassesInfoVisitor,
- LocalVariableInfoVisitor,
- LocalVariableTypeInfoVisitor,
- AnnotationVisitor,
- ElementValueVisitor
-{
- // A visitor info flag to indicate the UTF-8 constant pool entry is being used.
- private static final Object USED = new Object();
-
-
- // Implementations for ClassVisitor.
-
- public void visitProgramClass(ProgramClass programClass)
- {
- // Mark the UTF-8 entries referenced by the other constant pool entries.
- programClass.constantPoolEntriesAccept(this);
-
- // Mark the UTF-8 entries referenced by the fields and methods.
- programClass.fieldsAccept(this);
- programClass.methodsAccept(this);
-
- // Mark the UTF-8 entries referenced by the attributes.
- programClass.attributesAccept(this);
- }
-
-
- // Implementations for MemberVisitor.
-
- public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
- {
- // Mark the name and descriptor UTF-8 entries.
- markCpUtf8Entry(programClass, programMember.u2nameIndex);
- markCpUtf8Entry(programClass, programMember.u2descriptorIndex);
-
- // Mark the UTF-8 entries referenced by the attributes.
- programMember.attributesAccept(programClass, this);
- }
-
-
- // Implementations for ConstantVisitor.
-
- public void visitAnyConstant(Clazz clazz, Constant constant) {}
-
-
- public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
- {
- markCpUtf8Entry(clazz, stringConstant.u2stringIndex);
- }
-
-
- public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
- {
- markCpUtf8Entry(clazz, classConstant.u2nameIndex);
- }
-
-
- public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
- {
- markCpUtf8Entry(clazz, nameAndTypeConstant.u2nameIndex);
- markCpUtf8Entry(clazz, nameAndTypeConstant.u2descriptorIndex);
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
- {
- // This is the best we can do for unknown attributes.
- markCpUtf8Entry(clazz, unknownAttribute.u2attributeNameIndex);
- }
-
-
- public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
- {
- markCpUtf8Entry(clazz, sourceFileAttribute.u2attributeNameIndex);
-
- markCpUtf8Entry(clazz, sourceFileAttribute.u2sourceFileIndex);
- }
-
-
- public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
- {
- markCpUtf8Entry(clazz, sourceDirAttribute.u2attributeNameIndex);
-
- markCpUtf8Entry(clazz, sourceDirAttribute.u2sourceDirIndex);
- }
-
-
- public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
- {
- markCpUtf8Entry(clazz, innerClassesAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the inner classes.
- innerClassesAttribute.innerClassEntriesAccept(clazz, this);
- }
-
-
- public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
- {
- markCpUtf8Entry(clazz, enclosingMethodAttribute.u2attributeNameIndex);
-
- // These entries have already been marked in the constant pool.
- //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2classIndex);
- //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2nameAndTypeIndex);
- }
-
-
- public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
- {
- markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex);
- }
-
-
- public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
- {
- markCpUtf8Entry(clazz, syntheticAttribute.u2attributeNameIndex);
- }
-
-
- public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
- {
- markCpUtf8Entry(clazz, signatureAttribute.u2attributeNameIndex);
-
- markCpUtf8Entry(clazz, signatureAttribute.u2signatureIndex);
- }
-
-
- public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
- {
- markCpUtf8Entry(clazz, constantValueAttribute.u2attributeNameIndex);
- }
-
-
- public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
- {
- markCpUtf8Entry(clazz, exceptionsAttribute.u2attributeNameIndex);
- }
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- markCpUtf8Entry(clazz, codeAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the attributes.
- codeAttribute.attributesAccept(clazz, method, this);
- }
-
-
- public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
- {
- markCpUtf8Entry(clazz, stackMapAttribute.u2attributeNameIndex);
- }
-
-
- public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
- {
- markCpUtf8Entry(clazz, stackMapTableAttribute.u2attributeNameIndex);
- }
-
-
- public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
- {
- markCpUtf8Entry(clazz, lineNumberTableAttribute.u2attributeNameIndex);
- }
-
-
- public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
- {
- markCpUtf8Entry(clazz, localVariableTableAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the local variables.
- localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
- }
-
-
- public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
- {
- markCpUtf8Entry(clazz, localVariableTypeTableAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the local variable types.
- localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
- }
-
-
- public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
- {
- markCpUtf8Entry(clazz, annotationsAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the annotations.
- annotationsAttribute.annotationsAccept(clazz, this);
- }
-
-
- public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
- {
- markCpUtf8Entry(clazz, parameterAnnotationsAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the annotations.
- parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
- }
-
-
- public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
- {
- markCpUtf8Entry(clazz, annotationDefaultAttribute.u2attributeNameIndex);
-
- // Mark the UTF-8 entries referenced by the element value.
- annotationDefaultAttribute.defaultValueAccept(clazz, this);
- }
-
-
- // Implementations for InnerClassesInfoVisitor.
-
- public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
- {
- if (innerClassesInfo.u2innerNameIndex != 0)
- {
- markCpUtf8Entry(clazz, innerClassesInfo.u2innerNameIndex);
- }
- }
-
-
- // Implementations for LocalVariableInfoVisitor.
-
- public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
- {
- markCpUtf8Entry(clazz, localVariableInfo.u2nameIndex);
- markCpUtf8Entry(clazz, localVariableInfo.u2descriptorIndex);
- }
-
-
- // Implementations for LocalVariableTypeInfoVisitor.
-
- public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
- {
- markCpUtf8Entry(clazz, localVariableTypeInfo.u2nameIndex);
- markCpUtf8Entry(clazz, localVariableTypeInfo.u2signatureIndex);
- }
-
-
- // Implementations for AnnotationVisitor.
-
- public void visitAnnotation(Clazz clazz, Annotation annotation)
- {
- markCpUtf8Entry(clazz, annotation.u2typeIndex);
-
- // Mark the UTF-8 entries referenced by the element values.
- annotation.elementValuesAccept(clazz, this);
- }
-
-
- // Implementations for ElementValueVisitor.
-
- public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
- {
- if (constantElementValue.u2elementNameIndex != 0)
- {
- markCpUtf8Entry(clazz, constantElementValue.u2elementNameIndex);
- }
-
- // Only the string constant element value refers to a UTF-8 entry.
- if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT)
- {
- markCpUtf8Entry(clazz, constantElementValue.u2constantValueIndex);
- }
- }
-
-
- public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
- {
- if (enumConstantElementValue.u2elementNameIndex != 0)
- {
- markCpUtf8Entry(clazz, enumConstantElementValue.u2elementNameIndex);
- }
-
- markCpUtf8Entry(clazz, enumConstantElementValue.u2typeNameIndex);
- markCpUtf8Entry(clazz, enumConstantElementValue.u2constantNameIndex);
- }
-
-
- public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
- {
- if (classElementValue.u2elementNameIndex != 0)
- {
- markCpUtf8Entry(clazz, classElementValue.u2elementNameIndex);
- }
-
- markCpUtf8Entry(clazz, classElementValue.u2classInfoIndex);
- }
-
-
- public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
- {
- if (annotationElementValue.u2elementNameIndex != 0)
- {
- markCpUtf8Entry(clazz, annotationElementValue.u2elementNameIndex);
- }
-
- // Mark the UTF-8 entries referenced by the annotation.
- annotationElementValue.annotationAccept(clazz, this);
- }
-
-
- public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
- {
- if (arrayElementValue.u2elementNameIndex != 0)
- {
- markCpUtf8Entry(clazz, arrayElementValue.u2elementNameIndex);
- }
-
- // Mark the UTF-8 entries referenced by the element values.
- arrayElementValue.elementValuesAccept(clazz, annotation, this);
- }
-
-
- // Small utility methods.
-
- /**
- * Marks the given UTF-8 constant pool entry of the given class.
- */
- private void markCpUtf8Entry(Clazz clazz, int index)
- {
- markAsUsed((Utf8Constant)((ProgramClass)clazz).getConstant(index));
- }
-
-
- /**
- * Marks the given VisitorAccepter as being used.
- * In this context, the VisitorAccepter will be a Utf8Constant object.
- */
- private static void markAsUsed(VisitorAccepter visitorAccepter)
- {
- visitorAccepter.setVisitorInfo(USED);
- }
-
-
- /**
- * Returns whether the given VisitorAccepter has been marked as being used.
- * In this context, the VisitorAccepter will be a Utf8Constant object.
- */
- static boolean isUsed(VisitorAccepter visitorAccepter)
- {
- return visitorAccepter.getVisitorInfo() == USED;
- }
-}
diff --git a/src/proguard/optimize/BootstrapMethodArgumentShrinker.java b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
new file mode 100644
index 0000000..26f1349
--- /dev/null
+++ b/src/proguard/optimize/BootstrapMethodArgumentShrinker.java
@@ -0,0 +1,103 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.editor.ConstantPoolEditor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberVisitor;
+import proguard.optimize.info.*;
+import proguard.optimize.peephole.VariableShrinker;
+
+/**
+ * This BootstrapMethodInfoVisitor removes unused constant arguments from
+ * bootstrap method entries that it visits.
+ *
+ * @see ParameterUsageMarker
+ * @see VariableUsageMarker
+ * @see VariableShrinker
+ * @author Eric Lafortune
+ */
+public class BootstrapMethodArgumentShrinker
+extends SimplifiedVisitor
+implements BootstrapMethodInfoVisitor,
+ ConstantVisitor,
+ MemberVisitor
+{
+ private long usedParameters;
+
+
+ // Implementations for BootstrapMethodInfoVisitor.
+
+ public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
+ {
+ // Check which method parameters are used.
+ usedParameters = -1L;
+ clazz.constantPoolEntryAccept(bootstrapMethodInfo.u2methodHandleIndex, this);
+
+ // Remove the unused arguments.
+ int methodArgumentCount = bootstrapMethodInfo.u2methodArgumentCount;
+ int[] methodArguments = bootstrapMethodInfo.u2methodArguments;
+
+ int newArgumentIndex = 0;
+
+ for (int argumentIndex = 0; argumentIndex < methodArgumentCount; argumentIndex++)
+ {
+ if (argumentIndex >= 64 ||
+ (usedParameters & (1L << argumentIndex)) != 0L)
+ {
+ methodArguments[newArgumentIndex++] = methodArguments[argumentIndex];
+ }
+ }
+
+ // Update the number of arguments.
+ bootstrapMethodInfo.u2methodArgumentCount = newArgumentIndex;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ // Check the referenced bootstrap method.
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
+ }
+
+
+ public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
+ {
+ // Check the referenced class member itself.
+ refConstant.referencedMemberAccept(this);
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ usedParameters = ParameterUsageMarker.getUsedParameters(programMethod);
+ }
+}
diff --git a/src/proguard/optimize/ChangedCodePrinter.java b/src/proguard/optimize/ChangedCodePrinter.java
index 67a79ab..668d43d 100644
--- a/src/proguard/optimize/ChangedCodePrinter.java
+++ b/src/proguard/optimize/ChangedCodePrinter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -54,6 +54,12 @@ implements AttributeVisitor
}
+ public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute)
+ {
+ attributeVisitor.visitBootstrapMethodsAttribute(clazz, bootstrapMethodsAttribute);
+ }
+
+
public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
{
attributeVisitor.visitSourceFileAttribute(clazz, sourceFileAttribute);
diff --git a/src/proguard/optimize/ConstantMemberFilter.java b/src/proguard/optimize/ConstantMemberFilter.java
index 56437c3..1f30a30 100644
--- a/src/proguard/optimize/ConstantMemberFilter.java
+++ b/src/proguard/optimize/ConstantMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/ConstantParameterFilter.java b/src/proguard/optimize/ConstantParameterFilter.java
index 24a7040..1500fd0 100644
--- a/src/proguard/optimize/ConstantParameterFilter.java
+++ b/src/proguard/optimize/ConstantParameterFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/DuplicateInitializerFixer.java b/src/proguard/optimize/DuplicateInitializerFixer.java
index 746d182..95bc2f1 100644
--- a/src/proguard/optimize/DuplicateInitializerFixer.java
+++ b/src/proguard/optimize/DuplicateInitializerFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -86,7 +86,7 @@ implements MemberVisitor,
if (!programMethod.equals(similarMethod))
{
// Should this initializer be preserved?
- if (!KeepMarker.isKept(programMethod))
+ if (KeepMarker.isKept(programMethod))
{
// Fix the other initializer.
programMethod = (ProgramMethod)similarMethod;
@@ -95,12 +95,23 @@ implements MemberVisitor,
int index = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
// Try to find a new, unique descriptor.
- for (int typeIndex = 0; typeIndex < TYPES.length; typeIndex++)
+ int typeCounter = 0;
+ while (true)
{
- String newDescriptor =
- descriptor.substring(0, index) +
- TYPES[typeIndex] +
- descriptor.substring(index);
+ // Construct the new descriptor by inserting a new type
+ // as an additional last argument.
+ StringBuffer newDescriptorBuffer =
+ new StringBuffer(descriptor.substring(0, index));
+
+ for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++)
+ {
+ newDescriptorBuffer.append(ClassConstants.INTERNAL_TYPE_ARRAY);
+ }
+
+ newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]);
+ newDescriptorBuffer.append(descriptor.substring(index));
+
+ String newDescriptor = newDescriptorBuffer.toString();
// Is the new initializer descriptor unique?
if (programClass.findMethod(name, newDescriptor) == null)
@@ -108,7 +119,7 @@ implements MemberVisitor,
if (DEBUG)
{
System.out.println("DuplicateInitializerFixer:");
- System.out.println(" ["+programClass.getName()+"]: "+name+descriptor+" -> "+newDescriptor);
+ System.out.println(" ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]");
}
// Update the descriptor.
@@ -130,12 +141,9 @@ implements MemberVisitor,
// We're done with this constructor.
return;
}
- }
- throw new IllegalStateException("Can't find unique constructor descriptor for ["+
- programClass.getName()+"."+
- programMethod.getName(programClass)+
- programMethod.getDescriptor(programClass)+"]");
+ typeCounter++;
+ }
}
}
}
diff --git a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java b/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
index ca24481..5edaba0 100644
--- a/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
+++ b/src/proguard/optimize/DuplicateInitializerInvocationFixer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,7 @@ import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.editor.CodeAttributeEditor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
/**
@@ -48,12 +48,12 @@ implements AttributeVisitor,
private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
- private String descriptor;
- private boolean hasBeenFixed;
+ private String descriptor;
+ private int descriptorLengthDelta;
/**
- * Creates a new EvaluationSimplifier.
+ * Creates a new DuplicateInitializerInvocationFixer.
*/
public DuplicateInitializerInvocationFixer()
{
@@ -62,7 +62,7 @@ implements AttributeVisitor,
/**
- * Creates a new EvaluationSimplifier.
+ * Creates a new DuplicateInitializerInvocationFixer.
* @param extraAddedInstructionVisitor an optional extra visitor for all
* added instructions.
*/
@@ -102,21 +102,22 @@ implements AttributeVisitor,
{
if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL)
{
- hasBeenFixed = false;
+ descriptorLengthDelta = 0;
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
- if (hasBeenFixed)
+ if (descriptorLengthDelta > 0)
{
Instruction extraInstruction =
- new SimpleInstruction(InstructionConstants.OP_ICONST_0);
+ new SimpleInstruction(descriptorLengthDelta == 1 ?
+ InstructionConstants.OP_ICONST_0 :
+ InstructionConstants.OP_ACONST_NULL);
codeAttributeEditor.insertBeforeInstruction(offset,
extraInstruction);
if (DEBUG)
{
- System.out.println("DuplicateInitializerInvocationFixer:");
- System.out.println(" Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset));
+ System.out.println(" ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset));
}
if (extraAddedInstructionVisitor != null)
@@ -145,6 +146,16 @@ implements AttributeVisitor,
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- hasBeenFixed = !descriptor.equals(programMethod.getDescriptor(programClass));
+ descriptorLengthDelta =
+ programMethod.getDescriptor(programClass).length() - descriptor.length();
+
+ if (DEBUG)
+ {
+ if (descriptorLengthDelta > 0)
+ {
+ System.out.println("DuplicateInitializerInvocationFixer:");
+ System.out.println(" ["+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") referenced by:");
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/optimize/KeepMarker.java b/src/proguard/optimize/KeepMarker.java
index 4297996..b0eab7b 100644
--- a/src/proguard/optimize/KeepMarker.java
+++ b/src/proguard/optimize/KeepMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,6 +23,7 @@ package proguard.optimize;
import proguard.classfile.*;
import proguard.classfile.util.MethodLinker;
import proguard.classfile.visitor.*;
+import proguard.optimize.info.NoSideEffectMethodMarker;
/**
@@ -30,6 +31,7 @@ import proguard.classfile.visitor.*;
* marks classes and class members it visits. The marked elements
* will remain unchanged as necessary in the optimization step.
*
+ * @see NoSideEffectMethodMarker
* @author Eric Lafortune
*/
public class KeepMarker
@@ -90,6 +92,12 @@ implements ClassVisitor,
public static boolean isKept(VisitorAccepter visitorAccepter)
{
- return MethodLinker.lastVisitorAccepter(visitorAccepter).getVisitorInfo() == KEPT;
+ // 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;
}
}
diff --git a/src/proguard/optimize/KeptClassFilter.java b/src/proguard/optimize/KeptClassFilter.java
new file mode 100644
index 0000000..60a9d3e
--- /dev/null
+++ b/src/proguard/optimize/KeptClassFilter.java
@@ -0,0 +1,69 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This ClassVisitor delegates all its method calls to another ClassVisitor,
+ * but only for Clazz objects that are marked as kept.
+ *
+ * @see KeepMarker
+ *
+ * @author Eric Lafortune
+ */
+public class KeptClassFilter
+implements ClassVisitor
+{
+ private final ClassVisitor classVisitor;
+
+
+ /**
+ * Creates a new KeptClassFilter.
+ * @param classVisitor the class visitor to which the visiting will be
+ * delegated.
+ */
+ public KeptClassFilter(ClassVisitor classVisitor)
+ {
+ this.classVisitor = classVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (KeepMarker.isKept(programClass))
+ {
+ classVisitor.visitProgramClass(programClass);
+ }
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ if (KeepMarker.isKept(libraryClass))
+ {
+ classVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/KeptMemberFilter.java b/src/proguard/optimize/KeptMemberFilter.java
new file mode 100644
index 0000000..1bdadb4
--- /dev/null
+++ b/src/proguard/optimize/KeptMemberFilter.java
@@ -0,0 +1,87 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.MemberVisitor;
+
+/**
+ * This MemberVisitor delegates all its method calls to another MemberVisitor,
+ * but only for Member objects that are marked as kept.
+ *
+ * @see KeepMarker
+ *
+ * @author Eric Lafortune
+ */
+public class KeptMemberFilter
+implements MemberVisitor
+{
+ private final MemberVisitor memberVisitor;
+
+
+ /**
+ * Creates a new KeptMemberFilter.
+ * @param memberVisitor the member visitor to which the visiting will be
+ * delegated.
+ */
+ public KeptMemberFilter(MemberVisitor memberVisitor)
+ {
+ this.memberVisitor = memberVisitor;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ if (KeepMarker.isKept(programField))
+ {
+ memberVisitor.visitProgramField(programClass, programField);
+ }
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (KeepMarker.isKept(programMethod))
+ {
+ memberVisitor.visitProgramMethod(programClass, programMethod);
+ }
+ }
+
+
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
+ {
+ if (KeepMarker.isKept(libraryField))
+ {
+ memberVisitor.visitLibraryField(libraryClass, libraryField);
+ }
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ if (KeepMarker.isKept(libraryMethod))
+ {
+ memberVisitor.visitLibraryMethod(libraryClass, libraryMethod);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/MemberDescriptorSpecializer.java b/src/proguard/optimize/MemberDescriptorSpecializer.java
index 0d0b841..4dce62e 100644
--- a/src/proguard/optimize/MemberDescriptorSpecializer.java
+++ b/src/proguard/optimize/MemberDescriptorSpecializer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -39,7 +39,7 @@ public class MemberDescriptorSpecializer
extends SimplifiedVisitor
implements MemberVisitor
{
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final MemberVisitor extraParameterMemberVisitor;
diff --git a/src/proguard/optimize/MethodDescriptorShrinker.java b/src/proguard/optimize/MethodDescriptorShrinker.java
index 48374e7..d8d4425 100644
--- a/src/proguard/optimize/MethodDescriptorShrinker.java
+++ b/src/proguard/optimize/MethodDescriptorShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,7 @@ package proguard.optimize;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.attribute.visitor.*;
import proguard.classfile.editor.ConstantPoolEditor;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
@@ -95,11 +95,9 @@ implements MemberVisitor,
if (DEBUG)
{
System.out.println("MethodDescriptorShrinker:");
- System.out.println(" Class file = "+programClass.getName());
- System.out.println(" Method name = "+name);
- System.out.println(" -> "+newName);
- System.out.println(" Method descriptor = "+descriptor);
- System.out.println(" -> "+newDescriptor);
+ System.out.println(" ["+programClass.getName()+"."+
+ name+descriptor+"] -> ["+
+ newName+newDescriptor+"]");
}
ConstantPoolEditor constantPoolEditor =
diff --git a/src/proguard/optimize/MethodStaticizer.java b/src/proguard/optimize/MethodStaticizer.java
index 8dd11e1..c8bdd11 100644
--- a/src/proguard/optimize/MethodStaticizer.java
+++ b/src/proguard/optimize/MethodStaticizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/OptimizationInfoMemberFilter.java b/src/proguard/optimize/OptimizationInfoMemberFilter.java
index 8760aee..2c5454c 100644
--- a/src/proguard/optimize/OptimizationInfoMemberFilter.java
+++ b/src/proguard/optimize/OptimizationInfoMemberFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/Optimizer.java b/src/proguard/optimize/Optimizer.java
index a3e8a6e..8042825 100644
--- a/src/proguard/optimize/Optimizer.java
+++ b/src/proguard/optimize/Optimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,8 @@ package proguard.optimize;
import proguard.*;
import proguard.classfile.*;
import proguard.classfile.attribute.visitor.*;
-import proguard.classfile.constant.visitor.AllConstantVisitor;
+import proguard.classfile.constant.Constant;
+import proguard.classfile.constant.visitor.*;
import proguard.classfile.editor.*;
import proguard.classfile.instruction.visitor.*;
import proguard.classfile.util.MethodLinker;
@@ -66,6 +67,7 @@ public class Optimizer
private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast";
private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field";
private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch";
+ private static final String CODE_SIMPLIFICATION_STRING = "code/simplification/string";
private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced";
private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced";
private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple";
@@ -80,6 +82,7 @@ public class Optimizer
CLASS_MERGING_VERTICAL,
CLASS_MERGING_HORIZONTAL,
FIELD_REMOVAL_WRITEONLY,
+ FIELD_MARKING_PRIVATE,
FIELD_PROPAGATION_VALUE,
METHOD_MARKING_PRIVATE,
METHOD_MARKING_STATIC,
@@ -96,6 +99,7 @@ public class Optimizer
CODE_SIMPLIFICATION_CAST,
CODE_SIMPLIFICATION_FIELD,
CODE_SIMPLIFICATION_BRANCH,
+ CODE_SIMPLIFICATION_STRING,
CODE_SIMPLIFICATION_ADVANCED,
CODE_REMOVAL_ADVANCED,
CODE_REMOVAL_SIMPLE,
@@ -157,6 +161,7 @@ public class Optimizer
boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST);
boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD);
boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH);
+ boolean codeSimplificationString = filter.matches(CODE_SIMPLIFICATION_STRING);
boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED);
boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED);
boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE);
@@ -186,13 +191,15 @@ public class Optimizer
InstructionCounter codeSimplificationCastCounter = new InstructionCounter();
InstructionCounter codeSimplificationFieldCounter = new InstructionCounter();
InstructionCounter codeSimplificationBranchCounter = new InstructionCounter();
+ InstructionCounter codeSimplificationStringCounter = new InstructionCounter();
InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter();
InstructionCounter deletedCounter = new InstructionCounter();
InstructionCounter addedCounter = new InstructionCounter();
MemberCounter codeRemovalVariableCounter = new MemberCounter();
ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter();
MemberCounter codeAllocationVariableCounter = new MemberCounter();
- MemberCounter initializerFixCounter = new MemberCounter();
+ MemberCounter initializerFixCounter1 = new MemberCounter();
+ MemberCounter initializerFixCounter2 = new MemberCounter();
// Some optimizations are required by other optimizations.
codeSimplificationAdvanced =
@@ -250,10 +257,27 @@ public class Optimizer
new AllInstructionVisitor(
new DotClassClassVisitor(keepMarker)))));
- // We also keep all classes that are involved in Class.forName constructs.
+ // We also keep all classes that are accessed dynamically.
programClassPool.classesAccept(
new AllConstantVisitor(
- new ClassForNameClassVisitor(keepMarker)));
+ new ConstantTagFilter(ClassConstants.CONSTANT_String,
+ new ReferencedClassVisitor(keepMarker))));
+
+ // We also keep all class members that are accessed dynamically.
+ programClassPool.classesAccept(
+ new AllConstantVisitor(
+ new ConstantTagFilter(ClassConstants.CONSTANT_String,
+ new ReferencedMemberVisitor(keepMarker))));
+
+ // We also keep all bootstrap method signatures.
+ programClassPool.classesAccept(
+ new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_7,
+ new AllAttributeVisitor(
+ new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
+ new AllBootstrapMethodInfoVisitor(
+ new BootstrapMethodHandleTraveler(
+ new MethodrefTraveler(
+ new ReferencedMemberVisitor(keepMarker))))))));
// Attach some optimization info to all classes and class members, so
// it can be filled out later.
@@ -320,6 +344,9 @@ public class Optimizer
new ParameterUsageMarker(!methodMarkingStatic,
!methodRemovalParameter))));
+ // Mark all classes that have static initializers.
+ programClassPool.classesAccept(new StaticInitializerContainingClassMarker());
+
// Mark all methods that have side effects.
programClassPool.accept(new SideEffectMethodMarker());
@@ -347,18 +374,29 @@ public class Optimizer
new AllAttributeVisitor(
new PartialEvaluator(valueFactory, storingInvocationUnit, false))));
- // Count the constant fields and methods.
- programClassPool.classesAccept(
- new MultiClassVisitor(
- new ClassVisitor[]
- {
+ if (fieldPropagationValue)
+ {
+ // Count the constant fields.
+ programClassPool.classesAccept(
new AllFieldVisitor(
- new ConstantMemberFilter(fieldPropagationValueCounter)),
+ new ConstantMemberFilter(fieldPropagationValueCounter)));
+ }
+
+ if (methodPropagationParameter)
+ {
+ // Count the constant method parameters.
+ programClassPool.classesAccept(
new AllMethodVisitor(
- new ConstantParameterFilter(methodPropagationParameterCounter)),
+ new ConstantParameterFilter(methodPropagationParameterCounter)));
+ }
+
+ if (methodPropagationReturnvalue)
+ {
+ // Count the constant method return values.
+ programClassPool.classesAccept(
new AllMethodVisitor(
- new ConstantMemberFilter(methodPropagationReturnvalueCounter)),
- }));
+ new ConstantMemberFilter(methodPropagationReturnvalueCounter)));
+ }
}
InvocationUnit loadingInvocationUnit =
@@ -418,6 +456,12 @@ public class Optimizer
// This operation also updates the stack sizes.
programClassPool.classesAccept(
new MemberReferenceFixer());
+
+ // Remove unused bootstrap method arguments.
+ programClassPool.classesAccept(
+ new AllAttributeVisitor(
+ new AllBootstrapMethodInfoVisitor(
+ new BootstrapMethodArgumentShrinker())));
}
if (methodRemovalParameter ||
@@ -441,17 +485,39 @@ public class Optimizer
new StackSizeUpdater())));
}
-// // Specializing the class member descriptors seems to increase the
-// // class file size, on average.
-// // Specialize all class member descriptors.
-// programClassPool.classesAccept(new AllMemberVisitor(
-// new OptimizationInfoMemberFilter(
-// new MemberDescriptorSpecializer())));
-//
-// // Fix all references to classes, for MemberDescriptorSpecializer.
-// programClassPool.classesAccept(new AllMemberVisitor(
-// new OptimizationInfoMemberFilter(
-// new ClassReferenceFixer(true))));
+ if (methodRemovalParameter &&
+ methodRemovalParameterCounter.getCount() > 0)
+ {
+ // Tweak the descriptors of duplicate initializers, due to removed
+ // method parameters.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new DuplicateInitializerFixer(initializerFixCounter1)));
+
+ if (initializerFixCounter1.getCount() > 0)
+ {
+ // Fix all invocations of tweaked initializers.
+ programClassPool.classesAccept(
+ new AllMethodVisitor(
+ new AllAttributeVisitor(
+ new DuplicateInitializerInvocationFixer(addedCounter))));
+
+ // Fix all references to tweaked initializers.
+ programClassPool.classesAccept(new MemberReferenceFixer());
+ }
+ }
+
+ //// Specializing the class member descriptors seems to increase the
+ //// class file size, on average.
+ //// Specialize all class member descriptors.
+ //programClassPool.classesAccept(new AllMemberVisitor(
+ // new OptimizationInfoMemberFilter(
+ // new MemberDescriptorSpecializer())));
+ //
+ //// Fix all references to classes, for MemberDescriptorSpecializer.
+ //programClassPool.classesAccept(new AllMemberVisitor(
+ // new OptimizationInfoMemberFilter(
+ // new ClassReferenceFixer(true))));
// Mark all classes with package visible members.
// Mark all exception catches of methods.
@@ -461,13 +527,13 @@ public class Optimizer
new MultiClassVisitor(
new ClassVisitor[]
{
+ new PackageVisibleMemberContainingClassMarker(),
new AllConstantVisitor(
new PackageVisibleMemberInvokingClassMarker()),
new AllMethodVisitor(
new MultiMemberVisitor(
new MemberVisitor[]
{
- new PackageVisibleMemberContainingClassMarker(),
new AllAttributeVisitor(
new MultiAttributeVisitor(
new AttributeVisitor[]
@@ -511,8 +577,8 @@ public class Optimizer
classMergingHorizontalCounter));
}
- if (classMergingVertical ||
- classMergingHorizontal)
+ if (classMergingVerticalCounter .getCount() > 0 ||
+ classMergingHorizontalCounter.getCount() > 0)
{
// Clean up inner class attributes to avoid loops.
programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover());
@@ -530,18 +596,20 @@ public class Optimizer
new AllConstantVisitor(
new AccessFixer()));
}
- }
- if (methodRemovalParameter ||
- classMergingVertical ||
- classMergingHorizontal)
- {
- // Tweak the descriptors of duplicate initializers.
+ // Fix the access flags of the inner classes information.
+ programClassPool.classesAccept(
+ new AllAttributeVisitor(
+ new AllInnerClassesInfoVisitor(
+ new InnerClassesAccessFixer())));
+
+ // Tweak the descriptors of duplicate initializers, due to merged
+ // parameter classes.
programClassPool.classesAccept(
new AllMethodVisitor(
- new DuplicateInitializerFixer(initializerFixCounter)));
+ new DuplicateInitializerFixer(initializerFixCounter2)));
- if (initializerFixCounter.getCount() > 0)
+ if (initializerFixCounter2.getCount() > 0)
{
// Fix all invocations of tweaked initializers.
programClassPool.classesAccept(
@@ -595,14 +663,14 @@ public class Optimizer
new NonPrivateMemberMarker());
}
- if (fieldMarkingPrivate ||
- methodMarkingPrivate)
+ if (fieldMarkingPrivate)
{
// Make all non-private fields private, whereever possible.
programClassPool.classesAccept(
+ new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE,
new AllFieldVisitor(
new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
- new MemberPrivatizer(fieldMarkingPrivateCounter))));
+ new MemberPrivatizer(fieldMarkingPrivateCounter)))));
}
if (methodMarkingPrivate)
@@ -615,9 +683,9 @@ public class Optimizer
new MemberPrivatizer(methodMarkingPrivateCounter)))));
}
- if ((methodInliningUnique ||
- methodInliningShort ||
- methodInliningTailrecursion) &&
+ if ((methodInliningUniqueCounter .getCount() > 0 ||
+ methodInliningShortCounter .getCount() > 0 ||
+ methodInliningTailrecursionCounter.getCount() > 0) &&
configuration.allowAccessModification)
{
// Fix the access flags of referenced classes and class members,
@@ -627,10 +695,10 @@ public class Optimizer
new AccessFixer()));
}
- if (methodRemovalParameter ||
- classMergingVertical ||
- classMergingHorizontal ||
- methodMarkingPrivate)
+ if (methodRemovalParameterCounter .getCount() > 0 ||
+ classMergingVerticalCounter .getCount() > 0 ||
+ classMergingHorizontalCounter .getCount() > 0 ||
+ methodMarkingPrivateCounter .getCount() > 0 )
{
// Fix invocations of interface methods, of methods that have become
// non-abstract or private, and of methods that have moved to a
@@ -707,6 +775,15 @@ public class Optimizer
new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
}
+ if (codeSimplificationString)
+ {
+ // Peephole optimizations involving branches.
+ peepholeOptimizations.add(
+ new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
+ InstructionSequenceConstants.STRING,
+ branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter));
+ }
+
if (!peepholeOptimizations.isEmpty())
{
// Convert the list into an array.
@@ -749,14 +826,6 @@ public class Optimizer
new AllAttributeVisitor(
new VariableShrinker(codeRemovalVariableCounter))));
}
- else
- {
- // Clean up all unused local variables.
- programClassPool.classesAccept(
- new AllMethodVisitor(
- new AllAttributeVisitor(
- new VariableCleaner())));
- }
if (codeAllocationVariable)
{
@@ -767,6 +836,11 @@ public class Optimizer
new VariableOptimizer(false, codeAllocationVariableCounter))));
}
+
+ // Remove unused constants.
+ programClassPool.classesAccept(
+ new ConstantPoolShrinker());
+
int classMarkingFinalCount = classMarkingFinalCounter .getCount();
int classMergingVerticalCount = classMergingVerticalCounter .getCount();
int classMergingHorizontalCount = classMergingHorizontalCounter .getCount();
@@ -776,7 +850,7 @@ public class Optimizer
int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount();
int methodMarkingStaticCount = methodMarkingStaticCounter .getCount();
int methodMarkingFinalCount = methodMarkingFinalCounter .getCount();
- int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter.getCount();
+ int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount();
int methodPropagationParameterCount = methodPropagationParameterCounter .getCount();
int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount();
int methodInliningShortCount = methodInliningShortCounter .getCount();
@@ -788,12 +862,23 @@ public class Optimizer
int codeSimplificationCastCount = codeSimplificationCastCounter .getCount();
int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount();
int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount();
+ int codeSimplificationStringCount = codeSimplificationStringCounter .getCount();
int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount();
int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount();
int codeRemovalVariableCount = codeRemovalVariableCounter .getCount();
int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount();
int codeAllocationVariableCount = codeAllocationVariableCounter .getCount();
+ // Forget about constant fields, parameters, and return values, if they
+ // didn't lead to any useful optimizations. We want to avoid fruitless
+ // additional optimization passes.
+ if (codeSimplificationAdvancedCount == 0)
+ {
+ fieldPropagationValueCount = 0;
+ methodPropagationParameterCount = 0;
+ methodPropagationReturnvalueCount = 0;
+ }
+
if (configuration.verbose)
{
System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal));
@@ -817,6 +902,7 @@ public class Optimizer
System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast));
System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField));
System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch));
+ System.out.println(" Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString));
System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced));
System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced));
System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable));
@@ -845,6 +931,7 @@ public class Optimizer
codeSimplificationCastCount > 0 ||
codeSimplificationFieldCount > 0 ||
codeSimplificationBranchCount > 0 ||
+ codeSimplificationStringCount > 0 ||
codeSimplificationAdvancedCount > 0 ||
codeRemovalCount > 0 ||
codeRemovalVariableCount > 0 ||
diff --git a/src/proguard/optimize/ParameterShrinker.java b/src/proguard/optimize/ParameterShrinker.java
index a2bc6d3..33d37d1 100644
--- a/src/proguard/optimize/ParameterShrinker.java
+++ b/src/proguard/optimize/ParameterShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,7 @@ package proguard.optimize;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.editor.*;
+import proguard.classfile.editor.VariableRemapper;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
import proguard.optimize.info.ParameterUsageMarker;
diff --git a/src/proguard/optimize/TailRecursionSimplifier.java b/src/proguard/optimize/TailRecursionSimplifier.java
index 0946b6a..f820566 100644
--- a/src/proguard/optimize/TailRecursionSimplifier.java
+++ b/src/proguard/optimize/TailRecursionSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -54,9 +54,9 @@ implements AttributeVisitor,
private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer();
+ private final MyRecursionChecker recursionChecker = new MyRecursionChecker();
private Method targetMethod;
- private boolean recursive;
private boolean inlinedAny;
@@ -105,38 +105,31 @@ implements AttributeVisitor,
// clazz.getName().equals("abc/Def") &&
// method.getName(clazz).equals("abc");
- targetMethod = method;
- inlinedAny = false;
+ targetMethod = method;
+ inlinedAny = false;
codeAttributeComposer.reset();
- // Append the body of the code.
- copyCode(clazz, method, codeAttribute);
+ // The code may expand, due to expanding constant and variable
+ // instructions.
+ codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength);
+
+ // Copy the instructions.
+ codeAttribute.instructionsAccept(clazz, method, this);
// Update the code attribute if any code has been inlined.
if (inlinedAny)
{
- codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute);
- }
- }
- }
+ // Copy the exceptions.
+ codeAttribute.exceptionsAccept(clazz, method, this);
+ // Append a label just after the code.
+ codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
- /**
- * Appends the code of the given code attribute.
- */
- private void copyCode(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
- // The code may expand, due to expanding constant and variable
- // instructions.
- codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength);
-
- // Copy the instructions.
- codeAttribute.instructionsAccept(clazz, method, this);
+ codeAttributeComposer.endCodeFragment();
- // Append a label just after the code.
- codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
-
- codeAttributeComposer.endCodeFragment();
+ codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+ }
}
@@ -145,7 +138,7 @@ implements AttributeVisitor,
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
{
// Copy the instruction.
- codeAttributeComposer.appendInstruction(offset, instruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, instruction);
}
@@ -159,9 +152,9 @@ implements AttributeVisitor,
case InstructionConstants.OP_INVOKESTATIC:
{
// Is it a recursive call?
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, recursionChecker);
- if (recursive)
+ if (recursionChecker.isRecursive())
{
// Is the next instruction a return?
int nextOffset =
@@ -180,13 +173,13 @@ implements AttributeVisitor,
case InstructionConstants.OP_RETURN:
{
// Isn't the recursive call inside a try/catch block?
- codeAttribute.exceptionsAccept(clazz, method, offset, this);
+ codeAttribute.exceptionsAccept(clazz, method, offset, recursionChecker);
- if (recursive)
+ if (recursionChecker.isRecursive())
{
if (DEBUG)
{
- System.out.println("TailRecursionSimplifier.visitConstantInstruction: ["+
+ System.out.println("TailRecursionSimplifier: ["+
clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"], inlining "+constantInstruction.toString(offset));
}
@@ -223,23 +216,56 @@ implements AttributeVisitor,
}
// Copy the instruction.
- codeAttributeComposer.appendInstruction(offset, constantInstruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, constantInstruction);
}
- // Implementations for ConstantVisitor.
+ // Implementations for ExceptionInfoVisitor.
- public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
{
- recursive = targetMethod.equals(methodrefConstant.referencedMember);
+ codeAttributeComposer.appendException(new ExceptionInfo(exceptionInfo.u2startPC,
+ exceptionInfo.u2endPC,
+ exceptionInfo.u2handlerPC,
+ exceptionInfo.u2catchType));
}
- // Implementations for ExceptionInfoVisitor.
-
- public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
+ /**
+ * This ConstantVisitor and ExceptionInfoVisitor returns whether a method
+ * invocation can be treated as tail-recursive.
+ */
+ private class MyRecursionChecker
+ extends SimplifiedVisitor
+ implements ConstantVisitor,
+ ExceptionInfoVisitor
{
- recursive = false;
+ private boolean recursive;
+
+
+ /**
+ * Returns whether the method invocation can be treated as
+ * tail-recursive.
+ */
+ public boolean isRecursive()
+ {
+ return recursive;
+ }
+
+ // Implementations for ConstantVisitor.
+
+ public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ {
+ recursive = targetMethod.equals(methodrefConstant.referencedMember);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
+ {
+ recursive = false;
+ }
}
@@ -257,7 +283,6 @@ implements AttributeVisitor,
(method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0;
// Count the number of parameters, taking into account their categories.
- int parameterCount = ClassUtil.internalMethodParameterCount(descriptor);
int parameterSize = ClassUtil.internalMethodParameterSize(descriptor);
int parameterOffset = isStatic ? 0 : 1;
@@ -315,7 +340,7 @@ implements AttributeVisitor,
}
codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1,
- new VariableInstruction(opcode, parameterOffset + parameterIndex).shrink());
+ new VariableInstruction(opcode, parameterOffset + parameterIndex));
}
}
@@ -323,7 +348,7 @@ implements AttributeVisitor,
if (!isStatic)
{
codeAttributeComposer.appendInstruction(parameterSize,
- new VariableInstruction(InstructionConstants.OP_ASTORE, 0).shrink());
+ new VariableInstruction(InstructionConstants.OP_ASTORE, 0));
}
codeAttributeComposer.endCodeFragment();
diff --git a/src/proguard/optimize/WriteOnlyFieldFilter.java b/src/proguard/optimize/WriteOnlyFieldFilter.java
index 578beb2..762bd91 100644
--- a/src/proguard/optimize/WriteOnlyFieldFilter.java
+++ b/src/proguard/optimize/WriteOnlyFieldFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/EvaluationShrinker.java b/src/proguard/optimize/evaluation/EvaluationShrinker.java
index 1463feb..2e86532 100644
--- a/src/proguard/optimize/evaluation/EvaluationShrinker.java
+++ b/src/proguard/optimize/evaluation/EvaluationShrinker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -34,6 +34,8 @@ import proguard.evaluation.*;
import proguard.evaluation.value.*;
import proguard.optimize.info.*;
+import java.util.Arrays;
+
/**
* This AttributeVisitor simplifies the code attributes that it visits, based
* on partial evaluation.
@@ -52,21 +54,55 @@ implements AttributeVisitor
private static boolean DEBUG = true;
//*/
+ 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 InstructionVisitor extraDeletedInstructionVisitor;
private final InstructionVisitor extraAddedInstructionVisitor;
- private final PartialEvaluator partialEvaluator;
- private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator();
- private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
- private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier();
- private final MyProducerMarker producerMarker = new MyProducerMarker();
- private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer();
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false);
+ private final PartialEvaluator partialEvaluator;
+ private final PartialEvaluator simplePartialEvaluator = new PartialEvaluator();
+ private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
+ private final MyUnusedParameterSimplifier unusedParameterSimplifier = new MyUnusedParameterSimplifier();
+ private final MyProducerMarker producerMarker = new MyProducerMarker();
+ private final MyVariableInitializationMarker variableInitializationMarker = new MyVariableInitializationMarker();
+ private final MyStackConsistencyFixer stackConsistencyFixer = new MyStackConsistencyFixer();
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, false);
- private boolean[][] variablesNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_VARIABLES_SIZE];
- private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
- private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
- private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
+ private boolean[][] stacksNecessaryAfter = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
+ private boolean[][] stacksSimplifiedBefore = new boolean[ClassConstants.TYPICAL_CODE_LENGTH][ClassConstants.TYPICAL_STACK_SIZE];
+ private boolean[] instructionsNecessary = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
private int maxMarkedOffset;
@@ -154,6 +190,9 @@ implements AttributeVisitor
// Evaluate the method.
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;
// Reset the code changes.
@@ -272,22 +311,13 @@ implements AttributeVisitor
for (int offset = 0; offset < codeLength; offset++)
{
- // Is it a variable initialization that hasn't been marked yet?
- if (partialEvaluator.isTraced(offset) &&
- !isInstructionNecessary(offset))
+ if (isInstructionNecessary(offset))
{
- // Is the corresponding variable necessary anywhere in the code,
- // accoriding to a simple partial evaluation?
- int variableIndex = partialEvaluator.initializedVariable(offset);
- if (variableIndex >= 0 &&
- isVariableInitializationNecessary(clazz,
- method,
- codeAttribute,
- offset,
- variableIndex))
- {
- markInstruction(offset);
- }
+ // Mark initializations of the required instruction.
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+
+ instruction.accept(clazz, method, codeAttribute, offset, variableInitializationMarker);
}
}
if (DEBUG) System.out.println();
@@ -383,12 +413,9 @@ implements AttributeVisitor
offset);
if (!isInstructionNecessary(offset))
{
+ codeAttributeEditor.clearModifications(offset);
codeAttributeEditor.deleteInstruction(offset);
- codeAttributeEditor.insertBeforeInstruction(offset, (Instruction)null);
- codeAttributeEditor.replaceInstruction(offset, (Instruction)null);
- codeAttributeEditor.insertAfterInstruction(offset, (Instruction)null);
-
// Visit the instruction, if required.
if (extraDeletedInstructionVisitor != null)
{
@@ -467,7 +494,9 @@ implements AttributeVisitor
*/
private class MyUnusedParameterSimplifier
extends SimplifiedVisitor
- implements InstructionVisitor, ConstantVisitor, MemberVisitor
+ implements InstructionVisitor,
+ ConstantVisitor,
+ MemberVisitor
{
private int invocationOffset;
private ConstantInstruction invocationInstruction;
@@ -614,8 +643,8 @@ implements AttributeVisitor
public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
{
- // Is the variable being loaded (or incremented)?
- if (variableInstruction.opcode < InstructionConstants.OP_ISTORE)
+ // Is the variable being loaded or incremented?
+ if (variableInstruction.isLoad())
{
markVariableProducers(offset, variableInstruction.variableIndex);
}
@@ -656,6 +685,32 @@ implements AttributeVisitor
}
+ /**
+ * This InstructionVisitor marks variable initializations that are
+ * necessary to appease the JVM.
+ */
+ private class MyVariableInitializationMarker
+ extends SimplifiedVisitor
+ implements InstructionVisitor
+ {
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ // 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.
+ markVariableInitializers(offset, variableInstruction.variableIndex);
+ }
+ }
+ }
+
+
/**
* This InstructionVisitor fixes instructions locally, popping any unused
* produced stack entries after marked instructions, and popping produced
@@ -682,17 +737,25 @@ implements AttributeVisitor
TracedStack tracedStack =
partialEvaluator.getStackBefore(offset);
- int top = tracedStack.size() - 1;
+ int stackSize = tracedStack.size();
int requiredPushCount = 0;
- for (int stackIndex = 0; stackIndex < popCount; stackIndex++)
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
{
- // Is the stack entry required by other consumers?
- if (!isStackSimplifiedBefore(offset, top - stackIndex) &&
- !isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex))
+ if (!isStackSimplifiedBefore(offset, stackIndex))
{
- // Remember to push it.
- requiredPushCount++;
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex);
+ }
+ else
+ {
+ // Remember to push it.
+ requiredPushCount++;
+ }
}
}
@@ -703,13 +766,39 @@ implements AttributeVisitor
if (requiredPushCount > (instruction.isCategory2() ? 2 : 1))
{
- throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"]");
+ throw new IllegalArgumentException("Unsupported stack size increment ["+requiredPushCount+"] at ["+offset+"]");
}
insertPushInstructions(offset, false, tracedStack.getTop(0).computationalType());
}
}
+ // Check all other stack entries, if this is a return
+ // instruction.
+ // Typical case: the code returns, but there are still other
+ // entries left on the stack. These have to be consistent.
+ InstructionOffsetValue branchTargets =
+ partialEvaluator.branchTargets(offset);
+ if (branchTargets != null &&
+ branchTargets.instructionOffsetCount() == 0)
+ {
+ TracedStack tracedStack =
+ partialEvaluator.getStackBefore(offset);
+
+ int unpoppedStackSize = tracedStack.size() - popCount;
+
+ for (int stackIndex = 0; stackIndex < unpoppedStackSize; stackIndex++)
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex);
+ }
+ }
+ }
+
// Check all stack entries that are pushed.
// Typical case: a return value that wasn't really required and
// that should be popped.
@@ -719,13 +808,13 @@ implements AttributeVisitor
TracedStack tracedStack =
partialEvaluator.getStackAfter(offset);
- int top = tracedStack.size() - 1;
+ int stackSize = tracedStack.size();
int requiredPopCount = 0;
- for (int stackIndex = 0; stackIndex < pushCount; stackIndex++)
+ for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
{
// Is the stack entry required by consumers?
- if (!isStackEntryNecessaryAfter(offset, top - stackIndex))
+ if (!isStackEntryNecessaryAfter(offset, stackIndex))
{
// Remember to pop it.
requiredPopCount++;
@@ -752,14 +841,18 @@ implements AttributeVisitor
TracedStack tracedStack =
partialEvaluator.getStackBefore(offset);
- int top = tracedStack.size() - 1;
+ int stackSize = tracedStack.size();
int expectedPopCount = 0;
- for (int stackIndex = 0; stackIndex < popCount; stackIndex++)
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
{
- // Is the stack entry required by other consumers?
- if (isAnyStackEntryNecessaryAfter(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(), top - stackIndex))
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (isStackEntryPresentBefore(offset, stackIndex))
{
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex);
+
// Remember to pop it.
expectedPopCount++;
}
@@ -782,13 +875,13 @@ implements AttributeVisitor
TracedStack tracedStack =
partialEvaluator.getStackAfter(offset);
- int top = tracedStack.size() - 1;
+ int stackSize = tracedStack.size();
int expectedPushCount = 0;
- for (int stackIndex = 0; stackIndex < pushCount; stackIndex++)
+ for (int stackIndex = stackSize - pushCount; stackIndex < stackSize; stackIndex++)
{
// Is the stack entry required by consumers?
- if (isStackEntryNecessaryAfter(offset, top - stackIndex))
+ if (isStackEntryNecessaryAfter(offset, stackIndex))
{
// Remember to push it.
expectedPushCount++;
@@ -812,44 +905,546 @@ implements AttributeVisitor
if (isInstructionNecessary(offset) &&
isDupOrSwap(simpleInstruction))
{
- fixDupInstruction(clazz, codeAttribute, offset, simpleInstruction);
+ int stackSizeBefore = partialEvaluator.getStackBefore(offset).size();
+
+ // Check all stack entries that are popped.
+ // Typical case: a freshly marked variable initialization that
+ // requires some value on the stack.
+ int popCount = simpleInstruction.stackPopCount(clazz);
+ if (popCount > 0)
+ {
+ for (int stackIndex = stackSizeBefore - popCount; stackIndex < stackSizeBefore; stackIndex++)
+ {
+ // Is this stack entry pushed by any producer
+ // (because it is required by other consumers)?
+ if (isStackEntryPresentBefore(offset, stackIndex))
+ {
+ // Mark all produced stack entries.
+ markStackEntryProducers(offset, stackIndex);
+ }
+ }
+ }
+
+ int topBefore = stackSizeBefore - 1;
+ int topAfter = partialEvaluator.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 suitabe (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);
}
}
+
+
+ /**
+ * 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 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
+
+ boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
+ boolean stackEntryNecessary1 = 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 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
+ boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+
+ boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
+ boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = 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 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
+ boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+ boolean stackEntryPresent2 = isStackEntryPresentBefore(instructionOffset, topBefore - 2);
+
+ boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
+ boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = 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 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
+ boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+
+ boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
+ boolean stackEntryNecessary1 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 1);
+ boolean stackEntryNecessary2 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = 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 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1);
+ boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2);
+
+ boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1);
+ boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
+ boolean stackEntriesNecessary34 = 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 = isStackEntriesPresentBefore(instructionOffset, topBefore - 0, topBefore - 1);
+ boolean stackEntryPresent2 = isStackEntryPresentBefore( instructionOffset, topBefore - 2);
+ boolean stackEntryPresent3 = isStackEntryPresentBefore( instructionOffset, topBefore - 3);
+
+ boolean stackEntriesNecessary01 = isStackEntriesNecessaryAfter(instructionOffset, topAfter - 0, topAfter - 1);
+ boolean stackEntryNecessary2 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 2);
+ boolean stackEntryNecessary3 = isStackEntryNecessaryAfter( instructionOffset, topAfter - 3);
+ boolean stackEntriesNecessary45 = 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 = isStackEntryPresentBefore(instructionOffset, topBefore - 0);
+ boolean stackEntryPresent1 = isStackEntryPresentBefore(instructionOffset, topBefore - 1);
+
+ boolean stackEntryNecessary0 = isStackEntryNecessaryAfter(instructionOffset, topAfter - 0);
+ boolean stackEntryNecessary1 = 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
+ }
}
// Small utility methods.
/**
- * Marks the variable and the corresponding producing instructions
- * of the consumer at the given offset.
- * @param consumerOffset the offset of the consumer.
- * @param variableIndex the index of the variable to be marked.
+ * 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)
{
- TracedVariables tracedVariables =
- partialEvaluator.getVariablesBefore(consumerOffset);
+ InstructionOffsetValue producerOffsets =
+ partialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
- // Mark the producer of the loaded value.
- markVariableProducers(tracedVariables.getProducerValue(variableIndex).instructionOffsetValue(),
- variableIndex);
+ if (producerOffsets != null)
+ {
+ int offsetCount = producerOffsets.instructionOffsetCount();
+ for (int offsetIndex = 0; offsetIndex < offsetCount; offsetIndex++)
+ {
+ // Make sure the variable and the instruction are marked
+ // at the producing offset.
+ int offset = producerOffsets.instructionOffset(offsetIndex);
+
+ markInstruction(offset);
+ }
+ }
}
/**
- * Marks the variable and its producing instructions at the given offsets.
- * @param producerOffsets the offsets of the producers to be marked.
- * @param variableIndex the index of the variable to be marked.
+ * Marks the initializing instructions of the variable consumer at the given
+ * offset.
+ * @param consumerOffset the offset of the variable consumer.
+ * @param variableIndex the index of the variable that is loaded.
*/
- private void markVariableProducers(InstructionOffsetValue producerOffsets,
- int variableIndex)
+ private void markVariableInitializers(int consumerOffset,
+ int variableIndex)
{
+ InstructionOffsetValue producerOffsets =
+ simplePartialEvaluator.getVariablesBefore(consumerOffset).getProducerValue(variableIndex).instructionOffsetValue();
+
if (producerOffsets != null)
{
int offsetCount = producerOffsets.instructionOffsetCount();
@@ -859,8 +1454,15 @@ implements AttributeVisitor
// at the producing offset.
int offset = producerOffsets.instructionOffset(offsetIndex);
- markVariableAfter(offset, variableIndex);
- markInstruction(offset);
+ if (!isInstructionNecessary(offset) &&
+ isVariableInitialization(offset, variableIndex))
+ {
+ if (DEBUG) System.out.print(" Marking initialization of v"+variableIndex+" at ");
+
+ markInstruction(offset);
+
+ if (DEBUG) System.out.println();
+ }
}
}
}
@@ -877,9 +1479,14 @@ implements AttributeVisitor
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 = 0; stackIndex < popCount; stackIndex++)
+ for (int stackIndex = stackSize - popCount; stackIndex < stackSize; stackIndex++)
{
markStackEntryProducers(consumerOffset, stackIndex);
}
@@ -891,20 +1498,22 @@ implements AttributeVisitor
* of the consumer at the given offset, if the stack entry of the
* consumer is marked.
* @param consumerOffset the offset of the consumer.
- * @param consumerStackIndex the index of the stack entry to be checked
+ * @param consumerTopStackIndex the index of the stack entry to be checked
* (counting from the top).
- * @param producerStackIndex the index of the stack entry to be marked
+ * @param producerTopStackIndex the index of the stack entry to be marked
* (counting from the top).
*/
private void conditionallyMarkStackEntryProducers(int consumerOffset,
- int consumerStackIndex,
- int producerStackIndex)
+ int consumerTopStackIndex,
+ int producerTopStackIndex)
{
- int top = partialEvaluator.getStackAfter(consumerOffset).size() - 1;
+ int consumerBottomStackIndex = partialEvaluator.getStackAfter(consumerOffset).size() - consumerTopStackIndex - 1;
- if (isStackEntryNecessaryAfter(consumerOffset, top - consumerStackIndex))
+ if (isStackEntryNecessaryAfter(consumerOffset, consumerBottomStackIndex))
{
- markStackEntryProducers(consumerOffset, producerStackIndex);
+ int producerBottomStackIndex = partialEvaluator.getStackBefore(consumerOffset).size() - producerTopStackIndex - 1;
+
+ markStackEntryProducers(consumerOffset, producerBottomStackIndex);
}
}
@@ -914,20 +1523,15 @@ implements AttributeVisitor
* 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 top).
+ * (counting from the bottom).
*/
private void markStackEntryProducers(int consumerOffset,
int stackIndex)
{
- TracedStack tracedStack =
- partialEvaluator.getStackBefore(consumerOffset);
-
- int stackBottomIndex = tracedStack.size() - 1 - stackIndex;
-
- if (!isStackSimplifiedBefore(consumerOffset, stackBottomIndex))
+ if (!isStackSimplifiedBefore(consumerOffset, stackIndex))
{
- markStackEntryProducers(tracedStack.getTopProducerValue(stackIndex).instructionOffsetValue(),
- stackBottomIndex);
+ markStackEntryProducers(partialEvaluator.getStackBefore(consumerOffset).getBottomProducerValue(stackIndex).instructionOffsetValue(),
+ stackIndex);
}
}
@@ -1035,244 +1639,6 @@ implements AttributeVisitor
}
- /**
- * Marks the specified instruction if it is a required dup/swap instruction,
- * replacing it by an appropriate variant if necessary.
- * @param clazz the class that is being checked.
- * @param codeAttribute the code that is being checked.
- * @param dupOffset the offset of the dup/swap instruction.
- * @param instruction the dup/swap instruction.
- */
- private void fixDupInstruction(Clazz clazz,
- CodeAttribute codeAttribute,
- int dupOffset,
- Instruction instruction)
- {
- int top = partialEvaluator.getStackAfter(dupOffset).size() - 1;
-
- byte oldOpcode = instruction.opcode;
- byte newOpcode = 0;
-
- // Simplify the popping instruction if possible.
- switch (oldOpcode)
- {
- case InstructionConstants.OP_DUP:
- {
- boolean stackEntryPresent0 = isStackEntryNecessaryAfter(dupOffset, top - 0);
- boolean stackEntryPresent1 = isStackEntryNecessaryAfter(dupOffset, top - 1);
-
- // Should either the original element or the copy be present?
- if (stackEntryPresent0 ||
- stackEntryPresent1)
- {
- // Should both the original element and the copy be present?
- if (stackEntryPresent0 &&
- stackEntryPresent1)
- {
- newOpcode = InstructionConstants.OP_DUP;
- }
- }
- break;
- }
- case InstructionConstants.OP_DUP_X1:
- {
- boolean stackEntryPresent0 = isStackEntryNecessaryAfter(dupOffset, top - 0);
- boolean stackEntryPresent1 = isStackEntryNecessaryAfter(dupOffset, top - 1);
- boolean stackEntryPresent2 = isStackEntryNecessaryAfter(dupOffset, top - 2);
-
- // Should either the original element or the copy be present?
- if (stackEntryPresent0 ||
- stackEntryPresent2)
- {
- // Should the copy be present?
- if (stackEntryPresent2)
- {
- // Compute the number of elements to be skipped.
- int skipCount = stackEntryPresent1 ? 1 : 0;
-
- // Should the original element be present?
- if (stackEntryPresent0)
- {
- // Copy the original element.
- newOpcode = (byte)(InstructionConstants.OP_DUP + skipCount);
- }
- else if (skipCount == 1)
- {
- // Move the original element.
- newOpcode = InstructionConstants.OP_SWAP;
- }
- }
- }
- break;
- }
- case InstructionConstants.OP_DUP_X2:
- {
- boolean stackEntryPresent0 = isStackEntryNecessaryAfter(dupOffset, top - 0);
- boolean stackEntryPresent1 = isStackEntryNecessaryAfter(dupOffset, top - 1);
- boolean stackEntryPresent2 = isStackEntryNecessaryAfter(dupOffset, top - 2);
- boolean stackEntryPresent3 = isStackEntryNecessaryAfter(dupOffset, top - 3);
-
- // Should either the original element or the copy be present?
- if (stackEntryPresent0 ||
- stackEntryPresent3)
- {
- // Should the copy be present?
- if (stackEntryPresent3)
- {
- int skipCount = (stackEntryPresent1 ? 1 : 0) +
- (stackEntryPresent2 ? 1 : 0);
-
- // Should the original element be present?
- if (stackEntryPresent0)
- {
- // Copy the original element.
- newOpcode = (byte)(InstructionConstants.OP_DUP + skipCount);
- }
- else if (skipCount == 1)
- {
- // Move the original element.
- newOpcode = InstructionConstants.OP_SWAP;
- }
- else if (skipCount == 2)
- {
- // We can't easily move the original element.
- throw new UnsupportedOperationException("Can't handle dup_x2 instruction moving original element across two elements at ["+dupOffset +"]");
- }
- }
- }
- break;
- }
- case InstructionConstants.OP_DUP2:
- {
- boolean stackEntriesPresent01 = isStackEntriesNecessaryAfter(dupOffset, top - 0, top - 1);
- boolean stackEntriesPresent23 = isStackEntriesNecessaryAfter(dupOffset, top - 2, top - 3);
-
- // Should either the original element or the copy be present?
- if (stackEntriesPresent01 ||
- stackEntriesPresent23)
- {
- // Should both the original element and the copy be present?
- if (stackEntriesPresent01 &&
- stackEntriesPresent23)
- {
- newOpcode = InstructionConstants.OP_DUP2;
- }
- }
- break;
- }
- case InstructionConstants.OP_DUP2_X1:
- {
- boolean stackEntriesPresent01 = isStackEntriesNecessaryAfter(dupOffset, top - 0, top - 1);
- boolean stackEntryPresent2 = isStackEntryNecessaryAfter(dupOffset, top - 2);
- boolean stackEntriesPresent34 = isStackEntriesNecessaryAfter(dupOffset, top - 3, top - 4);
-
- // Should either the original element or the copy be present?
- if (stackEntriesPresent01 ||
- stackEntriesPresent34)
- {
- // Should the copy be present?
- if (stackEntriesPresent34)
- {
- int skipCount = stackEntryPresent2 ? 1 : 0;
-
- // Should the original element be present?
- if (stackEntriesPresent01)
- {
- // Copy the original element.
- newOpcode = (byte)(InstructionConstants.OP_DUP2 + skipCount);
- }
- else if (skipCount > 0)
- {
- // We can't easily move the original element.
- throw new UnsupportedOperationException("Can't handle dup2_x1 instruction moving original element across "+skipCount+" elements at ["+dupOffset +"]");
- }
- }
- }
- break;
- }
- case InstructionConstants.OP_DUP2_X2:
- {
- boolean stackEntriesPresent01 = isStackEntriesNecessaryAfter(dupOffset, top - 0, top - 1);
- boolean stackEntryPresent2 = isStackEntryNecessaryAfter(dupOffset, top - 2);
- boolean stackEntryPresent3 = isStackEntryNecessaryAfter(dupOffset, top - 3);
- boolean stackEntriesPresent45 = isStackEntriesNecessaryAfter(dupOffset, top - 4, top - 5);
-
- // Should either the original element or the copy be present?
- if (stackEntriesPresent01 ||
- stackEntriesPresent45)
- {
- // Should the copy be present?
- if (stackEntriesPresent45)
- {
- int skipCount = (stackEntryPresent2 ? 1 : 0) +
- (stackEntryPresent3 ? 1 : 0);
-
- // Should the original element be present?
- if (stackEntriesPresent01)
- {
- // Copy the original element.
- newOpcode = (byte)(InstructionConstants.OP_DUP2 + skipCount);
- }
- else if (skipCount > 0)
- {
- // We can't easily move the original element.
- throw new UnsupportedOperationException("Can't handle dup2_x2 instruction moving original element across "+skipCount+" elements at ["+dupOffset +"]");
- }
- }
- }
- break;
- }
- case InstructionConstants.OP_SWAP:
- {
- boolean stackEntryPresent0 = isStackEntryNecessaryAfter(dupOffset, top - 0);
- boolean stackEntryPresent1 = isStackEntryNecessaryAfter(dupOffset, top - 1);
-
- // Will either element be present?
- if (stackEntryPresent0 ||
- stackEntryPresent1)
- {
- // Will both elements be present?
- if (stackEntryPresent0 &&
- stackEntryPresent1)
- {
- newOpcode = InstructionConstants.OP_SWAP;
- }
- }
- break;
- }
- }
-
- if (newOpcode == 0)
- {
- // Delete the instruction.
- codeAttributeEditor.deleteInstruction(dupOffset);
-
- if (extraDeletedInstructionVisitor != null)
- {
- extraDeletedInstructionVisitor.visitSimpleInstruction(null, null, null, dupOffset, null);
- }
-
- if (DEBUG) System.out.println(" Marking but deleting instruction "+instruction.toString(dupOffset));
- }
- else if (newOpcode == oldOpcode)
- {
- // Leave the instruction unchanged.
- codeAttributeEditor.undeleteInstruction(dupOffset);
-
- if (DEBUG) System.out.println(" Marking unchanged instruction "+instruction.toString(dupOffset));
- }
- else
- {
- // Replace the instruction.
- Instruction replacementInstruction = new SimpleInstruction(newOpcode);
- codeAttributeEditor.replaceInstruction(dupOffset,
- replacementInstruction);
-
- if (DEBUG) System.out.println(" Replacing instruction "+instruction.toString(dupOffset)+" by "+replacementInstruction.toString());
- }
- }
-
-
/**
* Pushes a specified type of stack entry before or at the given offset.
* The instruction is marked as necessary.
@@ -1445,7 +1811,7 @@ implements AttributeVisitor
// Remember the replacement instruction.
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC,
- constantInstruction.constantIndex).shrink();
+ constantInstruction.constantIndex);
if (DEBUG) System.out.println(" Replacing by static invocation "+constantInstruction.toString(offset)+" -> "+replacementInstruction.toString());
@@ -1587,22 +1953,6 @@ implements AttributeVisitor
int maxStack = codeAttribute.u2maxStack;
// Create new arrays for storing information at each instruction offset.
- if (variablesNecessaryAfter.length < codeLength ||
- variablesNecessaryAfter[0].length < maxLocals)
- {
- variablesNecessaryAfter = new boolean[codeLength][maxLocals];
- }
- else
- {
- for (int offset = 0; offset < codeLength; offset++)
- {
- for (int index = 0; index < maxLocals; index++)
- {
- variablesNecessaryAfter[offset][index] = false;
- }
- }
- }
-
if (stacksNecessaryAfter.length < codeLength ||
stacksNecessaryAfter[0].length < maxStack)
{
@@ -1612,10 +1962,7 @@ implements AttributeVisitor
{
for (int offset = 0; offset < codeLength; offset++)
{
- for (int index = 0; index < maxStack; index++)
- {
- stacksNecessaryAfter[offset][index] = false;
- }
+ Arrays.fill(stacksNecessaryAfter[offset], 0, maxStack, false);
}
}
@@ -1628,10 +1975,7 @@ implements AttributeVisitor
{
for (int offset = 0; offset < codeLength; offset++)
{
- for (int index = 0; index < maxStack; index++)
- {
- stacksSimplifiedBefore[offset][index] = false;
- }
+ Arrays.fill(stacksSimplifiedBefore[offset], 0, maxStack, false);
}
}
@@ -1641,103 +1985,61 @@ implements AttributeVisitor
}
else
{
- for (int index = 0; index < codeLength; index++)
- {
- instructionsNecessary[index] = false;
- }
+ Arrays.fill(instructionsNecessary, 0, codeLength, false);
}
}
/**
- * Returns whether the given stack entry is present after execution of the
- * instruction at the given offset.
+ * Returns whether the specified variable is initialized at the specified
+ * offset.
*/
- private 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 the specified variable must be initialized at the
- * specified offset, according to the verifier of the JVM.
- */
- private boolean isVariableInitializationNecessary(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- int initializationOffset,
- int variableIndex)
+ private boolean isVariableInitialization(int instructionOffset,
+ int variableIndex)
{
- int codeLength = codeAttribute.u4codeLength;
-
- // Is the variable necessary anywhere at all?
- if (isVariableNecessaryAfterAny(0, codeLength, variableIndex))
+ // Wasn't the variable set yet?
+ Value valueBefore = partialEvaluator.getVariablesBefore(instructionOffset).getValue(variableIndex);
+ if (valueBefore == null)
{
- if (DEBUG) System.out.println("Simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
-
- // Lazily compute perform simple partial evaluation, the way the
- // JVM preverifier would do it.
- simplePartialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
+ return true;
+ }
- if (DEBUG) System.out.println("End of simple partial evaluation for initialization of variable v"+variableIndex+" at ["+initializationOffset+"]");
+ // Is the computational type different now?
+ Value valueAfter = partialEvaluator.getVariablesAfter(instructionOffset).getValue(variableIndex);
+ if (valueAfter.computationalType() != valueBefore.computationalType())
+ {
+ return true;
+ }
- // Check if the variable is necessary elsewhere.
- for (int offset = 0; offset < codeLength; offset++)
- {
- if (isInstructionNecessary(offset))
- {
- Value producer = partialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
- if (producer != null)
- {
- Value simpleProducer = simplePartialEvaluator.getVariablesBefore(offset).getProducerValue(variableIndex);
- if (simpleProducer != null)
- {
- InstructionOffsetValue producerOffsets =
- producer.instructionOffsetValue();
- InstructionOffsetValue simpleProducerOffsets =
- simpleProducer.instructionOffsetValue();
-
- // Does the sophisticated partial evaluation have fewer
- // producers than the simple one?
- // And does the simple partial evaluation point to an
- // initialization of the variable?
- if (producerOffsets.instructionOffsetCount() <
- simpleProducerOffsets.instructionOffsetCount() &&
- isVariableNecessaryAfterAny(producerOffsets, variableIndex) &&
- simpleProducerOffsets.contains(initializationOffset))
- {
- // Then the initialization is necessary.
- 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;
}
- return false;
+ // Was the producer an argument (which may be removed)?
+ Value producersBefore = partialEvaluator.getVariablesBefore(instructionOffset).getProducerValue(variableIndex);
+ return producersBefore.instructionOffsetValue().instructionOffsetCount() == 1 &&
+ producersBefore.instructionOffsetValue().instructionOffset(0) == PartialEvaluator.AT_METHOD_ENTRY;
}
- private void markVariableAfter(int instructionOffset,
- int variableIndex)
+ /**
+ * 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 (!isVariableNecessaryAfter(instructionOffset, variableIndex))
+ if (!isStackEntryNecessaryAfter(instructionOffset, stackIndex))
{
- if (DEBUG) System.out.print("["+instructionOffset+".v"+variableIndex+"],");
+ if (DEBUG) System.out.print("["+instructionOffset+".s"+stackIndex+"],");
- variablesNecessaryAfter[instructionOffset][variableIndex] = true;
+ stacksNecessaryAfter[instructionOffset][stackIndex] = true;
if (maxMarkedOffset < instructionOffset)
{
@@ -1747,73 +2049,74 @@ implements AttributeVisitor
}
+
/**
- * Returns whether the specified variable is ever necessary after any
- * instruction in the specified block.
+ * Returns whether the stack specified entries before the given offset are
+ * present.
*/
- private boolean isVariableNecessaryAfterAny(int startOffset,
- int endOffset,
- int variableIndex)
+ private boolean isStackEntriesPresentBefore(int instructionOffset,
+ int stackIndex1,
+ int stackIndex2)
{
- for (int offset = startOffset; offset < endOffset; offset++)
- {
- if (isVariableNecessaryAfter(offset, variableIndex))
- {
- return true;
- }
- }
+ boolean present1 = isStackEntryPresentBefore(instructionOffset, stackIndex1);
+ boolean present2 = isStackEntryPresentBefore(instructionOffset, stackIndex2);
- return false;
+// if (present1 ^ present2)
+// {
+// throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
+// }
+
+ return present1 || present2;
}
/**
- * Returns whether the specified variable is ever necessary after any
- * instruction in the specified set of instructions offsets.
+ * 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).
*/
- private boolean isVariableNecessaryAfterAny(InstructionOffsetValue instructionOffsetValue,
- int variableIndex)
+ private boolean isStackEntryPresentBefore(int instructionOffset,
+ int stackIndex)
{
- int count = instructionOffsetValue.instructionOffsetCount();
-
- for (int index = 0; index < count; index++)
- {
- if (isVariableNecessaryAfter(instructionOffsetValue.instructionOffset(index),
- variableIndex))
- {
- return true;
- }
- }
-
- return false;
- }
+ TracedStack tracedStack =
+ partialEvaluator.getStackBefore(instructionOffset);
+ InstructionOffsetValue producerOffsets =
+ tracedStack.getBottomProducerValue(stackIndex).instructionOffsetValue();
- private boolean isVariableNecessaryAfter(int instructionOffset,
- int variableIndex)
- {
- return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
- variablesNecessaryAfter[instructionOffset][variableIndex];
+ return isAnyStackEntryNecessaryAfter(producerOffsets, stackIndex);
}
- private void markStackEntryAfter(int instructionOffset,
- int stackIndex)
+ /**
+ * Returns whether the stack specified entries after the given offset are
+ * necessary.
+ */
+ private boolean isStackEntriesNecessaryAfter(int instructionOffset,
+ int stackIndex1,
+ int stackIndex2)
{
- if (!isStackEntryNecessaryAfter(instructionOffset, stackIndex))
- {
- if (DEBUG) System.out.print("["+instructionOffset+".s"+stackIndex+"],");
+ boolean present1 = isStackEntryNecessaryAfter(instructionOffset, stackIndex1);
+ boolean present2 = isStackEntryNecessaryAfter(instructionOffset, stackIndex2);
- stacksNecessaryAfter[instructionOffset][stackIndex] = true;
+// if (present1 ^ present2)
+// {
+// throw new UnsupportedOperationException("Can't handle partial use of dup2 instructions");
+// }
- if (maxMarkedOffset < instructionOffset)
- {
- maxMarkedOffset = instructionOffset;
- }
- }
+ 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).
+ */
private boolean isAnyStackEntryNecessaryAfter(InstructionOffsetValue instructionOffsets,
int stackIndex)
{
@@ -1831,6 +2134,13 @@ implements AttributeVisitor
}
+ /**
+ * 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).
+ */
private boolean isStackEntryNecessaryAfter(int instructionOffset,
int stackIndex)
{
@@ -1909,4 +2219,4 @@ implements AttributeVisitor
return instructionOffset == PartialEvaluator.AT_METHOD_ENTRY ||
instructionsNecessary[instructionOffset];
}
-}
\ No newline at end of file
+}
diff --git a/src/proguard/optimize/evaluation/EvaluationSimplifier.java b/src/proguard/optimize/evaluation/EvaluationSimplifier.java
index 0c3a9c7..e6e73d9 100644
--- a/src/proguard/optimize/evaluation/EvaluationSimplifier.java
+++ b/src/proguard/optimize/evaluation/EvaluationSimplifier.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -43,17 +43,20 @@ extends SimplifiedVisitor
implements AttributeVisitor,
InstructionVisitor
{
+ private static final int POS_ZERO_FLOAT_BITS = Float.floatToIntBits(0.0f);
+ private static final long POS_ZERO_DOUBLE_BITS = Double.doubleToLongBits(0.0);
+
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = true;
+ private static boolean DEBUG = true;
//*/
private final InstructionVisitor extraInstructionVisitor;
private final PartialEvaluator partialEvaluator;
- private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false);
+ private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false, true);
/**
@@ -426,8 +429,9 @@ implements AttributeVisitor,
Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
if (pushedValue.isParticular())
{
+ // Push a constant instead.
int value = pushedValue.integerValue().value();
- if (value << 16 >> 16 == value)
+ if ((short)value == value)
{
replaceConstantPushInstruction(clazz,
offset,
@@ -442,13 +446,14 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_LDC,
- constantPoolEditor.addIntegerConstant(value)).shrink();
+ constantPoolEditor.addIntegerConstant(value));
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
}
else if (pushedValue.isSpecific())
{
+ // Load an equivalent lower-numbered variable instead, if any.
TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
{
@@ -459,6 +464,7 @@ implements AttributeVisitor,
instruction,
InstructionConstants.OP_ILOAD,
variableIndex);
+ break;
}
}
}
@@ -492,6 +498,7 @@ implements AttributeVisitor,
Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
if (pushedValue.isParticular())
{
+ // Push a constant instead.
long value = pushedValue.longValue().value();
if (value == 0L ||
value == 1L)
@@ -509,17 +516,21 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_LDC2_W,
- constantPoolEditor.addLongConstant(value)).shrink();
+ constantPoolEditor.addLongConstant(value));
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
}
else if (pushedValue.isSpecific())
{
+ // Load an equivalent lower-numbered variable instead, if any.
TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
{
- if (pushedValue.equals(variables.load(variableIndex)))
+ // Note that we have to check the second part as well.
+ if (pushedValue.equals(variables.load(variableIndex)) &&
+ variables.load(variableIndex + 1) != null &&
+ variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP)
{
replaceVariablePushInstruction(clazz,
offset,
@@ -559,10 +570,12 @@ implements AttributeVisitor,
Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
if (pushedValue.isParticular())
{
+ // Push a constant instead.
+ // Make sure to distinguish between +0.0 and -0.0.
float value = pushedValue.floatValue().value();
- if (value == 0f ||
- value == 1f ||
- value == 2f)
+ if (value == 0.0f && Float.floatToIntBits(value) == POS_ZERO_FLOAT_BITS ||
+ value == 1.0f ||
+ value == 2.0f)
{
replaceConstantPushInstruction(clazz,
offset,
@@ -577,13 +590,14 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_LDC,
- constantPoolEditor.addFloatConstant(value)).shrink();
+ constantPoolEditor.addFloatConstant(value));
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
}
else if (pushedValue.isSpecific())
{
+ // Load an equivalent lower-numbered variable instead, if any.
TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
{
@@ -627,8 +641,10 @@ implements AttributeVisitor,
Value pushedValue = partialEvaluator.getStackAfter(offset).getTop(0);
if (pushedValue.isParticular())
{
+ // Push a constant instead.
+ // Make sure to distinguish between +0.0 and -0.0.
double value = pushedValue.doubleValue().value();
- if (value == 0.0 ||
+ if (value == 0.0 && Double.doubleToLongBits(value) == POS_ZERO_DOUBLE_BITS ||
value == 1.0)
{
replaceConstantPushInstruction(clazz,
@@ -644,17 +660,21 @@ implements AttributeVisitor,
Instruction replacementInstruction =
new ConstantInstruction(InstructionConstants.OP_LDC2_W,
- constantPoolEditor.addDoubleConstant(value)).shrink();
+ constantPoolEditor.addDoubleConstant(value));
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
}
else if (pushedValue.isSpecific())
{
+ // Load an equivalent lower-numbered variable instead, if any.
TracedVariables variables = partialEvaluator.getVariablesBefore(offset);
for (int variableIndex = 0; variableIndex < maxVariableIndex; variableIndex++)
{
- if (pushedValue.equals(variables.load(variableIndex)))
+ // Note that we have to check the second part as well.
+ if (pushedValue.equals(variables.load(variableIndex)) &&
+ variables.load(variableIndex + 1) != null &&
+ variables.load(variableIndex + 1).computationalType() == Value.TYPE_TOP)
{
replaceVariablePushInstruction(clazz,
offset,
@@ -699,7 +719,7 @@ implements AttributeVisitor,
int value)
{
Instruction replacementInstruction =
- new SimpleInstruction(replacementOpcode, value).shrink();
+ new SimpleInstruction(replacementOpcode, value);
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
@@ -716,7 +736,7 @@ implements AttributeVisitor,
int variableIndex)
{
Instruction replacementInstruction =
- new VariableInstruction(replacementOpcode, variableIndex).shrink();
+ new VariableInstruction(replacementOpcode, variableIndex);
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
@@ -794,8 +814,8 @@ implements AttributeVisitor,
{
// Replace the branch instruction by a simple branch instruction.
Instruction replacementInstruction =
- new BranchInstruction(InstructionConstants.OP_GOTO_W,
- branchOffset).shrink();
+ new BranchInstruction(InstructionConstants.OP_GOTO,
+ branchOffset);
replaceInstruction(clazz, offset, instruction, replacementInstruction);
}
diff --git a/src/proguard/optimize/evaluation/LivenessAnalyzer.java b/src/proguard/optimize/evaluation/LivenessAnalyzer.java
index 9915027..5ce8ccb 100644
--- a/src/proguard/optimize/evaluation/LivenessAnalyzer.java
+++ b/src/proguard/optimize/evaluation/LivenessAnalyzer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -78,6 +78,16 @@ implements AttributeVisitor,
}
+ /**
+ * Returns whether the instruction at the given offset has ever been
+ * executed during the partial evaluation.
+ */
+ public boolean isTraced(int instructionOffset)
+ {
+ return partialEvaluator.isTraced(instructionOffset);
+ }
+
+
/**
* Returns whether the specified variable is alive before the instruction
* at the given offset.
diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
index 8379c57..d6baa67 100644
--- a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
+++ b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -35,9 +35,9 @@ import proguard.evaluation.value.*;
public class LoadingInvocationUnit
extends BasicInvocationUnit
{
- private boolean loadFieldValues;
- private boolean loadMethodParameterValues;
- private boolean loadMethodReturnValues;
+ private final boolean loadFieldValues;
+ private final boolean loadMethodParameterValues;
+ private final boolean loadMethodReturnValues;
/**
@@ -84,8 +84,6 @@ extends BasicInvocationUnit
value.isParticular())
{
return value;
-// // Make sure the value is refreshed.
-// return refresh(value);
}
}
}
@@ -110,8 +108,6 @@ extends BasicInvocationUnit
value.isParticular())
{
return value;
-// // Make sure the value is refreshed.
-// return refresh(value);
}
}
}
@@ -134,8 +130,6 @@ extends BasicInvocationUnit
value.isParticular())
{
return value;
-// // Make sure the value is refreshed.
-// return refresh(value);
}
}
@@ -163,8 +157,6 @@ extends BasicInvocationUnit
value.isParticular())
{
return value;
-// // Make sure the value is refreshed.
-// return refresh(value);
}
}
}
@@ -173,8 +165,8 @@ extends BasicInvocationUnit
refConstant,
type);
}
-//
-//
+
+
// // Small utility methods.
//
// private Value refresh(Value value)
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java
index 5790a36..6a5bedf 100644
--- a/src/proguard/optimize/evaluation/PartialEvaluator.java
+++ b/src/proguard/optimize/evaluation/PartialEvaluator.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,8 @@ import proguard.evaluation.*;
import proguard.evaluation.value.*;
import proguard.optimize.peephole.BranchTargetFinder;
+import java.util.Arrays;
+
/**
* This AttributeVisitor performs partial evaluation on the code attributes
* that it visits.
@@ -68,7 +70,6 @@ implements AttributeVisitor,
private TracedStack[] stacksAfter = new TracedStack[ClassConstants.TYPICAL_CODE_LENGTH];
private boolean[] generalizedContexts = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
private int[] evaluationCounts = new int[ClassConstants.TYPICAL_CODE_LENGTH];
- private int[] initializedVariables = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private boolean evaluateExceptions;
private final BasicBranchUnit branchUnit;
@@ -189,6 +190,47 @@ implements AttributeVisitor,
if (DEBUG)
{
method.accept(clazz, new ClassPrinter());
+
+ System.out.println("Evaluation results:");
+
+ int offset = 0;
+ do
+ {
+ if (isBranchOrExceptionTarget(offset))
+ {
+ System.out.println("Branch target from ["+branchOriginValues[offset]+"]:");
+ if (isTraced(offset))
+ {
+ System.out.println(" Vars: "+variablesBefore[offset]);
+ System.out.println(" Stack: "+stacksBefore[offset]);
+ }
+ }
+
+ Instruction instruction = InstructionFactory.create(codeAttribute.code,
+ offset);
+ System.out.println(instruction.toString(offset));
+
+ if (isTraced(offset))
+ {
+ int initializationOffset = branchTargetFinder.initializationOffset(offset);
+ if (initializationOffset != NONE)
+ {
+ System.out.println(" is to be initialized at ["+initializationOffset+"]");
+ }
+
+ InstructionOffsetValue branchTargets = branchTargets(offset);
+ if (branchTargets != null)
+ {
+ System.out.println(" has overall been branching to "+branchTargets);
+ }
+
+ System.out.println(" Vars: "+variablesAfter[offset]);
+ System.out.println(" Stack: "+stacksAfter[offset]);
+ }
+
+ offset += instruction.length(offset);
+ }
+ while (offset < codeAttribute.u4codeLength);
}
throw ex;
@@ -212,7 +254,8 @@ implements AttributeVisitor,
TracedStack stack = new TracedStack(codeAttribute.u2maxStack);
// Initialize the reusable arrays and variables.
- initializeVariables(clazz, method, codeAttribute, variables, stack);
+ initializeArrays(codeAttribute);
+ initializeParameters(clazz, method, codeAttribute, variables);
// Find all instruction offsets,...
codeAttribute.accept(clazz, method, branchTargetFinder);
@@ -249,12 +292,6 @@ implements AttributeVisitor,
if (isTraced(offset))
{
- int variableIndex = initializedVariable(offset);
- if (variableIndex >= 0)
- {
- System.out.println(" is initializing variable v"+variableIndex);
- }
-
int initializationOffset = branchTargetFinder.initializationOffset(offset);
if (initializationOffset != NONE)
{
@@ -479,16 +516,6 @@ implements AttributeVisitor,
}
- /**
- * Returns the variable that is initialized at the given instruction offset,
- * or NONE
if no variable was initialized.
- */
- public int initializedVariable(int instructionOffset)
- {
- return initializedVariables[instructionOffset];
- }
-
-
// Utility methods to evaluate instruction blocks.
/**
@@ -702,9 +729,6 @@ implements AttributeVisitor,
// Reset the trace value.
InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE;
- // Reset the initialization flag.
- variables.resetInitialization();
-
// Note that the instruction is only volatile.
Instruction instruction = InstructionFactory.create(code, instructionOffset);
@@ -743,9 +767,6 @@ implements AttributeVisitor,
throw ex;
}
- // Collect the offsets of the instructions whose results were used.
- initializedVariables[instructionOffset] = variables.getInitializationIndex();
-
// Collect the branch targets from the branch unit.
InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
int branchTargetCount = branchTargets.instructionOffsetCount();
@@ -844,8 +865,7 @@ implements AttributeVisitor,
if (instruction.opcode == InstructionConstants.OP_JSR ||
instruction.opcode == InstructionConstants.OP_JSR_W)
{
- // Evaluate the subroutine, possibly in another partial
- // evaluator.
+ // Evaluate the subroutine in another partial evaluator.
evaluateSubroutine(clazz,
method,
codeAttribute,
@@ -887,21 +907,13 @@ implements AttributeVisitor,
if (DEBUG) System.out.println("Evaluating subroutine from "+subroutineStart+" to "+subroutineEnd);
- PartialEvaluator subroutinePartialEvaluator = this;
-
- // Create a temporary partial evaluator if necessary.
- if (evaluationCounts[subroutineStart] > 0)
- {
- if (DEBUG) System.out.println("Creating new partial evaluator for subroutine");
-
- subroutinePartialEvaluator = new PartialEvaluator(this);
+ // Create a temporary partial evaluator, so there are no conflicts
+ // with variables that are alive across subroutine invocations, between
+ // different invocations.
+ PartialEvaluator subroutinePartialEvaluator =
+ new PartialEvaluator(this);
- subroutinePartialEvaluator.initializeVariables(clazz,
- method,
- codeAttribute,
- variables,
- stack);
- }
+ subroutinePartialEvaluator.initializeArrays(codeAttribute);
// Evaluate the subroutine.
subroutinePartialEvaluator.evaluateInstructionBlockAndExceptionHandlers(clazz,
@@ -912,11 +924,9 @@ implements AttributeVisitor,
subroutineStart,
subroutineEnd);
- // Merge back the temporary partial evaluator if necessary.
- if (subroutinePartialEvaluator != this)
- {
- generalize(subroutinePartialEvaluator, 0, codeAttribute.u4codeLength);
- }
+ // Merge back the temporary partial evaluator. This way, we'll get
+ // the lowest common denominator of stacks and variables.
+ generalize(subroutinePartialEvaluator, 0, codeAttribute.u4codeLength);
if (DEBUG) System.out.println("Ending subroutine from "+subroutineStart+" to "+subroutineEnd);
}
@@ -952,13 +962,12 @@ implements AttributeVisitor,
if (evaluationCounts[offset] == 0)
{
- variablesBefore[offset] = other.variablesBefore[offset];
- stacksBefore[offset] = other.stacksBefore[offset];
- variablesAfter[offset] = other.variablesAfter[offset];
- stacksAfter[offset] = other.stacksAfter[offset];
- generalizedContexts[offset] = other.generalizedContexts[offset];
- evaluationCounts[offset] = other.evaluationCounts[offset];
- initializedVariables[offset] = other.initializedVariables[offset];
+ variablesBefore[offset] = other.variablesBefore[offset];
+ stacksBefore[offset] = other.stacksBefore[offset];
+ variablesAfter[offset] = other.variablesAfter[offset];
+ stacksAfter[offset] = other.stacksAfter[offset];
+ generalizedContexts[offset] = other.generalizedContexts[offset];
+ evaluationCounts[offset] = other.evaluationCounts[offset];
}
else
{
@@ -968,7 +977,6 @@ implements AttributeVisitor,
stacksAfter[offset] .generalize(other.stacksAfter[offset]);
//generalizedContexts[offset]
evaluationCounts[offset] += other.evaluationCounts[offset];
- //initializedVariables[offset]
}
}
}
@@ -1094,11 +1102,7 @@ implements AttributeVisitor,
/**
* Initializes the data structures for the variables, stack, etc.
*/
- private void initializeVariables(Clazz clazz,
- Method method,
- CodeAttribute codeAttribute,
- TracedVariables variables,
- TracedStack stack)
+ private void initializeArrays(CodeAttribute codeAttribute)
{
int codeLength = codeAttribute.u4codeLength;
@@ -1106,33 +1110,25 @@ implements AttributeVisitor,
if (variablesAfter.length < codeLength)
{
// Create new arrays.
- branchOriginValues = new InstructionOffsetValue[codeLength];
- branchTargetValues = new InstructionOffsetValue[codeLength];
- variablesBefore = new TracedVariables[codeLength];
- stacksBefore = new TracedStack[codeLength];
- variablesAfter = new TracedVariables[codeLength];
- stacksAfter = new TracedStack[codeLength];
- generalizedContexts = new boolean[codeLength];
- evaluationCounts = new int[codeLength];
- initializedVariables = new int[codeLength];
-
- // Reset the arrays.
- for (int index = 0; index < codeLength; index++)
- {
- initializedVariables[index] = NONE;
- }
+ branchOriginValues = new InstructionOffsetValue[codeLength];
+ branchTargetValues = new InstructionOffsetValue[codeLength];
+ variablesBefore = new TracedVariables[codeLength];
+ stacksBefore = new TracedStack[codeLength];
+ variablesAfter = new TracedVariables[codeLength];
+ stacksAfter = new TracedStack[codeLength];
+ generalizedContexts = new boolean[codeLength];
+ evaluationCounts = new int[codeLength];
}
else
{
// Reset the arrays.
+ Arrays.fill(branchOriginValues, null);
+ Arrays.fill(branchTargetValues, null);
+ Arrays.fill(generalizedContexts, false);
+ Arrays.fill(evaluationCounts, 0);
+
for (int index = 0; index < codeLength; index++)
{
- branchOriginValues[index] = null;
- branchTargetValues[index] = null;
- generalizedContexts[index] = false;
- evaluationCounts[index] = 0;
- initializedVariables[index] = NONE;
-
if (variablesBefore[index] != null)
{
variablesBefore[index].reset(codeAttribute.u2maxLocals);
@@ -1154,7 +1150,17 @@ implements AttributeVisitor,
}
}
}
+ }
+
+ /**
+ * Initializes the data structures for the variables, stack, etc.
+ */
+ private void initializeParameters(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ TracedVariables variables)
+ {
// Create the method parameters.
TracedVariables parameters = new TracedVariables(codeAttribute.u2maxLocals);
diff --git a/src/proguard/optimize/evaluation/StoringInvocationUnit.java b/src/proguard/optimize/evaluation/StoringInvocationUnit.java
index bcbb69f..846f685 100644
--- a/src/proguard/optimize/evaluation/StoringInvocationUnit.java
+++ b/src/proguard/optimize/evaluation/StoringInvocationUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java
index fa5bb79..e6acf6f 100644
--- a/src/proguard/optimize/evaluation/TracedBranchUnit.java
+++ b/src/proguard/optimize/evaluation/TracedBranchUnit.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/VariableOptimizer.java b/src/proguard/optimize/evaluation/VariableOptimizer.java
index b3ae81c..73efddc 100644
--- a/src/proguard/optimize/evaluation/VariableOptimizer.java
+++ b/src/proguard/optimize/evaluation/VariableOptimizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,10 +21,10 @@
package proguard.optimize.evaluation;
import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.editor.*;
import proguard.classfile.visitor.MemberVisitor;
import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.editor.VariableRemapper;
import proguard.classfile.util.*;
/**
@@ -35,7 +35,9 @@ import proguard.classfile.util.*;
*/
public class VariableOptimizer
extends SimplifiedVisitor
-implements AttributeVisitor
+implements AttributeVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor
{
//*
private static final boolean DEBUG = false;
@@ -51,6 +53,7 @@ implements AttributeVisitor
private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer();
private final VariableRemapper variableRemapper = new VariableRemapper();
+ private VariableCleaner variableCleaner = new VariableCleaner();
private int[] variableMap = new int[ClassConstants.TYPICAL_VARIABLES_SIZE];
@@ -101,6 +104,11 @@ implements AttributeVisitor
// Analyze the liveness of the variables in the code.
livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute);
+ // Trim the variables in the local variable tables, because even
+ // clipping the tables individually may leave some inconsistencies
+ // between them.
+ codeAttribute.attributesAccept(clazz, method, this);
+
int startIndex =
(method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ||
reuseThis ? 0 : 1;
@@ -142,23 +150,19 @@ implements AttributeVisitor
}
}
- // Remap the variables.
+ // Have we been able to remap any variables?
if (remapping)
{
if (DEBUG)
{
- System.out.println("Remapping variables:");
- System.out.println(" Class "+ ClassUtil.externalClassName(clazz.getName()));
- System.out.println(" Method "+ClassUtil.externalFullMethodDescription(clazz.getName(),
- 0,
- method.getName(clazz),
- method.getDescriptor(clazz)));
- for (int index = 0; index < variableSize; index++)
+ System.out.println("VariableOptimizer: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
+ for (int index= 0; index < variableSize; index++)
{
- System.out.println(" ["+index+"] -> ["+variableMap[index]+"]");
+ System.out.println(" v"+index+" -> "+variableMap[index]);
}
}
+ // Remap the variables.
variableRemapper.setVariableMap(variableMap);
variableRemapper.visitCodeAttribute(clazz, method, codeAttribute);
@@ -168,6 +172,71 @@ implements AttributeVisitor
method.accept(clazz, extraVariableMemberVisitor);
}
}
+ else
+ {
+ // Just clean up any empty variables.
+ variableCleaner.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+ }
+
+
+ public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
+ {
+ // Trim the variables in the local variable table.
+ localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
+ {
+ // Trim the variables in the local variable type table.
+ localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
+ {
+ // Trim the local variable to the instructions at which it is alive.
+ int variable = localVariableInfo.u2index;
+ int startPC = localVariableInfo.u2startPC;
+ int endPC = startPC + localVariableInfo.u2length;
+
+ startPC = firstLiveness(startPC, endPC, variable);
+ endPC = lastLiveness(startPC, endPC, variable);
+
+ // Leave the start address of unused variables unchanged.
+ int length = endPC - startPC;
+ if (length > 0)
+ {
+ localVariableInfo.u2startPC = startPC;
+ }
+
+ localVariableInfo.u2length = length;
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ // Trim the local variable type to the instructions at which it is alive.
+ int variable = localVariableTypeInfo.u2index;
+ int startPC = localVariableTypeInfo.u2startPC;
+ int endPC = startPC + localVariableTypeInfo.u2length;
+
+ startPC = firstLiveness(startPC, endPC, variable);
+ endPC = lastLiveness(startPC, endPC, variable);
+
+ // Leave the start address of unused variables unchanged.
+ int length = endPC - startPC;
+ if (length > 0)
+ {
+ localVariableTypeInfo.u2startPC = startPC;
+ }
+
+ localVariableTypeInfo.u2length = length;
}
@@ -241,4 +310,48 @@ implements AttributeVisitor
}
}
}
+
+
+ /**
+ * Returns the first instruction offset between the given offsets at which
+ * the given variable goes alive.
+ */
+ private int firstLiveness(int startOffset, int endOffset, int variableIndex)
+ {
+ for (int offset = startOffset; offset < endOffset; offset++)
+ {
+ if (livenessAnalyzer.isTraced(offset) &&
+ livenessAnalyzer.isAliveBefore(offset, variableIndex))
+ {
+ return offset;
+ }
+ }
+
+ return endOffset;
+ }
+
+
+ /**
+ * Returns the last instruction offset between the given offsets before
+ * which the given variable is still alive.
+ */
+ private int lastLiveness(int startOffset, int endOffset, int variableIndex)
+ {
+ int previousOffset = endOffset;
+
+ for (int offset = endOffset-1; offset >= startOffset; offset--)
+ {
+ if (livenessAnalyzer.isTraced(offset))
+ {
+ if (livenessAnalyzer.isAliveBefore(offset, variableIndex))
+ {
+ return previousOffset;
+ }
+
+ previousOffset = offset;
+ }
+ }
+
+ return endOffset;
+ }
}
diff --git a/src/proguard/optimize/info/AccessMethodMarker.java b/src/proguard/optimize/info/AccessMethodMarker.java
index 6965cec..e4c8d7c 100644
--- a/src/proguard/optimize/info/AccessMethodMarker.java
+++ b/src/proguard/optimize/info/AccessMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,7 +21,8 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
@@ -71,6 +72,20 @@ implements InstructionVisitor,
}
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // Check the bootstrap method.
+ invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this);
+ }
+
+
+ public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
+ {
+ // Check the method reference.
+ clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
// Check the referenced class.
diff --git a/src/proguard/optimize/info/BackwardBranchMarker.java b/src/proguard/optimize/info/BackwardBranchMarker.java
index 9e09b0f..07bfefb 100644
--- a/src/proguard/optimize/info/BackwardBranchMarker.java
+++ b/src/proguard/optimize/info/BackwardBranchMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CatchExceptionMarker.java b/src/proguard/optimize/info/CatchExceptionMarker.java
index 3f2a06f..8f87a08 100644
--- a/src/proguard/optimize/info/CatchExceptionMarker.java
+++ b/src/proguard/optimize/info/CatchExceptionMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CaughtClassFilter.java b/src/proguard/optimize/info/CaughtClassFilter.java
index 5e17763..762e7de 100644
--- a/src/proguard/optimize/info/CaughtClassFilter.java
+++ b/src/proguard/optimize/info/CaughtClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/CaughtClassMarker.java b/src/proguard/optimize/info/CaughtClassMarker.java
index 0cc350e..1752f0c 100644
--- a/src/proguard/optimize/info/CaughtClassMarker.java
+++ b/src/proguard/optimize/info/CaughtClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -25,8 +25,9 @@ import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.ClassVisitor;
/**
- * This InstructionVisitor marks all classes that are used in an 'instanceof'
- * test by any of the instructions that it visits.
+ * This ClassVisitor marks all program classes that it visits as caught.
+ * This means that these classes are exception classes that occur in exception
+ * handlers.
*
* @author Eric Lafortune
*/
diff --git a/src/proguard/optimize/info/ClassOptimizationInfo.java b/src/proguard/optimize/info/ClassOptimizationInfo.java
index 99b6e7b..dbe041e 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfo.java
+++ b/src/proguard/optimize/info/ClassOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -34,6 +34,7 @@ public class ClassOptimizationInfo
private boolean isInstanceofed = false;
private boolean isDotClassed = false;
private boolean isCaught = false;
+ private boolean containsStaticInitializer = false;
private boolean containsPackageVisibleMembers = false;
private boolean invokesPackageVisibleMembers = false;
private Clazz targetClass;
@@ -87,6 +88,18 @@ public class ClassOptimizationInfo
}
+ public void setContainsStaticInitializer()
+ {
+ containsStaticInitializer = true;
+ }
+
+
+ public boolean containsStaticInitializer()
+ {
+ return containsStaticInitializer;
+ }
+
+
public void setContainsPackageVisibleMembers()
{
containsPackageVisibleMembers = true;
@@ -129,6 +142,7 @@ public class ClassOptimizationInfo
this.isInstanceofed |= other.isInstanceofed;
this.isDotClassed |= other.isDotClassed;
this.isCaught |= other.isCaught;
+ this.containsStaticInitializer |= other.containsStaticInitializer;
this.containsPackageVisibleMembers |= other.containsPackageVisibleMembers;
this.invokesPackageVisibleMembers |= other.invokesPackageVisibleMembers;
}
diff --git a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
index 9cb167c..f3d78e2 100644
--- a/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
+++ b/src/proguard/optimize/info/ClassOptimizationInfoSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/DotClassFilter.java b/src/proguard/optimize/info/DotClassFilter.java
index 8cbe7f0..c3fd878 100644
--- a/src/proguard/optimize/info/DotClassFilter.java
+++ b/src/proguard/optimize/info/DotClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/DotClassMarker.java b/src/proguard/optimize/info/DotClassMarker.java
index b5f12a7..ef5cfd1 100644
--- a/src/proguard/optimize/info/DotClassMarker.java
+++ b/src/proguard/optimize/info/DotClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/ExceptionInstructionChecker.java b/src/proguard/optimize/info/ExceptionInstructionChecker.java
index 2792d90..4bfa96f 100644
--- a/src/proguard/optimize/info/ExceptionInstructionChecker.java
+++ b/src/proguard/optimize/info/ExceptionInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -67,34 +67,39 @@ implements InstructionVisitor
byte opcode = simpleInstruction.opcode;
// Check for instructions that may throw exceptions.
- if (opcode == InstructionConstants.OP_IDIV ||
- opcode == InstructionConstants.OP_LDIV ||
- opcode == InstructionConstants.OP_IREM ||
- opcode == InstructionConstants.OP_LREM ||
- opcode == InstructionConstants.OP_IALOAD ||
- opcode == InstructionConstants.OP_LALOAD ||
- opcode == InstructionConstants.OP_FALOAD ||
- opcode == InstructionConstants.OP_DALOAD ||
- opcode == InstructionConstants.OP_AALOAD ||
- opcode == InstructionConstants.OP_BALOAD ||
- opcode == InstructionConstants.OP_CALOAD ||
- opcode == InstructionConstants.OP_SALOAD ||
- opcode == InstructionConstants.OP_IASTORE ||
- opcode == InstructionConstants.OP_LASTORE ||
- opcode == InstructionConstants.OP_FASTORE ||
- opcode == InstructionConstants.OP_DASTORE ||
- opcode == InstructionConstants.OP_AASTORE ||
- opcode == InstructionConstants.OP_BASTORE ||
- opcode == InstructionConstants.OP_CASTORE ||
- opcode == InstructionConstants.OP_SASTORE ||
- opcode == InstructionConstants.OP_NEWARRAY ||
- opcode == InstructionConstants.OP_ARRAYLENGTH ||
- opcode == InstructionConstants.OP_ATHROW ||
- opcode == InstructionConstants.OP_MONITORENTER ||
- opcode == InstructionConstants.OP_MONITOREXIT)
+ // Note that monitorexit can not sensibly throw exceptions, except the
+ // broken and deprecated asynchronous ThreadDeath. Removing the
+ // artificial infinite looping exception blocks that recent compilers
+ // add does not strictly follow the JVM specs, but it does have the
+ // additional benefit of avoiding a bug in the JVM in JDK 1.1.
+ switch (opcode)
{
- // These instructions may throw exceptions.
- mayThrowExceptions = true;
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_IREM:
+ case InstructionConstants.OP_LREM:
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_LALOAD:
+ case InstructionConstants.OP_FALOAD:
+ case InstructionConstants.OP_DALOAD:
+ case InstructionConstants.OP_AALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ case InstructionConstants.OP_NEWARRAY:
+ case InstructionConstants.OP_ARRAYLENGTH:
+ case InstructionConstants.OP_ATHROW:
+ case InstructionConstants.OP_MONITORENTER:
+ // These instructions may throw exceptions.
+ mayThrowExceptions = true;
}
}
@@ -105,31 +110,32 @@ implements InstructionVisitor
byte opcode = constantInstruction.opcode;
// Check for instructions that may throw exceptions.
- if (opcode == InstructionConstants.OP_GETSTATIC ||
- opcode == InstructionConstants.OP_PUTSTATIC ||
- opcode == InstructionConstants.OP_GETFIELD ||
- opcode == InstructionConstants.OP_PUTFIELD ||
- opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
- opcode == InstructionConstants.OP_INVOKESPECIAL ||
- opcode == InstructionConstants.OP_INVOKESTATIC ||
- opcode == InstructionConstants.OP_INVOKEINTERFACE ||
- opcode == InstructionConstants.OP_NEW ||
- opcode == InstructionConstants.OP_ANEWARRAY ||
- opcode == InstructionConstants.OP_CHECKCAST ||
- opcode == InstructionConstants.OP_MULTIANEWARRAY)
+ switch (opcode)
{
- // These instructions may throw exceptions.
- mayThrowExceptions = true;
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_PUTFIELD:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_CHECKCAST:
+ case InstructionConstants.OP_INSTANCEOF:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ // These instructions may throw exceptions.
+ mayThrowExceptions = true;
}
-// else
-// if (opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
-// opcode == InstructionConstants.OP_INVOKESPECIAL ||
-// opcode == InstructionConstants.OP_INVOKESTATIC ||
-// opcode == InstructionConstants.OP_INVOKEINTERFACE)
-// {
+
+// case InstructionConstants.OP_INVOKEVIRTUAL:
+// case InstructionConstants.OP_INVOKESPECIAL:
+// case InstructionConstants.OP_INVOKESTATIC:
+// case InstructionConstants.OP_INVOKEINTERFACE:
// // Check if the invoking the method may throw an exception.
// clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
-// }
}
diff --git a/src/proguard/optimize/info/FieldOptimizationInfo.java b/src/proguard/optimize/info/FieldOptimizationInfo.java
index 7a2d068..0fa9167 100644
--- a/src/proguard/optimize/info/FieldOptimizationInfo.java
+++ b/src/proguard/optimize/info/FieldOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,8 +21,11 @@
package proguard.optimize.info;
import proguard.classfile.*;
-import proguard.classfile.util.MethodLinker;
+import proguard.classfile.attribute.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.util.*;
import proguard.evaluation.value.*;
+import proguard.evaluation.ConstantValueFactory;
/**
* This class stores some optimization information that can be attached to
@@ -31,8 +34,11 @@ import proguard.evaluation.value.*;
* @author Eric Lafortune
*/
public class FieldOptimizationInfo
+extends SimplifiedVisitor
+implements AttributeVisitor
{
- private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory();
+ private static final SpecificValueFactory VALUE_FACTORY = new SpecificValueFactory();
+ private static final ConstantValueFactory CONSTANT_VALUE_FACTORY = new ConstantValueFactory(VALUE_FACTORY);
private boolean isWritten;
private boolean isRead;
@@ -43,9 +49,33 @@ public class FieldOptimizationInfo
public FieldOptimizationInfo(Clazz clazz, Field field)
{
+ int accessFlags = field.getAccessFlags();
+
isWritten =
- isRead = (field.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0;
- value = initialValue(field.getDescriptor(clazz));
+ isRead = (accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0;
+
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
+ {
+ // See if we can initialize the static field with a constant value.
+ field.accept(clazz, new AllAttributeVisitor(this));
+ }
+
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
+ value == null)
+ {
+ // Otherwise initialize the non-final field with the default value.
+ value = initialValue(field.getDescriptor(clazz));
+ }
+ }
+
+
+ public FieldOptimizationInfo(FieldOptimizationInfo FieldOptimizationInfo)
+ {
+ this.isWritten = FieldOptimizationInfo.isWritten;
+ this.isRead = FieldOptimizationInfo.isRead;
+ this.canBeMadePrivate = FieldOptimizationInfo.canBeMadePrivate;
+ this.referencedClass = FieldOptimizationInfo.referencedClass;
+ this.value = FieldOptimizationInfo.value;
}
@@ -113,6 +143,18 @@ public class FieldOptimizationInfo
}
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
+ {
+ // Retrieve the initial static field value.
+ value = CONSTANT_VALUE_FACTORY.constantValue(clazz, constantValueAttribute.u2constantValueIndex);
+ }
+
+
// Small utility methods.
private Value initialValue(String type)
@@ -147,13 +189,13 @@ public class FieldOptimizationInfo
public static void setFieldOptimizationInfo(Clazz clazz, Field field)
{
- MethodLinker.lastMember(field).setVisitorInfo(new FieldOptimizationInfo(clazz, field));
+ field.setVisitorInfo(new FieldOptimizationInfo(clazz, field));
}
public static FieldOptimizationInfo getFieldOptimizationInfo(Field field)
{
- Object visitorInfo = MethodLinker.lastMember(field).getVisitorInfo();
+ Object visitorInfo = field.getVisitorInfo();
return visitorInfo instanceof FieldOptimizationInfo ?
(FieldOptimizationInfo)visitorInfo :
diff --git a/src/proguard/optimize/info/InstanceofClassFilter.java b/src/proguard/optimize/info/InstanceofClassFilter.java
index 35e1d77..7cd85bc 100644
--- a/src/proguard/optimize/info/InstanceofClassFilter.java
+++ b/src/proguard/optimize/info/InstanceofClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstanceofClassMarker.java b/src/proguard/optimize/info/InstanceofClassMarker.java
index c60e1f8..96d5baf 100644
--- a/src/proguard/optimize/info/InstanceofClassMarker.java
+++ b/src/proguard/optimize/info/InstanceofClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstantiationClassFilter.java b/src/proguard/optimize/info/InstantiationClassFilter.java
index a24e617..a659f06 100644
--- a/src/proguard/optimize/info/InstantiationClassFilter.java
+++ b/src/proguard/optimize/info/InstantiationClassFilter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/InstantiationClassMarker.java b/src/proguard/optimize/info/InstantiationClassMarker.java
index 124c23b..b4afffd 100644
--- a/src/proguard/optimize/info/InstantiationClassMarker.java
+++ b/src/proguard/optimize/info/InstantiationClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
index a170a8e..3c27c93 100644
--- a/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
+++ b/src/proguard/optimize/info/MemberOptimizationInfoSetter.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -38,22 +38,22 @@ implements MemberVisitor
{
// Implementations for MemberVisitor.
- public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- if (!KeepMarker.isKept(programMethod))
+ if (!KeepMarker.isKept(programField))
{
- MethodOptimizationInfo.setMethodOptimizationInfo(programClass,
- programMethod);
+ FieldOptimizationInfo.setFieldOptimizationInfo(programClass,
+ programField);
}
}
- public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- if (!KeepMarker.isKept(programField))
+ if (!KeepMarker.isKept(programMethod))
{
- FieldOptimizationInfo.setFieldOptimizationInfo(programClass,
- programField);
+ MethodOptimizationInfo.setMethodOptimizationInfo(programClass,
+ programMethod);
}
}
}
diff --git a/src/proguard/optimize/info/MethodInvocationMarker.java b/src/proguard/optimize/info/MethodInvocationMarker.java
index 2528c94..afb2336 100644
--- a/src/proguard/optimize/info/MethodInvocationMarker.java
+++ b/src/proguard/optimize/info/MethodInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/MethodOptimizationInfo.java b/src/proguard/optimize/info/MethodOptimizationInfo.java
index d3b1bde..fe754e5 100644
--- a/src/proguard/optimize/info/MethodOptimizationInfo.java
+++ b/src/proguard/optimize/info/MethodOptimizationInfo.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -204,7 +204,7 @@ public class MethodOptimizationInfo
public void setParameterUsed(int parameterIndex)
{
- usedParameters |= 1 << parameterIndex;
+ usedParameters |= 1L << parameterIndex;
}
@@ -216,7 +216,7 @@ public class MethodOptimizationInfo
public boolean isParameterUsed(int parameterIndex)
{
- return parameterIndex >= 64 || (usedParameters & (1 << parameterIndex)) != 0;
+ return parameterIndex >= 64 || (usedParameters & (1L << parameterIndex)) != 0;
}
diff --git a/src/proguard/optimize/info/NoSideEffectMethodMarker.java b/src/proguard/optimize/info/NoSideEffectMethodMarker.java
index 5c78408..bf5ce45 100644
--- a/src/proguard/optimize/info/NoSideEffectMethodMarker.java
+++ b/src/proguard/optimize/info/NoSideEffectMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -38,7 +38,7 @@ implements MemberVisitor
{
// A visitor info flag to indicate the visitor accepter is being kept,
// but that it doesn't have any side effects.
- private static final Object KEPT_BUT_NO_SIDE_EFFECTS = new Object();
+ public static final Object KEPT_BUT_NO_SIDE_EFFECTS = new Object();
// Implementations for MemberVisitor.
diff --git a/src/proguard/optimize/info/NonPrivateMemberMarker.java b/src/proguard/optimize/info/NonPrivateMemberMarker.java
index d451643..06f8500 100644
--- a/src/proguard/optimize/info/NonPrivateMemberMarker.java
+++ b/src/proguard/optimize/info/NonPrivateMemberMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -77,15 +77,9 @@ implements ClassVisitor,
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
- Clazz referencedClass = stringConstant.referencedClass;
-
- // Is it refering to another class or class member?
- if (referencedClass != null &&
- !referencedClass.equals(clazz))
- {
- // The referenced class member, if any, can never be made private.
- stringConstant.referencedMemberAccept(this);
- }
+ // The referenced class member, if any, can never be made private,
+ // even if it's in the same class.
+ stringConstant.referencedMemberAccept(this);
}
@@ -93,7 +87,7 @@ implements ClassVisitor,
{
Clazz referencedClass = refConstant.referencedClass;
- // Is it refering to a class member in another class?
+ // Is it referring to a class member in another class?
// The class member might be in another class, or
// it may be referenced through another class.
if (referencedClass != null &&
diff --git a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
index d40bc6b..02e1a18 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
+++ b/src/proguard/optimize/info/PackageVisibleMemberContainingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,18 +22,36 @@ package proguard.optimize.info;
import proguard.classfile.*;
import proguard.classfile.util.SimplifiedVisitor;
-import proguard.classfile.visitor.MemberVisitor;
+import proguard.classfile.visitor.*;
/**
- * This MemberVisitor marks all classes that contain visited package visible
- * members.
+ * This ClassVisitor marks all classes that contain package visible members.
*
* @author Eric Lafortune
*/
public class PackageVisibleMemberContainingClassMarker
extends SimplifiedVisitor
-implements MemberVisitor
+implements ClassVisitor,
+ MemberVisitor
{
+ // Implementations for ClassVisitor.
+
+ public void visitAnyClass(Clazz clazz)
+ {
+ // Check the class itself.
+ if ((clazz.getAccessFlags() & ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
+ {
+ setPackageVisibleMembers(clazz);
+ }
+ else
+ {
+ // Check the members.
+ clazz.fieldsAccept(this);
+ clazz.methodsAccept(this);
+ }
+ }
+
+
// Implementations for MemberVisitor.
public void visitAnyMember(Clazz clazz, Member member)
diff --git a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
index 9ec8ec6..3148e3d 100644
--- a/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
+++ b/src/proguard/optimize/info/PackageVisibleMemberInvokingClassMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -24,39 +24,87 @@ import proguard.classfile.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.constant.*;
import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
/**
- * This ConstantVisitor marks all classes that invoke package visible members
- * in other classes.
+ * This ConstantVisitor marks all classes that refer to package visible classes
+ * or class members.
*
* @author Eric Lafortune
*/
public class PackageVisibleMemberInvokingClassMarker
extends SimplifiedVisitor
-implements ConstantVisitor
+implements ConstantVisitor,
+ ClassVisitor,
+ MemberVisitor
{
+ private Clazz referencingClass;
+
+
// Implementations for ConstantVisitor.
public void visitAnyConstant(Clazz clazz, Constant constant) {}
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ // Check the referenced class and class member, if any.
+ if (stringConstant.referencedClass != clazz)
+ {
+ referencingClass = clazz;
+
+ stringConstant.referencedClassAccept(this);
+ stringConstant.referencedMemberAccept(this);
+ }
+ }
+
+
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
- Clazz referencedClass = refConstant.referencedClass;
- if (referencedClass != null &&
- (referencedClass.getAccessFlags() &
+ // Check the referenced class and class member.
+ if (refConstant.referencedClass != clazz)
+ {
+ referencingClass = clazz;
+
+ refConstant.referencedClassAccept(this);
+ refConstant.referencedMemberAccept(this);
+ }
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Check the referenced class.
+ if (classConstant.referencedClass != clazz)
+ {
+ referencingClass = clazz;
+
+ classConstant.referencedClassAccept(this);
+ }
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitAnyClass(Clazz clazz)
+ {
+ if ((clazz.getAccessFlags() &
ClassConstants.INTERNAL_ACC_PUBLIC) == 0)
{
- setInvokesPackageVisibleMembers(clazz);
+ setInvokesPackageVisibleMembers(referencingClass);
}
+ }
- Member referencedMember = refConstant.referencedMember;
- if (referencedMember != null &&
- (referencedMember.getAccessFlags() &
+
+ // Implementations for MemberVisitor.
+
+ public void visitAnyMember(Clazz clazz, Member member)
+ {
+ if ((member.getAccessFlags() &
(ClassConstants.INTERNAL_ACC_PUBLIC |
ClassConstants.INTERNAL_ACC_PRIVATE)) == 0)
{
- setInvokesPackageVisibleMembers(clazz);
+ setInvokesPackageVisibleMembers(referencingClass);
}
}
diff --git a/src/proguard/optimize/info/ParameterUsageMarker.java b/src/proguard/optimize/info/ParameterUsageMarker.java
index 15ce88a..a2a264d 100644
--- a/src/proguard/optimize/info/ParameterUsageMarker.java
+++ b/src/proguard/optimize/info/ParameterUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,14 +21,14 @@
package proguard.optimize.info;
import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.attribute.*;
import proguard.classfile.util.*;
import proguard.classfile.visitor.MemberVisitor;
+import proguard.evaluation.value.Value;
import proguard.optimize.evaluation.PartialEvaluator;
-import proguard.evaluation.value.*;
/**
* This MemberVisitor counts the parameters and marks the used parameters
diff --git a/src/proguard/optimize/info/ReadWriteFieldMarker.java b/src/proguard/optimize/info/ReadWriteFieldMarker.java
index 57d8561..6bd4b2f 100644
--- a/src/proguard/optimize/info/ReadWriteFieldMarker.java
+++ b/src/proguard/optimize/info/ReadWriteFieldMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/SideEffectInstructionChecker.java b/src/proguard/optimize/info/SideEffectInstructionChecker.java
index 8be9dc1..91f1f02 100644
--- a/src/proguard/optimize/info/SideEffectInstructionChecker.java
+++ b/src/proguard/optimize/info/SideEffectInstructionChecker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,11 +29,14 @@ import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.classfile.visitor.*;
+import java.util.*;
+
/**
- * This class can tell whether an instruction has any side effects. Return
- * instructions can be included or not.
+ * This class can tell whether an instruction has any side effects outside of
+ * its method. Return instructions can be included or not.
*
* @see ReadWriteFieldMarker
+ * @see StaticInitializerContainingClassMarker
* @see NoSideEffectMethodMarker
* @see SideEffectMethodMarker
* @author Eric Lafortune
@@ -44,23 +47,38 @@ implements InstructionVisitor,
ConstantVisitor,
MemberVisitor
{
+ private static final boolean OPTIMIZE_CONSERVATIVELY = System.getProperty("optimize.conservatively") != null;
+
+
private final boolean includeReturnInstructions;
+ private final boolean includeLocalFieldAccess;
// A return value for the visitor methods.
+ private Clazz referencingClass;
private boolean hasSideEffects;
- public SideEffectInstructionChecker(boolean includeReturnInstructions)
+ public SideEffectInstructionChecker(boolean includeReturnInstructions,
+ boolean includeLocalFieldAccess)
{
this.includeReturnInstructions = includeReturnInstructions;
+ this.includeLocalFieldAccess = includeLocalFieldAccess;
}
- public boolean hasSideEffects(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
+ /**
+ * 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)
{
hasSideEffects = false;
- instruction.accept(clazz, method, codeAttribute, offset, this);
+ instruction.accept(clazz, method, codeAttribute, offset, this);
return hasSideEffects;
}
@@ -76,29 +94,46 @@ implements InstructionVisitor,
byte opcode = simpleInstruction.opcode;
// Check for instructions that might cause side effects.
- if (opcode == InstructionConstants.OP_IASTORE ||
- opcode == InstructionConstants.OP_LASTORE ||
- opcode == InstructionConstants.OP_FASTORE ||
- opcode == InstructionConstants.OP_DASTORE ||
- opcode == InstructionConstants.OP_AASTORE ||
- opcode == InstructionConstants.OP_BASTORE ||
- opcode == InstructionConstants.OP_CASTORE ||
- opcode == InstructionConstants.OP_SASTORE ||
- opcode == InstructionConstants.OP_ATHROW ||
- opcode == InstructionConstants.OP_MONITORENTER ||
- opcode == InstructionConstants.OP_MONITOREXIT ||
- (includeReturnInstructions &&
- (opcode == InstructionConstants.OP_IRETURN ||
- opcode == InstructionConstants.OP_LRETURN ||
- opcode == InstructionConstants.OP_FRETURN ||
- opcode == InstructionConstants.OP_DRETURN ||
- opcode == InstructionConstants.OP_ARETURN ||
- opcode == InstructionConstants.OP_RETURN)))
+ switch (opcode)
{
- // These instructions always cause a side effect.
- hasSideEffects = true;
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_LALOAD:
+ case InstructionConstants.OP_FALOAD:
+ case InstructionConstants.OP_DALOAD:
+ case InstructionConstants.OP_AALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+ // These instructions strictly taken may cause a side effect
+ // (NullPointerException, ArrayIndexOutOfBoundsException).
+ hasSideEffects = OPTIMIZE_CONSERVATIVELY;
+ break;
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ case InstructionConstants.OP_ATHROW :
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ // These instructions always cause a side effect.
+ hasSideEffects = true;
+ break;
+
+ case InstructionConstants.OP_IRETURN:
+ case InstructionConstants.OP_LRETURN:
+ case InstructionConstants.OP_FRETURN:
+ case InstructionConstants.OP_DRETURN:
+ case InstructionConstants.OP_ARETURN:
+ case InstructionConstants.OP_RETURN:
+ // These instructions may have a side effect.
+ hasSideEffects = includeReturnInstructions;
+ break;
}
-
}
@@ -107,10 +142,12 @@ implements InstructionVisitor,
byte opcode = variableInstruction.opcode;
// Check for instructions that might cause side effects.
- if (includeReturnInstructions &&
- opcode == InstructionConstants.OP_RET)
+ switch (opcode)
{
- hasSideEffects = true;
+ case InstructionConstants.OP_RET:
+ // This instruction may have a side effect.
+ hasSideEffects = includeReturnInstructions;
+ break;
}
}
@@ -120,16 +157,41 @@ implements InstructionVisitor,
byte opcode = constantInstruction.opcode;
// Check for instructions that might cause side effects.
- if (opcode == InstructionConstants.OP_PUTSTATIC ||
- opcode == InstructionConstants.OP_PUTFIELD ||
- opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
- opcode == InstructionConstants.OP_INVOKESPECIAL ||
- opcode == InstructionConstants.OP_INVOKESTATIC ||
- opcode == InstructionConstants.OP_INVOKEINTERFACE)
+ switch (opcode)
{
- // Check if the field is write-only or volatile, or if the invoked
- // method is causing any side effects.
- clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ // Check if the field is write-only or volatile, or if the
+ // invoked method is causing any side effects.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ break;
+
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_PUTFIELD:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ case InstructionConstants.OP_INVOKEDYNAMIC:
+ if (OPTIMIZE_CONSERVATIVELY)
+ {
+ // These instructions strictly taken may cause a side effect
+ // (NullPointerException).
+ hasSideEffects = true;
+ }
+ else
+ {
+ // Check if the field is write-only or volatile, or if the
+ // invoked method is causing any side effects.
+ clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
+ }
+ break;
+
+ case InstructionConstants.OP_CHECKCAST:
+ // This instructions strictly taken may cause a side effect
+ // (ClassCastException).
+ hasSideEffects = OPTIMIZE_CONSERVATIVELY;
+ break;
}
}
@@ -139,59 +201,48 @@ implements InstructionVisitor,
byte opcode = branchInstruction.opcode;
// Check for instructions that might cause side effects.
- if (includeReturnInstructions &&
- (opcode == InstructionConstants.OP_JSR ||
- opcode == InstructionConstants.OP_JSR_W))
+ switch (opcode)
{
- hasSideEffects = true;
+ case InstructionConstants.OP_JSR:
+ case InstructionConstants.OP_JSR_W:
+ hasSideEffects = includeReturnInstructions;
+ break;
}
}
// Implementations for ConstantVisitor.
+ public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
+ {
+ // We'll have to assume invoking an unknown method has side effects.
+ hasSideEffects = true;
+ }
+
+
public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
{
+ // Pass the referencing class.
+ referencingClass = clazz;
+
// We'll have to assume accessing an unknown field has side effects.
hasSideEffects = true;
- // Check the referenced field.
+ // Check the referenced field, if known.
fieldrefConstant.referencedMemberAccept(this);
}
public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
{
- Member referencedMember = refConstant.referencedMember;
+ // Pass the referencing class.
+ referencingClass = clazz;
- // Do we have a reference to the method?
- if (referencedMember == null)
- {
- // We'll have to assume invoking the unknown method has side effects.
- hasSideEffects = true;
- }
- else
- {
- // First check the referenced method itself.
- refConstant.referencedMemberAccept(this);
-
- // If the result isn't conclusive, check down the hierarchy.
- if (!hasSideEffects)
- {
- Clazz referencedClass = refConstant.referencedClass;
- Method referencedMethod = (Method)referencedMember;
-
- // Check all other implementations of the method down the class
- // hierarchy.
- if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) == 0)
- {
- clazz.hierarchyAccept(false, false, false, true,
- new NamedMethodVisitor(referencedMethod.getName(referencedClass),
- referencedMethod.getDescriptor(referencedClass),
- this));
- }
- }
- }
+ // We'll have to assume invoking an unknown method has side effects.
+ hasSideEffects = true;
+
+ // Check the referenced method, if known.
+ refConstant.referencedMemberAccept(this);
}
@@ -199,14 +250,25 @@ implements InstructionVisitor,
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
- hasSideEffects = ReadWriteFieldMarker.isRead(programField);
+ hasSideEffects =
+ (includeLocalFieldAccess || !programClass.equals(referencingClass)) &&
+ ((ReadWriteFieldMarker.isRead(programField) &&
+ ReadWriteFieldMarker.isWritten(programField)) ||
+ ((programField.getAccessFlags() & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) ||
+ (!programClass.equals(referencingClass) &&
+ !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))));
}
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
- hasSideEffects = hasSideEffects ||
- SideEffectMethodMarker.hasSideEffects(programMethod);
+ // Note that side effects already include synchronization of some
+ // implementation of the method.
+ hasSideEffects =
+ !NoSideEffectMethodMarker.hasNoSideEffects(programMethod) &&
+ (SideEffectMethodMarker.hasSideEffects(programMethod) ||
+ (!programClass.equals(referencingClass) &&
+ !initializedSuperClasses(referencingClass).containsAll(initializedSuperClasses(programClass))));
}
@@ -218,7 +280,28 @@ implements InstructionVisitor,
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
- hasSideEffects = hasSideEffects ||
- !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod);
+ hasSideEffects =
+ !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethod);
+ }
+
+
+ /**
+ * Returns the set of superclasses and interfaces that are initialized.
+ */
+ private Set initializedSuperClasses(Clazz clazz)
+ {
+ Set set = new HashSet();
+
+ // Visit all superclasses and interfaces, collecting the ones that have
+ // static initializers.
+ clazz.hierarchyAccept(true, true, true, false,
+ new StaticInitializerContainingClassFilter(
+ new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+ ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+ new SideEffectMethodFilter(
+ new MemberToClassVisitor(
+ new ClassCollector(set))))));
+
+ return set;
}
}
diff --git a/src/proguard/optimize/info/SideEffectMethodFilter.java b/src/proguard/optimize/info/SideEffectMethodFilter.java
new file mode 100644
index 0000000..52e072a
--- /dev/null
+++ b/src/proguard/optimize/info/SideEffectMethodFilter.java
@@ -0,0 +1,73 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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.MemberVisitor;
+
+/**
+ * This MemberVisitor delegates all its method calls to another MemberVisitor,
+ * but only for Method objects that are marked as having side effects.
+ *
+ * @see SideEffectMethodMarker
+ *
+ * @author Eric Lafortune
+ */
+public class SideEffectMethodFilter
+implements MemberVisitor
+{
+ private final MemberVisitor memberVisitor;
+
+
+ /**
+ * Creates a new SideEffectMethodFilter.
+ * @param memberVisitor the member visitor to which the visiting will be
+ * delegated.
+ */
+ public SideEffectMethodFilter(MemberVisitor memberVisitor)
+ {
+ this.memberVisitor = memberVisitor;
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramField(ProgramClass programClass, ProgramField programField) {}
+ public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) {}
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ if (SideEffectMethodMarker.hasSideEffects(programMethod))
+ {
+ memberVisitor.visitProgramMethod(programClass, programMethod);
+ }
+ }
+
+
+ public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
+ {
+ if (SideEffectMethodMarker.hasSideEffects(libraryMethod))
+ {
+ memberVisitor.visitLibraryMethod(libraryClass, libraryMethod);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/SideEffectMethodMarker.java b/src/proguard/optimize/info/SideEffectMethodMarker.java
index 25fda72..f7953c0 100644
--- a/src/proguard/optimize/info/SideEffectMethodMarker.java
+++ b/src/proguard/optimize/info/SideEffectMethodMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -41,8 +41,9 @@ implements ClassPoolVisitor,
MemberVisitor,
AttributeVisitor
{
- // A reusable object for checking whether instructions have side effects.
- private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false);
+ // Reusable objects for checking whether instructions have side effects.
+ private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false, true);
+ private final SideEffectInstructionChecker initializerSideEffectInstructionChecker = new SideEffectInstructionChecker(false, false);
// Parameters and values for visitor methods.
private int newSideEffectCount;
@@ -130,6 +131,11 @@ implements ClassPoolVisitor,
byte[] code = codeAttribute.code;
int length = codeAttribute.u4codeLength;
+ SideEffectInstructionChecker checker =
+ method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ?
+ initializerSideEffectInstructionChecker :
+ sideEffectInstructionChecker;
+
// Go over all instructions.
int offset = 0;
do
@@ -138,11 +144,11 @@ implements ClassPoolVisitor,
Instruction instruction = InstructionFactory.create(code, offset);
// Check if it may be throwing exceptions.
- if (sideEffectInstructionChecker.hasSideEffects(clazz,
- method,
- codeAttribute,
- offset,
- instruction))
+ if (checker.hasSideEffects(clazz,
+ method,
+ codeAttribute,
+ offset,
+ instruction))
{
return true;
}
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
new file mode 100644
index 0000000..36aa392
--- /dev/null
+++ b/src/proguard/optimize/info/StaticInitializerContainingClassFilter.java
@@ -0,0 +1,62 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.ClassVisitor;
+
+/**
+ * This ClassVisitor delegates all its method calls to another ClassVisitor,
+ * but only for Clazz objects that are instantiated.
+ *
+ * @author Eric Lafortune
+ */
+public class StaticInitializerContainingClassFilter
+implements ClassVisitor
+{
+ private final ClassVisitor classVisitor;
+
+
+ public StaticInitializerContainingClassFilter(ClassVisitor classVisitor)
+ {
+ this.classVisitor = classVisitor;
+ }
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ if (StaticInitializerContainingClassMarker.containsStaticInitializer(programClass))
+ {
+ classVisitor.visitProgramClass(programClass);
+ }
+ }
+
+
+ public void visitLibraryClass(LibraryClass libraryClass)
+ {
+ if (StaticInitializerContainingClassMarker.containsStaticInitializer(libraryClass))
+ {
+ classVisitor.visitLibraryClass(libraryClass);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
new file mode 100644
index 0000000..3a7e642
--- /dev/null
+++ b/src/proguard/optimize/info/StaticInitializerContainingClassMarker.java
@@ -0,0 +1,65 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.info;
+
+import proguard.classfile.*;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassVisitor marks all classes that contain static initializers.
+ *
+ * @author Eric Lafortune
+ */
+public class StaticInitializerContainingClassMarker
+extends SimplifiedVisitor
+implements ClassVisitor
+{
+ // Implementations for ClassVisitor.
+
+ public void visitAnyClass(Clazz clazz)
+ {
+ if (clazz.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+ ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) != null)
+ {
+ setStaticInitializer(clazz);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private static void setStaticInitializer(Clazz clazz)
+ {
+ ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
+ if (info != null)
+ {
+ info.setContainsStaticInitializer();
+ }
+ }
+
+
+ public static boolean containsStaticInitializer(Clazz clazz)
+ {
+ ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
+ return info == null || info.containsStaticInitializer();
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/optimize/info/SuperInvocationMarker.java b/src/proguard/optimize/info/SuperInvocationMarker.java
index 6f3d3bd..37b118a 100644
--- a/src/proguard/optimize/info/SuperInvocationMarker.java
+++ b/src/proguard/optimize/info/SuperInvocationMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/info/VariableUsageMarker.java b/src/proguard/optimize/info/VariableUsageMarker.java
index 660c4ba..b189ca9 100644
--- a/src/proguard/optimize/info/VariableUsageMarker.java
+++ b/src/proguard/optimize/info/VariableUsageMarker.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -27,6 +27,8 @@ import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import java.util.Arrays;
+
/**
* This AttributeVisitor marks the local variables that are used in the code
* attributes that it visits.
@@ -62,14 +64,13 @@ implements AttributeVisitor,
// Try to reuse the previous array.
if (variableUsed.length < maxLocals)
{
+ // Create a new array.
variableUsed = new boolean[maxLocals];
}
else
{
- for (int index = 0; index < maxLocals; index++)
- {
- variableUsed[index] = false;
- }
+ // Reset the array.
+ Arrays.fill(variableUsed, 0, maxLocals, false);
}
codeAttribute.instructionsAccept(clazz, method, this);
diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java
index 8f650bb..79499f1 100644
--- a/src/proguard/optimize/peephole/BranchTargetFinder.java
+++ b/src/proguard/optimize/peephole/BranchTargetFinder.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,6 +29,8 @@ import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.SimplifiedVisitor;
+import java.util.Arrays;
+
/**
* This AttributeVisitor finds all instruction offsets, branch targets, and
* exception targets in the CodeAttribute objects that it visits.
@@ -45,12 +47,15 @@ implements AttributeVisitor,
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = true;
+ private static boolean DEBUG = System.getProperty("btf") != null;
//*/
public static final int NONE = -2;
public static final int AT_METHOD_ENTRY = -1;
+ public static final int UNKNOWN = -1;
+ public static final int NO_SUBROUTINE = -2;
+
private static final short INSTRUCTION = 1 << 0;
private static final short BRANCH_ORIGIN = 1 << 1;
private static final short BRANCH_TARGET = 1 << 2;
@@ -70,9 +75,10 @@ implements AttributeVisitor,
private int[] creationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
private int superInitializationOffset;
+ private boolean containsSubroutines;
+ private boolean repeat;
private int currentSubroutineStart;
- private int currentSubroutineEnd;
private int[] recentCreationOffsets = new int[MAXIMUM_CREATION_OFFSETS];
private int recentCreationOffsetIndex;
private boolean isInitializer;
@@ -189,7 +195,7 @@ implements AttributeVisitor,
*/
public boolean isSubroutine(int offset)
{
- return subroutineStarts[offset] != NONE;
+ return subroutineStarts[offset] >= 0;
}
@@ -289,6 +295,16 @@ implements AttributeVisitor,
}
+ /**
+ * Returns whether the method contains subroutines, in the CodeAttribute
+ * that was visited most recently.
+ */
+ public boolean containsSubroutines()
+ {
+ return containsSubroutines;
+ }
+
+
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
@@ -312,106 +328,98 @@ implements AttributeVisitor,
initializationOffsets = new int[codeLength];
// Reset the arrays.
- for (int index = 0; index < codeLength; index++)
- {
- subroutineStarts[index] = NONE;
- subroutineEnds[index] = NONE;
- creationOffsets[index] = NONE;
- initializationOffsets[index] = NONE;
- }
+ Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN);
+ Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN);
+ Arrays.fill(creationOffsets, 0, codeLength, NONE);
+ Arrays.fill(initializationOffsets, 0, codeLength, NONE);
}
else
{
// Reset the arrays.
- for (int index = 0; index < codeLength; index++)
- {
- instructionMarks[index] = 0;
- subroutineStarts[index] = NONE;
- subroutineEnds[index] = NONE;
- creationOffsets[index] = NONE;
- initializationOffsets[index] = NONE;
- }
+ Arrays.fill(instructionMarks, 0, codeLength, (short)0);
+ Arrays.fill(subroutineStarts, 0, codeLength, UNKNOWN);
+ Arrays.fill(subroutineEnds, 0, codeLength, UNKNOWN);
+ Arrays.fill(creationOffsets, 0, codeLength, NONE);
+ Arrays.fill(initializationOffsets, 0, codeLength, NONE);
instructionMarks[codeLength] = 0;
}
superInitializationOffset = NONE;
+ containsSubroutines = false;
- // We're assuming all subroutines are contiguous blocks of code.
- // We're not starting in a subroutine.
- currentSubroutineStart = NONE;
- currentSubroutineEnd = NONE;
+ // Iterate until all subroutines have been fully marked.
+ do
+ {
+ repeat = false;
+ currentSubroutineStart = NO_SUBROUTINE;
+ recentCreationOffsetIndex = 0;
- recentCreationOffsetIndex = 0;
+ // Initialize the stack of 'new' instruction offsets if this method
+ // is an instance initializer.
+ if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ {
+ recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY;
+ }
- // Initialize the stack of 'new' instruction offsets if this method is
- // an instance initializer.
- if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
- {
- recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY;
+ // Mark branch targets by going over all instructions.
+ codeAttribute.instructionsAccept(clazz, method, this);
}
+ while (repeat);
// The end of the code is a branch target sentinel.
instructionMarks[codeLength] = BRANCH_TARGET;
- // Mark branch targets by going over all instructions.
- codeAttribute.instructionsAccept(clazz, method, this);
-
// Mark branch targets in the exception table.
codeAttribute.exceptionsAccept(clazz, method, this);
- // Fill out any gaps in the subroutine starts and the subroutine ends
- // and subroutine returning flags, working backward.
-
- // We're not starting in a subroutine.
- int subroutineStart = NONE;
- int subroutineEnd = codeLength;
- boolean subroutineReturning = false;
-
- for (int index = codeLength - 1; index >= 0; index--)
+ if (containsSubroutines)
{
- if (isInstruction(index))
- {
- // Are we inside a previously marked subroutine?
- if (subroutineStarts[index] != NONE)
- {
- // Update the current subroutine start.
- subroutineStart = subroutineStarts[index];
- }
- else if (subroutineStart != NONE)
- {
- // Mark the subroutine start.
- subroutineStarts[index] = subroutineStart;
- }
+ // Set the subroutine returning flag and the subroutine end at each
+ // subroutine start.
+ int previousSubroutineStart = NO_SUBROUTINE;
- // Did we reach the start of the subroutine.
- if (isSubroutineStart(index))
- {
- // Stop marking it.
- subroutineStart = NONE;
- }
-
- // Are we inside a subroutine?
- if (isSubroutine(index))
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (isInstruction(offset))
{
- // Mark the subroutine end.
- subroutineEnds[index] = subroutineEnd;
+ int subroutineStart = subroutineStarts[offset];
- // Update or mark the subroutine returning flag.
- if (isSubroutineReturning(index))
+ if (subroutineStart >= 0 &&
+ isSubroutineReturning(offset))
{
- subroutineReturning = true;
+ instructionMarks[subroutineStart] |= SUBROUTINE_RETURNING;
}
- else if (subroutineReturning)
+
+ if (previousSubroutineStart >= 0)
{
- instructionMarks[index] |= SUBROUTINE_RETURNING;
+ subroutineEnds[previousSubroutineStart] = offset;
}
+
+ previousSubroutineStart = subroutineStart;
}
- else
+ }
+
+ if (previousSubroutineStart >= 0)
+ {
+ subroutineEnds[previousSubroutineStart] = codeLength;
+ }
+
+ // Set the subroutine returning flag and the subroutine end at each
+ // subroutine instruction, based on the marks at the subroutine
+ // start.
+ for (int offset = 0; offset < codeLength; offset++)
+ {
+ if (isSubroutine(offset))
{
- // Update the subroutine end and returning flag.
- subroutineEnd = index;
- subroutineReturning = false;
+ int subroutineStart = subroutineStarts[offset];
+
+ if (isSubroutineReturning(subroutineStart))
+ {
+ instructionMarks[offset] |= SUBROUTINE_RETURNING;
+ }
+
+ subroutineEnds[offset] = subroutineEnds[subroutineStart];
}
}
}
@@ -451,7 +459,7 @@ implements AttributeVisitor,
// Mark the instruction.
instructionMarks[offset] |= INSTRUCTION;
- // Check if this is the first instruction of a subroutine.
+ // Check if this is an instruction of a subroutine.
checkSubroutine(offset);
byte opcode = simpleInstruction.opcode;
@@ -476,7 +484,7 @@ implements AttributeVisitor,
// Mark the instruction.
instructionMarks[offset] |= INSTRUCTION;
- // Check if this is the first instruction of a subroutine.
+ // Check if this is an instruction of a subroutine.
checkSubroutine(offset);
// Check if the instruction is a 'new' instruction.
@@ -517,15 +525,18 @@ implements AttributeVisitor,
// Mark the instruction.
instructionMarks[offset] |= INSTRUCTION;
- // Check if this is the first instruction of a subroutine.
+ // Check if this is an instruction of a subroutine.
checkSubroutine(offset);
if (variableInstruction.opcode == InstructionConstants.OP_RET)
{
+ // Mark the method.
+ containsSubroutines = true;
+
// Mark the branch origin.
markBranchOrigin(offset);
- // Mark the regular subroutine return.
+ // Mark the subroutine return at its return instruction.
instructionMarks[offset] |= SUBROUTINE_RETURNING;
// Mark the next instruction.
@@ -536,28 +547,39 @@ implements AttributeVisitor,
public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
{
+ int branchOffset = branchInstruction.branchOffset;
+ int targetOffset = offset + branchOffset;
+
// Mark the branch origin.
markBranchOrigin(offset);
- // Check if this is the first instruction of a subroutine.
+ // Check if this is an instruction of a subroutine.
checkSubroutine(offset);
// Mark the branch target.
- markBranchTarget(offset, branchInstruction.branchOffset);
+ markBranchTarget(offset, branchOffset);
byte opcode = branchInstruction.opcode;
if (opcode == InstructionConstants.OP_JSR ||
opcode == InstructionConstants.OP_JSR_W)
{
+ // Mark the method.
+ containsSubroutines = true;
+
// Mark the subroutine invocation.
instructionMarks[offset] |= SUBROUTINE_INVOCATION;
- // Mark the subroutine start.
- int targetOffset = offset + branchInstruction.branchOffset;
- subroutineStarts[targetOffset] = targetOffset;
+ // Mark the new subroutine start.
+ markBranchSubroutineStart(offset, branchOffset, targetOffset);
}
- else if (opcode == InstructionConstants.OP_GOTO ||
- opcode == InstructionConstants.OP_GOTO_W)
+ else if (currentSubroutineStart != UNKNOWN)
+ {
+ // Mark the continued subroutine start.
+ markBranchSubroutineStart(offset, branchOffset, currentSubroutineStart);
+ }
+
+ if (opcode == InstructionConstants.OP_GOTO ||
+ opcode == InstructionConstants.OP_GOTO_W)
{
// Mark the next instruction.
markAfterBranchOrigin(offset + branchInstruction.length(offset));
@@ -570,15 +592,14 @@ implements AttributeVisitor,
// Mark the branch origin.
markBranchOrigin(offset);
- // Check if this is the first instruction of a subroutine.
+ // Check if this is an instruction of a subroutine.
checkSubroutine(offset);
// Mark the branch targets of the default jump offset.
- markBranchTarget(offset, switchInstruction.defaultOffset);
+ markBranch(offset, switchInstruction.defaultOffset);
// Mark the branch targets of the jump offsets.
- markBranchTargets(offset,
- switchInstruction.jumpOffsets);
+ markBranches(offset, switchInstruction.jumpOffsets);
// Mark the next instruction.
markAfterBranchOrigin(offset + switchInstruction.length(offset));
@@ -610,18 +631,31 @@ implements AttributeVisitor,
// Small utility methods.
/**
- * Marks the branch targets of the given jump offsets for the instruction
- * at the given offset.
+ * Marks the branch targets and their subroutine starts at the given
+ * offsets.
*/
- private void markBranchTargets(int offset, int[] jumpOffsets)
+ private void markBranches(int offset, int[] jumpOffsets)
{
for (int index = 0; index < jumpOffsets.length; index++)
{
- markBranchTarget(offset, jumpOffsets[index]);
+ markBranch(offset, jumpOffsets[index]);
}
}
+ /**
+ * Marks the branch target and its subroutine start at the given offset.
+ */
+ private void markBranch(int offset, int jumpOffset)
+ {
+ markBranchTarget(offset, jumpOffset);
+
+ if (currentSubroutineStart != UNKNOWN)
+ {
+ markBranchSubroutineStart(offset, jumpOffset, currentSubroutineStart);
+ }
+ }
+
/**
* Marks the branch origin at the given offset.
*/
@@ -639,18 +673,37 @@ implements AttributeVisitor,
int targetOffset = offset + jumpOffset;
instructionMarks[targetOffset] |= BRANCH_TARGET;
+ }
- // Are we inside a previously marked subroutine?
- if (isSubroutine(offset))
- {
- // Mark the subroutine start of the target.
- subroutineStarts[targetOffset] = currentSubroutineStart;
- // Update the current subroutine end.
- if (currentSubroutineEnd < targetOffset)
+ /**
+ * Marks the subroutine start at the given offset, if applicable.
+ */
+ private void markBranchSubroutineStart(int offset,
+ int jumpOffset,
+ int subroutineStart)
+ {
+ int targetOffset = offset + jumpOffset;
+
+ // Are we marking a subroutine and branching to an offset that hasn't
+ // been marked yet?
+ if (subroutineStarts[targetOffset] == UNKNOWN)
+ {
+ // Is it a backward branch?
+ if (jumpOffset < 0)
{
- currentSubroutineEnd = targetOffset;
+ // Remember the smallest subroutine start.
+ if (subroutineStart > targetOffset)
+ {
+ subroutineStart = targetOffset;
+ }
+
+ // We'll have to go over all instructions again.
+ repeat = true;
}
+
+ // Mark the subroutine start of the target.
+ subroutineStarts[targetOffset] = subroutineStart;
}
}
@@ -662,12 +715,8 @@ implements AttributeVisitor,
{
instructionMarks[nextOffset] |= AFTER_BRANCH;
- // Are we at the end of the current subroutine?
- if (currentSubroutineEnd <= nextOffset)
- {
- // Reset the subroutine start.
- currentSubroutineStart = NONE;
- }
+ // Stop marking a subroutine.
+ currentSubroutineStart = UNKNOWN;
}
@@ -677,15 +726,23 @@ implements AttributeVisitor,
private void checkSubroutine(int offset)
{
// Are we inside a previously marked subroutine?
- if (isSubroutine(offset))
+ if (subroutineStarts[offset] != UNKNOWN)
{
- // Update the current subroutine start.
+ // Start marking a subroutine.
currentSubroutineStart = subroutineStarts[offset];
}
- else
+
+ // Are we marking a subroutine?
+ else if (currentSubroutineStart != UNKNOWN)
{
- // Mark the subroutine start (or NONE).
+ // Mark the subroutine start.
subroutineStarts[offset] = currentSubroutineStart;
+
+ if (currentSubroutineStart >= 0)
+ {
+ // Mark the subroutine end at the subroutine start.
+ subroutineEnds[currentSubroutineStart] = offset;
+ }
}
}
}
diff --git a/src/proguard/optimize/peephole/ClassFinalizer.java b/src/proguard/optimize/peephole/ClassFinalizer.java
index b5e54f8..378f972 100644
--- a/src/proguard/optimize/peephole/ClassFinalizer.java
+++ b/src/proguard/optimize/peephole/ClassFinalizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/ClassMerger.java b/src/proguard/optimize/peephole/ClassMerger.java
index 1e1a950..aa40c75 100644
--- a/src/proguard/optimize/peephole/ClassMerger.java
+++ b/src/proguard/optimize/peephole/ClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
package proguard.optimize.peephole;
import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.AttributeNameFilter;
import proguard.classfile.constant.visitor.*;
import proguard.classfile.editor.*;
import proguard.classfile.util.*;
@@ -50,7 +51,7 @@ implements ClassVisitor,
//*
private static final boolean DEBUG = false;
/*/
- private static boolean DEBUG = true;
+ private static boolean DEBUG = System.getProperty("cm") != null;
//*/
@@ -59,6 +60,8 @@ implements ClassVisitor,
private final boolean mergeInterfacesAggressively;
private final ClassVisitor extraClassVisitor;
+ private final MemberVisitor fieldOptimizationInfoCopier = new FieldOptimizationInfoCopier();
+
/**
* Creates a new ClassMerger that will merge classes into the given target
@@ -151,7 +154,7 @@ implements ClassVisitor,
// infinite recursion.
(programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 &&
- // Only merge classes if we can change the access permissioms, or
+ // Only merge classes if we can change the access permissions, or
// if they are in the same package, or
// if they are public and don't contain or invoke package visible
// class members.
@@ -196,12 +199,19 @@ implements ClassVisitor,
!(DotClassMarker.isDotClassed(programClass) &&
DotClassMarker.isDotClassed(targetClass)) &&
+ // The classes must not have clashing fields.
+ !haveAnyIdenticalFields(programClass, targetClass) &&
+
// The two classes must not introduce any unwanted fields.
!introducesUnwantedFields(programClass, targetClass) &&
!introducesUnwantedFields(targetClass, programClass) &&
- // The classes must not have clashing constructors.
- !haveAnyIdenticalInitializers(programClass, targetClass) &&
+ // The two classes must not shadow each others fields.
+ !shadowsAnyFields(programClass, targetClass) &&
+ !shadowsAnyFields(targetClass, programClass) &&
+
+ // The classes must not have clashing methods.
+ !haveAnyIdenticalMethods(programClass, targetClass) &&
// The classes must not introduce abstract methods, unless
// explicitly allowed.
@@ -226,6 +236,10 @@ implements ClassVisitor,
System.out.println(" Target subclasses ["+targetClass.subClasses+"]");
System.out.println(" Source superclass ["+programClass.getSuperClass().getName()+"]");
System.out.println(" Target superclass ["+targetClass.getSuperClass().getName()+"]");
+
+ //System.out.println("=== Before ===");
+ //programClass.accept(new ClassPrinter());
+ //targetClass.accept(new ClassPrinter());
}
// Combine the access flags.
@@ -235,11 +249,12 @@ implements ClassVisitor,
targetClass.u2accessFlags =
((targetAccessFlags &
sourceAccessFlags) &
- (ClassConstants.INTERNAL_ACC_INTERFACE |
+ (ClassConstants.INTERNAL_ACC_INTERFACE |
ClassConstants.INTERNAL_ACC_ABSTRACT)) |
((targetAccessFlags |
sourceAccessFlags) &
- (ClassConstants.INTERNAL_ACC_PUBLIC |
+ (ClassConstants.INTERNAL_ACC_PUBLIC |
+ ClassConstants.INTERNAL_ACC_SUPER |
ClassConstants.INTERNAL_ACC_ANNOTATTION |
ClassConstants.INTERNAL_ACC_ENUM));
@@ -260,14 +275,18 @@ implements ClassVisitor,
// Copy over the class members.
MemberAdder memberAdder =
- new MemberAdder(targetClass);
+ new MemberAdder(targetClass, fieldOptimizationInfoCopier);
programClass.fieldsAccept(memberAdder);
programClass.methodsAccept(memberAdder);
// Copy over the other attributes.
programClass.attributesAccept(
- new AttributeAdder(targetClass, true));
+ new AttributeNameFilter(new NotMatcher(new OrMatcher(new OrMatcher(
+ new FixedStringMatcher(ClassConstants.ATTR_SourceFile),
+ new FixedStringMatcher(ClassConstants.ATTR_InnerClasses)),
+ new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))),
+ new AttributeAdder(targetClass, true)));
// Update the optimization information of the target class.
ClassOptimizationInfo info =
@@ -280,6 +299,12 @@ implements ClassVisitor,
// Remember to replace the inlined class by the target class.
setTargetClass(programClass, targetClass);
+ //if (DEBUG)
+ //{
+ // System.out.println("=== After ====");
+ // targetClass.accept(new ClassPrinter());
+ //}
+
// Visit the merged class, if required.
if (extraClassVisitor != null)
{
@@ -336,10 +361,8 @@ implements ClassVisitor,
// Visit all superclasses and interfaces, collecting the ones that have
// static initializers.
clazz.hierarchyAccept(true, true, true, false,
- new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
- ClassConstants.INTERNAL_METHOD_TYPE_INIT,
- new MemberToClassVisitor(
- new ClassCollector(set))));
+ new StaticInitializerContainingClassFilter(
+ new ClassCollector(set)));
return set;
}
@@ -368,9 +391,16 @@ implements ClassVisitor,
*/
private Set caughtSuperClasses(Clazz clazz)
{
+ // Don't bother if this isn't an exception at all.
+ if (!clazz.extends_(ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE))
+ {
+ return Collections.EMPTY_SET;
+ }
+
+ // Visit all superclasses, collecting the ones that are caught
+ // (plus java.lang.Object, in the current implementation).
Set set = new HashSet();
- // Visit all superclasses, collecting the ones that are caught.
clazz.hierarchyAccept(true, true, false, false,
new CaughtClassFilter(
new ClassCollector(set)));
@@ -379,6 +409,23 @@ implements ClassVisitor,
}
+ /**
+ * Returns whether the two given classes have class members with the same
+ * name and descriptor.
+ */
+ private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass)
+ {
+ MemberCounter counter = new MemberCounter();
+
+ // Visit all fields, counting the with the same name and descriptor in
+ // the target class.
+ clazz.fieldsAccept(new SimilarMemberVisitor(targetClass, true, false, false, false,
+ counter));
+
+ return counter.getCount() > 0;
+ }
+
+
/**
* Returns whether the given class would introduce any unwanted fields
* in the target class.
@@ -386,32 +433,59 @@ implements ClassVisitor,
private boolean introducesUnwantedFields(ProgramClass programClass,
ProgramClass targetClass)
{
- // The class must not have any fields, or it must not be instantiated,
- // without any other subclasses.
- return
- programClass.u2fieldsCount != 0 &&
- (InstantiationClassMarker.isInstantiated(targetClass) ||
- (targetClass.subClasses != null &&
- !isOnlySubClass(programClass, targetClass)));
+ // It's ok if the target class is never instantiated, without any other
+ // subclasses except for maybe the source class.
+ if (!InstantiationClassMarker.isInstantiated(targetClass) &&
+ (targetClass.subClasses == null ||
+ isOnlySubClass(programClass, targetClass)))
+ {
+ return false;
+ }
+
+ MemberCounter counter = new MemberCounter();
+
+ // Count all non-static fields in the the source class.
+ programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC,
+ counter));
+
+ return counter.getCount() > 0;
+ }
+
+
+ /**
+ * Returns whether the given class or its subclasses shadow any fields in
+ * the given target class.
+ */
+ private boolean shadowsAnyFields(Clazz clazz, Clazz targetClass)
+ {
+ MemberCounter counter = new MemberCounter();
+
+ // Visit all fields, counting the ones that are shadowing non-private
+ // fields in the class hierarchy of the target class.
+ clazz.hierarchyAccept(true, false, false, true,
+ new AllFieldVisitor(
+ new SimilarMemberVisitor(targetClass, true, true, true, false,
+ new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+ counter))));
+
+ return counter.getCount() > 0;
}
/**
- * Returns whether the two given classes have initializers with the same
- * descriptors.
+ * Returns whether the two given classes have class members with the same
+ * name and descriptor.
*/
- private boolean haveAnyIdenticalInitializers(Clazz clazz, Clazz targetClass)
+ private boolean haveAnyIdenticalMethods(Clazz clazz, Clazz targetClass)
{
MemberCounter counter = new MemberCounter();
- // TODO: Currently checking shared methods, not just initializers.
- // TODO: Allow identical methods.
- // Visit all methods, counting the ones that are also present in the
- // target class.
- clazz.methodsAccept(//new MemberNameFilter(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT),
+ // Visit all non-abstract methods, counting the ones that are also
+ // present in the target class.
+ clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT,
new SimilarMemberVisitor(targetClass, true, false, false, false,
new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT,
- counter)));
+ counter))));
return counter.getCount() > 0;
}
@@ -538,4 +612,30 @@ implements ClassVisitor,
targetClass = clazz;
}
}
+
+
+ /**
+ * This MemberVisitor copies field optimization info from copied fields.
+ */
+ private static class FieldOptimizationInfoCopier
+ extends SimplifiedVisitor
+ implements MemberVisitor
+ {
+ public void visitProgramField(ProgramClass programClass, ProgramField programField)
+ {
+ // Copy the optimization info from the field that was just copied.
+ ProgramField copiedField = (ProgramField)programField.getVisitorInfo();
+ Object info = copiedField.getVisitorInfo();
+
+ programField.setVisitorInfo(info instanceof FieldOptimizationInfo ?
+ new FieldOptimizationInfo((FieldOptimizationInfo)info) :
+ info);
+ }
+
+
+ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
+ {
+ // Linked methods share their optimization info.
+ }
+ }
}
\ No newline at end of file
diff --git a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
index 4833275..3bfd98c 100644
--- a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
+++ b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -50,7 +50,7 @@ implements AttributeVisitor,
private final InstructionVisitor extraInstructionVisitor;
private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
+ private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, false);
/**
@@ -123,10 +123,7 @@ implements AttributeVisitor,
int deleteOffset = offset - delta;
if (branchTargetFinder.isInstruction(deleteOffset))
{
- codeAttributeEditor.replaceInstruction( deleteOffset, (Instruction)null);
- codeAttributeEditor.insertBeforeInstruction(deleteOffset, (Instruction)null);
- codeAttributeEditor.insertAfterInstruction( deleteOffset, (Instruction)null);
-
+ codeAttributeEditor.clearModifications(deleteOffset);
codeAttributeEditor.deleteInstruction(deleteOffset);
}
}
@@ -136,7 +133,7 @@ implements AttributeVisitor,
if (newBranchOffset != branchInstruction.length(offset))
{
Instruction newGotoInstruction =
- new BranchInstruction(opcode, newBranchOffset);
+ new BranchInstruction(opcode, newBranchOffset).shrink();
codeAttributeEditor.replaceInstruction(offset,
newGotoInstruction);
}
diff --git a/src/proguard/optimize/peephole/GotoGotoReplacer.java b/src/proguard/optimize/peephole/GotoGotoReplacer.java
index 7d7e66c..4a490a1 100644
--- a/src/proguard/optimize/peephole/GotoGotoReplacer.java
+++ b/src/proguard/optimize/peephole/GotoGotoReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -84,8 +84,9 @@ implements InstructionVisitor
int branchOffset = branchInstruction.branchOffset;
int targetOffset = offset + branchOffset;
- if (branchOffset != branchInstruction.length(offset) &&
- !codeAttributeEditor.isModified(offset) &&
+ if (branchOffset != 0 &&
+ branchOffset != branchInstruction.length(offset) &&
+ !codeAttributeEditor.isModified(offset) &&
!codeAttributeEditor.isModified(targetOffset))
{
Instruction targetInstruction =
diff --git a/src/proguard/optimize/peephole/GotoReturnReplacer.java b/src/proguard/optimize/peephole/GotoReturnReplacer.java
index 5c3eb77..b6deec8 100644
--- a/src/proguard/optimize/peephole/GotoReturnReplacer.java
+++ b/src/proguard/optimize/peephole/GotoReturnReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/HorizontalClassMerger.java b/src/proguard/optimize/peephole/HorizontalClassMerger.java
index a37b9a5..31d3d33 100644
--- a/src/proguard/optimize/peephole/HorizontalClassMerger.java
+++ b/src/proguard/optimize/peephole/HorizontalClassMerger.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/InstructionSequenceConstants.java b/src/proguard/optimize/peephole/InstructionSequenceConstants.java
index b33204b..4ab9056 100644
--- a/src/proguard/optimize/peephole/InstructionSequenceConstants.java
+++ b/src/proguard/optimize/peephole/InstructionSequenceConstants.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -20,81 +20,207 @@
*/
package proguard.optimize.peephole;
+import proguard.classfile.*;
import proguard.classfile.constant.*;
import proguard.classfile.instruction.*;
-import proguard.classfile.util.InstructionSequenceMatcher;
+import proguard.classfile.visitor.ClassPrinter;
/**
* This class contains a set of instruction sequences and their suggested
* replacements.
*
* @see InstructionSequencesReplacer
+ * @see InstructionSequenceReplacer
* @author Eric Lafortune
*/
public class InstructionSequenceConstants
{
- public static final int X = InstructionSequenceMatcher.X;
- public static final int Y = InstructionSequenceMatcher.Y;
- public static final int Z = InstructionSequenceMatcher.Z;
+ private static final int X = InstructionSequenceReplacer.X;
+ private static final int Y = InstructionSequenceReplacer.Y;
+ private static final int Z = InstructionSequenceReplacer.Z;
- public static final int A = InstructionSequenceMatcher.A;
- public static final int B = InstructionSequenceMatcher.B;
- public static final int C = InstructionSequenceMatcher.C;
- public static final int D = InstructionSequenceMatcher.D;
+ private static final int A = InstructionSequenceReplacer.A;
+ private static final int B = InstructionSequenceReplacer.B;
+ private static final int C = InstructionSequenceReplacer.C;
+ private static final int D = InstructionSequenceReplacer.D;
+ private static final int STRING_A_LENGTH = InstructionSequenceReplacer.STRING_A_LENGTH;
+ private static final int BOOLEAN_A_STRING = InstructionSequenceReplacer.BOOLEAN_A_STRING;
+ private static final int CHAR_A_STRING = InstructionSequenceReplacer.CHAR_A_STRING;
+ private static final int INT_A_STRING = InstructionSequenceReplacer.INT_A_STRING;
+ private static final int LONG_A_STRING = InstructionSequenceReplacer.LONG_A_STRING;
+ private static final int FLOAT_A_STRING = InstructionSequenceReplacer.FLOAT_A_STRING;
+ private static final int DOUBLE_A_STRING = InstructionSequenceReplacer.DOUBLE_A_STRING;
+ private static final int STRING_A_STRING = InstructionSequenceReplacer.STRING_A_STRING;
+ private static final int BOOLEAN_B_STRING = InstructionSequenceReplacer.BOOLEAN_B_STRING;
+ private static final int CHAR_B_STRING = InstructionSequenceReplacer.CHAR_B_STRING;
+ private static final int INT_B_STRING = InstructionSequenceReplacer.INT_B_STRING;
+ private static final int LONG_B_STRING = InstructionSequenceReplacer.LONG_B_STRING;
+ private static final int FLOAT_B_STRING = InstructionSequenceReplacer.FLOAT_B_STRING;
+ private static final int DOUBLE_B_STRING = InstructionSequenceReplacer.DOUBLE_B_STRING;
+ private static final int STRING_B_STRING = InstructionSequenceReplacer.STRING_B_STRING;
- private static final int I_32768 = 0;
- private static final int I_65536 = 1;
- private static final int I_16777216 = 2;
+ private static final int I_32768 = 0;
+ private static final int I_65536 = 1;
+ private static final int I_16777216 = 2;
// private static final int I_0x000000ff
- private static final int I_0x0000ff00 = 3;
- private static final int I_0x00ff0000 = 4;
- private static final int I_0xff000000 = 5;
- private static final int I_0x0000ffff = 6;
- private static final int I_0xffff0000 = 7;
+ private static final int I_0x0000ff00 = 3;
+ private static final int I_0x00ff0000 = 4;
+ private static final int I_0xff000000 = 5;
+ private static final int I_0x0000ffff = 6;
+ private static final int I_0xffff0000 = 7;
- private static final int L_M1 = 8;
- private static final int L_2 = 9;
- private static final int L_4 = 10;
- private static final int L_8 = 11;
- private static final int L_16 = 12;
- private static final int L_32 = 13;
- private static final int L_64 = 14;
- private static final int L_128 = 15;
- private static final int L_256 = 16;
- private static final int L_512 = 17;
- private static final int L_1024 = 18;
- private static final int L_2048 = 19;
- private static final int L_4096 = 20;
- private static final int L_8192 = 21;
- private static final int L_16384 = 22;
- private static final int L_32768 = 23;
- private static final int L_65536 = 24;
- private static final int L_16777216 = 25;
- private static final int L_4294967296 = 26;
+ private static final int L_M1 = 8;
+ private static final int L_2 = 9;
+ private static final int L_4 = 10;
+ private static final int L_8 = 11;
+ private static final int L_16 = 12;
+ private static final int L_32 = 13;
+ private static final int L_64 = 14;
+ private static final int L_128 = 15;
+ private static final int L_256 = 16;
+ private static final int L_512 = 17;
+ private static final int L_1024 = 18;
+ private static final int L_2048 = 19;
+ private static final int L_4096 = 20;
+ private static final int L_8192 = 21;
+ private static final int L_16384 = 22;
+ private static final int L_32768 = 23;
+ private static final int L_65536 = 24;
+ private static final int L_16777216 = 25;
+ private static final int L_4294967296 = 26;
- private static final int L_0x00000000ffffffff = 27;
- private static final int L_0xffffffff00000000 = 28;
+ private static final int L_0x00000000ffffffff = 27;
+ private static final int L_0xffffffff00000000 = 28;
- private static final int F_M1 = 29;
+ private static final int F_M1 = 29;
- private static final int D_M1 = 30;
+ private static final int D_M1 = 30;
- private static final int FIELD_I = 31;
- private static final int FIELD_L = 32;
- private static final int FIELD_F = 33;
- private static final int FIELD_D = 34;
+ private static final int STRING_EMPTY = 31;
- private static final int NAME_AND_TYPE_I = 35;
- private static final int NAME_AND_TYPE_L = 36;
- private static final int NAME_AND_TYPE_F = 37;
- private static final int NAME_AND_TYPE_D = 38;
+ private static final int FIELD_I = 32; // Implicitly uses X and Y.
+ private static final int FIELD_L = 33; // Implicitly uses X and Y.
+ private static final int FIELD_F = 34; // Implicitly uses X and Y.
+ private static final int FIELD_D = 35; // Implicitly uses X and Y.
- private static final int TYPE_I = 39;
- private static final int TYPE_L = 40;
- private static final int TYPE_F = 41;
- private static final int TYPE_D = 42;
+ private static final int METHOD_STRING_EQUALS = 36;
+ private static final int METHOD_STRING_LENGTH = 37;
+ private static final int METHOD_STRING_VALUEOF_Z = 38;
+ private static final int METHOD_STRING_VALUEOF_C = 39;
+ private static final int METHOD_STRING_VALUEOF_I = 40;
+ private static final int METHOD_STRING_VALUEOF_J = 41;
+ private static final int METHOD_STRING_VALUEOF_F = 42;
+ private static final int METHOD_STRING_VALUEOF_D = 43;
+ private static final int METHOD_STRING_VALUEOF_OBJECT = 44;
+ private static final int METHOD_STRINGBUFFER_INIT = 45;
+ private static final int METHOD_STRINGBUFFER_INIT_STRING = 46;
+ private static final int METHOD_STRINGBUFFER_APPEND_Z = 47;
+ private static final int METHOD_STRINGBUFFER_APPEND_C = 48;
+ private static final int METHOD_STRINGBUFFER_APPEND_I = 49;
+ private static final int METHOD_STRINGBUFFER_APPEND_J = 50;
+ private static final int METHOD_STRINGBUFFER_APPEND_F = 51;
+ private static final int METHOD_STRINGBUFFER_APPEND_D = 52;
+ private static final int METHOD_STRINGBUFFER_APPEND_STRING = 53;
+ private static final int METHOD_STRINGBUFFER_APPEND_OBJECT = 54;
+ private static final int METHOD_STRINGBUFFER_LENGTH = 55;
+ private static final int METHOD_STRINGBUFFER_TOSTRING = 56;
+ private static final int METHOD_STRINGBUILDER_INIT = 57;
+ private static final int METHOD_STRINGBUILDER_INIT_STRING = 58;
+ private static final int METHOD_STRINGBUILDER_APPEND_Z = 59;
+ private static final int METHOD_STRINGBUILDER_APPEND_C = 60;
+ private static final int METHOD_STRINGBUILDER_APPEND_I = 61;
+ private static final int METHOD_STRINGBUILDER_APPEND_J = 62;
+ private static final int METHOD_STRINGBUILDER_APPEND_F = 63;
+ private static final int METHOD_STRINGBUILDER_APPEND_D = 64;
+ private static final int METHOD_STRINGBUILDER_APPEND_STRING = 65;
+ private static final int METHOD_STRINGBUILDER_APPEND_OBJECT = 66;
+ private static final int METHOD_STRINGBUILDER_LENGTH = 67;
+ private static final int METHOD_STRINGBUILDER_TOSTRING = 68;
+
+ private static final int CLASS_STRING = 69;
+ private static final int CLASS_STRINGBUFFER = 70;
+ private static final int CLASS_STRINGBUILDER = 71;
+
+ private static final int NAME_AND_TYPE_I = 72; // Implicitly uses Y.
+ private static final int NAME_AND_TYPE_L = 73; // Implicitly uses Y.
+ private static final int NAME_AND_TYPE_F = 74; // Implicitly uses Y.
+ private static final int NAME_AND_TYPE_D = 75; // Implicitly uses Y.
+
+ private static final int NAME_AND_TYPE_EQUALS = 76;
+ private static final int NAME_AND_TYPE_LENGTH = 77;
+ private static final int NAME_AND_TYPE_VALUEOF_Z = 78;
+ private static final int NAME_AND_TYPE_VALUEOF_C = 79;
+ private static final int NAME_AND_TYPE_VALUEOF_I = 80;
+ private static final int NAME_AND_TYPE_VALUEOF_J = 81;
+ private static final int NAME_AND_TYPE_VALUEOF_F = 82;
+ private static final int NAME_AND_TYPE_VALUEOF_D = 83;
+ private static final int NAME_AND_TYPE_VALUEOF_OBJECT = 84;
+ private static final int NAME_AND_TYPE_INIT = 85;
+ private static final int NAME_AND_TYPE_INIT_STRING = 86;
+ private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUFFER = 87;
+ private static final int NAME_AND_TYPE_APPEND_C_STRINGBUFFER = 88;
+ private static final int NAME_AND_TYPE_APPEND_I_STRINGBUFFER = 89;
+ private static final int NAME_AND_TYPE_APPEND_J_STRINGBUFFER = 90;
+ private static final int NAME_AND_TYPE_APPEND_F_STRINGBUFFER = 91;
+ private static final int NAME_AND_TYPE_APPEND_D_STRINGBUFFER = 92;
+ private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER = 93;
+ private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER = 94;
+ private static final int NAME_AND_TYPE_APPEND_Z_STRINGBUILDER = 95;
+ private static final int NAME_AND_TYPE_APPEND_C_STRINGBUILDER = 96;
+ private static final int NAME_AND_TYPE_APPEND_I_STRINGBUILDER = 97;
+ private static final int NAME_AND_TYPE_APPEND_J_STRINGBUILDER = 98;
+ private static final int NAME_AND_TYPE_APPEND_F_STRINGBUILDER = 99;
+ private static final int NAME_AND_TYPE_APPEND_D_STRINGBUILDER = 100;
+ private static final int NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER = 101;
+ private static final int NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER = 102;
+ private static final int NAME_AND_TYPE_TOSTRING = 103;
+
+ private static final int UTF8_EMPTY = 104;
+ private static final int UTF8_I = 105;
+ private static final int UTF8_L = 106;
+ private static final int UTF8_F = 107;
+ private static final int UTF8_D = 108;
+ private static final int UTF8_STRING = 109;
+ private static final int UTF8_STRINGBUFFER = 110;
+ private static final int UTF8_STRINGBUILDER = 111;
+ private static final int UTF8_EQUALS = 112;
+ private static final int UTF8_OBJECT_Z = 113;
+ private static final int UTF8_LENGTH = 114;
+ private static final int UTF8__I = 115;
+ private static final int UTF8_VALUEOF = 116;
+ private static final int UTF8_Z_STRING = 117;
+ private static final int UTF8_C_STRING = 118;
+ private static final int UTF8_I_STRING = 119;
+ private static final int UTF8_J_STRING = 120;
+ private static final int UTF8_F_STRING = 121;
+ private static final int UTF8_D_STRING = 122;
+ private static final int UTF8_OBJECT_STRING = 123;
+ private static final int UTF8_INIT = 124;
+ private static final int UTF8__VOID = 125;
+ private static final int UTF8_STRING_VOID = 126;
+ private static final int UTF8_TOSTRING = 127;
+ private static final int UTF8__STRING = 128;
+ private static final int UTF8_APPEND = 129;
+ private static final int UTF8_Z_STRINGBUFFER = 130;
+ private static final int UTF8_C_STRINGBUFFER = 131;
+ private static final int UTF8_I_STRINGBUFFER = 132;
+ private static final int UTF8_J_STRINGBUFFER = 133;
+ private static final int UTF8_F_STRINGBUFFER = 134;
+ private static final int UTF8_D_STRINGBUFFER = 135;
+ private static final int UTF8_STRING_STRINGBUFFER = 136;
+ private static final int UTF8_OBJECT_STRINGBUFFER = 137;
+ private static final int UTF8_Z_STRINGBUILDER = 138;
+ private static final int UTF8_C_STRINGBUILDER = 139;
+ private static final int UTF8_I_STRINGBUILDER = 140;
+ private static final int UTF8_J_STRINGBUILDER = 141;
+ private static final int UTF8_F_STRINGBUILDER = 142;
+ private static final int UTF8_D_STRINGBUILDER = 143;
+ private static final int UTF8_STRING_STRINGBUILDER = 144;
+ private static final int UTF8_OBJECT_STRINGBUILDER = 145;
+
+ private static final int SENTINEL = 146;
public static final Constant[] CONSTANTS = new Constant[]
@@ -136,23 +262,128 @@ public class InstructionSequenceConstants
new DoubleConstant(-1d),
+ new StringConstant(UTF8_EMPTY, null, null),
+
new FieldrefConstant(X, NAME_AND_TYPE_I, null, null),
new FieldrefConstant(X, NAME_AND_TYPE_L, null, null),
new FieldrefConstant(X, NAME_AND_TYPE_F, null, null),
new FieldrefConstant(X, NAME_AND_TYPE_D, null, null),
- new NameAndTypeConstant(Y, TYPE_I),
- new NameAndTypeConstant(Y, TYPE_L),
- new NameAndTypeConstant(Y, TYPE_F),
- new NameAndTypeConstant(Y, TYPE_D),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_EQUALS, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_LENGTH, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_Z, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_C, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_I, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_J, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_F, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_D, null, null),
+ new MethodrefConstant(CLASS_STRING, NAME_AND_TYPE_VALUEOF_OBJECT, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_INIT_STRING, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_Z_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_C_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_I_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_J_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_F_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_D_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_STRING_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUFFER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_LENGTH, null, null),
+ new MethodrefConstant(CLASS_STRINGBUFFER, NAME_AND_TYPE_TOSTRING, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_INIT_STRING, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_Z_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_C_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_I_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_J_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_F_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_D_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_STRING_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_APPEND_OBJECT_STRINGBUILDER, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_LENGTH, null, null),
+ new MethodrefConstant(CLASS_STRINGBUILDER, NAME_AND_TYPE_TOSTRING, null, null),
+
+ new ClassConstant(UTF8_STRING, null),
+ new ClassConstant(UTF8_STRINGBUFFER, null),
+ new ClassConstant(UTF8_STRINGBUILDER, null),
+
+ new NameAndTypeConstant(Y, UTF8_I),
+ new NameAndTypeConstant(Y, UTF8_L),
+ new NameAndTypeConstant(Y, UTF8_F),
+ new NameAndTypeConstant(Y, UTF8_D),
+ new NameAndTypeConstant(UTF8_EQUALS, UTF8_OBJECT_Z),
+ new NameAndTypeConstant(UTF8_LENGTH, UTF8__I),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_Z_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_C_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_I_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_J_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_F_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_D_STRING),
+ new NameAndTypeConstant(UTF8_VALUEOF, UTF8_OBJECT_STRING),
+ new NameAndTypeConstant(UTF8_INIT, UTF8__VOID),
+ new NameAndTypeConstant(UTF8_INIT, UTF8_STRING_VOID),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUFFER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_Z_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_C_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_I_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_J_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_F_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_D_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_STRING_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_APPEND, UTF8_OBJECT_STRINGBUILDER),
+ new NameAndTypeConstant(UTF8_TOSTRING, UTF8__STRING),
+ new Utf8Constant(""),
new Utf8Constant("I"),
new Utf8Constant("J"),
new Utf8Constant("F"),
new Utf8Constant("D"),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_EQUALS),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_EQUALS),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_LENGTH),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LENGTH),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_VALUEOF),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_CHAR),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_INT),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_LONG),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_FLOAT),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_VALUEOF_OBJECT),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_INIT),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INIT),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_VOID),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_TOSTRING),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_TOSTRING),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_APPEND),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_INT_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER),
+ new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER),
};
-
public static final Instruction[][][] VARIABLE = new Instruction[][][]
{
{ // nop = nothing
@@ -237,7 +468,7 @@ public class InstructionSequenceConstants
{ // a = a = nothing
{
new VariableInstruction(InstructionConstants.OP_ALOAD, X),
- new SimpleInstruction(InstructionConstants.OP_POP),
+ new VariableInstruction(InstructionConstants.OP_ASTORE, X),
},{
// Nothing.
},
@@ -382,12 +613,12 @@ public class InstructionSequenceConstants
},
{ // c * i = i * c
{
- new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, A),
new VariableInstruction(InstructionConstants.OP_ILOAD, X),
new SimpleInstruction(InstructionConstants.OP_IMUL),
},{
new VariableInstruction(InstructionConstants.OP_ILOAD, X),
- new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, A),
new SimpleInstruction(InstructionConstants.OP_IMUL),
},
},
@@ -548,7 +779,7 @@ public class InstructionSequenceConstants
{ // i = i + c = i += c
{
new VariableInstruction(InstructionConstants.OP_ILOAD, X),
- new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, A),
new SimpleInstruction(InstructionConstants.OP_IADD),
new VariableInstruction(InstructionConstants.OP_ISTORE, X),
},{
@@ -651,22 +882,23 @@ public class InstructionSequenceConstants
// Nothing.
},
},
- { // ... + 0f = ...
- {
- new SimpleInstruction(InstructionConstants.OP_FCONST_0),
- new SimpleInstruction(InstructionConstants.OP_FADD),
- },{
- // Nothing.
- },
- },
- { // ... + 0d = ...
- {
- new SimpleInstruction(InstructionConstants.OP_DCONST_0),
- new SimpleInstruction(InstructionConstants.OP_DADD),
- },{
- // Nothing.
- },
- },
+ // Not valid for -0.0.
+// { // ... + 0f = ...
+// {
+// new SimpleInstruction(InstructionConstants.OP_FCONST_0),
+// new SimpleInstruction(InstructionConstants.OP_FADD),
+// },{
+// // Nothing.
+// },
+// },
+// { // ... + 0d = ...
+// {
+// new SimpleInstruction(InstructionConstants.OP_DCONST_0),
+// new SimpleInstruction(InstructionConstants.OP_DADD),
+// },{
+// // Nothing.
+// },
+// },
{ // ... - 0 = ...
{
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
@@ -1072,7 +1304,8 @@ public class InstructionSequenceConstants
new SimpleInstruction(InstructionConstants.OP_FNEG),
},
},
-// { // ... * 0f = 0f (or NaN)
+ // Not valid for -0.0 and for NaN.
+// { // ... * 0f = 0f
// {
// new SimpleInstruction(InstructionConstants.OP_FCONST_0),
// new SimpleInstruction(InstructionConstants.OP_FMUL),
@@ -1097,7 +1330,8 @@ public class InstructionSequenceConstants
new SimpleInstruction(InstructionConstants.OP_DNEG),
},
},
-// { // ... * 0d = 0d (or NaN)
+ // Not valid for -0.0 and for NaN.
+// { // ... * 0d = 0d
// {
// new SimpleInstruction(InstructionConstants.OP_DCONST_0),
// new SimpleInstruction(InstructionConstants.OP_DMUL),
@@ -1504,6 +1738,7 @@ public class InstructionSequenceConstants
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
},
},
+ // Not valid for negative values.
// { // ... % 2 = ... & 0x1
// {
// new SimpleInstruction(InstructionConstants.OP_ICONST_2),
@@ -3348,4 +3583,1508 @@ public class InstructionSequenceConstants
// },
// }
};
-}
\ No newline at end of file
+
+ public static final Instruction[][][] STRING = new Instruction[][][]
+ {
+ { // "...".equals("...") = true
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_EQUALS),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_ICONST_1),
+ },
+ },
+ { // "...".length() = ...
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRING_LENGTH),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH),
+ },
+ },
+ { // String.valueOf(Z) = "....
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING),
+ },
+ },
+ { // String.valueOf(C) = "...."
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ },
+ },
+ { // String.valueOf(Cc) = "...."
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ },
+ },
+ { // String.valueOf(I) = "...."
+ {
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ },
+ },
+ { // String.valueOf(Ic) = "...."
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ },
+ },
+ { // String.valueOf(J) = "...."
+ {
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ },
+ },
+ { // String.valueOf(Jc) = "...."
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ },
+ },
+ { // String.valueOf(F) = "...."
+ {
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ },
+ },
+ { // String.valueOf(Fc) = "...."
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ },
+ },
+ { // String.valueOf(D) = "...."
+ {
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ },
+ },
+ { // String.valueOf(Dc) = "...."
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ },
+ },
+
+ { // new StringBuffer("...").toString() = "..." (ignoring identity)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ },
+ },
+ { // new StringBuffer(string).toString() = string (ignoring identity)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ },
+ },
+ { // new StringBuffer("...").length() = length
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_LENGTH),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH),
+ },
+ },
+ { // new StringBuffer() (without dup) = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...") (without dup) = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer()/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...")/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(z)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(c)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(i)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(l)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_LLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(f)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_FLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(d)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_DLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer("...").append(s)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // StringBuffer#toString()/pop = pop
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },
+ },
+ { // StringBuffer#append("") = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuffer().append(Z) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(C) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(Cc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(I) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(Ic) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(J) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(Jc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(F) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(Fc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(D) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append(Dc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer().append("...") = new StringBuffer("...")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Z) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(C) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Cc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(I) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Ic) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(J) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Jc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(F) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Fc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(D) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append(Dc) = new StringBuffer("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // new StringBuffer("...").append("...") = new StringBuffer("......")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Z) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(C) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Cc) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(I) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Ic) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(J) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Jc) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(F) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Fc) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(D) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append(Dc) = StringBuffer#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // StringBuffer#append("...").append("...") = StringBuffer#append("......")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ },
+ },
+ { // new StringBuffer().append(z).toString() = String.valueOf(z)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_Z),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z),
+ },
+ },
+ { // new StringBuffer().append(c).toString() = String.valueOf(c)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_C),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C),
+ },
+ },
+ { // new StringBuffer().append(i).toString() = String.valueOf(i)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_I),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I),
+ },
+ },
+ { // new StringBuffer().append(j).toString() = String.valueOf(j)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_LLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_J),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_LLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J),
+ },
+ },
+ { // new StringBuffer().append(f).toString() = String.valueOf(f)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_FLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_F),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_FLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F),
+ },
+ },
+ { // new StringBuffer().append(d).toString() = String.valueOf(d)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_DLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_D),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_DLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D),
+ },
+ },
+ { // new StringBuffer().append(string).toString() = string
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ },
+ },
+ { // new StringBuffer().append(object).toString() = String.valueOf(object)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUFFER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUFFER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_APPEND_OBJECT),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUFFER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT),
+ },
+ },
+
+ { // new StringBuilder("...").toString() = "..." (ignoring identity)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ },
+ },
+ { // new StringBuilder(string).toString() = string (ignoring identity)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ },
+ },
+ { // new StringBuilder("...").length() = length
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_LENGTH),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_SIPUSH, STRING_A_LENGTH),
+ },
+ },
+ { // new StringBuilder() (without dup) = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...") (without dup) = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder()/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...")/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(z)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(c)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(i)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(l)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_LLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(f)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_FLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(d)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_DLOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder("...").append(s)/pop = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ // Nothing.
+ },
+ },
+ { // StringBuilder#toString()/pop = pop
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },{
+ new SimpleInstruction(InstructionConstants.OP_POP),
+ },
+ },
+ { // StringBuilder#append("") = nothing
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_EMPTY),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },{
+ // Nothing.
+ },
+ },
+ { // new StringBuilder().append(Z) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, BOOLEAN_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(C) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(Cc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, CHAR_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(I) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(Ic) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, INT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(J) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(Jc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, LONG_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(F) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(Fc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, FLOAT_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(D) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append(Dc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, DOUBLE_A_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder().append("...") = new StringBuilder("...")
+ {
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Z) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(C) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Cc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(I) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Ic) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(J) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Jc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(F) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Fc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(D) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append(Dc) = new StringBuilder("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // new StringBuilder("...").append("...") = new StringBuilder("......")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Z) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | BOOLEAN_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(C) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Cc) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | CHAR_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(I) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_ICONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Ic) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | INT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(J) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_LCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Jc) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | LONG_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(F) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_FCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Fc) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | FLOAT_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(D) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new SimpleInstruction(InstructionConstants.OP_DCONST_0, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append(Dc) = StringBuilder#append("....")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC2_W, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | DOUBLE_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // StringBuilder#append("...").append("...") = StringBuilder#append("......")
+ {
+ new ConstantInstruction(InstructionConstants.OP_LDC, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_LDC, B),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },{
+ new ConstantInstruction(InstructionConstants.OP_LDC, STRING_A_STRING | STRING_B_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ },
+ },
+ { // new StringBuilder().append(z).toString() = String.valueOf(z)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_Z),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_Z),
+ },
+ },
+ { // new StringBuilder().append(c).toString() = String.valueOf(c)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_C),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_C),
+ },
+ },
+ { // new StringBuilder().append(i).toString() = String.valueOf(i)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_I),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ILOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_I),
+ },
+ },
+ { // new StringBuilder().append(j).toString() = String.valueOf(j)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_LLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_J),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_LLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_J),
+ },
+ },
+ { // new StringBuilder().append(f).toString() = String.valueOf(f)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_FLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_F),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_FLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_F),
+ },
+ },
+ { // new StringBuilder().append(d).toString() = String.valueOf(d)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_DLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_D),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_DLOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_D),
+ },
+ },
+ { // new StringBuilder().append(string).toString() = string
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_STRING),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ },
+ },
+ { // new StringBuilder().append(object).toString() = String.valueOf(object)
+ {
+ new ConstantInstruction(InstructionConstants.OP_NEW, CLASS_STRINGBUILDER),
+ new SimpleInstruction(InstructionConstants.OP_DUP),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, METHOD_STRINGBUILDER_INIT),
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_APPEND_OBJECT),
+ new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, METHOD_STRINGBUILDER_TOSTRING),
+ },{
+ new VariableInstruction(InstructionConstants.OP_ALOAD, A),
+ new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, METHOD_STRING_VALUEOF_OBJECT),
+ },
+ },
+ };
+
+
+ /**
+ * Prints out the constants and the instruction sequences.
+ */
+ public static void main(String[] args)
+ {
+ ProgramClass clazz = new ProgramClass();
+ clazz.constantPool = CONSTANTS;
+
+ ClassPrinter printer = new ClassPrinter();
+
+ for (int index = 0; index < CONSTANTS.length; index++)
+ {
+ System.out.print("["+index+"] ");
+ try
+ {
+ CONSTANTS[index].accept(clazz, printer);
+ }
+ catch (Exception e)
+ {
+ System.out.println("("+e.getClass().getName()+")");
+ }
+ }
+
+ if (CONSTANTS.length != SENTINEL)
+ {
+ throw new IllegalStateException("Constants length ["+CONSTANTS.length+"] different from number of constant names ["+SENTINEL+"]");
+ }
+
+ Instruction[][][] sequences = STRING;
+
+ for (int sequence = 0; sequence < sequences.length; sequence++)
+ {
+ System.out.println();
+ Instruction[] instructions = sequences[sequence][0];
+ for (int index = 0; index < instructions.length; index++)
+ {
+ Instruction instruction = instructions[index];
+ try
+ {
+ instruction.accept(clazz, null, null, index, new ClassPrinter());
+ }
+ catch (Exception e) {}
+ }
+
+ System.out.println("=>");
+ instructions = sequences[sequence][1];
+ for (int index = 0; index < instructions.length; index++)
+ {
+ Instruction instruction = instructions[index];
+ try
+ {
+ instruction.accept(clazz, null, null, index, new ClassPrinter());
+ }
+ catch (Exception e) {}
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
index bce06e2..7ec1a95 100644
--- a/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
+++ b/src/proguard/optimize/peephole/InstructionSequenceReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,9 +22,9 @@ package proguard.optimize.peephole;
import proguard.classfile.*;
import proguard.classfile.attribute.CodeAttribute;
-import proguard.classfile.constant.Constant;
+import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
-import proguard.classfile.editor.CodeAttributeEditor;
+import proguard.classfile.editor.*;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
@@ -42,10 +42,48 @@ extends SimplifiedVisitor
implements InstructionVisitor,
ConstantVisitor
{
+ //*
private static final boolean DEBUG = false;
+ /*/
+ public static boolean DEBUG = true;
+ //*/
+
+ public static final int X = InstructionSequenceMatcher.X;
+ public static final int Y = InstructionSequenceMatcher.Y;
+ public static final int Z = InstructionSequenceMatcher.Z;
+
+ public static final int A = InstructionSequenceMatcher.A;
+ public static final int B = InstructionSequenceMatcher.B;
+ public static final int C = InstructionSequenceMatcher.C;
+ public static final int D = InstructionSequenceMatcher.D;
+
+ private static final int BOOLEAN_STRING = 0x1;
+ private static final int CHAR_STRING = 0x2;
+ private static final int INT_STRING = 0x3;
+ private static final int LONG_STRING = 0x4;
+ private static final int FLOAT_STRING = 0x5;
+ private static final int DOUBLE_STRING = 0x6;
+ private static final int STRING_STRING = 0x7;
+
+ public static final int STRING_A_LENGTH = 0x20000000;
+ public static final int BOOLEAN_A_STRING = 0x20000001;
+ public static final int CHAR_A_STRING = 0x20000002;
+ public static final int INT_A_STRING = 0x20000003;
+ public static final int LONG_A_STRING = 0x20000004;
+ public static final int FLOAT_A_STRING = 0x20000005;
+ public static final int DOUBLE_A_STRING = 0x20000006;
+ public static final int STRING_A_STRING = 0x20000007;
+ public static final int BOOLEAN_B_STRING = 0x20000010;
+ public static final int CHAR_B_STRING = 0x20000020;
+ public static final int INT_B_STRING = 0x20000030;
+ public static final int LONG_B_STRING = 0x20000040;
+ public static final int FLOAT_B_STRING = 0x20000050;
+ public static final int DOUBLE_B_STRING = 0x20000060;
+ public static final int STRING_B_STRING = 0x20000070;
private final InstructionSequenceMatcher instructionSequenceMatcher;
+ private final Constant[] patternConstants;
private final Instruction[] replacementInstructions;
private final BranchTargetFinder branchTargetFinder;
private final CodeAttributeEditor codeAttributeEditor;
@@ -101,6 +139,7 @@ implements InstructionVisitor,
InstructionVisitor extraInstructionVisitor)
{
this.instructionSequenceMatcher = new InstructionSequenceMatcher(patternConstants, patternInstructions);
+ this.patternConstants = patternConstants;
this.replacementInstructions = replacementInstructions;
this.branchTargetFinder = branchTargetFinder;
this.codeAttributeEditor = codeAttributeEditor;
@@ -140,7 +179,7 @@ implements InstructionVisitor,
for (int index = 0; index < replacementInstructions.length; index++)
{
int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index);
- System.out.println(" "+replacementInstructionFactory.create(index).shrink().toString(matchedOffset));
+ System.out.println(" "+replacementInstructionFactory.create(clazz, index).shrink().toString(matchedOffset));
}
}
@@ -148,7 +187,7 @@ implements InstructionVisitor,
for (int index = 0; index < replacementInstructions.length; index++)
{
codeAttributeEditor.replaceInstruction(instructionSequenceMatcher.matchedInstructionOffset(index),
- replacementInstructionFactory.create(index).shrink());
+ replacementInstructionFactory.create(clazz, index));
}
// Delete any remaining instructions in the from sequence.
@@ -204,17 +243,17 @@ implements InstructionVisitor,
* Creates the replacement instruction for the given index in the
* instruction sequence.
*/
- public Instruction create(int index)
+ public Instruction create(Clazz clazz, int index)
{
// Create the instruction.
- replacementInstructions[index].accept(null,
+ replacementInstructions[index].accept(clazz,
null,
null,
instructionSequenceMatcher.matchedInstructionOffset(index),
this);
// Return it.
- return replacementInstruction.shrink();
+ return replacementInstruction;
}
@@ -224,7 +263,7 @@ implements InstructionVisitor,
{
replacementInstruction =
new SimpleInstruction(simpleInstruction.opcode,
- instructionSequenceMatcher.matchedArgument(simpleInstruction.constant));
+ matchedArgument(clazz, simpleInstruction.constant));
}
@@ -241,7 +280,8 @@ implements InstructionVisitor,
{
replacementInstruction =
new ConstantInstruction(constantInstruction.opcode,
- instructionSequenceMatcher.matchedConstantIndex(constantInstruction.constantIndex),
+ matchedConstantIndex((ProgramClass)clazz,
+ constantInstruction.constantIndex),
instructionSequenceMatcher.matchedArgument(constantInstruction.constant));
}
@@ -250,7 +290,8 @@ implements InstructionVisitor,
{
replacementInstruction =
new BranchInstruction(branchInstruction.opcode,
- instructionSequenceMatcher.matchedBranchOffset(offset, branchInstruction.branchOffset));
+ instructionSequenceMatcher.matchedBranchOffset(offset,
+ branchInstruction.branchOffset));
}
@@ -261,7 +302,8 @@ implements InstructionVisitor,
instructionSequenceMatcher.matchedBranchOffset(offset, tableSwitchInstruction.defaultOffset),
instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.lowCase),
instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.highCase),
- instructionSequenceMatcher.matchedJumpOffsets(offset, tableSwitchInstruction.jumpOffsets));
+ instructionSequenceMatcher.matchedJumpOffsets(offset,
+ tableSwitchInstruction.jumpOffsets));
}
@@ -274,5 +316,105 @@ implements InstructionVisitor,
instructionSequenceMatcher.matchedArguments(lookUpSwitchInstruction.cases),
instructionSequenceMatcher.matchedJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets));
}
+
+
+ /**
+ * Returns the matched argument for the given pattern argument.
+ */
+ private int matchedArgument(Clazz clazz, int argument)
+ {
+ // Special case: do we have to compute the string length?
+ if (argument == STRING_A_LENGTH)
+ {
+ // Return the string length.
+ return clazz.getStringString(instructionSequenceMatcher.matchedArgument(A)).length();
+ }
+
+ // Otherwise, just return the matched argument.
+ return instructionSequenceMatcher.matchedArgument(argument);
+ }
+
+
+ /**
+ * Returns the matched or newly created constant index for the given
+ * pattern constant index.
+ */
+ private int matchedConstantIndex(ProgramClass programClass, int constantIndex)
+ {
+ // Special case: do we have to create a concatenated string?
+ if (constantIndex >= BOOLEAN_A_STRING &&
+ constantIndex <= (STRING_A_STRING | STRING_B_STRING))
+ {
+ // Create a new string constant and return its index.
+ return new ConstantPoolEditor(programClass).addStringConstant(
+ argumentAsString(programClass, constantIndex & 0xf, A) +
+ argumentAsString(programClass, (constantIndex >>> 4) & 0xf, B),
+ null,
+ null);
+ }
+
+ int matchedConstantIndex =
+ instructionSequenceMatcher.matchedConstantIndex(constantIndex);
+
+ // Do we have a matched constant index?
+ if (matchedConstantIndex > 0)
+ {
+ // Return its index.
+ return matchedConstantIndex;
+ }
+
+ // Otherwise, we still have to create a new constant.
+ // This currently only works for constants without any wildcards.
+ ProgramClass dummyClass = new ProgramClass();
+ dummyClass.constantPool = patternConstants;
+
+ return new ConstantAdder(programClass).addConstant(dummyClass, constantIndex);
+ }
+
+
+ private String argumentAsString(ProgramClass programClass,
+ int valueType,
+ int argument)
+ {
+ switch (valueType)
+ {
+ case BOOLEAN_STRING:
+ return Boolean.toString((instructionSequenceMatcher.wasConstant(argument) ?
+ ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument)) != 0);
+
+ case CHAR_STRING:
+ return Character.toString((char)(instructionSequenceMatcher.wasConstant(argument) ?
+ ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument)));
+
+ case INT_STRING:
+ return Integer.toString(instructionSequenceMatcher.wasConstant(argument) ?
+ ((IntegerConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument));
+
+ case LONG_STRING:
+ return Long.toString(instructionSequenceMatcher.wasConstant(argument) ?
+ ((LongConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument));
+
+ case FLOAT_STRING:
+ return Float.toString(instructionSequenceMatcher.wasConstant(argument) ?
+ ((FloatConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument));
+
+ case DOUBLE_STRING:
+ return Double.toString(instructionSequenceMatcher.wasConstant(argument) ?
+ ((DoubleConstant)(programClass.getConstant(instructionSequenceMatcher.matchedConstantIndex(argument)))).getValue() :
+ instructionSequenceMatcher.matchedArgument(argument));
+
+ case STRING_STRING:
+ return
+ programClass.getStringString(instructionSequenceMatcher.matchedConstantIndex(argument));
+
+ default:
+ return "";
+ }
+ }
}
}
diff --git a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
index f12b51a..22fb6cd 100644
--- a/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
+++ b/src/proguard/optimize/peephole/InstructionSequencesReplacer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/MemberPrivatizer.java b/src/proguard/optimize/peephole/MemberPrivatizer.java
index 55b2f31..f57281c 100644
--- a/src/proguard/optimize/peephole/MemberPrivatizer.java
+++ b/src/proguard/optimize/peephole/MemberPrivatizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/MethodFinalizer.java b/src/proguard/optimize/peephole/MethodFinalizer.java
index af1811b..89174ac 100644
--- a/src/proguard/optimize/peephole/MethodFinalizer.java
+++ b/src/proguard/optimize/peephole/MethodFinalizer.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/MethodInliner.java b/src/proguard/optimize/peephole/MethodInliner.java
index 55f9ccb..947cd43 100644
--- a/src/proguard/optimize/peephole/MethodInliner.java
+++ b/src/proguard/optimize/peephole/MethodInliner.java
@@ -2,7 +2,7 @@
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
- * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -29,10 +29,11 @@ import proguard.classfile.editor.*;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.util.*;
-import proguard.classfile.visitor.MemberVisitor;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
import proguard.optimize.info.*;
-import java.util.Stack;
+import java.util.*;
/**
* This AttributeVisitor inlines short methods or methods that are only invoked
@@ -48,10 +49,8 @@ implements AttributeVisitor,
MemberVisitor
{
private static final int MAXIMUM_INLINED_CODE_LENGTH = Integer.parseInt(System.getProperty("maximum.inlined.code.length", "8"));
- private static final int MAXIMUM_RESULTING_CODE_LENGTH_JSE = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "8000"));
+ private static final int MAXIMUM_RESULTING_CODE_LENGTH_JSE = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "7000"));
private static final int MAXIMUM_RESULTING_CODE_LENGTH_JME = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "2000"));
- private static final int MAXIMUM_CODE_EXPANSION = 2;
- private static final int MAXIMUM_EXTRA_CODE_LENGTH = 128;
//*
private static final boolean DEBUG = false;
@@ -137,6 +136,42 @@ implements AttributeVisitor,
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // TODO: Remove this when the method inliner has stabilized.
+ // Catch any unexpected exceptions from the actual visiting method.
+ try
+ {
+ // Process the code.
+ visitCodeAttribute0(clazz, method, codeAttribute);
+ }
+ catch (RuntimeException ex)
+ {
+ System.err.println("Unexpected error while inlining method:");
+ System.err.println(" Target class = ["+targetClass.getName()+"]");
+ System.err.println(" Target method = ["+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]");
+ if (inlining)
+ {
+ System.err.println(" Inlined class = ["+clazz.getName()+"]");
+ System.err.println(" Inlined method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
+ }
+ System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
+ System.err.println("Not inlining this method");
+
+ if (DEBUG)
+ {
+ targetMethod.accept(targetClass, new ClassPrinter());
+ if (inlining)
+ {
+ method.accept(clazz, new ClassPrinter());
+ }
+
+ throw ex;
+ }
+ }
+ }
+
+
+ public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
{
if (!inlining)
{
@@ -278,7 +313,7 @@ implements AttributeVisitor,
}
codeAttributeComposer.appendInstruction(parameterSize-parameterIndex-1,
- new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex).shrink());
+ new VariableInstruction(opcode, variableOffset + parameterOffset + parameterIndex));
}
}
@@ -286,7 +321,7 @@ implements AttributeVisitor,
if (!isStatic)
{
codeAttributeComposer.appendInstruction(parameterSize,
- new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset).shrink());
+ new VariableInstruction(InstructionConstants.OP_ASTORE, variableOffset));
}
codeAttributeComposer.endCodeFragment();
@@ -305,12 +340,12 @@ implements AttributeVisitor,
// Copy the instructions.
codeAttribute.instructionsAccept(clazz, method, this);
- // Copy the exceptions.
- codeAttribute.exceptionsAccept(clazz, method, exceptionInfoAdder);
-
// Append a label just after the code.
codeAttributeComposer.appendLabel(codeAttribute.u4codeLength);
+ // Copy the exceptions.
+ codeAttribute.exceptionsAccept(clazz, method, exceptionInfoAdder);
+
codeAttributeComposer.endCodeFragment();
}
@@ -319,7 +354,7 @@ implements AttributeVisitor,
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
{
- codeAttributeComposer.appendInstruction(offset, instruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, instruction);
}
@@ -346,7 +381,7 @@ implements AttributeVisitor,
codeAttribute.u4codeLength - offset);
codeAttributeComposer.appendInstruction(offset,
- branchInstruction.shrink());
+ branchInstruction);
}
else
{
@@ -359,7 +394,7 @@ implements AttributeVisitor,
}
}
- codeAttributeComposer.appendInstruction(offset, simpleInstruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, simpleInstruction);
}
@@ -372,7 +407,7 @@ implements AttributeVisitor,
variableInstruction.variableIndex += variableOffset;
}
- codeAttributeComposer.appendInstruction(offset, variableInstruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, variableInstruction);
}
@@ -430,7 +465,7 @@ implements AttributeVisitor,
constantAdder.addConstant(clazz, constantInstruction.constantIndex);
}
- codeAttributeComposer.appendInstruction(offset, constantInstruction.shrink());
+ codeAttributeComposer.appendInstruction(offset, constantInstruction);
}
@@ -454,45 +489,48 @@ implements AttributeVisitor,
{
int accessFlags = programMethod.getAccessFlags();
- if (// Only inline the method if it is private, static, or final.
+ if (// Don't inline methods that must be preserved.
+ !KeepMarker.isKept(programMethod) &&
+
+ // Only inline the method if it is private, static, or final.
(accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE |
ClassConstants.INTERNAL_ACC_STATIC |
- ClassConstants.INTERNAL_ACC_FINAL)) != 0 &&
+ ClassConstants.INTERNAL_ACC_FINAL)) != 0 &&
// Only inline the method if it is not synchronized, etc.
(accessFlags & (ClassConstants.INTERNAL_ACC_SYNCHRONIZED |
ClassConstants.INTERNAL_ACC_NATIVE |
ClassConstants.INTERNAL_ACC_INTERFACE |
- ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
+ ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
// Don't inline an