diff options
Diffstat (limited to 'src/proguard')
596 files changed, 16075 insertions, 4141 deletions
diff --git a/src/proguard/ArgumentWordReader.java b/src/proguard/ArgumentWordReader.java index 89f3824..efe8e6e 100644 --- a/src/proguard/ArgumentWordReader.java +++ b/src/proguard/ArgumentWordReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -32,7 +32,8 @@ import java.io.*; public class ArgumentWordReader extends WordReader { private final String[] arguments; - private int index = 0; + + private int index = 0; // /** @@ -86,7 +87,7 @@ public class ArgumentWordReader extends WordReader { while (true) { - String word = reader.nextWord(); + String word = reader.nextWord(false); if (word == null) System.exit(-1); diff --git a/src/proguard/ClassPath.java b/src/proguard/ClassPath.java index f4eeaad..3d7d119 100644 --- a/src/proguard/ClassPath.java +++ b/src/proguard/ClassPath.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/ClassPathEntry.java b/src/proguard/ClassPathEntry.java index 28483be..7051955 100644 --- a/src/proguard/ClassPathEntry.java +++ b/src/proguard/ClassPathEntry.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,6 +20,8 @@ */ package proguard; +import proguard.util.ListUtil; + import java.io.*; import java.util.List; @@ -44,7 +46,7 @@ public class ClassPathEntry /** - * Creates a new ClassPathEntry with the given name and type. + * Creates a new ClassPathEntry with the given file and output flag. */ public ClassPathEntry(File file, boolean isOutput) { @@ -69,81 +71,212 @@ public class ClassPathEntry } + /** + * Returns the file. + */ public File getFile() { return file; } + /** + * Sets the file. + */ public void setFile(File file) { this.file = file; } + /** + * Returns whether this data entry is an output entry. + */ public boolean isOutput() { return output; } + /** + * Specifies whether this data entry is an output entry. + */ public void setOutput(boolean output) { this.output = output; } + /** + * Returns whether this data entry is a jar file. + */ + public boolean isJar() + { + return hasExtension(".jar"); + } + + + /** + * Returns whether this data entry is a war file. + */ + public boolean isWar() + { + return hasExtension(".war"); + } + + + /** + * Returns whether this data entry is a ear file. + */ + public boolean isEar() + { + return hasExtension(".ear"); + } + + + /** + * Returns whether this data entry is a zip file. + */ + public boolean isZip() + { + return hasExtension(".zip"); + } + + + /** + * Returns whether this data entry has the given extension. + */ + private boolean hasExtension(String extension) + { + return endsWithIgnoreCase(file.getPath(), extension); + } + + + /** + * Returns whether the given string ends with the given suffix, ignoring + * its case. + */ + private static boolean endsWithIgnoreCase(String string, String suffix) + { + int stringLength = string.length(); + int suffixLength = suffix.length(); + + return string.regionMatches(true, stringLength - + suffixLength, suffix, 0, suffixLength); + } + + + /** + * Returns the name filter that is applied to bottom-level files in this entry. + */ public List getFilter() { return filter; } + /** + * Sets the name filter that is applied to bottom-level files in this entry. + */ public void setFilter(List filter) { this.filter = filter == null || filter.size() == 0 ? null : filter; } + /** + * Returns the name filter that is applied to jar files in this entry, if any. + */ public List getJarFilter() { return jarFilter; } + /** + * Sets the name filter that is applied to jar files in this entry, if any. + */ public void setJarFilter(List filter) { this.jarFilter = filter == null || filter.size() == 0 ? null : filter; } + /** + * Returns the name filter that is applied to war files in this entry, if any. + */ public List getWarFilter() { return warFilter; } + /** + * Sets the name filter that is applied to war files in this entry, if any. + */ public void setWarFilter(List filter) { this.warFilter = filter == null || filter.size() == 0 ? null : filter; } + /** + * Returns the name filter that is applied to ear files in this entry, if any. + */ public List getEarFilter() { return earFilter; } + /** + * Sets the name filter that is applied to ear files in this entry, if any. + */ public void setEarFilter(List filter) { this.earFilter = filter == null || filter.size() == 0 ? null : filter; } + /** + * Returns the name filter that is applied to zip files in this entry, if any. + */ public List getZipFilter() { return zipFilter; } + /** + * Sets the name filter that is applied to zip files in this entry, if any. + */ public void setZipFilter(List filter) { this.zipFilter = filter == null || filter.size() == 0 ? null : filter; } + + + // Implementations for Object. + + public String toString() + { + String string = getName(); + + if (filter != null || + jarFilter != null || + warFilter != null || + earFilter != null || + zipFilter != null) + { + string += + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD + + (zipFilter != null ? ListUtil.commaSeparatedString(zipFilter, true) : "") + + ConfigurationConstants.SEPARATOR_KEYWORD + + (earFilter != null ? ListUtil.commaSeparatedString(earFilter, true) : "") + + ConfigurationConstants.SEPARATOR_KEYWORD + + (warFilter != null ? ListUtil.commaSeparatedString(warFilter, true) : "") + + ConfigurationConstants.SEPARATOR_KEYWORD + + (jarFilter != null ? ListUtil.commaSeparatedString(jarFilter, true) : "") + + ConfigurationConstants.SEPARATOR_KEYWORD + + (filter != null ? ListUtil.commaSeparatedString(filter, true) : "") + + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD; + } + + return string; + } } diff --git a/src/proguard/ClassSpecification.java b/src/proguard/ClassSpecification.java index a84e0c8..485c0b0 100644 --- a/src/proguard/ClassSpecification.java +++ b/src/proguard/ClassSpecification.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/ClassSpecificationVisitorFactory.java b/src/proguard/ClassSpecificationVisitorFactory.java index c99ab2c..dc5d71f 100644 --- a/src/proguard/ClassSpecificationVisitorFactory.java +++ b/src/proguard/ClassSpecificationVisitorFactory.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -493,7 +493,8 @@ public class ClassSpecificationVisitorFactory private static boolean containsWildCards(String string) { return string != null && - (string.indexOf('*') >= 0 || + (string.indexOf('!') >= 0 || + string.indexOf('*') >= 0 || string.indexOf('?') >= 0 || string.indexOf('%') >= 0 || string.indexOf(',') >= 0 || diff --git a/src/proguard/Configuration.java b/src/proguard/Configuration.java index d513e2c..4711260 100644 --- a/src/proguard/Configuration.java +++ b/src/proguard/Configuration.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -32,6 +32,9 @@ import java.util.List; */ public class Configuration { + public static final File STD_OUT = new File(""); + + /////////////////////////////////////////////////////////////////////////// // Input and output options. /////////////////////////////////////////////////////////////////////////// @@ -50,7 +53,7 @@ public class Configuration * Specifies whether to skip non-public library classes while reading * library jars. */ - public boolean skipNonPublicLibraryClasses = true; + public boolean skipNonPublicLibraryClasses = false; /** * Specifies whether to skip non-public library class members while reading @@ -237,12 +240,19 @@ public class Configuration public List keepAttributes; /** + * Specifies whether method parameter names and types should be kept for + * methods that are not obfuscated. This is achieved by keeping partial + * "LocalVariableTable" and "LocalVariableTypeTable" attributes. + */ + public boolean keepParameterNames = false; + + /** * An optional replacement for all SourceFile attributes. */ public String newSourceFileAttribute; /** - * A list of <code>String</code>s specifying a filter for clases whose + * A list of <code>String</code>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 "<java.home>" is replaced by its value). + * Replaces any properties in the given word by their values. + * For instance, the substring "<java.home>" is replaced by its value. */ private String replaceSystemProperties(String word) throws ParseException { @@ -1073,7 +1147,7 @@ public class ConfigurationParser } String propertyName = word.substring(fromIndex+1, toIndex); - String propertyValue = System.getProperty(propertyName); + String propertyValue = properties.getProperty(propertyName); if (propertyValue == null) { throw new ParseException("Value of system property '" + propertyName + @@ -1096,7 +1170,7 @@ public class ConfigurationParser private void readNextWord(String expectedDescription) throws ParseException, IOException { - readNextWord(expectedDescription, false); + readNextWord(expectedDescription, false, false); } @@ -1105,10 +1179,11 @@ public class ConfigurationParser * throwing an exception if there is no next word. */ private void readNextWord(String expectedDescription, + boolean isFileName, boolean expectingAtCharacter) throws ParseException, IOException { - readNextWord(); + readNextWord(isFileName); if (configurationEnd(expectingAtCharacter)) { throw new ParseException("Expecting " + expectedDescription + @@ -1122,7 +1197,16 @@ public class ConfigurationParser */ private void readNextWord() throws IOException { - nextWord = reader.nextWord(); + readNextWord(false); + } + + + /** + * Reads the next word of the configuration in the 'nextWord' field. + */ + private void readNextWord(boolean isFileName) throws IOException + { + nextWord = reader.nextWord(isFileName); } @@ -1168,6 +1252,11 @@ public class ConfigurationParser */ private boolean isJavaIdentifier(String aWord) { + if (aWord.length() == 0) + { + return false; + } + for (int index = 0; index < aWord.length(); index++) { char c = aWord.charAt(index); @@ -1234,7 +1323,8 @@ public class ConfigurationParser { try { - ConfigurationParser parser = new ConfigurationParser(args); + ConfigurationParser parser = + new ConfigurationParser(args, System.getProperties()); try { diff --git a/src/proguard/ConfigurationWriter.java b/src/proguard/ConfigurationWriter.java index 5d112d6..00dfa9e 100644 --- a/src/proguard/ConfigurationWriter.java +++ b/src/proguard/ConfigurationWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -25,7 +25,7 @@ import proguard.classfile.util.ClassUtil; import proguard.util.ListUtil; import java.io.*; -import java.util.List; +import java.util.*; /** @@ -44,7 +44,7 @@ public class ConfigurationWriter private final PrintWriter writer; - private File baseDir; + private File baseDir; /** @@ -105,7 +105,7 @@ public class ConfigurationWriter writer.println(); // Write the other options. - writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, !configuration.skipNonPublicLibraryClasses); + writeOption(ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, configuration.skipNonPublicLibraryClasses); writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers); writeOption(ConfigurationConstants.KEEP_DIRECTORIES_OPTION, configuration.keepDirectories); writeOption(ConfigurationConstants.TARGET_OPTION, ClassUtil.externalClassVersion(configuration.targetClassVersion)); @@ -115,7 +115,7 @@ public class ConfigurationWriter writeOption(ConfigurationConstants.PRINT_USAGE_OPTION, configuration.printUsage); writeOption(ConfigurationConstants.DONT_OPTIMIZE_OPTION, !configuration.optimize); - writeOption(ConfigurationConstants.OPTIMIZATIONS, configuration.optimize ? ListUtil.commaSeparatedString(configuration.optimizations) : null); + writeOption(ConfigurationConstants.OPTIMIZATIONS, configuration.optimizations); writeOption(ConfigurationConstants.OPTIMIZATION_PASSES, configuration.optimizationPasses); writeOption(ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION, configuration.allowAccessModification); writeOption(ConfigurationConstants.MERGE_INTERFACES_AGGRESSIVELY_OPTION, configuration.mergeInterfacesAggressively); @@ -133,6 +133,7 @@ public class ConfigurationWriter writeOption(ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION, configuration.flattenPackageHierarchy, true); writeOption(ConfigurationConstants.REPACKAGE_CLASSES_OPTION, configuration.repackageClasses, true); writeOption(ConfigurationConstants.KEEP_ATTRIBUTES_OPTION, configuration.keepAttributes); + writeOption(ConfigurationConstants.KEEP_PARAMETER_NAMES_OPTION, configuration.keepParameterNames); writeOption(ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION, configuration.newSourceFileAttribute); writeOption(ConfigurationConstants.ADAPT_CLASS_STRINGS_OPTION, configuration.adaptClassStrings, true); writeOption(ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION, configuration.adaptResourceFileNames); @@ -218,15 +219,7 @@ public class ConfigurationWriter writer.print(ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD); } - for (int index = 0; index < filter.size(); index++) - { - if (index > 0) - { - writer.print(ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD); - } - - writer.print(quotedString((String)filter.get(index))); - } + writer.print(ListUtil.commaSeparatedString(filter, true)); filtered = true; } @@ -273,16 +266,14 @@ public class ConfigurationWriter } else { - String argumentString = ListUtil.commaSeparatedString(arguments); - if (replaceInternalClassNames) { - argumentString = ClassUtil.externalClassName(argumentString); + arguments = externalClassNames(arguments); } writer.print(optionName); writer.print(' '); - writer.println(quotedString(argumentString)); + writer.println(ListUtil.commaSeparatedString(arguments, true)); } } } @@ -585,6 +576,23 @@ public class ConfigurationWriter /** + * Returns a list with external versions of the given list of internal + * class names. + */ + private List externalClassNames(List internalClassNames) + { + List externalClassNames = new ArrayList(internalClassNames.size()); + + for (int index = 0; index < internalClassNames.size(); index++) + { + externalClassNames.add(ClassUtil.externalClassName((String)internalClassNames.get(index))); + } + + return externalClassNames; + } + + + /** * Returns a relative file name of the given file, if possible. * The file name is also quoted, if necessary. */ diff --git a/src/proguard/DataEntryReaderFactory.java b/src/proguard/DataEntryReaderFactory.java index a9724b5..3bf6f56 100644 --- a/src/proguard/DataEntryReaderFactory.java +++ b/src/proguard/DataEntryReaderFactory.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,11 +48,10 @@ public class DataEntryReaderFactory ClassPathEntry classPathEntry, DataEntryReader reader) { - String entryName = classPathEntry.getName(); - boolean isJar = endsWithIgnoreCase(entryName, ".jar"); - boolean isWar = endsWithIgnoreCase(entryName, ".war"); - boolean isEar = endsWithIgnoreCase(entryName, ".ear"); - boolean isZip = endsWithIgnoreCase(entryName, ".zip"); + boolean isJar = classPathEntry.isJar(); + boolean isWar = classPathEntry.isWar(); + boolean isEar = classPathEntry.isEar(); + boolean isZip = classPathEntry.isZip(); List filter = classPathEntry.getFilter(); List jarFilter = classPathEntry.getJarFilter(); @@ -139,17 +138,4 @@ public class DataEntryReaderFactory reader); } } - - - /** - * Returns whether the given string ends with the given suffix, ignoring its - * case. - */ - private static boolean endsWithIgnoreCase(String string, String suffix) - { - int stringLength = string.length(); - int suffixLength = suffix.length(); - - return string.regionMatches(true, stringLength - suffixLength, suffix, 0, suffixLength); - } } diff --git a/src/proguard/DataEntryWriterFactory.java b/src/proguard/DataEntryWriterFactory.java index 9fbc6d0..ca33a35 100644 --- a/src/proguard/DataEntryWriterFactory.java +++ b/src/proguard/DataEntryWriterFactory.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -65,11 +65,10 @@ public class DataEntryWriterFactory private static DataEntryWriter createClassPathEntryWriter(ClassPathEntry classPathEntry, DataEntryWriter alternativeWriter) { - String entryName = classPathEntry.getName(); - boolean isJar = endsWithIgnoreCase(entryName, ".jar"); - boolean isWar = endsWithIgnoreCase(entryName, ".war"); - boolean isEar = endsWithIgnoreCase(entryName, ".ear"); - boolean isZip = endsWithIgnoreCase(entryName, ".zip"); + boolean isJar = classPathEntry.isJar(); + boolean isWar = classPathEntry.isWar(); + boolean isEar = classPathEntry.isEar(); + boolean isZip = classPathEntry.isZip(); List filter = classPathEntry.getFilter(); List jarFilter = classPathEntry.getJarFilter(); @@ -83,7 +82,7 @@ public class DataEntryWriterFactory isEar ? "ear" : isZip ? "zip" : "directory") + - " [" + entryName + "]" + + " [" + classPathEntry.getName() + "]" + (filter != null || jarFilter != null || warFilter != null || @@ -148,17 +147,4 @@ public class DataEntryWriterFactory filteredJarWriter, isJar ? jarWriter : writer); } - - - /** - * Returns whether the given string ends with the given suffix, ignoring its - * case. - */ - private static boolean endsWithIgnoreCase(String string, String suffix) - { - int stringLength = string.length(); - int suffixLength = suffix.length(); - - return string.regionMatches(true, stringLength - suffixLength, suffix, 0, suffixLength); - } } diff --git a/src/proguard/DescriptorKeepChecker.java b/src/proguard/DescriptorKeepChecker.java index 1dfaf1a..fcd80b2 100644 --- a/src/proguard/DescriptorKeepChecker.java +++ b/src/proguard/DescriptorKeepChecker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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; import proguard.classfile.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; -import proguard.optimize.KeepMarker; +import proguard.optimize.*; import java.util.List; @@ -64,7 +64,7 @@ implements MemberVisitor, /** * Checks the classes mentioned in the given keep specifications, printing - * notes if necessary. Returns the number of notes printed. + * notes if necessary. */ public void checkClassSpecifications(List keepSpecifications) { @@ -85,8 +85,11 @@ implements MemberVisitor, programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); - // Print out notes about argument types that are not being kept. - programClassPool.classesAccept(new AllMemberVisitor(this)); + // Print out notes about argument types that are not being kept in + // class members that are being kept. + programClassPool.classesAccept( + new AllMemberVisitor( + new KeptMemberFilter(this))); } @@ -94,39 +97,42 @@ implements MemberVisitor, public void visitProgramField(ProgramClass programClass, ProgramField programField) { - if (KeepMarker.isKept(programField)) - { - referencingClass = programClass; - referencingMember = programField; - isField = true; - - // Don't check the type, because it is not required for introspection. - //programField.referencedClassesAccept(this); - } + //referencingClass = programClass; + //referencingMember = programField; + //isField = true; + // + // Don't check the type, because it is not required for introspection. + //programField.referencedClassesAccept(this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { - if (KeepMarker.isKept(programMethod)) + referencingClass = programClass; + referencingMember = programMethod; + isField = false; + + // Don't check the return type, because it is not required for + // introspection (e.g. the return type of the special Enum methods). + //programMethod.referencedClassesAccept(this); + + Clazz[] referencedClasses = programMethod.referencedClasses; + if (referencedClasses != null) { - referencingClass = programClass; - referencingMember = programMethod; - isField = false; + int count = referencedClasses.length; - // Don't check the return type, because it is not required for - // introspection (e.g. the return type of the special Enum methods). - //programMethod.referencedClassesAccept(this); + // Adapt the count if the return type is a class type (not so + // pretty; assuming test just checks for final ';'). + if (ClassUtil.isInternalClassType(programMethod.getDescriptor(programClass))) + { + count--; + } - Clazz[] referencedClasses = programMethod.referencedClasses; - if (referencedClasses != null) + for (int index = 0; index < count; index++) { - for (int index = 0; index < referencedClasses.length-1; index++) + if (referencedClasses[index] != null) { - if (referencedClasses[index] != null) - { - referencedClasses[index].accept(this); - } + referencedClasses[index].accept(this); } } } diff --git a/src/proguard/DuplicateClassPrinter.java b/src/proguard/DuplicateClassPrinter.java index 21b6aa0..7a071ce 100644 --- a/src/proguard/DuplicateClassPrinter.java +++ b/src/proguard/DuplicateClassPrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/FileWordReader.java b/src/proguard/FileWordReader.java index fb9fa50..7309843 100644 --- a/src/proguard/FileWordReader.java +++ b/src/proguard/FileWordReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,23 +29,17 @@ import java.net.URL; * * @author Eric Lafortune */ -public class FileWordReader extends WordReader +public class FileWordReader extends LineWordReader { - private final String name; - private LineNumberReader reader; - - /** * Creates a new FileWordReader for the given file. */ public FileWordReader(File file) throws IOException { - super(file.getParentFile()); - - this.name = file.getPath(); - this.reader = new LineNumberReader( - new BufferedReader( - new FileReader(file))); + super(new LineNumberReader(new BufferedReader(new FileReader(file))), + "file '" + file.getPath() + "'", + file.getParentFile() + ); } @@ -54,36 +48,8 @@ public class FileWordReader extends WordReader */ public FileWordReader(URL url) throws IOException { - super(null); - - this.name = url.toString(); - this.reader = new LineNumberReader( - new BufferedReader( - new InputStreamReader(url.openStream()))); - } - - - // Implementations for WordReader. - - protected String nextLine() throws IOException - { - return reader.readLine(); - } - - - protected String lineLocationDescription() - { - return "line " + reader.getLineNumber() + " of file '" + name + "'"; - } - - - public void close() throws IOException - { - super.close(); - - if (reader != null) - { - reader.close(); - } + super(new LineNumberReader(new BufferedReader(new InputStreamReader(url.openStream()))), + "file '" + url.toString() + "'", + null); } } diff --git a/src/proguard/FullyQualifiedClassNameChecker.java b/src/proguard/FullyQualifiedClassNameChecker.java index 06949b5..eb1865a 100644 --- a/src/proguard/FullyQualifiedClassNameChecker.java +++ b/src/proguard/FullyQualifiedClassNameChecker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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 @@ implements ClassVisitor /** - * Creates a new DescriptorKeepChecker. + * Creates a new FullyQualifiedClassNameChecker. */ public FullyQualifiedClassNameChecker(ClassPool programClassPool, ClassPool libraryClassPool, @@ -56,7 +56,7 @@ implements ClassVisitor /** * Checks the classes mentioned in the given class specifications, printing - * notes if necessary. Returns the number of notes printed. + * notes if necessary. */ public void checkClassSpecifications(List classSpecifications) { @@ -173,7 +173,8 @@ implements ClassVisitor private static boolean containsWildCards(String string) { return string != null && - (string.indexOf('*') >= 0 || + (string.indexOf('!') >= 0 || + string.indexOf('*') >= 0 || string.indexOf('?') >= 0 || string.indexOf(',') >= 0 || string.indexOf("///") >= 0); diff --git a/src/proguard/GPL.java b/src/proguard/GPL.java index 272a837..51220b8 100644 --- a/src/proguard/GPL.java +++ b/src/proguard/GPL.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,9 +48,10 @@ public class GPL { String uniquePackageNames = uniquePackageNames(unknownPackageNames); - System.out.println("ProGuard is released under the GNU General Public License. The authors of all"); - System.out.println("programs or plugins that link to it ("+uniquePackageNames+"...) therefore"); - System.out.println("must ensure that these programs carry the GNU General Public License as well."); + System.out.println("ProGuard is released under the GNU General Public License. You therefore"); + System.out.println("must ensure that programs that link to it ("+uniquePackageNames+"...)"); + System.out.println("carry the GNU General Public License as well. Alternatively, you can"); + System.out.println("apply for an exception with the author of ProGuard."); } } @@ -163,11 +164,20 @@ public class GPL packageName.startsWith("proguard") || packageName.startsWith("org.apache.tools.ant") || packageName.startsWith("org.apache.tools.maven") || + packageName.startsWith("org.gradle") || + packageName.startsWith("org.codehaus.groovy") || packageName.startsWith("org.eclipse") || packageName.startsWith("org.netbeans") || + packageName.startsWith("com.android") || packageName.startsWith("com.sun.kvem") || + packageName.startsWith("com.intel") || packageName.startsWith("net.certiv.proguarddt") || + packageName.startsWith("groovy") || + packageName.startsWith("scala") || + packageName.startsWith("sbt") || + packageName.startsWith("xsbt") || packageName.startsWith("eclipseme") || + packageName.startsWith("com.neomades") || packageName.startsWith("jg.j2me") || packageName.startsWith("jg.common") || packageName.startsWith("jg.buildengine"); diff --git a/src/proguard/Initializer.java b/src/proguard/Initializer.java index 41cf971..405c06d 100644 --- a/src/proguard/Initializer.java +++ b/src/proguard/Initializer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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; import proguard.classfile.ClassPool; +import proguard.classfile.attribute.annotation.visitor.*; import proguard.classfile.attribute.visitor.AllAttributeVisitor; import proguard.classfile.constant.visitor.*; import proguard.classfile.instruction.visitor.AllInstructionVisitor; @@ -60,6 +61,16 @@ public class Initializer { int originalLibraryClassPoolSize = libraryClassPool.size(); + // Perform basic checks on the configuration. + WarningPrinter fullyQualifiedClassNameNotePrinter = new WarningPrinter(System.out, configuration.note); + WarningPrinter keepClassMemberNotePrinter = new WarningPrinter(System.out, configuration.note); + + new FullyQualifiedClassNameChecker(programClassPool, + libraryClassPool, + fullyQualifiedClassNameNotePrinter).checkClassSpecifications(configuration.keep); + + new KeepClassMemberChecker(keepClassMemberNotePrinter).checkClassSpecifications(configuration.keep); + // Construct a reduced library class pool with only those library // classes whose hierarchies are referenced by the program classes. // We can't do this if we later have to come up with the obfuscated @@ -88,13 +99,15 @@ public class Initializer // Initialize the class references of program class members and // attributes. Note that all superclass hierarchies have to be // initialized for this purpose. - WarningPrinter memberReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); + WarningPrinter programMemberReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); + WarningPrinter libraryMemberReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); programClassPool.classesAccept( new ClassReferenceInitializer(programClassPool, libraryClassPool, classReferenceWarningPrinter, - memberReferenceWarningPrinter, + programMemberReferenceWarningPrinter, + libraryMemberReferenceWarningPrinter, null)); if (reducedLibraryClassPool != null) @@ -115,7 +128,13 @@ public class Initializer null)); } - // Initialize the Class.forName references. + // Initialize the enum annotation references. + programClassPool.classesAccept( + new AllAttributeVisitor(true, + new AllElementValueVisitor(true, + new EnumFieldReferenceInitializer()))); + + // Initialize the Class.forName references. WarningPrinter dynamicClassReferenceNotePrinter = new WarningPrinter(System.out, configuration.note); WarningPrinter classForNameNotePrinter = new WarningPrinter(System.out, configuration.note); @@ -153,13 +172,8 @@ public class Initializer libraryClassPool)))); } - // Print various notes, if specified. - WarningPrinter fullyQualifiedClassNameNotePrinter = new WarningPrinter(System.out, configuration.note); - WarningPrinter descriptorKeepNotePrinter = new WarningPrinter(System.out, configuration.note); - - new FullyQualifiedClassNameChecker(programClassPool, - libraryClassPool, - fullyQualifiedClassNameNotePrinter).checkClassSpecifications(configuration.keep); + // Check for unkept descriptor classes of kept class members. + WarningPrinter descriptorKeepNotePrinter = new WarningPrinter(System.out, configuration.note); new DescriptorKeepChecker(programClassPool, libraryClassPool, @@ -184,6 +198,7 @@ public class Initializer libraryClassPool, null, null, + null, dependencyWarningPrinter)); // Reset the library class pool. @@ -214,6 +229,7 @@ public class Initializer libraryClassPool, null, null, + null, dependencyWarningPrinter)); } @@ -232,6 +248,18 @@ public class Initializer System.out.println("Note: there were " + fullyQualifiedNoteCount + " references to unknown classes."); System.out.println(" You should check your configuration for typos."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unknownclass)"); + } + + // Print out a summary of the notes, if necessary. + int keepClassMemberNoteCount = keepClassMemberNotePrinter.getWarningCount(); + if (keepClassMemberNoteCount > 0) + { + System.out.println("Note: there were " + keepClassMemberNoteCount + + " '-keepclassmembers' options that didn't specify class"); + System.out.println(" members. You should specify at least some class members or consider"); + System.out.println(" if you just need '-keep'."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#classmembers)"); } int descriptorNoteCount = descriptorKeepNotePrinter.getWarningCount(); @@ -241,6 +269,7 @@ public class Initializer " unkept descriptor classes in kept class members."); System.out.println(" You should consider explicitly keeping the mentioned classes"); System.out.println(" (using '-keep')."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#descriptorclass)"); } int dynamicClassReferenceNoteCount = dynamicClassReferenceNotePrinter.getWarningCount(); @@ -248,7 +277,8 @@ public class Initializer { System.out.println("Note: there were " + dynamicClassReferenceNoteCount + " unresolved dynamic references to classes or interfaces."); - System.err.println(" You should check if you need to specify additional program jars."); + System.out.println(" You should check if you need to specify additional program jars."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)"); } int classForNameNoteCount = classForNameNotePrinter.getWarningCount(); @@ -258,6 +288,7 @@ public class Initializer " class casts of dynamically created class instances."); System.out.println(" You might consider explicitly keeping the mentioned classes and/or"); System.out.println(" their implementations (using '-keep')."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)"); } int getmemberNoteCount = getMemberNotePrinter.getWarningCount(); @@ -267,6 +298,7 @@ public class Initializer " accesses to class members by means of introspection."); System.out.println(" You should consider explicitly keeping the mentioned class members"); System.out.println(" (using '-keep' or '-keepclassmembers')."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)"); } // Print out a summary of the warnings, if necessary. @@ -275,8 +307,16 @@ public class Initializer { System.err.println("Warning: there were " + classReferenceWarningCount + " unresolved references to classes or interfaces."); - System.err.println(" You may need to specify additional library jars (using '-libraryjars'),"); - System.err.println(" or perhaps the '-dontskipnonpubliclibraryclasses' option."); + System.err.println(" You may need to add missing library jars or update their versions."); + System.err.println(" If your code works fine without the missing classes, you can suppress"); + System.err.println(" the warnings with '-dontwarn' options."); + + if (configuration.skipNonPublicLibraryClasses) + { + System.err.println(" You may also have to remove the option '-skipnonpubliclibraryclasses'."); + } + + System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)"); } int dependencyWarningCount = dependencyWarningPrinter.getWarningCount(); @@ -286,23 +326,44 @@ public class Initializer " instances of library classes depending on program classes."); System.err.println(" You must avoid such dependencies, since the program classes will"); System.err.println(" be processed, while the library classes will remain unchanged."); + System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)"); } - int memberReferenceWarningCount = memberReferenceWarningPrinter.getWarningCount(); - if (memberReferenceWarningCount > 0) + int programMemberReferenceWarningCount = programMemberReferenceWarningPrinter.getWarningCount(); + if (programMemberReferenceWarningCount > 0) { - System.err.println("Warning: there were " + memberReferenceWarningCount + + System.err.println("Warning: there were " + programMemberReferenceWarningCount + " unresolved references to program class members."); System.err.println(" Your input classes appear to be inconsistent."); - System.err.println(" You may need to recompile them and try again."); - System.err.println(" Alternatively, you may have to specify the options "); - System.err.println(" '-dontskipnonpubliclibraryclasses' and/or"); - System.err.println(" '-dontskipnonpubliclibraryclassmembers'."); + System.err.println(" You may need to recompile the code."); + System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)"); + } + + int libraryMemberReferenceWarningCount = libraryMemberReferenceWarningPrinter.getWarningCount(); + if (libraryMemberReferenceWarningCount > 0) + { + System.err.println("Warning: there were " + libraryMemberReferenceWarningCount + + " unresolved references to library class members."); + System.err.println(" You probably need to update the library versions."); + + if (!configuration.skipNonPublicLibraryClassMembers) + { + System.err.println(" Alternatively, you may have to specify the option "); + System.err.println(" '-dontskipnonpubliclibraryclassmembers'."); + } + + if (configuration.skipNonPublicLibraryClasses) + { + System.err.println(" You may also have to remove the option '-skipnonpubliclibraryclasses'."); + } + + System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedlibraryclassmember)"); } - if ((classReferenceWarningCount > 0 || - dependencyWarningCount > 0 || - memberReferenceWarningCount > 0) && + if ((classReferenceWarningCount > 0 || + dependencyWarningCount > 0 || + programMemberReferenceWarningCount > 0 || + libraryMemberReferenceWarningCount > 0) && !configuration.ignoreWarnings) { throw new IOException("Please correct the above warnings first."); diff --git a/src/proguard/InputReader.java b/src/proguard/InputReader.java index c088324..707774e 100644 --- a/src/proguard/InputReader.java +++ b/src/proguard/InputReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -115,6 +115,7 @@ public class InputReader { System.err.println("Note: there were " + noteCount + " duplicate class definitions."); + System.out.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)"); } // Print out a summary of the warnings, if necessary. @@ -125,6 +126,7 @@ public class InputReader " classes in incorrectly named files."); System.err.println(" You should make sure all file names correspond to their class names."); System.err.println(" The directory hierarchies must correspond to the package hierarchies."); + System.err.println(" (http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)"); if (!configuration.ignoreWarnings) { @@ -227,7 +229,7 @@ public class InputReader } catch (IOException ex) { - throw new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")"); + throw (IOException)new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")").initCause(ex); } } } diff --git a/src/proguard/KeepClassMemberChecker.java b/src/proguard/KeepClassMemberChecker.java new file mode 100644 index 0000000..3ea518e --- /dev/null +++ b/src/proguard/KeepClassMemberChecker.java @@ -0,0 +1,88 @@ +/* + * 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.util.*; +import proguard.classfile.visitor.ClassVisitor; + +import java.util.List; + +/** + * This class checks if the user has forgotten to specify class members in + * some keep options in the configuration. + * + * @author Eric Lafortune + */ +public class KeepClassMemberChecker +extends SimplifiedVisitor +implements ClassVisitor +{ + private final WarningPrinter notePrinter; + + + /** + * Creates a new KeepClassMemberChecker. + */ + public KeepClassMemberChecker(WarningPrinter notePrinter) + { + this.notePrinter = notePrinter; + } + + + /** + * Checks if the given class specifications try to keep class members + * without actually specifying any, printing notes if necessary. Returns + * the number of notes printed. + */ + public void checkClassSpecifications(List keepClassSpecifications) + { + if (keepClassSpecifications != null) + { + for (int index = 0; index < keepClassSpecifications.size(); index++) + { + KeepClassSpecification keepClassSpecification = + (KeepClassSpecification)keepClassSpecifications.get(index); + + if (!keepClassSpecification.markClasses && + (keepClassSpecification.fieldSpecifications == null || + keepClassSpecification.fieldSpecifications.size() == 0) && + (keepClassSpecification.methodSpecifications == null || + keepClassSpecification.methodSpecifications.size() == 0)) + { + String className = keepClassSpecification.className; + if (className == null) + { + className = keepClassSpecification.extendsClassName; + } + + if (notePrinter.accepts(className)) + { + notePrinter.print(className, + "Note: the configuration doesn't specify which class members to keep for class '" + + (className == null ? + ConfigurationConstants.ANY_CLASS_KEYWORD : + ClassUtil.externalClassName(className)) + "'"); + } + } + } + } + } +} diff --git a/src/proguard/KeepClassSpecification.java b/src/proguard/KeepClassSpecification.java index 29c0d3c..a6215c5 100644 --- a/src/proguard/KeepClassSpecification.java +++ b/src/proguard/KeepClassSpecification.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/LineWordReader.java b/src/proguard/LineWordReader.java new file mode 100644 index 0000000..64a228c --- /dev/null +++ b/src/proguard/LineWordReader.java @@ -0,0 +1,74 @@ +/* + * 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 java.io.*; + + +/** + * A <code>WordReader</code> 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 <configuration> must have a refid attribute"); + // Get the referenced path or file set. + Object referencedObject = getCheckedRef(Object.class, + Object.class.getName()); + + if (referencedObject instanceof ConfigurationTask) + { + // The reference doesn't point to a file set, but to a + // configuration task. + ConfigurationTask configurationTask = + (ConfigurationTask)referencedObject; + + // Append the contents of the referenced configuration to the + // current configuration. + configurationTask.appendTo(configuration); + + return; + } + else if (referencedObject instanceof AbstractFileSet) + { + AbstractFileSet fileSet = (AbstractFileSet)referencedObject; + + // Get the names of the existing input files in the referenced file set. + DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); + baseDir = scanner.getBasedir(); + fileNames = scanner.getIncludedFiles(); + } + else + { + throw new BuildException("The refid attribute doesn't point to a <proguardconfiguration> element or a <fileset> element"); + } } + else + { + // Get the names of the existing input files in the referenced file set. + DirectoryScanner scanner = getDirectoryScanner(getProject()); + baseDir = scanner.getBasedir(); + fileNames = scanner.getIncludedFiles(); + } + + // Get the combined system properties and Ant properties, for + // replacing ProGuard-style properties ('<...>'). + Properties properties = new Properties(); + properties.putAll(getProject().getProperties()); - ConfigurationTask configurationTask = - (ConfigurationTask)getCheckedRef(ConfigurationTask.class, - ConfigurationTask.class.getName()); + try + { + // Append the contents of the configuration files to the current + // configuration. + for (int index = 0; index < fileNames.length; index++) + { + File configurationFile = new File(baseDir, fileNames[index]); - // Append the referenced configuration entries to the given configuration. - configurationTask.appendTo(configuration); + ConfigurationParser parser = + new ConfigurationParser(configurationFile, properties); + try + { + parser.parse(configuration); + } + catch (ParseException ex) + { + throw new BuildException(ex.getMessage()); + } + finally + { + parser.close(); + } + } + } + catch (IOException ex) + { + throw new BuildException(ex.getMessage()); + } } } diff --git a/src/proguard/ant/ConfigurationTask.java b/src/proguard/ant/ConfigurationTask.java index 0d2f04f..376a1a1 100644 --- a/src/proguard/ant/ConfigurationTask.java +++ b/src/proguard/ant/ConfigurationTask.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -291,10 +291,20 @@ public class ConfigurationTask extends Task { try { - String arg = getProject().replaceProperties(text); + Project project = getProject(); - ConfigurationParser parser = new ConfigurationParser(new String[] { arg }, - getProject().getBaseDir()); + // Replace Ant-style properties ('${...}'). + String arg = project.replaceProperties(text); + + // Get the combined system properties and Ant properties, for + // replacing ProGuard-style properties ('<...>'). + Properties properties = new Properties(); + properties.putAll(project.getProperties()); + + ConfigurationParser parser = new ConfigurationParser(arg, + "embedded configuration", + project.getBaseDir(), + properties); try { diff --git a/src/proguard/ant/FilterElement.java b/src/proguard/ant/FilterElement.java index d792c5d..ab3364a 100644 --- a/src/proguard/ant/FilterElement.java +++ b/src/proguard/ant/FilterElement.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute 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/KeepSpecificationElement.java b/src/proguard/ant/KeepSpecificationElement.java index e36b744..feabc18 100644 --- a/src/proguard/ant/KeepSpecificationElement.java +++ b/src/proguard/ant/KeepSpecificationElement.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -39,9 +39,9 @@ public class KeepSpecificationElement extends ClassSpecificationElement /** * Adds the contents of this class specification element to the given list. * @param keepSpecifications the class specifications to be extended. - * @param markClasses specifies whether to mark the classes. - * @param markConditionally specifies whether to mark the classes - * and class members conditionally. + * @param markClasses specifies whether to mark the classes. + * @param markConditionally specifies whether to mark the classes + * and class members conditionally. */ public void appendTo(List keepSpecifications, boolean markClasses, @@ -50,16 +50,16 @@ public class KeepSpecificationElement extends ClassSpecificationElement // Get the referenced file set, or else this one. KeepSpecificationElement keepSpecificationElement = isReference() ? (KeepSpecificationElement)getCheckedRef(this.getClass(), - this.getClass().getName()) : + this.getClass().getName()) : this; KeepClassSpecification keepClassSpecification = new KeepClassSpecification(markClasses, - markConditionally, - allowShrinking, - allowOptimization, - allowObfuscation, - createClassSpecification(keepSpecificationElement)); + markConditionally, + allowShrinking, + allowOptimization, + allowObfuscation, + createClassSpecification(keepSpecificationElement)); // Add it to the list. keepSpecifications.add(keepClassSpecification); diff --git a/src/proguard/ant/MemberSpecificationElement.java b/src/proguard/ant/MemberSpecificationElement.java index d4bb4a9..9762009 100644 --- a/src/proguard/ant/MemberSpecificationElement.java +++ b/src/proguard/ant/MemberSpecificationElement.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,7 +63,7 @@ public class MemberSpecificationElement extends DataType this.getClass().getName()) : this; - // Create a new class specification. + // Create a new class member specification. String access = memberSpecificationElement.access; String type = memberSpecificationElement.type; String annotation = memberSpecificationElement.annotation; @@ -195,9 +195,12 @@ public class MemberSpecificationElement extends DataType strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : strippedToken.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_BRIDGE) ? ClassConstants.INTERNAL_ACC_BRIDGE : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_VARARGS) ? ClassConstants.INTERNAL_ACC_VARARGS : strippedToken.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : strippedToken.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : 0; if (accessFlag == 0) diff --git a/src/proguard/ant/ProGuardTask.java b/src/proguard/ant/ProGuardTask.java index b7fc361..7ab1cdf 100644 --- a/src/proguard/ant/ProGuardTask.java +++ b/src/proguard/ant/ProGuardTask.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -25,7 +25,7 @@ import proguard.*; import proguard.classfile.util.ClassUtil; import java.io.*; -import java.util.ArrayList; +import java.util.*; /** * This Task allows to configure and run ProGuard from Ant. @@ -40,8 +40,13 @@ public class ProGuardTask extends ConfigurationTask { try { - ConfigurationParser parser = new ConfigurationParser(configurationFile); + // Get the combined system properties and Ant properties, for + // replacing ProGuard-style properties ('<...>'). + Properties properties = new Properties(); + properties.putAll(getProject().getProperties()); + ConfigurationParser parser = new ConfigurationParser(configurationFile, + properties); try { parser.parse(configuration); @@ -215,6 +220,12 @@ public class ProGuardTask extends ConfigurationTask } + public void setKeepparameternames(boolean keepParameterNames) + { + configuration.keepParameterNames = keepParameterNames; + } + + public void setRenamesourcefileattribute(String newSourceFileAttribute) { configuration.newSourceFileAttribute = newSourceFileAttribute; @@ -241,13 +252,39 @@ public class ProGuardTask extends ConfigurationTask public void setNote(boolean note) { - configuration.note = note ? null : new ArrayList(); + if (note) + { + // Switch on notes if they were completely disabled. + if (configuration.note != null && + configuration.note.isEmpty()) + { + configuration.note = null; + } + } + else + { + // Switch off notes. + configuration.note = new ArrayList(); + } } public void setWarn(boolean warn) { - configuration.warn = warn ? null : new ArrayList(); + if (warn) + { + // Switch on warnings if they were completely disabled. + if (configuration.warn != null && + configuration.warn.isEmpty()) + { + configuration.warn = null; + } + } + else + { + // Switch off warnings. + configuration.warn = new ArrayList(); + } } @@ -302,7 +339,7 @@ public class ProGuardTask extends ConfigurationTask fileName.equalsIgnoreCase("off") ? null : fileName.equalsIgnoreCase("true") || fileName.equalsIgnoreCase("yes") || - fileName.equalsIgnoreCase("on") ? new File("") : + fileName.equalsIgnoreCase("on") ? Configuration.STD_OUT : resolvedFile(file); } diff --git a/src/proguard/ant/task.properties b/src/proguard/ant/task.properties index b676db7..82d0f3f 100644 --- a/src/proguard/ant/task.properties +++ b/src/proguard/ant/task.properties @@ -1,2 +1,2 @@ -proguard = proguard.ant.ProGuardTask
-proguardconfiguration = proguard.ant.ConfigurationTask
+proguard = proguard.ant.ProGuardTask +proguardconfiguration = proguard.ant.ConfigurationTask diff --git a/src/proguard/classfile/ClassConstants.java b/src/proguard/classfile/ClassConstants.java index 3b243e0..59580c5 100644 --- a/src/proguard/classfile/ClassConstants.java +++ b/src/proguard/classfile/ClassConstants.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -43,6 +43,8 @@ public interface ClassConstants public static final int INTERNAL_CLASS_VERSION_1_5_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_6_MAJOR = 50; public static final int INTERNAL_CLASS_VERSION_1_6_MINOR = 0; + public static final int INTERNAL_CLASS_VERSION_1_7_MAJOR = 51; + public static final int INTERNAL_CLASS_VERSION_1_7_MINOR = 0; public static final int INTERNAL_CLASS_VERSION_1_0 = (INTERNAL_CLASS_VERSION_1_0_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_0_MINOR; public static final int INTERNAL_CLASS_VERSION_1_2 = (INTERNAL_CLASS_VERSION_1_2_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_2_MINOR; @@ -50,6 +52,7 @@ public interface ClassConstants public static final int INTERNAL_CLASS_VERSION_1_4 = (INTERNAL_CLASS_VERSION_1_4_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_4_MINOR; public static final int INTERNAL_CLASS_VERSION_1_5 = (INTERNAL_CLASS_VERSION_1_5_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_5_MINOR; public static final int INTERNAL_CLASS_VERSION_1_6 = (INTERNAL_CLASS_VERSION_1_6_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_6_MINOR; + public static final int INTERNAL_CLASS_VERSION_1_7 = (INTERNAL_CLASS_VERSION_1_7_MAJOR << 16) | INTERNAL_CLASS_VERSION_1_7_MINOR; public static final String EXTERNAL_CLASS_VERSION_1_0 = "1.0"; public static final String EXTERNAL_CLASS_VERSION_1_1 = "1.1"; @@ -58,8 +61,10 @@ public interface ClassConstants public static final String EXTERNAL_CLASS_VERSION_1_4 = "1.4"; public static final String EXTERNAL_CLASS_VERSION_1_5 = "1.5"; public static final String EXTERNAL_CLASS_VERSION_1_6 = "1.6"; + public static final String EXTERNAL_CLASS_VERSION_1_7 = "1.7"; public static final String EXTERNAL_CLASS_VERSION_1_5_ALIAS = "5"; public static final String EXTERNAL_CLASS_VERSION_1_6_ALIAS = "6"; + public static final String EXTERNAL_CLASS_VERSION_1_7_ALIAS = "7"; public static final int INTERNAL_ACC_PUBLIC = 0x0001; public static final int INTERNAL_ACC_PRIVATE = 0x0002; @@ -119,10 +124,13 @@ public interface ClassConstants public static final String EXTERNAL_ACC_SYNCHRONIZED = "synchronized"; public static final String EXTERNAL_ACC_VOLATILE = "volatile"; public static final String EXTERNAL_ACC_TRANSIENT = "transient"; + public static final String EXTERNAL_ACC_BRIDGE = "bridge"; + public static final String EXTERNAL_ACC_VARARGS = "varargs"; public static final String EXTERNAL_ACC_NATIVE = "native"; public static final String EXTERNAL_ACC_INTERFACE = "interface"; public static final String EXTERNAL_ACC_ABSTRACT = "abstract"; public static final String EXTERNAL_ACC_STRICT = "strictfp"; + public static final String EXTERNAL_ACC_SYNTHETIC = "synthetic"; public static final String EXTERNAL_ACC_ANNOTATION = "@"; public static final String EXTERNAL_ACC_ENUM = "enum"; @@ -137,7 +145,21 @@ public interface ClassConstants public static final int CONSTANT_Methodref = 10; public static final int CONSTANT_InterfaceMethodref = 11; public static final int CONSTANT_NameAndType = 12; + public static final int CONSTANT_MethodHandle = 15; + public static final int CONSTANT_MethodType = 16; + public static final int CONSTANT_InvokeDynamic = 18; + public static final int REF_getField = 1; + public static final int REF_getStatic = 2; + public static final int REF_putField = 3; + public static final int REF_putStatic = 4; + public static final int REF_invokeVirtual = 5; + public static final int REF_invokeStatic = 6; + public static final int REF_invokeSpecial = 7; + public static final int REF_newInvokeSpecial = 8; + public static final int REF_invokeInterface = 9; + + public static final String ATTR_BootstrapMethods = "BootstrapMethods"; public static final String ATTR_SourceFile = "SourceFile"; public static final String ATTR_SourceDir = "SourceDir"; public static final String ATTR_InnerClasses = "InnerClasses"; @@ -159,11 +181,11 @@ public interface ClassConstants public static final String ATTR_RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; public static final String ATTR_AnnotationDefault = "AnnotationDefault"; - public static final int ELEMENT_VALUE_STRING_CONSTANT = 's'; - public static final int ELEMENT_VALUE_ENUM_CONSTANT = 'e'; - public static final int ELEMENT_VALUE_CLASS = 'c'; - public static final int ELEMENT_VALUE_ANNOTATION = '@'; - public static final int ELEMENT_VALUE_ARRAY = '['; + public static final char ELEMENT_VALUE_STRING_CONSTANT = 's'; + public static final char ELEMENT_VALUE_ENUM_CONSTANT = 'e'; + public static final char ELEMENT_VALUE_CLASS = 'c'; + public static final char ELEMENT_VALUE_ANNOTATION = '@'; + public static final char ELEMENT_VALUE_ARRAY = '['; public static final char EXTERNAL_PACKAGE_SEPARATOR = '.'; public static final char EXTERNAL_INNER_CLASS_SEPARATOR = '.'; @@ -179,41 +201,93 @@ public interface ClassConstants public static final char INTERNAL_METHOD_ARGUMENTS_OPEN = '('; public static final char INTERNAL_METHOD_ARGUMENTS_CLOSE = ')'; - public static final String INTERNAL_PACKAGE_JAVA_LANG = "java/lang/"; - public static final String INTERNAL_NAME_JAVA_LANG_OBJECT = "java/lang/Object"; - public static final String INTERNAL_TYPE_JAVA_LANG_OBJECT = "Ljava/lang/Object;"; - public static final String INTERNAL_NAME_JAVA_LANG_CLONEABLE = "java/lang/Cloneable"; - public static final String INTERNAL_NAME_JAVA_LANG_THROWABLE = "java/lang/Throwable"; - public static final String INTERNAL_NAME_JAVA_LANG_CLASS = "java/lang/Class"; - public static final String INTERNAL_NAME_JAVA_LANG_STRING = "java/lang/String"; - public static final String INTERNAL_NAME_JAVA_IO_SERIALIZABLE = "java/io/Serializable"; + public static final String INTERNAL_PACKAGE_JAVA_LANG = "java/lang/"; + public static final String INTERNAL_NAME_JAVA_LANG_OBJECT = "java/lang/Object"; + public static final String INTERNAL_TYPE_JAVA_LANG_OBJECT = "Ljava/lang/Object;"; + public static final String INTERNAL_NAME_JAVA_LANG_CLONEABLE = "java/lang/Cloneable"; + public static final String INTERNAL_NAME_JAVA_LANG_THROWABLE = "java/lang/Throwable"; + public static final String INTERNAL_NAME_JAVA_LANG_CLASS = "java/lang/Class"; + public static final String INTERNAL_NAME_JAVA_LANG_STRING = "java/lang/String"; + public static final String INTERNAL_NAME_JAVA_LANG_STRING_BUFFER = "java/lang/StringBuffer"; + public static final String INTERNAL_NAME_JAVA_LANG_STRING_BUILDER = "java/lang/StringBuilder"; + public static final String INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_HANDLE = "java/lang/invoke/MethodHandle"; + public static final String INTERNAL_NAME_JAVA_LANG_INVOKE_METHOD_TYPE = "java/lang/invoke/MethodType"; + public static final String INTERNAL_NAME_JAVA_IO_SERIALIZABLE = "java/io/Serializable"; + + public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicIntegerFieldUpdater"; + public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicLongFieldUpdater"; + public static final String INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER = "java/util/concurrent/atomic/AtomicReferenceFieldUpdater"; public static final String INTERNAL_METHOD_NAME_INIT = "<init>"; public static final String INTERNAL_METHOD_TYPE_INIT = "()V"; public static final String INTERNAL_METHOD_NAME_CLINIT = "<clinit>"; public static final String INTERNAL_METHOD_TYPE_CLINIT = "()V"; - public static final String INTERNAL_METHOD_NAME_CLASS_FOR_NAME = "forName"; - public static final String INTERNAL_METHOD_TYPE_CLASS_FOR_NAME = "(Ljava/lang/String;)Ljava/lang/Class;"; - public static final String INTERNAL_METHOD_NAME_CLASS_GET_COMPONENT_TYPE = "getComponentType"; - public static final String INTERNAL_METHOD_TYPE_CLASS_GET_COMPONENT_TYPE = "()Ljava/lang/Class;"; - public static final String INTERNAL_METHOD_NAME_CLASS_GET_FIELD = "getField"; - public static final String INTERNAL_METHOD_TYPE_CLASS_GET_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; - public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD = "getDeclaredField"; - public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; - public static final String INTERNAL_METHOD_NAME_CLASS_GET_METHOD = "getMethod"; - public static final String INTERNAL_METHOD_TYPE_CLASS_GET_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; - public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD = "getDeclaredMethod"; - public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; + public static final String INTERNAL_METHOD_NAME_CLASS_FOR_NAME = "forName"; + public static final String INTERNAL_METHOD_TYPE_CLASS_FOR_NAME = "(Ljava/lang/String;)Ljava/lang/Class;"; + public static final String INTERNAL_METHOD_NAME_CLASS_GET_COMPONENT_TYPE = "getComponentType"; + public static final String INTERNAL_METHOD_TYPE_CLASS_GET_COMPONENT_TYPE = "()Ljava/lang/Class;"; + public static final String INTERNAL_METHOD_NAME_CLASS_GET_FIELD = "getField"; + public static final String INTERNAL_METHOD_TYPE_CLASS_GET_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; + public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD = "getDeclaredField"; + public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD = "(Ljava/lang/String;)Ljava/lang/reflect/Field;"; + public static final String INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR = "getConstructor"; + public static final String INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"; + public static final String INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR = "getDeclaredConstructor"; + public static final String INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR = "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"; + public static final String INTERNAL_METHOD_NAME_CLASS_GET_METHOD = "getMethod"; + public static final String INTERNAL_METHOD_TYPE_CLASS_GET_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; + public static final String INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD = "getDeclaredMethod"; + public static final String INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD = "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"; + public static final String INTERNAL_METHOD_NAME_NEW_UPDATER = "newUpdater"; + public static final String INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER = "(Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;"; + public static final String INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER = "(Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicLongFieldUpdater;"; + public static final String INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER = "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;"; public static final String INTERNAL_METHOD_NAME_DOT_CLASS_JAVAC = "class$"; public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC = "(Ljava/lang/String;)Ljava/lang/Class;"; public static final String INTERNAL_METHOD_NAME_DOT_CLASS_JIKES = "class"; public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES = "(Ljava/lang/String;Z)Ljava/lang/Class;"; + public static final String INTERNAL_METHOD_TYPE_INIT_ENUM = "(Ljava/lang/String;I)V"; + public static final String INTERNAL_METHOD_NAME_NEW_INSTANCE = "newInstance"; public static final String INTERNAL_METHOD_TYPE_NEW_INSTANCE = "()Ljava/lang/Object;"; + public static final String INTERNAL_METHOD_NAME_EQUALS = "equals"; + public static final String INTERNAL_METHOD_TYPE_EQUALS = "(Ljava/lang/Object;)Z"; + public static final String INTERNAL_METHOD_NAME_LENGTH = "length"; + public static final String INTERNAL_METHOD_NAME_VALUEOF = "valueOf"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_BOOLEAN = "(Z)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_CHAR = "(C)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_INT = "(I)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_LONG = "(J)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_FLOAT = "(F)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_DOUBLE = "(D)Ljava/lang/String;"; + public static final String INTERNAL_METHOD_TYPE_VALUEOF_OBJECT = "(Ljava/lang/Object;)Ljava/lang/String;"; + + public static final String INTERNAL_METHOD_TYPE_LENGTH = "()I"; + public static final String INTERNAL_METHOD_NAME_APPEND = "append"; + public static final String INTERNAL_METHOD_TYPE_STRING_VOID = "(Ljava/lang/String;)V"; + public static final String INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUFFER = "(Z)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_CHAR_STRING_BUFFER = "(C)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_INT_STRING_BUFFER = "(I)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_LONG_STRING_BUFFER = "(J)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_FLOAT_STRING_BUFFER = "(F)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUFFER = "(D)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_STRING_STRING_BUFFER = "(Ljava/lang/String;)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_OBJECT_STRING_BUFFER = "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"; + public static final String INTERNAL_METHOD_TYPE_BOOLEAN_STRING_BUILDER = "(Z)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_CHAR_STRING_BUILDER = "(C)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_INT_STRING_BUILDER = "(I)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_LONG_STRING_BUILDER = "(J)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_FLOAT_STRING_BUILDER = "(F)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_DOUBLE_STRING_BUILDER = "(D)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_STRING_STRING_BUILDER = "(Ljava/lang/String;)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_TYPE_OBJECT_STRING_BUILDER = "(Ljava/lang/Object;)Ljava/lang/StringBuilder;"; + public static final String INTERNAL_METHOD_NAME_TOSTRING = "toString"; + public static final String INTERNAL_METHOD_TYPE_TOSTRING = "()Ljava/lang/String;"; + public static final char INTERNAL_TYPE_VOID = 'V'; public static final char INTERNAL_TYPE_BOOLEAN = 'Z'; public static final char INTERNAL_TYPE_BYTE = 'B'; diff --git a/src/proguard/classfile/ClassPool.java b/src/proguard/classfile/ClassPool.java index 57728a5..5439c6f 100644 --- a/src/proguard/classfile/ClassPool.java +++ b/src/proguard/classfile/ClassPool.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,14 +26,16 @@ import proguard.classfile.visitor.*; import java.util.*; /** - * This is a set of representations of classes. They can be enumerated or + * This is a set of representations of classes. They can be enumerated or * retrieved by name. They can also be accessed by means of class visitors. * * @author Eric Lafortune */ public class ClassPool { - private final Map classes = new HashMap(); + // We're using a sorted tree map instead of a hash map to store the classes, + // in order to make the processing more deterministic. + private final Map classes = new TreeMap(); /** @@ -59,18 +61,27 @@ public class ClassPool */ public void removeClass(Clazz clazz) { - classes.remove(clazz.getName()); + removeClass(clazz.getName()); + } + + + /** + * Removes the specified Clazz from the class pool. + */ + public void removeClass(String className) + { + classes.remove(className); } /** * Returns a Clazz from the class pool based on its name. Returns * <code>null</code> 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. @@ -116,12 +126,26 @@ 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. * Interfaces are considered to implement all their superinterfaces. */ 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, @@ -70,34 +70,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 <code>null</code> 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. */ private Attribute getAttribute(Clazz clazz, String 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 <code>{@link + * proguard.classfile.util.ClassReferenceInitializer + * ClassReferenceInitializer}</code>. + */ + public Field referencedField; + /** * Creates an uninitialized EnumConstantElementValue. @@ -67,6 +75,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. */ public void referencedClassesAccept(ClassVisitor classVisitor) @@ -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 <code>AttributeVisitor</code> to which - * visits will be delegated. + * @param regularExpression the regular expression against which attribute + * names will be matched. + * @param attributeVisitor the <code>AttributeVisitor</code> 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 <code>AttributeVisitor</code> 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 <code>AttributeVisitor</code> 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 + * <code>BootstrapMethodInfo</code> objects. Note that there is only a single + * implementation of <code>BootstrapMethodInfo</code>, 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 <code>AttributeVisitor</code> 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 <code>{@link + * proguard.classfile.util.ClassReferenceInitializer ClassReferenceInitializer}</code>. + * 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 <code>{@link + * proguard.classfile.util.ClassReferenceInitializer + * ClassReferenceInitializer}</code>.. + */ + 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 <code>{@link + * proguard.classfile.util.ClassReferenceInitializer + * ClassReferenceInitializer}</code>.. + */ + 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 <code>ConstantVisitor</code> 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 <code>ConstantVisitor</code> 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 <code>ConstantVisitor</code> 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 <code>ConstantVisitor</code> 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/visitor/ClassForNameClassVisitor.java b/src/proguard/classfile/constant/visitor/MethodrefTraveler.java index ee028f8..acd1bc8 100644 --- a/src/proguard/classfile/visitor/ClassForNameClassVisitor.java +++ b/src/proguard/classfile/constant/visitor/MethodrefTraveler.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -18,38 +18,32 @@ * 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; +package proguard.classfile.constant.visitor; import proguard.classfile.Clazz; +import proguard.classfile.attribute.*; import proguard.classfile.constant.*; -import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; - /** - * This ConstantVisitor lets a given <code>ClassVisitor</code> visit all - * constant classes involved in any <code>Class.forName</code> constructs that - * it visits. - * - * @see DotClassClassVisitor + * 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 ClassForNameClassVisitor +public class MethodrefTraveler extends SimplifiedVisitor implements ConstantVisitor { - private final ClassVisitor classVisitor; + private ConstantVisitor methodrefConstantVisitor; /** - * Creates a new ClassHierarchyTraveler. - * @param classVisitor the <code>ClassVisitor</code> to which visits will - * be delegated. + * Creates a new v that will delegate to the given constant visitor. */ - public ClassForNameClassVisitor(ClassVisitor classVisitor) + public MethodrefTraveler(ConstantVisitor methodrefConstantVisitor) { - this.classVisitor = classVisitor; + this.methodrefConstantVisitor = methodrefConstantVisitor; } @@ -58,9 +52,9 @@ implements ConstantVisitor public void visitAnyConstant(Clazz clazz, Constant constant) {} - public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { - // Visit the referenced class from the Class.forName construct, if any. - stringConstant.referencedClassAccept(classVisitor); + 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,12 +229,70 @@ 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; @@ -282,6 +342,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 @@ -199,6 +199,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. * @return the constant pool index of the FieldrefConstant. @@ -563,6 +650,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. * @return the constant pool index of the NameAndTypeConstant. 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/obfuscate/NameAndTypeUsageMarker.java b/src/proguard/classfile/editor/NameAndTypeShrinker.java index cc779f0..650f9ba 100644 --- a/src/proguard/obfuscate/NameAndTypeUsageMarker.java +++ b/src/proguard/classfile/editor/NameAndTypeShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -18,25 +18,27 @@ * 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; +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 marks all NameAndType constant pool entries that are - * being used in the program classes it visits. - * - * @see NameAndTypeShrinker + * This ClassVisitor removes NameAndType constant pool entries that are not + * used. * * @author Eric Lafortune */ -public class NameAndTypeUsageMarker +public class NameAndTypeShrinker extends SimplifiedVisitor implements ClassVisitor, ConstantVisitor, @@ -45,6 +47,9 @@ implements ClassVisitor, // 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. @@ -57,33 +62,37 @@ implements ClassVisitor, // 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); - // Implementations for ConstantVisitor. - - public void visitAnyConstant(Clazz clazz, Constant constant) {} - + // Remap the references to the constant pool if it has shrunk. + if (newConstantPoolCount < programClass.u2constantPoolCount) + { + programClass.u2constantPoolCount = newConstantPoolCount; - public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) - { - visitRefConstant(clazz, fieldrefConstant); + // Remap all constant pool references. + constantPoolRemapper.setConstantIndexMap(constantIndexMap); + constantPoolRemapper.visitProgramClass(programClass); + } } - public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) - { - visitRefConstant(clazz, interfaceMethodrefConstant); - } + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} - public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { - visitRefConstant(clazz, methodrefConstant); + markNameAndTypeConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); } - private void visitRefConstant(Clazz clazz, RefConstant refConstant) + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex); } @@ -118,7 +127,7 @@ implements ClassVisitor, * Marks the given VisitorAccepter as being used. * In this context, the VisitorAccepter will be a NameAndTypeConstant object. */ - private static void markAsUsed(VisitorAccepter visitorAccepter) + private void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } @@ -128,8 +137,52 @@ implements ClassVisitor, * 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) + 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/obfuscate/Utf8UsageMarker.java b/src/proguard/classfile/editor/Utf8Shrinker.java index c59ebb8..eda5826 100644 --- a/src/proguard/obfuscate/Utf8UsageMarker.java +++ b/src/proguard/classfile/editor/Utf8Shrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package proguard.obfuscate; +package proguard.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; @@ -28,18 +28,19 @@ 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 marks all UTF-8 constant pool entries that are - * being used in the program classes it visits. - * - * @see Utf8Shrinker + * This ClassVisitor removes UTF-8 constant pool entries that are not used. * * @author Eric Lafortune */ -public class Utf8UsageMarker +public class Utf8Shrinker extends SimplifiedVisitor implements ClassVisitor, MemberVisitor, @@ -54,6 +55,9 @@ implements ClassVisitor, // 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. @@ -68,6 +72,22 @@ implements ClassVisitor, // 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); + } } @@ -375,7 +395,7 @@ implements ClassVisitor, * Marks the given VisitorAccepter as being used. * In this context, the VisitorAccepter will be a Utf8Constant object. */ - private static void markAsUsed(VisitorAccepter visitorAccepter) + private void markAsUsed(VisitorAccepter visitorAccepter) { visitorAccepter.setVisitorInfo(USED); } @@ -385,8 +405,51 @@ implements ClassVisitor, * 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) + 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. "<code>java.lang.Object[][]</code>" + * @return the external base type, + * e.g. "<code>java.lang.Object</code>". + */ + 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. "<code>java.lang.Object</code>" * @return the external short class name, @@ -410,6 +433,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. "<code><clinit></code>". + * @return whether the method name refers to an initializer, + * e.g. <code>true</code>. + */ + 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, * e.g. "<code>(II)Z</code>". @@ -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 <code>InternalTypeEnumeration</code> 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. - * <p> - * As a MemberVisitor, it links all corresponding class members that it visits, - * including fields and private class members. - * <p> - * 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/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 <code>ClassVisitor</code> 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 @@ -39,6 +39,19 @@ public class ClassVersionFilter implements ClassVisitor /** * Creates a new ClassVersionFilter. * @param minimumClassVersion the minimum class version number. + * @param classVisitor the <code>ClassVisitor</code> 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. * @param maximumClassVersion the maximum class version number. * @param classVisitor the <code>ClassVisitor</code> to which visits * will be delegated. 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, <code>.class</code> constructs are actually * compiled differently, using <code>Class.forName</code> 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 <code>Value</code> * 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. - * <p> - * 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; /** @@ -78,24 +74,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. * @return the producer value of the given variable. @@ -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 <code>Value</code> * 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<File> files = fileCollection.iterator(); + while (files.hasNext()) + { + ConfigurationParser parser = + new ConfigurationParser(files.next(), System.getProperties()); + + try + { + parser.parse(configuration); + } + finally + { + parser.close(); + } + } + + // Make sure the code is processed. Gradle has already checked that it + // was necessary. + configuration.lastModified = Long.MAX_VALUE; + + // Let the logging manager capture the standard output and errors from + // ProGuard. + LoggingManager loggingManager = getLogging(); + loggingManager.captureStandardOutput(LogLevel.INFO); + loggingManager.captureStandardError(LogLevel.WARN); + + // Run ProGuard with the collected configuration. + new ProGuard(configuration).execute(); + + } + + + // Small utility methods. + + /** + * Extends the given class path with the given filtered input or output + * files. + */ + private ClassPath extendClassPath(ClassPath classPath, + Object files, + Map filterArgs, + boolean output) + { + ConfigurableFileCollection fileCollection = getProject().files(files); + + if (classPath == null) + { + classPath = new ClassPath(); + } + + Iterator fileIterator = fileCollection.iterator(); + while (fileIterator.hasNext()) + { + File file = (File)fileIterator.next(); + if (output || file.exists()) + { + // Create the class path entry. + ClassPathEntry classPathEntry = new ClassPathEntry(file, output); + + // Add any filters to the class path entry. + if (filterArgs != null) + { + classPathEntry.setFilter(ListUtil.commaSeparatedList((String)filterArgs.get("filter"))); + classPathEntry.setJarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("jarfilter"))); + classPathEntry.setWarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("warfilter"))); + classPathEntry.setEarFilter(ListUtil.commaSeparatedList((String)filterArgs.get("earfilter"))); + classPathEntry.setZipFilter(ListUtil.commaSeparatedList((String)filterArgs.get("zipfilter"))); + } + + classPath.add(classPathEntry); + } + } + + return classPath; + } + + + /** + * Creates specifications to keep classes and class members, based on the + * given parameters. + */ + private KeepClassSpecification createKeepClassSpecification(boolean allowShrinking, + boolean markClasses, + boolean markConditionally, + Map keepArgs, + String classSpecificationString) + throws ParseException + { + ClassSpecification classSpecification = + createClassSpecification(classSpecificationString); + + return + createKeepClassSpecification(allowShrinking, + markClasses, + markConditionally, + keepArgs, + classSpecification); + } + + + /** + * Creates specifications to keep classes and class members, based on the + * given parameters. + */ + private KeepClassSpecification createKeepClassSpecification(boolean allowShrinking, + boolean markClasses, + boolean markConditionally, + Map classSpecificationArgs, + Closure classMembersClosure) + throws ParseException + { + ClassSpecification classSpecification = + createClassSpecification(classSpecificationArgs, + classMembersClosure); + return + createKeepClassSpecification(allowShrinking, + markClasses, + markConditionally, + classSpecificationArgs, + classSpecification); + } + + + /** + * Creates specifications to keep classes and class members, based on the + * given parameters. + */ + private KeepClassSpecification createKeepClassSpecification(boolean allowShrinking, + boolean markClasses, + boolean markConditionally, + Map keepArgs, + ClassSpecification classSpecification) + { + return + new KeepClassSpecification(markClasses, + markConditionally, + retrieveBoolean(keepArgs, "allowshrinking", allowShrinking), + retrieveBoolean(keepArgs, "allowoptimization", false), + retrieveBoolean(keepArgs, "allowobfuscation", false), + classSpecification); + } + + + /** + * Creates specifications to keep classes and class members, based on the + * given ProGuard-style class specification. + */ + private ClassSpecification createClassSpecification(String classSpecificationString) + throws ParseException + { + try + { + ConfigurationParser parser = + new ConfigurationParser(new String[] { classSpecificationString }, null); + + try + { + return parser.parseClassSpecificationArguments(); + } + finally + { + parser.close(); + } + } + catch (IOException e) + { + throw new ParseException(e.getMessage()); + } + } + + + /** + * Creates a specification of classes and class members, based on the + * given parameters. + */ + private ClassSpecification createClassSpecification(Map classSpecificationArgs, + Closure classMembersClosure) + throws ParseException + { + // Extract the arguments. + String access = (String)classSpecificationArgs.get("access"); + String annotation = (String)classSpecificationArgs.get("annotation"); + String type = (String)classSpecificationArgs.get("type"); + String name = (String)classSpecificationArgs.get("name"); + String extendsAnnotation = (String)classSpecificationArgs.get("extendsannotation"); + String extends_ = (String)classSpecificationArgs.get("extends"); + if (extends_ == null) + { + extends_ = (String)classSpecificationArgs.get("implements"); + } + + // Create the class specification. + ClassSpecification classSpecification = + new ClassSpecification(null, + requiredClassAccessFlags(true, access, type), + requiredClassAccessFlags(false, access, type), + annotation != null ? ClassUtil.internalType(annotation) : null, + name != null ? ClassUtil.internalClassName(name) : null, + extendsAnnotation != null ? ClassUtil.internalType(extendsAnnotation) : null, + extends_ != null ? ClassUtil.internalClassName(extends_) : null); + + // Initialize the class specification with its closure. + if (classMembersClosure != null) + { + // Temporarily remember the class specification, so we can add + // class member specifications. + this.classSpecification = classSpecification; + classMembersClosure.call(classSpecification); + this.classSpecification = null; + } + + return classSpecification; + } + + + /** + * Parses the class access flags that must be set (or not), based on the + * given ProGuard-style flag specification. + */ + private int requiredClassAccessFlags(boolean set, + String access, + String type) + throws ParseException + { + int accessFlags = 0; + + if (access != null) + { + StringTokenizer tokenizer = new StringTokenizer(access, " ,"); + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + + if (token.startsWith("!") ^ set) + { + String strippedToken = token.startsWith("!") ? + token.substring(1) : + token; + + int accessFlag = + 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; + + if (accessFlag == 0) + { + throw new ParseException("Incorrect class access modifier ["+strippedToken+"]"); + } + + accessFlags |= accessFlag; + } + } + } + + if (type != null && (type.startsWith("!") ^ set)) + { + int accessFlag = + type.equals("class") ? 0 : + type.equals( ClassConstants.EXTERNAL_ACC_INTERFACE) || + type.equals("!" + ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE : + type.equals( ClassConstants.EXTERNAL_ACC_ENUM) || + type.equals("!" + ClassConstants.EXTERNAL_ACC_ENUM) ? ClassConstants.INTERNAL_ACC_ENUM : + -1; + if (accessFlag == -1) + { + throw new ParseException("Incorrect class type ["+type+"]"); + } + + accessFlags |= accessFlag; + } + + return accessFlags; + } + + + /** + * Creates a specification of class members, based on the given parameters. + */ + private MemberSpecification createMemberSpecification(boolean isMethod, + boolean isConstructor, + Map classSpecificationArgs) + throws ParseException + { + // Extract the arguments. + String access = (String)classSpecificationArgs.get("access"); + String type = (String)classSpecificationArgs.get("type"); + String annotation = (String)classSpecificationArgs.get("annotation"); + String name = (String)classSpecificationArgs.get("name"); + String parameters = (String)classSpecificationArgs.get("parameters"); + + // Perform some basic conversions and checks on the attributes. + if (annotation != null) + { + annotation = ClassUtil.internalType(annotation); + } + + if (isMethod) + { + if (isConstructor) + { + if (type != null) + { + throw new ParseException("Type attribute not allowed in constructor specification ["+type+"]"); + } + + if (parameters != null) + { + type = ClassConstants.EXTERNAL_TYPE_VOID; + } + + name = ClassConstants.INTERNAL_METHOD_NAME_INIT; + } + else if ((type != null) ^ (parameters != null)) + { + throw new ParseException("Type and parameters attributes must always be present in combination in method specification"); + } + } + else + { + if (parameters != null) + { + throw new ParseException("Parameters attribute not allowed in field specification ["+parameters+"]"); + } + } + + List parameterList = ListUtil.commaSeparatedList(parameters); + + String descriptor = + parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) : + type != null ? ClassUtil.internalType(type) : + null; + + return new MemberSpecification(requiredMemberAccessFlags(true, access), + requiredMemberAccessFlags(false, access), + annotation, + name, + descriptor); + } + + + /** + * Parses the class member access flags that must be set (or not), based on + * the given ProGuard-style flag specification. + */ + private int requiredMemberAccessFlags(boolean set, + String access) + throws ParseException + { + int accessFlags = 0; + + if (access != null) + { + StringTokenizer tokenizer = new StringTokenizer(access, " ,"); + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + + if (token.startsWith("!") ^ set) + { + String strippedToken = token.startsWith("!") ? + token.substring(1) : + token; + + int accessFlag = + strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_BRIDGE) ? ClassConstants.INTERNAL_ACC_BRIDGE : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_VARARGS) ? ClassConstants.INTERNAL_ACC_VARARGS : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT : + strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNTHETIC) ? ClassConstants.INTERNAL_ACC_SYNTHETIC : + 0; + + if (accessFlag == 0) + { + throw new ParseException("Incorrect class member access modifier ["+strippedToken+"]"); + } + + accessFlags |= accessFlag; + } + } + } + + return accessFlags; + } + + + /** + * Retrieves a specified boolean flag from the given map. + */ + private boolean retrieveBoolean(Map args, String name, boolean defaultValue) + { + if (args == null) + { + return defaultValue; + } + + Object arg = args.get(name); + + return arg == null ? defaultValue : ((Boolean)arg).booleanValue(); + } + + + /** + * Adds the given class specification to the given list, creating a new list + * if necessary. + */ + private List extendClassSpecifications(List classSpecifications, + ClassSpecification classSpecification) + { + if (classSpecifications == null) + { + classSpecifications = new ArrayList(); + } + + classSpecifications.add(classSpecification); + + return classSpecifications; + } + + + /** + * Adds the given class specifications to the given list, creating a new + * list if necessary. + */ + private List extendClassSpecifications(List classSpecifications, + List additionalClassSpecifications) + { + if (additionalClassSpecifications != null) + { + if (classSpecifications == null) + { + classSpecifications = new ArrayList(); + } + + classSpecifications.addAll(additionalClassSpecifications); + } + + return classSpecifications; + } + + + /** + * Adds the given filter to the given list, creating a new list if + * necessary. + */ + private List extendFilter(List filter, + String filterString) + { + return extendFilter(filter, filterString, false); + } + + + /** + * Adds the given filter to the given list, creating a new list if + * necessary. External class names are converted to internal class names, + * if requested. + */ + private List extendFilter(List filter, + String filterString, + boolean convertExternalClassNames) + { + if (filter == null) + { + filter = new ArrayList(); + } + + if (filterString == null) + { + // Clear the filter to keep all names. + filter.clear(); + } + else + { + if (convertExternalClassNames) + { + filterString = ClassUtil.internalClassName(filterString); + } + + // Append the filter. + filter.addAll(ListUtil.commaSeparatedList(filterString)); + } + + return filter; + } +} diff --git a/src/proguard/gui/ClassPathPanel.java b/src/proguard/gui/ClassPathPanel.java index 95f3d1b..8f41db6 100644 --- a/src/proguard/gui/ClassPathPanel.java +++ b/src/proguard/gui/ClassPathPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -26,7 +26,7 @@ import proguard.util.ListUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; -import java.io.File; +import java.io.*; import java.util.List; /** @@ -141,7 +141,7 @@ class ClassPathPanel extends ListPanel // Up to JDK 1.3.1, setSelectedFiles doesn't show in the file // chooser, so we just use setSelectedFile first. It also sets // the current directory. - chooser.setSelectedFile(selectedFiles[0]); + chooser.setSelectedFile(selectedFiles[0].getAbsoluteFile()); chooser.setSelectedFiles(selectedFiles); int returnValue = chooser.showOpenDialog(owner); @@ -432,7 +432,7 @@ class ClassPathPanel extends ListPanel filter = new StringBuffer().append('('); } - filter.append(ListUtil.commaSeparatedString(additionalFilter)); + filter.append(ListUtil.commaSeparatedString(additionalFilter, true)); } return filter; diff --git a/src/proguard/gui/ClassSpecificationDialog.java b/src/proguard/gui/ClassSpecificationDialog.java index 36d80d4..38a3146 100644 --- a/src/proguard/gui/ClassSpecificationDialog.java +++ b/src/proguard/gui/ClassSpecificationDialog.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,9 +63,10 @@ final class ClassSpecificationDialog extends JDialog private final JRadioButton[] publicRadioButtons; private final JRadioButton[] finalRadioButtons; private final JRadioButton[] abstractRadioButtons; - private final JRadioButton[] enumRadioButtons; - private final JRadioButton[] annotationRadioButtons; private final JRadioButton[] interfaceRadioButtons; + private final JRadioButton[] annotationRadioButtons; + private final JRadioButton[] enumRadioButtons; + private final JRadioButton[] syntheticRadioButtons; private final JTextField annotationTypeTextField = new JTextField(20); private final JTextField classNameTextField = new JTextField(20); @@ -199,9 +200,10 @@ final class ClassSpecificationDialog extends JDialog publicRadioButtons = addRadioButtonTriplet("Public", accessPanel); finalRadioButtons = addRadioButtonTriplet("Final", accessPanel); abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel); - enumRadioButtons = addRadioButtonTriplet("Enum", accessPanel); - annotationRadioButtons = addRadioButtonTriplet("Annotation", accessPanel); interfaceRadioButtons = addRadioButtonTriplet("Interface", accessPanel); + annotationRadioButtons = addRadioButtonTriplet("Annotation", accessPanel); + enumRadioButtons = addRadioButtonTriplet("Enum", accessPanel); + syntheticRadioButtons = addRadioButtonTriplet("Synthetic", accessPanel); // Create the annotation type panel. final JPanel annotationTypePanel = new JPanel(layout); @@ -393,9 +395,10 @@ final class ClassSpecificationDialog extends JDialog setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); - setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); - setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons); + setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); + setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); + setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); // Set the class and annotation text fields. annotationTypeTextField .setText(annotationType == null ? "" : ClassUtil.externalType(annotationType)); @@ -453,9 +456,10 @@ final class ClassSpecificationDialog extends JDialog getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); - getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); - getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons); + getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ANNOTATTION, annotationRadioButtons); + getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ENUM, enumRadioButtons); + getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); // Get the keep class member option lists. classSpecification.fieldSpecifications = memberSpecificationsPanel.getMemberSpecifications(true); diff --git a/src/proguard/gui/ClassSpecificationsPanel.java b/src/proguard/gui/ClassSpecificationsPanel.java index 2cf0b1d..bc29247 100644 --- a/src/proguard/gui/ClassSpecificationsPanel.java +++ b/src/proguard/gui/ClassSpecificationsPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/ExtensionFileFilter.java b/src/proguard/gui/ExtensionFileFilter.java index d67be40..ee09714 100644 --- a/src/proguard/gui/ExtensionFileFilter.java +++ b/src/proguard/gui/ExtensionFileFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/FilterBuilder.java b/src/proguard/gui/FilterBuilder.java index e46193f..c362cb6 100644 --- a/src/proguard/gui/FilterBuilder.java +++ b/src/proguard/gui/FilterBuilder.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/FilterDialog.java b/src/proguard/gui/FilterDialog.java index 1567a31..88dbd8b 100644 --- a/src/proguard/gui/FilterDialog.java +++ b/src/proguard/gui/FilterDialog.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,7 +182,7 @@ public class FilterDialog extends JDialog */ public void setFilter(List filter) { - filterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter) : DEFAULT_FILTER); + filterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_FILTER); } @@ -202,7 +202,7 @@ public class FilterDialog extends JDialog */ public void setJarFilter(List filter) { - jarFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter) : DEFAULT_JAR_FILTER); + jarFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_JAR_FILTER); } @@ -222,7 +222,7 @@ public class FilterDialog extends JDialog */ public void setWarFilter(List filter) { - warFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter) : DEFAULT_WAR_FILTER); + warFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_WAR_FILTER); } @@ -242,7 +242,7 @@ public class FilterDialog extends JDialog */ public void setEarFilter(List filter) { - earFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter) : DEFAULT_EAR_FILTER); + earFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_EAR_FILTER); } @@ -262,7 +262,7 @@ public class FilterDialog extends JDialog */ public void setZipFilter(List filter) { - zipFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter) : DEFAULT_ZIP_FILTER); + zipFilterTextField.setText(filter != null ? ListUtil.commaSeparatedString(filter, true) : DEFAULT_ZIP_FILTER); } diff --git a/src/proguard/gui/GUIResources.java b/src/proguard/gui/GUIResources.java index 85d582c..3d7c6c6 100644 --- a/src/proguard/gui/GUIResources.java +++ b/src/proguard/gui/GUIResources.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/GUIResources.properties b/src/proguard/gui/GUIResources.properties index 86ab7a1..b27075d 100644 --- a/src/proguard/gui/GUIResources.properties +++ b/src/proguard/gui/GUIResources.properties @@ -1,5 +1,5 @@ # ProGuard -- shrinking, optimization, and obfuscation of Java class files. -# Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) +# Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) # # Tab names. @@ -25,7 +25,7 @@ preverification = Preverification # # Panel titles. # -welcome = Welcome to ProGuard, version 4.4 +welcome = Welcome to ProGuard, version 4.10 options = Options keepAdditional = Keep additional classes and class members keepNamesAdditional = Keep additional class names and class member names @@ -51,20 +51,26 @@ whyAreYouKeepingTip = \ # Info texts. # proGuardInfo = \ - ProGuard is a free class file shrinker, optimizer, obfuscator, and preverifier.\ - \n\n\ - With this GUI, you can create, load, modify, and save ProGuard configurations. \ - \n\ + <html>ProGuard is a free class file shrinker, optimizer, obfuscator, and preverifier.\ + <p>\ + With this GUI, you can create, load, modify, and save ProGuard configurations.\ + <br>\ 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.\ + <p>\ With the ReTrace part of this GUI you can de-obfuscate your stack traces.\ - \n\n\ + <p>\ ProGuard and ReTrace are written and maintained by Eric Lafortune.\ - \n\n\ + <p>\ + Official site at Sourceforge: \ + <a href="http://proguard.sourceforge.net/\">http://proguard.sourceforge.net/</a>\ + <br>\ + Professional support by Saikoa: \ + <a href="http://www.saikoa.com/\">http://www.saikoa.com/</a>\ + <p>\ Distributed under the GNU General Public License.\ - \n\ - Copyright (c) 2002-2009. + <br>\ + Copyright © 2002-2013.</html> 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 = \ <li>"*Annotations*" is necessary for preserving annotations.\ </ul>\ The wildcard <code>*</code> and the negator <code>!</code> are allowed.</html> +keepParameterNamesTip = \ + <html>Keep parameter names and types in "LocalVariable*Table" attributes<br>\ + in methods that are not obfuscated.</html> renameSourceFileAttributeTip = \ <html>Put the given string in the "SourceFile" attribute of the processed class files.<br>\ It will appear as the file name of the classes in stack traces.</html> @@ -246,12 +256,12 @@ noteTip = \ noteFilterTip = \ A filter matching classes for which no notes should be printed. warnTip = \ - <html>Print out warnings about possibly erronous input.<br>\ + <html>Print out warnings about possibly erroneous input.<br>\ <i>Only unset this option if you know what you're doing!</i></html> warnFilterTip = \ A filter matching classes for which no warnings should be printed. ignoreWarningsTip = \ - <html>Ignore any warnings about possibly erronous input.<br>\ + <html>Ignore any warnings about possibly erroneous input.<br>\ <i>Only set this option if you know what you're doing!</i></html> skipNonPublicLibraryClassesTip = \ <html>Skip reading non-public library classes, for efficiency.<br>\ @@ -495,6 +505,8 @@ code_simplification_fieldTip = \ Perform peephole optimizations for field loading and storing. code_simplification_branchTip = \ Perform peephole optimizations for branch instructions. +code_simplification_stringTip = \ + Perform peephole optimizations for constant strings. code_simplification_advancedTip = \ Simplify code based on control flow analysis and data flow analysis. code_removal_advancedTip = \ @@ -504,7 +516,7 @@ code_removal_simpleTip = \ code_removal_variableTip = \ Remove unused variables from the local variable frame. code_removal_exceptionTip = \ - Remove exceptions with empty catch blocks. + Remove exceptions with empty try blocks. code_allocation_variableTip = \ Optimize variable allocation on the local variable frame. diff --git a/src/proguard/gui/KeepSpecificationsPanel.java b/src/proguard/gui/KeepSpecificationsPanel.java index 4c3c953..908f028 100644 --- a/src/proguard/gui/KeepSpecificationsPanel.java +++ b/src/proguard/gui/KeepSpecificationsPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/ListPanel.java b/src/proguard/gui/ListPanel.java index 0132340..19a0c4d 100644 --- a/src/proguard/gui/ListPanel.java +++ b/src/proguard/gui/ListPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/MemberSpecificationDialog.java b/src/proguard/gui/MemberSpecificationDialog.java index 46a3f6f..4bf72ca 100644 --- a/src/proguard/gui/MemberSpecificationDialog.java +++ b/src/proguard/gui/MemberSpecificationDialog.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -56,6 +56,7 @@ final class MemberSpecificationDialog extends JDialog private final JRadioButton[] protectedRadioButtons; private final JRadioButton[] staticRadioButtons; private final JRadioButton[] finalRadioButtons; + private final JRadioButton[] syntheticRadioButtons; private JRadioButton[] volatileRadioButtons; private JRadioButton[] transientRadioButtons; @@ -64,6 +65,8 @@ final class MemberSpecificationDialog extends JDialog private JRadioButton[] nativeRadioButtons; private JRadioButton[] abstractRadioButtons; private JRadioButton[] strictRadioButtons; + private JRadioButton[] bridgeRadioButtons; + private JRadioButton[] varargsRadioButtons; private final JTextField annotationTypeTextField = new JTextField(20); private final JTextField nameTextField = new JTextField(20); @@ -166,6 +169,7 @@ final class MemberSpecificationDialog extends JDialog protectedRadioButtons = addRadioButtonTriplet("Protected", accessPanel); staticRadioButtons = addRadioButtonTriplet("Static", accessPanel); finalRadioButtons = addRadioButtonTriplet("Final", accessPanel); + syntheticRadioButtons = addRadioButtonTriplet("Synthetic", accessPanel); if (isField) { @@ -178,6 +182,8 @@ final class MemberSpecificationDialog extends JDialog nativeRadioButtons = addRadioButtonTriplet("Native", accessPanel); abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel); strictRadioButtons = addRadioButtonTriplet("Strict", accessPanel); + bridgeRadioButtons = addRadioButtonTriplet("Bridge", accessPanel); + varargsRadioButtons = addRadioButtonTriplet("Varargs", accessPanel); } // Create the type panel. @@ -332,12 +338,15 @@ final class MemberSpecificationDialog extends JDialog setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_BRIDGE, bridgeRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VARARGS, varargsRadioButtons); // Set the class name text fields. nameTextField.setText(name == null ? "*" : name); @@ -403,12 +412,15 @@ final class MemberSpecificationDialog extends JDialog getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNTHETIC, syntheticRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_BRIDGE, bridgeRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VARARGS, varargsRadioButtons); return memberSpecification; } diff --git a/src/proguard/gui/MemberSpecificationsPanel.java b/src/proguard/gui/MemberSpecificationsPanel.java index 20b2f17..6a72a1d 100644 --- a/src/proguard/gui/MemberSpecificationsPanel.java +++ b/src/proguard/gui/MemberSpecificationsPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/MessageDialogRunnable.java b/src/proguard/gui/MessageDialogRunnable.java index e58f1c6..6c2152c 100644 --- a/src/proguard/gui/MessageDialogRunnable.java +++ b/src/proguard/gui/MessageDialogRunnable.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/OptimizationsDialog.java b/src/proguard/gui/OptimizationsDialog.java index 044c338..0af0979 100644 --- a/src/proguard/gui/OptimizationsDialog.java +++ b/src/proguard/gui/OptimizationsDialog.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/ProGuardGUI.java b/src/proguard/gui/ProGuardGUI.java index f27d698..6b08aa8 100644 --- a/src/proguard/gui/ProGuardGUI.java +++ b/src/proguard/gui/ProGuardGUI.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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 java.io.*; import java.net.URL; import java.util.*; import java.util.List; -import java.lang.reflect.InvocationTargetException; /** @@ -110,6 +109,7 @@ public class ProGuardGUI extends JFrame private final JCheckBox flattenPackageHierarchyCheckBox = new JCheckBox(msg("flattenPackageHierarchy")); private final JCheckBox repackageClassesCheckBox = new JCheckBox(msg("repackageClasses")); private final JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes")); + private final JCheckBox keepParameterNamesCheckBox = new JCheckBox(msg("keepParameterNames")); private final JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute")); private final JCheckBox adaptClassStringsCheckBox = new JCheckBox(msg("adaptClassStrings")); private final JCheckBox adaptResourceFileNamesCheckBox = new JCheckBox(msg("adaptResourceFileNames")); @@ -202,13 +202,13 @@ public class ProGuardGUI extends JFrame splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST; //splashPanelConstraints.insets = constraints.insets; - GridBagConstraints welcomeTextAreaConstraints = new GridBagConstraints(); - welcomeTextAreaConstraints.gridwidth = GridBagConstraints.REMAINDER; - welcomeTextAreaConstraints.fill = GridBagConstraints.NONE; - welcomeTextAreaConstraints.weightx = 1.0; - welcomeTextAreaConstraints.weighty = 0.01; - welcomeTextAreaConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST; - welcomeTextAreaConstraints.insets = new Insets(20, 40, 20, 40); + GridBagConstraints welcomePaneConstraints = new GridBagConstraints(); + welcomePaneConstraints.gridwidth = GridBagConstraints.REMAINDER; + welcomePaneConstraints.fill = GridBagConstraints.NONE; + welcomePaneConstraints.weightx = 1.0; + welcomePaneConstraints.weighty = 0.01; + welcomePaneConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST; + welcomePaneConstraints.insets = new Insets(20, 40, 20, 40); GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; @@ -295,18 +295,19 @@ public class ProGuardGUI extends JFrame splashPanel = new SplashPanel(splash, 0.5, 5500L); splashPanel.setPreferredSize(new Dimension(0, 200)); - JTextArea welcomeTextArea = new JTextArea(msg("proGuardInfo"), 18, 50); - welcomeTextArea.setOpaque(false); - welcomeTextArea.setEditable(false); - welcomeTextArea.setLineWrap(true); - welcomeTextArea.setWrapStyleWord(true); - welcomeTextArea.setPreferredSize(new Dimension(0, 0)); - welcomeTextArea.setBorder(new EmptyBorder(20, 20, 20, 20)); - addBorder(welcomeTextArea, "welcome"); + JEditorPane welcomePane = new JEditorPane("text/html", msg("proGuardInfo")); + welcomePane.setPreferredSize(new Dimension(640, 350)); + // The constant HONOR_DISPLAY_PROPERTIES isn't present yet in JDK 1.4. + //welcomePane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); + welcomePane.putClientProperty("JEditorPane.honorDisplayProperties", Boolean.TRUE); + welcomePane.setOpaque(false); + welcomePane.setEditable(false); + welcomePane.setBorder(new EmptyBorder(20, 20, 20, 20)); + addBorder(welcomePane, "welcome"); JPanel proGuardPanel = new JPanel(layout); proGuardPanel.add(splashPanel, splashPanelConstraints); - proGuardPanel.add(welcomeTextArea, welcomeTextAreaConstraints); + proGuardPanel.add(welcomePane, welcomePaneConstraints); // Create the input panel. // TODO: properly clone the ClassPath objects. @@ -403,6 +404,7 @@ public class ProGuardGUI extends JFrame obfuscationOptionsPanel.add(tip(repackageClassesTextField, "packageTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(keepAttributesCheckBox, "keepAttributesTip"), constraints); obfuscationOptionsPanel.add(tip(keepAttributesTextField, "attributesTip"), constraintsLastStretch); + obfuscationOptionsPanel.add(tip(keepParameterNamesCheckBox, "keepParameterNamesTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(newSourceFileAttributeCheckBox, "renameSourceFileAttributeTip"), constraints); obfuscationOptionsPanel.add(tip(newSourceFileAttributeTextField, "sourceFileAttributeTip"), constraintsLastStretch); obfuscationOptionsPanel.add(tip(adaptClassStringsCheckBox, "adaptClassStringsTip"), constraints); @@ -631,11 +633,14 @@ public class ProGuardGUI extends JFrame reTracePanel .add(tip(loadStackTraceButton, "loadStackTraceTip"), bottomButtonConstraints); reTracePanel .add(tip(reTraceButton, "reTraceTip"), lastBottomButtonConstraints); + // Add the main tabs to the frame. + getContentPane().add(tabs); + + // Pack the entire GUI before setting some default values. + pack(); + // Initialize the GUI settings to reasonable defaults. loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION)); - - // Add the main tabs to the frame and pack it. - getContentPane().add(tabs); } @@ -661,7 +666,9 @@ public class ProGuardGUI extends JFrame { // Parse the boilerplate configuration file. ConfigurationParser parser = new ConfigurationParser( - this.getClass().getResource(BOILERPLATE_CONFIGURATION)); + this.getClass().getResource(BOILERPLATE_CONFIGURATION), + System.getProperties()); + Configuration configuration = new Configuration(); try @@ -1019,6 +1026,7 @@ public class ProGuardGUI extends JFrame flattenPackageHierarchyCheckBox .setSelected(configuration.flattenPackageHierarchy != null); repackageClassesCheckBox .setSelected(configuration.repackageClasses != null); keepAttributesCheckBox .setSelected(configuration.keepAttributes != null); + keepParameterNamesCheckBox .setSelected(configuration.keepParameterNames); newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null); adaptClassStringsCheckBox .setSelected(configuration.adaptClassStrings != null); adaptResourceFileNamesCheckBox .setSelected(configuration.adaptResourceFileNames != null); @@ -1041,21 +1049,23 @@ public class ProGuardGUI extends JFrame dumpCheckBox .setSelected(configuration.dump != null); printUsageTextField .setText(fileName(configuration.printUsage)); - optimizationsTextField .setText(configuration.optimizations == null ? OPTIMIZATIONS_DEFAULT : ListUtil.commaSeparatedString(configuration.optimizations)); + optimizationsTextField .setText(configuration.optimizations == null ? OPTIMIZATIONS_DEFAULT : ListUtil.commaSeparatedString(configuration.optimizations, true)); printMappingTextField .setText(fileName(configuration.printMapping)); applyMappingTextField .setText(fileName(configuration.applyMapping)); obfuscationDictionaryTextField .setText(fileName(configuration.obfuscationDictionary)); - keepPackageNamesTextField .setText(configuration.keepPackageNames == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.keepPackageNames))); + classObfuscationDictionaryTextField .setText(fileName(configuration.classObfuscationDictionary)); + packageObfuscationDictionaryTextField .setText(fileName(configuration.packageObfuscationDictionary)); + keepPackageNamesTextField .setText(configuration.keepPackageNames == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.keepPackageNames, true))); flattenPackageHierarchyTextField .setText(configuration.flattenPackageHierarchy); repackageClassesTextField .setText(configuration.repackageClasses); - keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes)); + keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes, true)); newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute); - adaptClassStringsTextField .setText(configuration.adaptClassStrings == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.adaptClassStrings))); - adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames)); - adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents)); - noteTextField .setText(ListUtil.commaSeparatedString(configuration.note)); - warnTextField .setText(ListUtil.commaSeparatedString(configuration.warn)); - keepDirectoriesTextField .setText(ListUtil.commaSeparatedString(configuration.keepDirectories)); + adaptClassStringsTextField .setText(configuration.adaptClassStrings == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.adaptClassStrings, true))); + adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames, true)); + adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents, true)); + noteTextField .setText(ListUtil.commaSeparatedString(configuration.note, true)); + warnTextField .setText(ListUtil.commaSeparatedString(configuration.warn, true)); + keepDirectoriesTextField .setText(ListUtil.commaSeparatedString(configuration.keepDirectories, true)); printSeedsTextField .setText(fileName(configuration.printSeeds)); printConfigurationTextField .setText(fileName(configuration.printConfiguration)); dumpTextField .setText(fileName(configuration.dump)); @@ -1182,6 +1192,7 @@ public class ProGuardGUI extends JFrame configuration.flattenPackageHierarchy = flattenPackageHierarchyCheckBox .isSelected() ? ClassUtil.internalClassName(flattenPackageHierarchyTextField .getText()) : null; configuration.repackageClasses = repackageClassesCheckBox .isSelected() ? ClassUtil.internalClassName(repackageClassesTextField .getText()) : null; configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField .getText()) : null; + configuration.keepParameterNames = keepParameterNamesCheckBox .isSelected(); configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null; configuration.adaptClassStrings = adaptClassStringsCheckBox .isSelected() ? adaptClassStringsTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(adaptClassStringsTextField.getText())) : new ArrayList() : null; configuration.adaptResourceFileNames = adaptResourceFileNamesCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileNamesTextField .getText()) : null; @@ -1339,7 +1350,9 @@ public class ProGuardGUI extends JFrame try { // Parse the configuration file. - ConfigurationParser parser = new ConfigurationParser(file); + ConfigurationParser parser = new ConfigurationParser(file, + System.getProperties()); + Configuration configuration = new Configuration(); try @@ -1379,7 +1392,9 @@ public class ProGuardGUI extends JFrame try { // Parse the configuration file. - ConfigurationParser parser = new ConfigurationParser(url); + ConfigurationParser parser = new ConfigurationParser(url, + System.getProperties()); + Configuration configuration = new Configuration(); try @@ -1436,13 +1451,13 @@ public class ProGuardGUI extends JFrame /** * Loads the given stack trace into the GUI. */ - private void loadStackTrace(String fileName) + private void loadStackTrace(File file) { try { StringBuffer buffer = new StringBuffer(1024); - Reader reader = new BufferedReader(new FileReader(fileName)); + Reader reader = new BufferedReader(new FileReader(file)); try { while (true) @@ -1467,7 +1482,7 @@ public class ProGuardGUI extends JFrame catch (IOException ex) { JOptionPane.showMessageDialog(getContentPane(), - msg("cantOpenStackTraceFile", fileName), + msg("cantOpenStackTraceFile", fileName(file)), msg("warning"), JOptionPane.ERROR_MESSAGE); } @@ -1600,10 +1615,8 @@ public class ProGuardGUI extends JFrame int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this); if (returnValue == JFileChooser.APPROVE_OPTION) { - File selectedFile = fileChooser.getSelectedFile(); - String fileName = selectedFile.getPath(); - loadStackTrace(fileName); + loadStackTrace(fileChooser.getSelectedFile()); } } } @@ -1641,11 +1654,26 @@ public class ProGuardGUI extends JFrame // Small utility methods. /** - * Returns the file name of the given file, if any. + * Returns the canonical file name for the given file, or the empty string + * if the file name is empty. */ - private static String fileName(File file) + private String fileName(File file) { - return file == null ? "" : file.getAbsolutePath(); + if (file == null) + { + return ""; + } + else + { + try + { + return file.getCanonicalPath(); + } + catch (IOException ex) + { + return file.getPath(); + } + } } @@ -1693,46 +1721,51 @@ public class ProGuardGUI extends JFrame { public void run() { - ProGuardGUI gui = new ProGuardGUI(); - gui.pack(); - - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - Dimension guiSize = gui.getSize(); - gui.setLocation((screenSize.width - guiSize.width) / 2, - (screenSize.height - guiSize.height) / 2); - gui.show(); - - // Start the splash animation, unless specified otherwise. - int argIndex = 0; - if (argIndex < args.length && - NO_SPLASH_OPTION.startsWith(args[argIndex])) - { - gui.skipSplash(); - argIndex++; - } - else - { - gui.startSplash(); - } - - // Load an initial configuration, if specified. - if (argIndex < args.length) + try { - gui.loadConfiguration(new File(args[argIndex])); - argIndex++; + ProGuardGUI gui = new ProGuardGUI(); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension guiSize = gui.getSize(); + gui.setLocation((screenSize.width - guiSize.width) / 2, + (screenSize.height - guiSize.height) / 2); + gui.show(); + + // Start the splash animation, unless specified otherwise. + int argIndex = 0; + if (argIndex < args.length && + NO_SPLASH_OPTION.startsWith(args[argIndex])) + { + gui.skipSplash(); + argIndex++; + } + else + { + gui.startSplash(); + } + + // Load an initial configuration, if specified. + if (argIndex < args.length) + { + gui.loadConfiguration(new File(args[argIndex])); + argIndex++; + } + + if (argIndex < args.length) + { + System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]"); + } } - - if (argIndex < args.length) + catch (Exception e) { - System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]"); + System.out.println("Internal problem starting the ProGuard GUI (" + e.getMessage() + ")"); } - } }); } catch (Exception e) { - // Nothing. + System.out.println("Internal problem starting the ProGuard GUI (" + e.getMessage() + ")"); } } } diff --git a/src/proguard/gui/ProGuardRunnable.java b/src/proguard/gui/ProGuardRunnable.java index c5c5937..b341b7b 100644 --- a/src/proguard/gui/ProGuardRunnable.java +++ b/src/proguard/gui/ProGuardRunnable.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/ReTraceRunnable.java b/src/proguard/gui/ReTraceRunnable.java index 1ca19ca..6f1b135 100644 --- a/src/proguard/gui/ReTraceRunnable.java +++ b/src/proguard/gui/ReTraceRunnable.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/SwingUtil.java b/src/proguard/gui/SwingUtil.java index 75d2f02..373fdc9 100644 --- a/src/proguard/gui/SwingUtil.java +++ b/src/proguard/gui/SwingUtil.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/TabbedPane.java b/src/proguard/gui/TabbedPane.java index a6460f5..c6b6678 100644 --- a/src/proguard/gui/TabbedPane.java +++ b/src/proguard/gui/TabbedPane.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/TextAreaOutputStream.java b/src/proguard/gui/TextAreaOutputStream.java index 57f983d..84ba562 100644 --- a/src/proguard/gui/TextAreaOutputStream.java +++ b/src/proguard/gui/TextAreaOutputStream.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/boilerplate.pro b/src/proguard/gui/boilerplate.pro index 70efb82..711c07d 100644 --- a/src/proguard/gui/boilerplate.pro +++ b/src/proguard/gui/boilerplate.pro @@ -257,13 +257,6 @@ public boolean isInfinite(); public int compareTo(java.lang.Double); - public <init>(byte); - public <init>(short); - public <init>(int); - public <init>(long); - public <init>(float); - public <init>(double); - public <init>(java.lang.String); public byte byteValue(); public short shortValue(); public int intValue(); @@ -280,17 +273,6 @@ # Remove - String method calls. Remove all invocations of String # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.String { - public java.lang.String(); - public java.lang.String(byte[]); - public java.lang.String(byte[],int); - public java.lang.String(byte[],int,int); - public java.lang.String(byte[],int,int,int); - public java.lang.String(byte[],int,int,java.lang.String); - public java.lang.String(byte[],java.lang.String); - public java.lang.String(char[]); - public java.lang.String(char[],int,int); - public java.lang.String(java.lang.String); - public java.lang.String(java.lang.StringBuffer); public static java.lang.String copyValueOf(char[]); public static java.lang.String copyValueOf(char[],int,int); public static java.lang.String valueOf(boolean); @@ -348,10 +330,6 @@ # Remove - StringBuffer method calls. Remove all invocations of StringBuffer # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuffer { - public java.lang.StringBuffer(); - public java.lang.StringBuffer(int); - public java.lang.StringBuffer(java.lang.String); - public java.lang.StringBuffer(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); @@ -368,10 +346,6 @@ # Remove - StringBuilder method calls. Remove all invocations of StringBuilder # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuilder { - public java.lang.StringBuilder(); - public java.lang.StringBuilder(int); - public java.lang.StringBuilder(java.lang.String); - public java.lang.StringBuilder(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); diff --git a/src/proguard/gui/default.pro b/src/proguard/gui/default.pro index 3bfe2d6..752c9b2 100644 --- a/src/proguard/gui/default.pro +++ b/src/proguard/gui/default.pro @@ -190,13 +190,6 @@ public boolean isNaN(); public boolean isInfinite(); public int compareTo(java.lang.Double); - public <init>(byte); - public <init>(short); - public <init>(int); - public <init>(long); - public <init>(float); - public <init>(double); - public <init>(java.lang.String); public byte byteValue(); public short shortValue(); public int intValue(); @@ -212,17 +205,6 @@ # Remove - String method calls. Remove all invocations of String # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.String { - public <init>(); - public <init>(byte[]); - public <init>(byte[],int); - public <init>(byte[],int,int); - public <init>(byte[],int,int,int); - public <init>(byte[],int,int,java.lang.String); - public <init>(byte[],java.lang.String); - public <init>(char[]); - public <init>(char[],int,int); - public <init>(java.lang.String); - public <init>(java.lang.StringBuffer); public static java.lang.String copyValueOf(char[]); public static java.lang.String copyValueOf(char[],int,int); public static java.lang.String valueOf(boolean); @@ -280,10 +262,6 @@ # Remove - StringBuffer method calls. Remove all invocations of StringBuffer # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuffer { - public <init>(); - public <init>(int); - public <init>(java.lang.String); - public <init>(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); @@ -300,10 +278,6 @@ # Remove - StringBuilder method calls. Remove all invocations of StringBuilder # methods without side effects whose return values are not used. -assumenosideeffects public class java.lang.StringBuilder { - public <init>(); - public <init>(int); - public <init>(java.lang.String); - public <init>(java.lang.CharSequence); public java.lang.String toString(); public char charAt(int); public int capacity(); diff --git a/src/proguard/gui/splash/BufferedSprite.java b/src/proguard/gui/splash/BufferedSprite.java index 8427832..5625acb 100644 --- a/src/proguard/gui/splash/BufferedSprite.java +++ b/src/proguard/gui/splash/BufferedSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/CircleSprite.java b/src/proguard/gui/splash/CircleSprite.java index 5dc65eb..0443a0c 100644 --- a/src/proguard/gui/splash/CircleSprite.java +++ b/src/proguard/gui/splash/CircleSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ClipSprite.java b/src/proguard/gui/splash/ClipSprite.java index 55f9eac..a8ac368 100644 --- a/src/proguard/gui/splash/ClipSprite.java +++ b/src/proguard/gui/splash/ClipSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ColorSprite.java b/src/proguard/gui/splash/ColorSprite.java index 3f9bc3b..95153a2 100644 --- a/src/proguard/gui/splash/ColorSprite.java +++ b/src/proguard/gui/splash/ColorSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/CompositeSprite.java b/src/proguard/gui/splash/CompositeSprite.java index 2480ead..68cbe35 100644 --- a/src/proguard/gui/splash/CompositeSprite.java +++ b/src/proguard/gui/splash/CompositeSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantColor.java b/src/proguard/gui/splash/ConstantColor.java index 94c78df..fa7f3a5 100644 --- a/src/proguard/gui/splash/ConstantColor.java +++ b/src/proguard/gui/splash/ConstantColor.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantDouble.java b/src/proguard/gui/splash/ConstantDouble.java index 0874d6d..c969332 100644 --- a/src/proguard/gui/splash/ConstantDouble.java +++ b/src/proguard/gui/splash/ConstantDouble.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantFont.java b/src/proguard/gui/splash/ConstantFont.java index 3f1ac03..26691b9 100644 --- a/src/proguard/gui/splash/ConstantFont.java +++ b/src/proguard/gui/splash/ConstantFont.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantInt.java b/src/proguard/gui/splash/ConstantInt.java index 537196d..ff79dd0 100644 --- a/src/proguard/gui/splash/ConstantInt.java +++ b/src/proguard/gui/splash/ConstantInt.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantString.java b/src/proguard/gui/splash/ConstantString.java index 7617c3f..e76f1eb 100644 --- a/src/proguard/gui/splash/ConstantString.java +++ b/src/proguard/gui/splash/ConstantString.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ConstantTiming.java b/src/proguard/gui/splash/ConstantTiming.java index dfde644..b6a7762 100644 --- a/src/proguard/gui/splash/ConstantTiming.java +++ b/src/proguard/gui/splash/ConstantTiming.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/FontSprite.java b/src/proguard/gui/splash/FontSprite.java index 9a554ba..42f165d 100644 --- a/src/proguard/gui/splash/FontSprite.java +++ b/src/proguard/gui/splash/FontSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ImageSprite.java b/src/proguard/gui/splash/ImageSprite.java index 6e7c189..f7704f9 100644 --- a/src/proguard/gui/splash/ImageSprite.java +++ b/src/proguard/gui/splash/ImageSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/LinearColor.java b/src/proguard/gui/splash/LinearColor.java index 3a7674d..283a1c9 100644 --- a/src/proguard/gui/splash/LinearColor.java +++ b/src/proguard/gui/splash/LinearColor.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/LinearDouble.java b/src/proguard/gui/splash/LinearDouble.java index 046ae84..bf926b0 100644 --- a/src/proguard/gui/splash/LinearDouble.java +++ b/src/proguard/gui/splash/LinearDouble.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/LinearInt.java b/src/proguard/gui/splash/LinearInt.java index 8d299bc..46c35bc 100644 --- a/src/proguard/gui/splash/LinearInt.java +++ b/src/proguard/gui/splash/LinearInt.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/LinearTiming.java b/src/proguard/gui/splash/LinearTiming.java index 9b26644..c35348e 100644 --- a/src/proguard/gui/splash/LinearTiming.java +++ b/src/proguard/gui/splash/LinearTiming.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/OverrideGraphics2D.java b/src/proguard/gui/splash/OverrideGraphics2D.java index 4333459..81a9429 100644 --- a/src/proguard/gui/splash/OverrideGraphics2D.java +++ b/src/proguard/gui/splash/OverrideGraphics2D.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/RectangleSprite.java b/src/proguard/gui/splash/RectangleSprite.java index d204831..547b549 100644 --- a/src/proguard/gui/splash/RectangleSprite.java +++ b/src/proguard/gui/splash/RectangleSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/SawToothTiming.java b/src/proguard/gui/splash/SawToothTiming.java index 076d5e2..393f27e 100644 --- a/src/proguard/gui/splash/SawToothTiming.java +++ b/src/proguard/gui/splash/SawToothTiming.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/ShadowedSprite.java b/src/proguard/gui/splash/ShadowedSprite.java index c3504f3..fadca5f 100644 --- a/src/proguard/gui/splash/ShadowedSprite.java +++ b/src/proguard/gui/splash/ShadowedSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/SineTiming.java b/src/proguard/gui/splash/SineTiming.java index eb0a7cc..ab3d0c1 100644 --- a/src/proguard/gui/splash/SineTiming.java +++ b/src/proguard/gui/splash/SineTiming.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/SmoothTiming.java b/src/proguard/gui/splash/SmoothTiming.java index a985712..a691d3c 100644 --- a/src/proguard/gui/splash/SmoothTiming.java +++ b/src/proguard/gui/splash/SmoothTiming.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/SplashPanel.java b/src/proguard/gui/splash/SplashPanel.java index 23a9ce4..af959e9 100644 --- a/src/proguard/gui/splash/SplashPanel.java +++ b/src/proguard/gui/splash/SplashPanel.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/Sprite.java b/src/proguard/gui/splash/Sprite.java index ada7a81..f1f6e72 100644 --- a/src/proguard/gui/splash/Sprite.java +++ b/src/proguard/gui/splash/Sprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/TextSprite.java b/src/proguard/gui/splash/TextSprite.java index bbf37d4..69bd4c7 100644 --- a/src/proguard/gui/splash/TextSprite.java +++ b/src/proguard/gui/splash/TextSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/TimeSwitchSprite.java b/src/proguard/gui/splash/TimeSwitchSprite.java index 921bef2..dd292ad 100644 --- a/src/proguard/gui/splash/TimeSwitchSprite.java +++ b/src/proguard/gui/splash/TimeSwitchSprite.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/Timing.java b/src/proguard/gui/splash/Timing.java index 887d737..bb15900 100644 --- a/src/proguard/gui/splash/Timing.java +++ b/src/proguard/gui/splash/Timing.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/TypeWriterString.java b/src/proguard/gui/splash/TypeWriterString.java index 9f1441e..d304dca 100644 --- a/src/proguard/gui/splash/TypeWriterString.java +++ b/src/proguard/gui/splash/TypeWriterString.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableColor.java b/src/proguard/gui/splash/VariableColor.java index 6a30062..ce573aa 100644 --- a/src/proguard/gui/splash/VariableColor.java +++ b/src/proguard/gui/splash/VariableColor.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableDouble.java b/src/proguard/gui/splash/VariableDouble.java index 39302dd..7317403 100644 --- a/src/proguard/gui/splash/VariableDouble.java +++ b/src/proguard/gui/splash/VariableDouble.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableFont.java b/src/proguard/gui/splash/VariableFont.java index a7de8d7..0668c38 100644 --- a/src/proguard/gui/splash/VariableFont.java +++ b/src/proguard/gui/splash/VariableFont.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableInt.java b/src/proguard/gui/splash/VariableInt.java index 68a33af..b4523ef 100644 --- a/src/proguard/gui/splash/VariableInt.java +++ b/src/proguard/gui/splash/VariableInt.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableSizeFont.java b/src/proguard/gui/splash/VariableSizeFont.java index e36d28c..52b8ab2 100644 --- a/src/proguard/gui/splash/VariableSizeFont.java +++ b/src/proguard/gui/splash/VariableSizeFont.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/gui/splash/VariableString.java b/src/proguard/gui/splash/VariableString.java index 1dec23b..81ca8f6 100644 --- a/src/proguard/gui/splash/VariableString.java +++ b/src/proguard/gui/splash/VariableString.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/CascadingDataEntryWriter.java b/src/proguard/io/CascadingDataEntryWriter.java index 15719e6..62f3bf7 100644 --- a/src/proguard/io/CascadingDataEntryWriter.java +++ b/src/proguard/io/CascadingDataEntryWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/ClassFilter.java b/src/proguard/io/ClassFilter.java index bf591ab..aabc5ba 100644 --- a/src/proguard/io/ClassFilter.java +++ b/src/proguard/io/ClassFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/ClassReader.java b/src/proguard/io/ClassReader.java index e21968c..0ad382b 100644 --- a/src/proguard/io/ClassReader.java +++ b/src/proguard/io/ClassReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -109,7 +109,7 @@ public class ClassReader implements DataEntryReader } catch (Exception ex) { - throw new IOException("Can't process class ["+dataEntry.getName()+"] ("+ex.getMessage()+")"); + throw (IOException)new IOException("Can't process class ["+dataEntry.getName()+"] ("+ex.getMessage()+")").initCause(ex); } } } diff --git a/src/proguard/io/ClassRewriter.java b/src/proguard/io/ClassRewriter.java index bd19e1d..97e8aef 100644 --- a/src/proguard/io/ClassRewriter.java +++ b/src/proguard/io/ClassRewriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntry.java b/src/proguard/io/DataEntry.java index af0e373..681331b 100644 --- a/src/proguard/io/DataEntry.java +++ b/src/proguard/io/DataEntry.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryClassWriter.java b/src/proguard/io/DataEntryClassWriter.java new file mode 100644 index 0000000..e9f0327 --- /dev/null +++ b/src/proguard/io/DataEntryClassWriter.java @@ -0,0 +1,85 @@ +/* + * 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.io; + +import proguard.classfile.*; +import proguard.classfile.io.*; +import proguard.classfile.util.*; +import proguard.classfile.visitor.*; + +import java.io.*; + +/** + * This ClassVisitor writes out the ProgramClass objects that it visits to the + * given DataEntry, modified to have the correct name. + * + * @author Eric Lafortune + */ +public class DataEntryClassWriter +extends SimplifiedVisitor +implements ClassVisitor +{ + private final DataEntryWriter dataEntryWriter; + private final DataEntry templateDataEntry; + + + /** + * Creates a new DataEntryClassWriter for writing to the given + * DataEntryWriter, based on the given template DataEntry. + */ + public DataEntryClassWriter(DataEntryWriter dataEntryWriter, + DataEntry templateDataEntry) + { + this.dataEntryWriter = dataEntryWriter; + this.templateDataEntry = templateDataEntry; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Rename the data entry if necessary. + String actualClassName = programClass.getName(); + DataEntry actualDataEntry = + new RenamedDataEntry(templateDataEntry, + actualClassName + ClassConstants.CLASS_FILE_EXTENSION); + + try + { + // Get the output entry corresponding to this input entry. + OutputStream outputStream = dataEntryWriter.getOutputStream(actualDataEntry); + if (outputStream != null) + { + // Write the class to the output entry. + DataOutputStream classOutputStream = new DataOutputStream(outputStream); + + new ProgramClassWriter(classOutputStream).visitProgramClass(programClass); + + classOutputStream.flush(); + } + } + catch (IOException e) + { + throw new RuntimeException("Can't write program class ["+actualClassName+"] to ["+actualDataEntry+"] ("+e.getMessage()+")", e); + } + } +} diff --git a/src/proguard/io/DataEntryCopier.java b/src/proguard/io/DataEntryCopier.java index faaa555..440e73b 100644 --- a/src/proguard/io/DataEntryCopier.java +++ b/src/proguard/io/DataEntryCopier.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,11 +64,16 @@ public class DataEntryCopier implements DataEntryReader { InputStream inputStream = dataEntry.getInputStream(); - // Copy the data from the input entry to the output entry. - copyData(inputStream, outputStream); - - // Close the data entries. - dataEntry.closeInputStream(); + try + { + // Copy the data from the input entry to the output entry. + copyData(inputStream, outputStream); + } + finally + { + // Close the data entries. + dataEntry.closeInputStream(); + } } } } @@ -76,6 +81,10 @@ public class DataEntryCopier implements DataEntryReader { System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")"); } + catch (Exception ex) + { + throw (IOException)new IOException("Can't write resource ["+dataEntry.getName()+"] ("+ex.getMessage()+")").initCause(ex); + } } diff --git a/src/proguard/io/DataEntryDirectoryFilter.java b/src/proguard/io/DataEntryDirectoryFilter.java index bb36f3e..5bf46bb 100644 --- a/src/proguard/io/DataEntryDirectoryFilter.java +++ b/src/proguard/io/DataEntryDirectoryFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryFilter.java b/src/proguard/io/DataEntryFilter.java index ddcd0be..b8b6b20 100644 --- a/src/proguard/io/DataEntryFilter.java +++ b/src/proguard/io/DataEntryFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryNameFilter.java b/src/proguard/io/DataEntryNameFilter.java index d6afd2e..5aebcdd 100644 --- a/src/proguard/io/DataEntryNameFilter.java +++ b/src/proguard/io/DataEntryNameFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryObfuscator.java b/src/proguard/io/DataEntryObfuscator.java index aa63af1..c5742e9 100644 --- a/src/proguard/io/DataEntryObfuscator.java +++ b/src/proguard/io/DataEntryObfuscator.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -75,7 +75,7 @@ public class DataEntryObfuscator implements DataEntryReader String dataEntryName = dataEntry.getName(); // Try to find a corresponding class name by removing increasingly - // long suffixes, + // long suffixes. for (int suffixIndex = dataEntryName.length() - 1; suffixIndex > 0; suffixIndex--) @@ -106,25 +106,44 @@ public class DataEntryObfuscator implements DataEntryReader return new RenamedDataEntry(dataEntry, newDataEntryName); } - - // Otherwise stop looking. - break; + else + { + // Otherwise stop looking. + return dataEntry; + } } } } - // Did the package get a new name? - String packagePrefix = ClassUtil.internalPackagePrefix(dataEntryName); - String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); - if (newPackagePrefix != null && - !packagePrefix.equals(newPackagePrefix)) + // Try to find a corresponding package name by increasingly removing + // more subpackages. + String packagePrefix = dataEntryName; + do { - // Return a renamed data entry. - String newDataEntryName = - newPackagePrefix + dataEntryName.substring(packagePrefix.length()); + // Chop off the class name or the last subpackage name. + packagePrefix = ClassUtil.internalPackagePrefix(packagePrefix); - return new RenamedDataEntry(dataEntry, newDataEntryName); + // Is there a package corresponding to the package prefix? + String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); + if (newPackagePrefix != null) + { + // Did the package get a new name? + if (!packagePrefix.equals(newPackagePrefix)) + { + // Return a renamed data entry. + String newDataEntryName = + newPackagePrefix + dataEntryName.substring(packagePrefix.length()); + + return new RenamedDataEntry(dataEntry, newDataEntryName); + } + else + { + // Otherwise stop looking. + return dataEntry; + } + } } + while (packagePrefix.length() > 0); return dataEntry; } diff --git a/src/proguard/io/DataEntryParentFilter.java b/src/proguard/io/DataEntryParentFilter.java index fbeac4f..1cc1997 100644 --- a/src/proguard/io/DataEntryParentFilter.java +++ b/src/proguard/io/DataEntryParentFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryPump.java b/src/proguard/io/DataEntryPump.java index bfe22a3..ddf946b 100644 --- a/src/proguard/io/DataEntryPump.java +++ b/src/proguard/io/DataEntryPump.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryReader.java b/src/proguard/io/DataEntryReader.java index e77f7bf..39dc82d 100644 --- a/src/proguard/io/DataEntryReader.java +++ b/src/proguard/io/DataEntryReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryRenamer.java b/src/proguard/io/DataEntryRenamer.java index 45c61ee..99600ae 100644 --- a/src/proguard/io/DataEntryRenamer.java +++ b/src/proguard/io/DataEntryRenamer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -87,7 +87,7 @@ public class DataEntryRenamer implements DataEntryReader String newName = (String)nameMap.get(name); if (newName != null) { - // Add remove the directory separator if necessary. + // Remove the directory separator if necessary. if (dataEntry.isDirectory() && newName.length() > 0) { @@ -101,4 +101,4 @@ public class DataEntryRenamer implements DataEntryReader missingDataEntryReader.read(dataEntry); } } -}
\ No newline at end of file +} diff --git a/src/proguard/io/DataEntryRewriter.java b/src/proguard/io/DataEntryRewriter.java index eefced4..ec07767 100644 --- a/src/proguard/io/DataEntryRewriter.java +++ b/src/proguard/io/DataEntryRewriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DataEntryWriter.java b/src/proguard/io/DataEntryWriter.java index 9ecf79b..871f823 100644 --- a/src/proguard/io/DataEntryWriter.java +++ b/src/proguard/io/DataEntryWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DirectoryFilter.java b/src/proguard/io/DirectoryFilter.java index a45d1aa..72e2e6d 100644 --- a/src/proguard/io/DirectoryFilter.java +++ b/src/proguard/io/DirectoryFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DirectoryPump.java b/src/proguard/io/DirectoryPump.java index cab2ff3..cd6c2ab 100644 --- a/src/proguard/io/DirectoryPump.java +++ b/src/proguard/io/DirectoryPump.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/DirectoryWriter.java b/src/proguard/io/DirectoryWriter.java index c6605df..7948ee2 100644 --- a/src/proguard/io/DirectoryWriter.java +++ b/src/proguard/io/DirectoryWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/FileDataEntry.java b/src/proguard/io/FileDataEntry.java index d0449ee..618a092 100644 --- a/src/proguard/io/FileDataEntry.java +++ b/src/proguard/io/FileDataEntry.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/FilteredDataEntryReader.java b/src/proguard/io/FilteredDataEntryReader.java index 11da0d4..03b5dd8 100644 --- a/src/proguard/io/FilteredDataEntryReader.java +++ b/src/proguard/io/FilteredDataEntryReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/FilteredDataEntryWriter.java b/src/proguard/io/FilteredDataEntryWriter.java index 40a8c64..b3b751c 100644 --- a/src/proguard/io/FilteredDataEntryWriter.java +++ b/src/proguard/io/FilteredDataEntryWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/Finisher.java b/src/proguard/io/Finisher.java index 8c4cc1e..7d5f93f 100644 --- a/src/proguard/io/Finisher.java +++ b/src/proguard/io/Finisher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/JarReader.java b/src/proguard/io/JarReader.java index f96b4aa..be4c97b 100644 --- a/src/proguard/io/JarReader.java +++ b/src/proguard/io/JarReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/JarWriter.java b/src/proguard/io/JarWriter.java index 3e40cdf..d85e63b 100644 --- a/src/proguard/io/JarWriter.java +++ b/src/proguard/io/JarWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/ManifestRewriter.java b/src/proguard/io/ManifestRewriter.java index f10307e..8a8c7ae 100644 --- a/src/proguard/io/ManifestRewriter.java +++ b/src/proguard/io/ManifestRewriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -55,13 +55,14 @@ public class ManifestRewriter extends DataEntryRewriter /** - * This Reader reads manifest files, joining any split lines. + * This Reader reads manifest files, joining any split lines. It replaces + * the allowed CR/LF/CR+LF alternatives by simple LF in the process. */ private static class SplitLineReader extends FilterReader { - private char[] buffer = new char[2]; - private int bufferIndex = 0; - private int bufferSize = 0; + private static final int NONE = -2; + + private int bufferedCharacter = NONE; public SplitLineReader(Reader reader) @@ -76,45 +77,39 @@ public class ManifestRewriter extends DataEntryRewriter { while (true) { - if (bufferIndex < bufferSize) - { - return buffer[bufferIndex++]; - } + // Get the buffered character or the first character. + int c1 = bufferedCharacter != NONE ? + bufferedCharacter : + super.read(); + + // Clear the buffered character. + bufferedCharacter = NONE; - // Read the first character. - int c1 = super.read(); + // Return it if it's an ordinary character. if (c1 != '\n' && c1 != '\r') { return c1; } - bufferIndex = 0; - bufferSize = 0; - buffer[bufferSize++] = '\n'; - - // Read the second character. + // It's a newline. Read the second character to see if it's a + // continuation. int c2 = super.read(); - if (c2 == ' ') - { - bufferSize = 0; - continue; - } - if (c1 != '\r' || c2 != '\n') + // Skip any corresponding, redundant \n or \r. + if ((c2 == '\n' || c2 == '\r') && c1 != c2) { - buffer[bufferSize++] = (char)c2; - continue; + c2 = super.read(); } - // Read the third character. - int c3 = super.read(); - if (c3 == ' ') + // Isn't it a continuation after all? + if (c2 != ' ') { - bufferSize = 0; - continue; + // Buffer the second character and return a newline. + bufferedCharacter = c2; + return '\n'; } - buffer[bufferSize++] = (char)c3; + // Just continue after the continuation characters. } } @@ -184,7 +179,7 @@ public class ManifestRewriter extends DataEntryRewriter } else if (counter == 70) { - // Insert are newline and space. + // Insert a newline and a space. super.write('\n'); super.write(' '); diff --git a/src/proguard/io/NameFilter.java b/src/proguard/io/NameFilter.java index 2a9fbc3..67d630e 100644 --- a/src/proguard/io/NameFilter.java +++ b/src/proguard/io/NameFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/ParentDataEntryWriter.java b/src/proguard/io/ParentDataEntryWriter.java index 4f16d12..f24ef37 100644 --- a/src/proguard/io/ParentDataEntryWriter.java +++ b/src/proguard/io/ParentDataEntryWriter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/RenamedDataEntry.java b/src/proguard/io/RenamedDataEntry.java index ae2d267..a0f5657 100644 --- a/src/proguard/io/RenamedDataEntry.java +++ b/src/proguard/io/RenamedDataEntry.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/io/ZipDataEntry.java b/src/proguard/io/ZipDataEntry.java index 5779fd8..20a9d3b 100644 --- a/src/proguard/io/ZipDataEntry.java +++ b/src/proguard/io/ZipDataEntry.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute 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/AttributeShrinker.java b/src/proguard/obfuscate/AttributeShrinker.java index a8bc36b..0c3ab94 100644 --- a/src/proguard/obfuscate/AttributeShrinker.java +++ b/src/proguard/obfuscate/AttributeShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -26,6 +26,8 @@ import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.*; +import java.util.Arrays; + /** * This ClassVisitor removes attributes that are not marked as being used or * required. @@ -111,10 +113,7 @@ implements ClassVisitor, } // Clear the remaining array elements. - for (int index = counter; index < length; index++) - { - array[index] = null; - } + Arrays.fill(array, counter, length, null); return counter; } diff --git a/src/proguard/obfuscate/AttributeUsageMarker.java b/src/proguard/obfuscate/AttributeUsageMarker.java index e772324..32a512b 100644 --- a/src/proguard/obfuscate/AttributeUsageMarker.java +++ b/src/proguard/obfuscate/AttributeUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -26,7 +26,7 @@ import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; /** - * This ClassVisitor marks all attributes that it visits. + * This AttributeVisitor marks all attributes that it visits. * * @see AttributeShrinker * diff --git a/src/proguard/obfuscate/ClassObfuscator.java b/src/proguard/obfuscate/ClassObfuscator.java index 9af0c82..9e1a91c 100644 --- a/src/proguard/obfuscate/ClassObfuscator.java +++ b/src/proguard/obfuscate/ClassObfuscator.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -164,6 +164,14 @@ implements ClassVisitor, } + public void visitLibraryClass(LibraryClass libraryClass) + { + // This can happen for dubious input, if the outer class of a program + // class is a library class, and its name is requested. + newClassName = libraryClass.getName(); + } + + // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} @@ -469,13 +477,25 @@ implements ClassVisitor, { // Come up with class names until we get an original one. String newClassName; + String newMixedCaseClassName; do { // Let the factory produce a class name. newClassName = newPackagePrefix + classNameFactory.nextName(); + + newMixedCaseClassName = mixedCaseClassName(newClassName); + } + while (classNamesToAvoid.contains(newMixedCaseClassName)); + + // Explicitly make sure the name isn't used again if we have a + // user-specified dictionary and we're not allowed to have mixed case + // class names -- just to protect against problematic dictionaries. + if (this.classNameFactory != null && + !useMixedCaseClassNames) + { + classNamesToAvoid.add(newMixedCaseClassName); } - while (classNamesToAvoid.contains(mixedCaseClassName(newClassName))); return newClassName; } diff --git a/src/proguard/obfuscate/ClassRenamer.java b/src/proguard/obfuscate/ClassRenamer.java index 143e3fb..4c5e496 100644 --- a/src/proguard/obfuscate/ClassRenamer.java +++ b/src/proguard/obfuscate/ClassRenamer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/DictionaryNameFactory.java b/src/proguard/obfuscate/DictionaryNameFactory.java index f262664..4a7e28c 100644 --- a/src/proguard/obfuscate/DictionaryNameFactory.java +++ b/src/proguard/obfuscate/DictionaryNameFactory.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute 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/MapCleaner.java b/src/proguard/obfuscate/MapCleaner.java index fdefec5..d11f443 100644 --- a/src/proguard/obfuscate/MapCleaner.java +++ b/src/proguard/obfuscate/MapCleaner.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MappingKeeper.java b/src/proguard/obfuscate/MappingKeeper.java index c9d6aa6..7ab1e25 100644 --- a/src/proguard/obfuscate/MappingKeeper.java +++ b/src/proguard/obfuscate/MappingKeeper.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MappingPrinter.java b/src/proguard/obfuscate/MappingPrinter.java index aa8b13e..a28d10c 100644 --- a/src/proguard/obfuscate/MappingPrinter.java +++ b/src/proguard/obfuscate/MappingPrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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.obfuscate; import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; @@ -38,7 +40,8 @@ import java.io.PrintStream; public class MappingPrinter extends SimplifiedVisitor implements ClassVisitor, - MemberVisitor + MemberVisitor, + AttributeVisitor { private final PrintStream ps; @@ -80,11 +83,6 @@ implements ClassVisitor, } - public void visitLibraryClass(LibraryClass libraryClass) - { - } - - // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) @@ -93,7 +91,6 @@ implements ClassVisitor, if (newName != null) { ps.println(" " + - //lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( 0, programField.getName(programClass), @@ -118,9 +115,9 @@ implements ClassVisitor, String newName = MemberObfuscator.newMemberName(programMethod); if (newName != null) { - ps.println(" " + - lineNumberRange(programClass, programMethod) + - ClassUtil.externalFullMethodDescription( + ps.print(" "); + programMethod.attributesAccept(programClass, this); + ps.println(ClassUtil.externalFullMethodDescription( programClass.getName(), 0, programMethod.getName(programClass), @@ -131,17 +128,20 @@ implements ClassVisitor, } - // Small utility methods. + // Implementations for AttributeVisitor. - /** - * Returns the line number range of the given class member, followed by a - * colon, or just an empty String if no range is available. - */ - private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) { - String range = programMember.getLineNumberRange(programClass); - return range != null ? - (range + ":") : - ""; + ps.print(lineNumberTableAttribute.getLowestLineNumber() + ":" + + lineNumberTableAttribute.getHighestLineNumber() + ":"); } } diff --git a/src/proguard/obfuscate/MappingProcessor.java b/src/proguard/obfuscate/MappingProcessor.java index 01c1809..92a916a 100644 --- a/src/proguard/obfuscate/MappingProcessor.java +++ b/src/proguard/obfuscate/MappingProcessor.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MappingReader.java b/src/proguard/obfuscate/MappingReader.java index 24fd26c..51d14ac 100644 --- a/src/proguard/obfuscate/MappingReader.java +++ b/src/proguard/obfuscate/MappingReader.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MemberNameCleaner.java b/src/proguard/obfuscate/MemberNameCleaner.java index c41c59d..5205fee 100644 --- a/src/proguard/obfuscate/MemberNameCleaner.java +++ b/src/proguard/obfuscate/MemberNameCleaner.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MemberNameCollector.java b/src/proguard/obfuscate/MemberNameCollector.java index c248820..1544901 100644 --- a/src/proguard/obfuscate/MemberNameCollector.java +++ b/src/proguard/obfuscate/MemberNameCollector.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MemberNameConflictFixer.java b/src/proguard/obfuscate/MemberNameConflictFixer.java index b9093a6..68e7c05 100644 --- a/src/proguard/obfuscate/MemberNameConflictFixer.java +++ b/src/proguard/obfuscate/MemberNameConflictFixer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/obfuscate/MemberNameFilter.java b/src/proguard/obfuscate/MemberNameFilter.java new file mode 100644 index 0000000..6d95270 --- /dev/null +++ b/src/proguard/obfuscate/MemberNameFilter.java @@ -0,0 +1,120 @@ +/* + * 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.visitor.MemberVisitor; + +/** + * This <code>MemberVisitor</code> delegates its visits to another given + * <code>MemberVisitor</code>, 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 <code>MemberVisitor</code> 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/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/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); } @@ -657,6 +686,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 * stack entries and pushing missing stack entries instead of unmarked @@ -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); } } @@ -1036,244 +1640,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 @@ -79,6 +79,16 @@ implements AttributeVisitor, /** + * Returns whether the instruction at the given offset has ever been + * executed during the partial evaluation. + */ + public boolean isTraced(int instructionOffset) + { + return partialEvaluator.isTraced(instructionOffset); + } + + + /** * Returns whether the specified variable is alive before the instruction * at the given offset. */ diff --git a/src/proguard/optimize/evaluation/LoadingInvocationUnit.java b/src/proguard/optimize/evaluation/LoadingInvocationUnit.java index 8379c57..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 <code>NONE</code> if no variable was initialized. - */ - public int initializedVariable(int instructionOffset) - { - return initializedVariables[instructionOffset]; - } - - // Utility methods to evaluate instruction blocks. /** @@ -702,9 +729,6 @@ implements AttributeVisitor, // Reset the trace value. InstructionOffsetValue traceValue = InstructionOffsetValue.EMPTY_VALUE; - // Reset the initialization flag. - variables.resetInitialization(); - // Note that the instruction is only volatile. Instruction instruction = InstructionFactory.create(code, instructionOffset); @@ -743,9 +767,6 @@ implements AttributeVisitor, throw ex; } - // Collect the offsets of the instructions whose results were used. - initializedVariables[instructionOffset] = variables.getInitializationIndex(); - // Collect the branch targets from the branch unit. InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets(); int branchTargetCount = branchTargets.instructionOffsetCount(); @@ -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,19 +631,32 @@ 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. */ private void markBranchOrigin(int 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))); @@ -380,38 +410,82 @@ 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. */ 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; @@ -138,6 +137,42 @@ implements AttributeVisitor, public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { + // TODO: Remove this when the method inliner has stabilized. + // Catch any unexpected exceptions from the actual visiting method. + try + { + // Process the code. + visitCodeAttribute0(clazz, method, codeAttribute); + } + catch (RuntimeException ex) + { + System.err.println("Unexpected error while inlining method:"); + System.err.println(" Target class = ["+targetClass.getName()+"]"); + System.err.println(" Target method = ["+targetMethod.getName(targetClass)+targetMethod.getDescriptor(targetClass)+"]"); + if (inlining) + { + System.err.println(" Inlined class = ["+clazz.getName()+"]"); + System.err.println(" Inlined method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); + } + System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); + System.err.println("Not inlining this method"); + + if (DEBUG) + { + targetMethod.accept(targetClass, new ClassPrinter()); + if (inlining) + { + method.accept(clazz, new ClassPrinter()); + } + + throw ex; + } + } + } + + + public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) + { if (!inlining) { // codeAttributeComposer.DEBUG = DEBUG = @@ -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 <init> method, except in an <init> method in the // same class. // (!programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) || // (programClass.equals(targetClass) && // targetMethod.getName(targetClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))) && - !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && + !programMethod.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) && // Don't inline a method into itself. (!programMethod.equals(targetMethod) || - !programClass.equals(targetClass)) && + !programClass.equals(targetClass)) && // Only inline the method if it isn't recursing. - !inliningMethods.contains(programMethod) && + !inliningMethods.contains(programMethod) && // Only inline the method if its target class has at least the // same version number as the source class, in order to avoid // introducing incompatible constructs. - targetClass.u4version >= programClass.u4version && + targetClass.u4version >= programClass.u4version && // Only inline the method if it doesn't invoke a super method, or if // it is in the same class. (!SuperInvocationMarker.invokesSuperMethods(programMethod) || - programClass.equals(targetClass)) && + programClass.equals(targetClass)) && // Only inline the method if it doesn't branch backward while there // are uninitialized objects. (!BackwardBranchMarker.branchesBackward(programMethod) || - uninitializedObjectCount == 0) && + uninitializedObjectCount == 0) && // Only inline if the code access of the inlined method allows it. (allowAccessModification || @@ -501,47 +539,24 @@ implements AttributeVisitor, (!AccessMethodMarker.accessesPackageCode(programMethod) || ClassUtil.internalPackageName(programClass.getName()).equals( - ClassUtil.internalPackageName(targetClass.getName()))))) && + ClassUtil.internalPackageName(targetClass.getName()))))) && // (!AccessMethodMarker.accessesProtectedCode(programMethod) || // targetClass.extends_(programClass) || // targetClass.implements_(programClass)) || (!AccessMethodMarker.accessesProtectedCode(programMethod) || - programClass.equals(targetClass)) && + programClass.equals(targetClass)) && // Only inline the method if it doesn't catch exceptions, or if it // is invoked with an empty stack. (!CatchExceptionMarker.catchesExceptions(programMethod) || - emptyInvokingStack) && + emptyInvokingStack) && - // Only inline the method if it comes from the same class or from - // a class with a static initializer. + // Only inline the method if it comes from the a class with at most + // a subset of the initialized superclasses. (programClass.equals(targetClass) || - programClass.findMethod(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, - ClassConstants.INTERNAL_METHOD_TYPE_CLINIT) == null)) - { -// System.out.print("MethodInliner: inlining "); -// programMethod.accept(programClass, new SimpleClassPrinter(true)); -// System.out.print(" in "); -// targetMethod.accept(targetClass, new SimpleClassPrinter(true)); -// -// System.out.println(" Private: "+ -// (!AccessMethodMarker.accessesPrivateCode(programMethod) || -// programClass.equals(targetClass))); -// -// System.out.println(" Package: "+ -// (!AccessMethodMarker.accessesPackageCode(programMethod) || -// ClassUtil.internalPackageName(programClass.getName()).equals( -// ClassUtil.internalPackageName(targetClass.getName())))); -// -// System.out.println(" Protected: "+ -// ((!AccessMethodMarker.accessesProtectedCode(programMethod) || -// targetClass.extends_(programClass) || -// targetClass.implements_(programClass)) || -// ClassUtil.internalPackageName(programClass.getName()).equals( -// ClassUtil.internalPackageName(targetClass.getName())))); - - boolean oldInlining = inlining; + initializedSuperClasses(targetClass).containsAll(initializedSuperClasses(programClass)))) + { boolean oldInlining = inlining; inlining = true; inliningMethods.push(programMethod); @@ -564,4 +579,21 @@ implements AttributeVisitor, uninitializedObjectCount--; } } + + + /** + * Returns the set of superclasses and interfaces that are initialized. + */ + private Set initializedSuperClasses(Clazz clazz) + { + Set set = new HashSet(); + + // Visit all superclasses and interfaces, collecting the ones that have + // static initializers. + clazz.hierarchyAccept(true, true, true, false, + new StaticInitializerContainingClassFilter( + new ClassCollector(set))); + + return set; + } } diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/peephole/NopRemover.java index 69adb30..9396c40 100644 --- a/src/proguard/optimize/peephole/NopRemover.java +++ b/src/proguard/optimize/peephole/NopRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/PeepholeOptimizer.java b/src/proguard/optimize/peephole/PeepholeOptimizer.java index 98f8e8d..2a602ee 100644 --- a/src/proguard/optimize/peephole/PeepholeOptimizer.java +++ b/src/proguard/optimize/peephole/PeepholeOptimizer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/ReachableCodeMarker.java b/src/proguard/optimize/peephole/ReachableCodeMarker.java index d9dbf2d..b6fcf18 100644 --- a/src/proguard/optimize/peephole/ReachableCodeMarker.java +++ b/src/proguard/optimize/peephole/ReachableCodeMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -27,6 +27,8 @@ import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; +import java.util.Arrays; + /** * This AttributeVisitor finds all instruction offsets, branch targets, and * exception targets in the CodeAttribute objects that it visits. @@ -91,10 +93,7 @@ implements AttributeVisitor, else { // Reset the array. - for (int index = 0; index < codeLength; index++) - { - isReachable[index] = false; - } + Arrays.fill(isReachable, 0, codeLength, false); } // Mark the code, starting at the entry point. diff --git a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java index 6707a12..a67c6ff 100644 --- a/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java +++ b/src/proguard/optimize/peephole/RetargetedInnerClassAttributeRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -28,6 +28,8 @@ import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.ClassVisitor; +import java.util.Arrays; + /** * This ClassVisitor removes InnerClasses and EnclosingMethod attributes in * classes that are retargeted or that refer to classes that are retargeted. @@ -70,12 +72,9 @@ implements ClassVisitor, } // Clean up any remaining array elements. - for (int index = newAtributesCount; index < attributesCount; index++) - { - attributes[index] = null; - } + Arrays.fill(attributes, newAtributesCount, attributesCount, null); - // Update the number of attribuets. + // Update the number of attributes. programClass.u2attributesCount = newAtributesCount; } @@ -90,8 +89,39 @@ implements ClassVisitor, // Check whether the class itself is retargeted. checkTarget(clazz); - // Check whether the referenced classes are retargeted. - innerClassesAttribute.innerClassEntriesAccept(clazz, this); + if (!retargeted) + { + // Check whether the referenced classes are retargeted. + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + int classesCount = innerClassesAttribute.u2classesCount; + InnerClassesInfo[] classes = innerClassesAttribute.classes; + + int newClassesCount = 0; + + // Copy over all non-retargeted attributes. + for (int index = 0; index < classesCount; index++) + { + InnerClassesInfo classInfo = classes[index]; + + // Check if the outer class or inner class is a retargeted class. + retargeted = false; + classInfo.outerClassConstantAccept(clazz, this); + classInfo.innerClassConstantAccept(clazz, this); + if (!retargeted) + { + classes[newClassesCount++] = classInfo; + } + } + + // Clean up any remaining array elements. + Arrays.fill(classes, newClassesCount, classesCount, null); + + // Update the number of classes. + innerClassesAttribute.u2classesCount = newClassesCount; + + // Remove the attribute altogether if it's empty. + retargeted = newClassesCount == 0; + } } diff --git a/src/proguard/optimize/peephole/TargetClassChanger.java b/src/proguard/optimize/peephole/TargetClassChanger.java index 22fd83d..f997e03 100644 --- a/src/proguard/optimize/peephole/TargetClassChanger.java +++ b/src/proguard/optimize/peephole/TargetClassChanger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -51,13 +51,13 @@ implements ClassVisitor, AnnotationVisitor, ElementValueVisitor { + private static final boolean DEBUG = false; + + // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { - Clazz superClass = null; - Clazz[] interfaceClasses = null; - // Change the references of the constant pool. programClass.constantPoolEntriesAccept(this); @@ -80,34 +80,39 @@ implements ClassVisitor, programClass.getName(), programClass); + // This class will loose all its interfaces. + programClass.u2interfacesCount = 0; + // This class will loose all its subclasses. programClass.subClasses = null; } - - // Remove interface classes that are pointing to this class. - int newInterfacesCount = 0; - for (int index = 0; index < programClass.u2interfacesCount; index++) + else { - Clazz interfaceClass = programClass.getInterface(index); - if (!programClass.equals(interfaceClass)) + // Remove interface classes that are pointing to this class. + int newInterfacesCount = 0; + for (int index = 0; index < programClass.u2interfacesCount; index++) { - programClass.u2interfaces[newInterfacesCount++] = - programClass.u2interfaces[index]; + Clazz interfaceClass = programClass.getInterface(index); + if (!programClass.equals(interfaceClass)) + { + programClass.u2interfaces[newInterfacesCount++] = + programClass.u2interfaces[index]; + } } - } - programClass.u2interfacesCount = newInterfacesCount; + programClass.u2interfacesCount = newInterfacesCount; - // Update the subclasses of the superclass and interfaces of the - // target class. - ConstantVisitor subclassAdder = - new ReferencedClassVisitor( - new SubclassFilter(programClass, - new SubclassAdder(programClass))); + // Update the subclasses of the superclass and interfaces of the + // target class. + ConstantVisitor subclassAdder = + new ReferencedClassVisitor( + new SubclassFilter(programClass, + new SubclassAdder(programClass))); - programClass.superClassConstantAccept(subclassAdder); - programClass.interfaceConstantsAccept(subclassAdder); + programClass.superClassConstantAccept(subclassAdder); + programClass.interfaceConstantsAccept(subclassAdder); - // TODO: Maybe restore private method references. + // TODO: Maybe restore private method references. + } } @@ -188,6 +193,12 @@ implements ClassVisitor, Clazz newReferencedClass = updateReferencedClass(referencedClass); if (referencedClass != newReferencedClass) { + if (DEBUG) + { + System.out.println("TargetClassChanger:"); + System.out.println(" ["+clazz.getName()+"] changing reference from ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); + } + // Change the referenced class. refConstant.referencedClass = newReferencedClass; @@ -197,6 +208,11 @@ implements ClassVisitor, refConstant.getName(clazz), refConstant.getType(clazz), newReferencedClass); + + if (DEBUG) + { + System.out.println(" ["+clazz.getName()+"] to ["+refConstant.referencedClass+"."+refConstant.referencedMember.getName(refConstant.referencedClass)+refConstant.referencedMember.getDescriptor(refConstant.referencedClass)+"]"); + } } } diff --git a/src/proguard/optimize/peephole/UnreachableCodeRemover.java b/src/proguard/optimize/peephole/UnreachableCodeRemover.java index e8a99ab..570b3ca 100644 --- a/src/proguard/optimize/peephole/UnreachableCodeRemover.java +++ b/src/proguard/optimize/peephole/UnreachableCodeRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java index 048f5e3..8e77716 100644 --- a/src/proguard/optimize/peephole/UnreachableExceptionRemover.java +++ b/src/proguard/optimize/peephole/UnreachableExceptionRemover.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/VariableShrinker.java b/src/proguard/optimize/peephole/VariableShrinker.java index 45b694f..6c05944 100644 --- a/src/proguard/optimize/peephole/VariableShrinker.java +++ b/src/proguard/optimize/peephole/VariableShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/optimize/peephole/VerticalClassMerger.java b/src/proguard/optimize/peephole/VerticalClassMerger.java index 29ed6ff..825de94 100644 --- a/src/proguard/optimize/peephole/VerticalClassMerger.java +++ b/src/proguard/optimize/peephole/VerticalClassMerger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/preverify/CodePreverifier.java b/src/proguard/preverify/CodePreverifier.java index fa60b9a..7c38259 100644 --- a/src/proguard/preverify/CodePreverifier.java +++ b/src/proguard/preverify/CodePreverifier.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,8 +42,7 @@ import java.util.*; */ public class CodePreverifier extends SimplifiedVisitor -implements MemberVisitor, - AttributeVisitor +implements AttributeVisitor { //* private static final boolean DEBUG = false; @@ -54,8 +53,9 @@ implements MemberVisitor, private final boolean microEdition; - private final PartialEvaluator partialEvaluator = new PartialEvaluator(); - private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(partialEvaluator); + private final PartialEvaluator partialEvaluator = new PartialEvaluator(); + private final LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(partialEvaluator); + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); /** @@ -102,18 +102,27 @@ implements MemberVisitor, ProgramClass programClass = (ProgramClass)clazz; ProgramMethod programMethod = (ProgramMethod)method; + int codeLength = codeAttribute.u4codeLength; + // Evaluate the method. //partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute); livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); + // We may have to remove unreachable code. + codeAttributeEditor.reset(codeLength); + // Collect the stack map frames. List stackMapFrameList = new ArrayList(); - for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) + for (int offset = 0; offset < codeLength; offset++) { // Only store frames at the beginning of code blocks. - if (partialEvaluator.isTraced(offset) && - partialEvaluator.isBranchOrExceptionTarget(offset)) + if (!partialEvaluator.isTraced(offset)) + { + // Mark the unreachable instruction for deletion. + codeAttributeEditor.deleteInstruction(offset); + } + else if (partialEvaluator.isBranchOrExceptionTarget(offset)) { // Convert the variable values to types. VerificationType[] variableTypes = @@ -235,6 +244,9 @@ implements MemberVisitor, stackMapAttribute.accept(programClass, programMethod, codeAttribute, new ClassPrinter()); } } + + // Apply code modifications, deleting unreachable code. + codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); } @@ -433,7 +445,7 @@ implements MemberVisitor, isDupOrSwap(codeAttribute.code[producerOffset])) { producers = partialEvaluator.getStackBefore(producerOffset).getTopProducerValue(0).instructionOffsetValue(); - producerOffset = producers.instructionOffset(0); + producerOffset = producers.minimumValue(); } // Are we in an instance initialization method, diff --git a/src/proguard/preverify/CodeSubroutineInliner.java b/src/proguard/preverify/CodeSubroutineInliner.java index 603eb75..c1549a3 100644 --- a/src/proguard/preverify/CodeSubroutineInliner.java +++ b/src/proguard/preverify/CodeSubroutineInliner.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -45,12 +45,12 @@ implements AttributeVisitor, //* private static final boolean DEBUG = false; /*/ - private static boolean DEBUG = true; + private static boolean DEBUG = System.getProperty("csi") != null; //*/ private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); - private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(true); + private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(true, true); private ExceptionInfoVisitor subroutineExceptionInliner = this; private int clipStart = 0; @@ -67,6 +67,7 @@ implements AttributeVisitor, // DEBUG = // clazz.getName().equals("abc/Def") && // method.getName(clazz).equals("abc"); +// CodeAttributeComposer.DEBUG = DEBUG; // TODO: Remove this when the subroutine inliner has stabilized. // Catch any unexpected exceptions from the actual visiting method. @@ -97,7 +98,7 @@ implements AttributeVisitor, branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); // Don't bother if there aren't any subroutines anyway. - if (!containsSubroutines(codeAttribute)) + if (!branchTargetFinder.containsSubroutines()) { return; } @@ -161,23 +162,6 @@ implements AttributeVisitor, /** - * Returns whether the given code attribute contains any subroutines. - */ - private boolean containsSubroutines(CodeAttribute codeAttribute) - { - for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) - { - if (branchTargetFinder.isSubroutineInvocation(offset)) - { - return true; - } - } - - return false; - } - - - /** * Appends the specified subroutine. */ private void inlineSubroutine(Clazz clazz, @@ -245,7 +229,7 @@ implements AttributeVisitor, public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) { // Append the instruction. - codeAttributeComposer.appendInstruction(offset, instruction.shrink()); + codeAttributeComposer.appendInstruction(offset, instruction); } @@ -275,7 +259,7 @@ implements AttributeVisitor, // Replace the instruction by a branch. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, - branchTargetFinder.subroutineEnd(offset) - offset).shrink(); + branchTargetFinder.subroutineEnd(offset) - offset); codeAttributeComposer.appendInstruction(offset, replacementInstruction); } @@ -331,7 +315,7 @@ implements AttributeVisitor, // Replace the subroutine invocation by a simple branch. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO, - branchOffset).shrink(); + branchOffset); codeAttributeComposer.appendInstruction(offset, replacementInstruction); } diff --git a/src/proguard/preverify/Preverifier.java b/src/proguard/preverify/Preverifier.java index e071c5c..da9649b 100644 --- a/src/proguard/preverify/Preverifier.java +++ b/src/proguard/preverify/Preverifier.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -59,13 +59,12 @@ public class Preverifier new AllAttributeVisitor( new CodePreverifier(configuration.microEdition))); - // In Java Standard Edition, only class files from Java 6 or higher - // should be preverified. + // Classes from Java 6 may optionally be preverified. + // Classes from Java 7 or higher must be preverified. if (!configuration.microEdition) { preverifier = new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_6, - Integer.MAX_VALUE, preverifier); } diff --git a/src/proguard/preverify/SubroutineInliner.java b/src/proguard/preverify/SubroutineInliner.java index e28512f..e21c469 100644 --- a/src/proguard/preverify/SubroutineInliner.java +++ b/src/proguard/preverify/SubroutineInliner.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -65,7 +65,6 @@ public class SubroutineInliner { inliner = new ClassVersionFilter(ClassConstants.INTERNAL_CLASS_VERSION_1_6, - Integer.MAX_VALUE, inliner); } diff --git a/src/proguard/retrace/ReTrace.java b/src/proguard/retrace/ReTrace.java index bf6a145..91ab2a7 100644 --- a/src/proguard/retrace/ReTrace.java +++ b/src/proguard/retrace/ReTrace.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,17 +40,14 @@ implements MappingProcessor private static final String REGEX_OPTION = "-regex"; private static final String VERBOSE_OPTION = "-verbose"; - // BEGIN android-changed - // Use regex from latest version (4.9) because it is - // able to handle Android Bugreport format + public static final String STACK_TRACE_EXPRESSION = "(?:.*?\\bat\\s+%c.%m\\s*\\(.*?(?::%l)?\\)\\s*)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)"; - // END android-changed private static final String REGEX_CLASS = "\\b(?:[A-Za-z0-9_$]+\\.)*[A-Za-z0-9_$]+\\b"; private static final String REGEX_CLASS_SLASH = "\\b(?:[A-Za-z0-9_$]+/)*[A-Za-z0-9_$]+\\b"; private static final String REGEX_LINE_NUMBER = "\\b[0-9]+\\b"; private static final String REGEX_TYPE = REGEX_CLASS + "(?:\\[\\])*"; - private static final String REGEX_MEMBER = "\\b[A-Za-z0-9_$]+\\b"; + private static final String REGEX_MEMBER = "<?\\b[A-Za-z0-9_$]+\\b>?"; private static final String REGEX_ARGUMENTS = "(?:" + REGEX_TYPE + "(?:\\s*,\\s*" + REGEX_TYPE + ")*)?"; // The class settings. diff --git a/src/proguard/shrink/AnnotationUsageMarker.java b/src/proguard/shrink/AnnotationUsageMarker.java index 9aaae34..b9051a0 100644 --- a/src/proguard/shrink/AnnotationUsageMarker.java +++ b/src/proguard/shrink/AnnotationUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,8 +52,7 @@ implements AttributeVisitor, // Fields acting as a return parameters for several methods. private boolean attributeUsed; private boolean annotationUsed; - private boolean elementValueUsed; - private boolean classUsed; + private boolean allClassesUsed; private boolean methodUsed; @@ -151,9 +150,6 @@ implements AttributeVisitor, markConstant(clazz, constantElementValue.u2elementNameIndex); markConstant(clazz, constantElementValue.u2constantValueIndex); - - // The return value. - elementValueUsed = true; } } @@ -163,10 +159,10 @@ implements AttributeVisitor, if (isReferencedMethodUsed(enumConstantElementValue)) { // Check the referenced classes. - classUsed = true; - enumConstantElementValue.referencedClassesAccept(usageMarker); + allClassesUsed = true; + enumConstantElementValue.referencedClassesAccept(this); - if (classUsed) + if (allClassesUsed) { // Mark the element value as being used. usageMarker.markAsUsed(enumConstantElementValue); @@ -174,9 +170,6 @@ implements AttributeVisitor, markConstant(clazz, enumConstantElementValue.u2elementNameIndex); markConstant(clazz, enumConstantElementValue.u2typeNameIndex); markConstant(clazz, enumConstantElementValue.u2constantNameIndex); - - // The return value. - elementValueUsed = true; } } } @@ -186,21 +179,16 @@ implements AttributeVisitor, { if (isReferencedMethodUsed(classElementValue)) { - // Check the referenced classes. - classUsed = true; - classElementValue.referencedClassesAccept(usageMarker); - - if (classUsed) - { - // Mark the element value as being used. - usageMarker.markAsUsed(classElementValue); + // Mark the element value as being used. + usageMarker.markAsUsed(classElementValue); - markConstant(clazz, classElementValue.u2elementNameIndex); - markConstant(clazz, classElementValue.u2classInfoIndex); + markConstant(clazz, classElementValue.u2elementNameIndex); + markConstant(clazz, classElementValue.u2classInfoIndex); - // The return value. - elementValueUsed = true; - } + // Mark the referenced classes, since they can be retrieved from + // the annotation and then used. + // TODO: This could mark more annotation methods, affecting other annotations. + classElementValue.referencedClassesAccept(usageMarker); } } @@ -221,9 +209,6 @@ implements AttributeVisitor, usageMarker.markAsUsed(annotationElementValue); markConstant(clazz, annotationElementValue.u2elementNameIndex); - - // The return value. - elementValueUsed = true; } annotationUsed = oldAnnotationUsed; @@ -235,26 +220,13 @@ implements AttributeVisitor, { if (isReferencedMethodUsed(arrayElementValue)) { - boolean oldelementValueUsed = elementValueUsed; - // Check and mark the contained element values. - elementValueUsed = false; arrayElementValue.elementValuesAccept(clazz, annotation, this); - if (elementValueUsed) - { - // Mark the element value as being used. - usageMarker.markAsUsed(arrayElementValue); - - markConstant(clazz, arrayElementValue.u2elementNameIndex); + // Mark the element value as being used. + usageMarker.markAsUsed(arrayElementValue); - // The return value. - //elementValueUsed = true; - } - else - { - elementValueUsed = oldelementValueUsed; - } + markConstant(clazz, arrayElementValue.u2elementNameIndex); } } @@ -269,17 +241,15 @@ implements AttributeVisitor, public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { - classUsed = usageMarker.isUsed(classConstant); - // Is the class constant marked as being used? - if (!classUsed) + if (!usageMarker.isUsed(classConstant)) { // Check the referenced class. - classUsed = true; + allClassesUsed = true; classConstant.referencedClassAccept(this); // Is the referenced class marked as being used? - if (classUsed) + if (allClassesUsed) { // Mark the class constant and its Utf8 constant. usageMarker.markAsUsed(classConstant); @@ -294,13 +264,12 @@ implements AttributeVisitor, public void visitProgramClass(ProgramClass programClass) { - classUsed = usageMarker.isUsed(programClass); + allClassesUsed &= usageMarker.isUsed(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { - classUsed = true; } @@ -314,7 +283,6 @@ implements AttributeVisitor, public void visitLibraryMethod(LibraryClass LibraryClass, LibraryMethod libraryMethod) { - classUsed = true; } @@ -326,10 +294,10 @@ implements AttributeVisitor, private boolean isReferencedClassUsed(Annotation annotation) { // Check if the referenced class is being used. - classUsed = true; + allClassesUsed = true; annotation.referencedClassAccept(this); - return classUsed; + return allClassesUsed; } diff --git a/src/proguard/shrink/ClassShrinker.java b/src/proguard/shrink/ClassShrinker.java index 0b5c5b7..f590c63 100644 --- a/src/proguard/shrink/ClassShrinker.java +++ b/src/proguard/shrink/ClassShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,15 +24,17 @@ import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; -import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; +import java.util.Arrays; + /** - * This ClassVisitor removes constant pool entries and class members that - * are not marked as being used. + * This ClassVisitor removes constant pool entries, class members, and other + * class elements that are not marked as being used. * * @see UsageMarker * @@ -48,8 +50,7 @@ implements ClassVisitor, { private final UsageMarker usageMarker; - private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; - + private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); @@ -76,7 +77,7 @@ implements ClassVisitor, programClass.u2interfacesCount); // Shrinking the constant pool also sets up an index map. - programClass.u2constantPoolCount = + int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); @@ -98,9 +99,15 @@ implements ClassVisitor, programClass.methodsAccept(this); programClass.attributesAccept(this); - // Remap all constant pool references. - constantPoolRemapper.setConstantIndexMap(constantIndexMap); - constantPoolRemapper.visitProgramClass(programClass); + // 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); + } // Remove the unused interfaces from the class signature. programClass.attributesAccept(new SignatureShrinker()); @@ -140,6 +147,15 @@ implements ClassVisitor, public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + // Shrink the array of BootstrapMethodInfo objects. + bootstrapMethodsAttribute.u2bootstrapMethodsCount = + shrinkArray(bootstrapMethodsAttribute.bootstrapMethods, + bootstrapMethodsAttribute.u2bootstrapMethodsCount); + } + + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Shrink the array of InnerClassesInfo objects. @@ -173,6 +189,27 @@ implements ClassVisitor, codeAttribute.u2attributesCount = shrinkArray(codeAttribute.attributes, codeAttribute.u2attributesCount); + + // Shrink the attributes themselves. + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + // Shrink the local variable info array. + localVariableTableAttribute.u2localVariableTableLength = + shrinkArray(localVariableTableAttribute.localVariableTable, + localVariableTableAttribute.u2localVariableTableLength); + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + // Shrink the local variable type info array. + localVariableTypeTableAttribute.u2localVariableTypeTableLength = + shrinkArray(localVariableTypeTableAttribute.localVariableTypeTable, + localVariableTypeTableAttribute.u2localVariableTypeTableLength); } @@ -349,10 +386,7 @@ implements ClassVisitor, } // Clear the remaining constant pool elements. - for (int index = counter; index < length; index++) - { - constantPool[index] = null; - } + Arrays.fill(constantPool, counter, length, null); return counter; } @@ -377,10 +411,7 @@ implements ClassVisitor, } // Clear the remaining array elements. - for (int index = counter; index < length; index++) - { - array[index] = 0; - } + Arrays.fill(array, counter, length, 0); return counter; } @@ -437,10 +468,10 @@ implements ClassVisitor, } } - // Clear the remaining array elements. - for (int index = counter; index < length; index++) + // Clear any remaining array elements. + if (counter < length) { - array[index] = null; + Arrays.fill(array, counter, length, null); } return counter; diff --git a/src/proguard/shrink/InnerUsageMarker.java b/src/proguard/shrink/InnerUsageMarker.java index b8ca801..6d77e81 100644 --- a/src/proguard/shrink/InnerUsageMarker.java +++ b/src/proguard/shrink/InnerUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/shrink/InterfaceUsageMarker.java b/src/proguard/shrink/InterfaceUsageMarker.java index 7599898..240838e 100644 --- a/src/proguard/shrink/InterfaceUsageMarker.java +++ b/src/proguard/shrink/InterfaceUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/shrink/LocalVariableTypeUsageMarker.java b/src/proguard/shrink/LocalVariableTypeUsageMarker.java new file mode 100644 index 0000000..573d8f6 --- /dev/null +++ b/src/proguard/shrink/LocalVariableTypeUsageMarker.java @@ -0,0 +1,178 @@ +/* + * 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.shrink; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This AttributeVisitor recursively marks all information that points to used + * classes, in the LocalVariableTable and LocalVariableTypeTable attributes that + * it visits. + * + * @see UsageMarker + * + * @author Eric Lafortune + */ +public class LocalVariableTypeUsageMarker +extends SimplifiedVisitor +implements AttributeVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + ClassVisitor, + ConstantVisitor +{ + private final UsageMarker usageMarker; + + // Fields acting as a return parameters for several methods. + private boolean tableUsed; + private boolean variableInfoUsed; + + + /** + * Creates a new LocalVariableTypeUsageMarker. + * @param usageMarker the usage marker that is used to mark the classes + * and class members. + */ + public LocalVariableTypeUsageMarker(UsageMarker usageMarker) + { + this.usageMarker = usageMarker; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + // Check and mark the individual entries. + tableUsed = false; + localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + + // Mark the table if any of the entries is marked. + if (tableUsed) + { + usageMarker.markAsUsed(localVariableTableAttribute); + + markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); + } + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + // Check and mark the individual entries. + tableUsed = false; + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + + // Mark the table if any of the entries is marked. + if (tableUsed) + { + usageMarker.markAsUsed(localVariableTypeTableAttribute); + + markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + } + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + // Only keep the local variable info if all of its classes are used. + variableInfoUsed = true; + localVariableInfo.referencedClassAccept(this); + + if (variableInfoUsed) + { + // We got a positive used flag, so the local variable info is useful. + usageMarker.markAsUsed(localVariableInfo); + + markConstant(clazz, localVariableInfo.u2nameIndex); + markConstant(clazz, localVariableInfo.u2descriptorIndex); + + tableUsed = true; + } + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + // Only keep the local variable info if all of its classes are used. + variableInfoUsed = true; + localVariableTypeInfo.referencedClassesAccept(this); + + if (variableInfoUsed) + { + // We got a positive used flag, so the local variable info is useful. + usageMarker.markAsUsed(localVariableTypeInfo); + + markConstant(clazz, localVariableTypeInfo.u2nameIndex); + markConstant(clazz, localVariableTypeInfo.u2signatureIndex); + + tableUsed = true; + } + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + + public void visitProgramClass(ProgramClass programClass) + { + // Don't keep the local variable info if one of its classes is not used. + if (!usageMarker.isUsed(programClass)) + { + variableInfoUsed = false; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) + { + usageMarker.markAsUsed(constant); + } + + + // Small utility methods. + + /** + * Marks the given constant pool entry of the given class. + */ + private void markConstant(Clazz clazz, int index) + { + clazz.constantPoolEntryAccept(index, this); + } +} diff --git a/src/proguard/shrink/ShortestUsageMark.java b/src/proguard/shrink/ShortestUsageMark.java index 757c713..e2df7fa 100644 --- a/src/proguard/shrink/ShortestUsageMark.java +++ b/src/proguard/shrink/ShortestUsageMark.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/shrink/ShortestUsageMarker.java b/src/proguard/shrink/ShortestUsageMarker.java index da8fad3..1ac6e7e 100644 --- a/src/proguard/shrink/ShortestUsageMarker.java +++ b/src/proguard/shrink/ShortestUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/shrink/ShortestUsagePrinter.java b/src/proguard/shrink/ShortestUsagePrinter.java index db42fe1..8740b9f 100644 --- a/src/proguard/shrink/ShortestUsagePrinter.java +++ b/src/proguard/shrink/ShortestUsagePrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,9 @@ package proguard.shrink; import proguard.classfile.*; -import proguard.classfile.util.ClassUtil; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.PrintStream; @@ -36,8 +38,10 @@ import java.io.PrintStream; * @author Eric Lafortune */ public class ShortestUsagePrinter +extends SimplifiedVisitor implements ClassVisitor, - MemberVisitor + MemberVisitor, + AttributeVisitor { private final ShortestUsageMarker shortestUsageMarker; private final boolean verbose; @@ -117,8 +121,7 @@ implements ClassVisitor, ps.println(ClassUtil.externalClassName(programClass.getName()) + (verbose ? ": " + ClassUtil.externalFullFieldDescription(0, name, type): - "." + name) + - lineNumberRange(programClass, programField)); + "." + name)); // Print the reason for keeping this method. printReason(programField); @@ -131,11 +134,12 @@ implements ClassVisitor, String name = programMethod.getName(programClass); String type = programMethod.getDescriptor(programClass); - ps.println(ClassUtil.externalClassName(programClass.getName()) + - (verbose ? - ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type): - "." + name) + - lineNumberRange(programClass, programMethod)); + ps.print(ClassUtil.externalClassName(programClass.getName()) + + (verbose ? + ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type): + "." + name)); + programMethod.attributesAccept(programClass, this); + ps.println(); // Print the reason for keeping this method. printReason(programMethod); @@ -174,6 +178,25 @@ implements ClassVisitor, } + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + ps.print(" (" + + lineNumberTableAttribute.getLowestLineNumber() + ":" + + lineNumberTableAttribute.getHighestLineNumber() + ")"); + } + + // Small utility methods. private void printReason(VisitorAccepter visitorAccepter) @@ -194,17 +217,4 @@ implements ClassVisitor, ps.println(" is not being kept.\n"); } } - - - /** - * Returns the line number range of the given class member, followed by a - * colon, or just an empty String if no range is available. - */ - private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) - { - String range = programMember.getLineNumberRange(programClass); - return range != null ? - (" (" + range + ")") : - ""; - } } diff --git a/src/proguard/shrink/Shrinker.java b/src/proguard/shrink/Shrinker.java index edbc27f..0472c3d 100644 --- a/src/proguard/shrink/Shrinker.java +++ b/src/proguard/shrink/Shrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -21,7 +21,7 @@ package proguard.shrink; import proguard.*; -import proguard.classfile.ClassPool; +import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.visitor.*; @@ -67,9 +67,20 @@ public class Shrinker new UsageMarker() : new ShortestUsageMarker(); + // Automatically mark the parameterless constructors of seed classes, + // mainly for convenience and for backward compatibility. + ClassVisitor classUsageMarker = + new MultiClassVisitor(new ClassVisitor[] + { + usageMarker, + new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, + ClassConstants.INTERNAL_METHOD_TYPE_INIT, + usageMarker) + }); + ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, - usageMarker, + classUsageMarker, usageMarker, true, false, @@ -89,6 +100,8 @@ public class Shrinker { new InnerUsageMarker(usageMarker), new AnnotationUsageMarker(usageMarker), + new SignatureUsageMarker(usageMarker), + new LocalVariableTypeUsageMarker(usageMarker) })))); // Should we explain ourselves? @@ -113,15 +126,21 @@ public class Shrinker if (configuration.printUsage != null) { - PrintStream ps = isFile(configuration.printUsage) ? - new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) : - System.out; + PrintStream ps = + configuration.printUsage == Configuration.STD_OUT ? System.out : + new PrintStream( + new BufferedOutputStream( + new FileOutputStream(configuration.printUsage))); // Print out items that will be removed. programClassPool.classesAcceptAlphabetically( new UsagePrinter(usageMarker, true, ps)); - if (ps != System.out) + if (ps == System.out) + { + ps.flush(); + } + else { ps.close(); } @@ -157,14 +176,4 @@ public class Shrinker return newProgramClassPool; } - - - /** - * 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; - } } diff --git a/src/proguard/shrink/SignatureUsageMarker.java b/src/proguard/shrink/SignatureUsageMarker.java new file mode 100644 index 0000000..9c5cd4d --- /dev/null +++ b/src/proguard/shrink/SignatureUsageMarker.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.shrink; + +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.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This AttributeVisitor recursively marks all Signature attributes that it + * visits and that point to used classes. + * + * @see UsageMarker + * + * @author Eric Lafortune + */ +public class SignatureUsageMarker +extends SimplifiedVisitor +implements AttributeVisitor, + ClassVisitor, + ConstantVisitor +{ + private final UsageMarker usageMarker; + + // Fields acting as a return parameters for several methods. + private boolean attributeUsed; + + + /** + * Creates a new SignatureUsageMarker. + * @param usageMarker the usage marker that is used to mark the classes + * and class members. + */ + public SignatureUsageMarker(UsageMarker usageMarker) + { + this.usageMarker = usageMarker; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + // Only keep the signature if all of its classes are used. + attributeUsed = true; + signatureAttribute.referencedClassesAccept(this); + + if (attributeUsed) + { + // We got a positive used flag, so the signature is useful. + usageMarker.markAsUsed(signatureAttribute); + + markConstant(clazz, signatureAttribute.u2attributeNameIndex); + markConstant(clazz, signatureAttribute.u2signatureIndex); + } + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + + public void visitProgramClass(ProgramClass programClass) + { + // Don't keep the signature if one of its classes is not used. + if (!usageMarker.isUsed(programClass)) + { + attributeUsed = false; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) + { + usageMarker.markAsUsed(constant); + } + + + // Small utility methods. + + /** + * Marks the given constant pool entry of the given class. + */ + private void markConstant(Clazz clazz, int index) + { + clazz.constantPoolEntryAccept(index, this); + } +} diff --git a/src/proguard/shrink/UsageMarker.java b/src/proguard/shrink/UsageMarker.java index e913046..51210b5 100644 --- a/src/proguard/shrink/UsageMarker.java +++ b/src/proguard/shrink/UsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -27,10 +27,10 @@ import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; -import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.constant.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; -import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.*; @@ -65,18 +65,15 @@ implements ClassVisitor, private static final Object USED = new Object(); - private final MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker(); - private final MyPossiblyUsedMemberUsageMarker possiblyUsedMemberUsageMarker = new MyPossiblyUsedMemberUsageMarker(); -// private ClassVisitor dynamicClassMarker = -// new MultiClassVisitor( -// new ClassVisitor[] -// { -// this, -// new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, -// ClassConstants.INTERNAL_METHOD_TYPE_INIT, -// this) -// }); - + private final MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker(); + private final MyPossiblyUsedMemberUsageMarker possiblyUsedMemberUsageMarker = new MyPossiblyUsedMemberUsageMarker(); + private final MemberVisitor nonEmptyMethodUsageMarker = new AllAttributeVisitor( + new MyNonEmptyMethodUsageMarker()); + private final ConstantVisitor parameterlessConstructorMarker = new ConstantTagFilter(new int[] { ClassConstants.CONSTANT_String, ClassConstants.CONSTANT_Class }, + new ReferencedClassVisitor( + new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, + ClassConstants.INTERNAL_METHOD_TYPE_INIT, + this))); // Implementations for ClassVisitor. @@ -107,15 +104,10 @@ implements ClassVisitor, programClass.hierarchyAccept(false, false, true, false, interfaceUsageMarker); - // Explicitly mark the <clinit> method. + // Explicitly mark the <clinit> method, if it's not empty. programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, ClassConstants.INTERNAL_METHOD_TYPE_CLINIT, - this); - - // Explicitly mark the parameterless <init> method. - programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT, - ClassConstants.INTERNAL_METHOD_TYPE_INIT, - this); + nonEmptyMethodUsageMarker); // Process all class members that have already been marked as possibly used. programClass.fieldsAccept(possiblyUsedMemberUsageMarker); @@ -187,6 +179,10 @@ implements ClassVisitor, } + /** + * This MemberVisitor marks ProgramField and ProgramMethod objects that + * have already been marked as possibly used. + */ private class MyPossiblyUsedMemberUsageMarker extends SimplifiedVisitor implements MemberVisitor @@ -230,6 +226,28 @@ implements ClassVisitor, } + /** + * This AttributeVisitor marks ProgramMethod objects of non-empty methods. + */ + private class MyNonEmptyMethodUsageMarker + extends SimplifiedVisitor + implements AttributeVisitor + { + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + if (codeAttribute.u4codeLength > 1) + { + method.accept(clazz, UsageMarker.this); + } + } + } + + // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) @@ -335,15 +353,26 @@ implements ClassVisitor, */ protected void markMethodHierarchy(Clazz clazz, Method method) { - if ((method.getAccessFlags() & + int accessFlags = method.getAccessFlags(); + if ((accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | - ClassConstants.INTERNAL_ACC_STATIC)) == 0) + ClassConstants.INTERNAL_ACC_STATIC)) == 0 && + !ClassUtil.isInitializer(method.getName(clazz))) { + // We can skip private and static methods in the hierarchy, and + // also abstract methods, unless they might widen a current + // non-public access. + int requiredUnsetAccessFlags = + ClassConstants.INTERNAL_ACC_PRIVATE | + ClassConstants.INTERNAL_ACC_STATIC | + ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0 ? 0 : + ClassConstants.INTERNAL_ACC_ABSTRACT); + clazz.accept(new ConcreteClassDownTraveler( new ClassHierarchyTraveler(true, true, false, true, new NamedMethodVisitor(method.getName(clazz), method.getDescriptor(clazz), - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, + new MemberAccessFilter(0, requiredUnsetAccessFlags, this))))); } } @@ -395,11 +424,7 @@ implements ClassVisitor, markConstant(clazz, stringConstant.u2stringIndex); - // Mark the referenced class and its parameterless constructor, - // if the string is being used in a Class.forName construct. - //stringConstant.referencedClassAccept(dynamicClassMarker); - - // Mark the referenced class or class member, if any. + // Mark the referenced class and class member, if any. stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } @@ -415,6 +440,31 @@ implements ClassVisitor, } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + if (shouldBeMarkedAsUsed(invokeDynamicConstant)) + { + markAsUsed(invokeDynamicConstant); + + markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); + + // Mark the bootstrap methods attribute. + clazz.attributesAccept(new MyBootStrapMethodUsageMarker(invokeDynamicConstant.u2bootstrapMethodAttributeIndex)); + } + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + if (shouldBeMarkedAsUsed(methodHandleConstant)) + { + markAsUsed(methodHandleConstant); + + markConstant(clazz, methodHandleConstant.u2referenceIndex); + } + } + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { if (shouldBeMarkedAsUsed(refConstant)) @@ -450,6 +500,17 @@ implements ClassVisitor, } + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) + { + if (shouldBeMarkedAsUsed(methodTypeConstant)) + { + markAsUsed(methodTypeConstant); + + markConstant(clazz, methodTypeConstant.u2descriptorIndex); + } + } + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { if (shouldBeMarkedAsUsed(nameAndTypeConstant)) @@ -462,6 +523,58 @@ implements ClassVisitor, } + /** + * This AttributeVisitor marks the bootstrap methods attributes, their + * method entries, their method handles, and their arguments. + */ + private class MyBootStrapMethodUsageMarker + extends SimplifiedVisitor + implements AttributeVisitor, + BootstrapMethodInfoVisitor + { + private int bootstrapMethodIndex; + + + private MyBootStrapMethodUsageMarker(int bootstrapMethodIndex) + { + this.bootstrapMethodIndex = bootstrapMethodIndex; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + if (shouldBeMarkedAsUsed(bootstrapMethodsAttribute)) + { + markAsUsed(bootstrapMethodsAttribute); + + markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); + + bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz, + bootstrapMethodIndex, + this); + } + } + + + // Implementations for BootstrapMethodInfoVisitor. + + public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) + { + markAsUsed(bootstrapMethodInfo); + + markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); + + // Mark the constant pool entries referenced by the arguments. + bootstrapMethodInfo.methodArgumentsAccept(clazz, UsageMarker.this); + } + } + + // Implementations for AttributeVisitor. // Note that attributes are typically only referenced once, so we don't // test if they have been marked already. @@ -475,6 +588,13 @@ implements ClassVisitor, } + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + // Don't mark the attribute and its name here. We may mark it in + // MyBootStrapMethodsAttributeUsageMarker. + } + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { markAsUsed(sourceFileAttribute); @@ -538,10 +658,12 @@ implements ClassVisitor, public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { - markAsUsed(signatureAttribute); - - markConstant(clazz, signatureAttribute.u2attributeNameIndex); - markConstant(clazz, signatureAttribute.u2signatureIndex); + // Don't mark the attribute and its contents yet. We may mark them later, + // in SignatureUsageMarker. + //markAsUsed(signatureAttribute); + // + //markConstant(clazz, signatureAttribute.u2attributeNameIndex); + //markConstant(clazz, signatureAttribute.u2signatureIndex); } @@ -611,23 +733,27 @@ implements ClassVisitor, public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { - markAsUsed(localVariableTableAttribute); - - markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); - - // Mark the constant pool entries referenced by the local variables. - localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + // Don't mark the attribute and its contents yet. We may mark them later, + // in LocalVariableTypeUsageMarker. + //markAsUsed(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) { - markAsUsed(localVariableTypeTableAttribute); - - markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); - - // Mark the constant pool entries referenced by the local variable types. - localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + // Don't mark the attribute and its contents yet. We may mark them later, + // in LocalVariableTypeUsageMarker. + //markAsUsed(localVariableTypeTableAttribute); + // + //markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the local variable types. + //localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } @@ -635,12 +761,12 @@ implements ClassVisitor, { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. -// markAsUsed(annotationsAttribute); -// -// markConstant(clazz, annotationsAttribute.u2attributeNameIndex); -// -// // Mark the constant pool entries referenced by the annotations. -// annotationsAttribute.annotationsAccept(clazz, this); + //markAsUsed(annotationsAttribute); + // + //markConstant(clazz, annotationsAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the annotations. + //annotationsAttribute.annotationsAccept(clazz, this); } @@ -648,12 +774,12 @@ implements ClassVisitor, { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. -// markAsUsed(parameterAnnotationsAttribute); -// -// markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); -// -// // Mark the constant pool entries referenced by the annotations. -// parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); + //markAsUsed(parameterAnnotationsAttribute); + // + //markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the annotations. + //parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } @@ -837,6 +963,12 @@ implements ClassVisitor, public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { markConstant(clazz, constantInstruction.constantIndex); + + // Also mark the parameterless constructor of the class, in case the + // string constant or class constant is being used in a Class.forName + // or a .class construct. + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, + parameterlessConstructorMarker); } @@ -915,6 +1047,6 @@ implements ClassVisitor, */ private void markConstant(Clazz clazz, int index) { - clazz.constantPoolEntryAccept(index, this); + clazz.constantPoolEntryAccept(index, this); } } diff --git a/src/proguard/shrink/UsagePrinter.java b/src/proguard/shrink/UsagePrinter.java index 294b9e1..69df7fa 100644 --- a/src/proguard/shrink/UsagePrinter.java +++ b/src/proguard/shrink/UsagePrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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.shrink; import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; @@ -38,7 +40,8 @@ import java.io.PrintStream; public class UsagePrinter extends SimplifiedVisitor implements ClassVisitor, - MemberVisitor + MemberVisitor, + AttributeVisitor { private final UsageMarker usageMarker; private final boolean printUnusedItems; @@ -121,7 +124,6 @@ implements ClassVisitor, printClassNameHeader(); ps.println(" " + - lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( programField.getAccessFlags(), programField.getName(programClass), @@ -136,9 +138,10 @@ implements ClassVisitor, { printClassNameHeader(); - ps.println(" " + - lineNumberRange(programClass, programMethod) + - ClassUtil.externalFullMethodDescription( + ps.print("===="); + ps.print(" "); + programMethod.attributesAccept(programClass, this); + ps.println(ClassUtil.externalFullMethodDescription( programClass.getName(), programMethod.getAccessFlags(), programMethod.getName(programClass), @@ -147,6 +150,24 @@ implements ClassVisitor, } + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + ps.print(lineNumberTableAttribute.getLowestLineNumber() + ":" + + lineNumberTableAttribute.getHighestLineNumber() + ":"); + } + + // Small utility methods. /** @@ -161,17 +182,4 @@ implements ClassVisitor, className = null; } } - - - /** - * Returns the line number range of the given class member, followed by a - * colon, or just an empty String if no range is available. - */ - private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) - { - String range = programMember.getLineNumberRange(programClass); - return range != null ? - (range + ":") : - ""; - } } diff --git a/src/proguard/shrink/UsedClassFilter.java b/src/proguard/shrink/UsedClassFilter.java index ec180bd..7630b0b 100644 --- a/src/proguard/shrink/UsedClassFilter.java +++ b/src/proguard/shrink/UsedClassFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/shrink/UsedMemberFilter.java b/src/proguard/shrink/UsedMemberFilter.java index 755cfd1..f1a9c75 100644 --- a/src/proguard/shrink/UsedMemberFilter.java +++ b/src/proguard/shrink/UsedMemberFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -39,7 +39,7 @@ implements MemberVisitor /** - * Creates a new UsedClassFilter. + * Creates a new UsedMemberFilter. * @param usageMarker the usage marker that is used to mark the classes * and class members. * @param memberVisitor the member visitor to which the visiting will be diff --git a/src/proguard/util/AndMatcher.java b/src/proguard/util/AndMatcher.java index 94a37e5..1aa3726 100644 --- a/src/proguard/util/AndMatcher.java +++ b/src/proguard/util/AndMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ArrayUtil.java b/src/proguard/util/ArrayUtil.java new file mode 100644 index 0000000..8584700 --- /dev/null +++ b/src/proguard/util/ArrayUtil.java @@ -0,0 +1,960 @@ +/* + * 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.util; + +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * This class contains utility methods operating on arrays. + */ +public class ArrayUtil +{ + /** + * Returns whether the elements of the two given arrays are the same. + * @param array1 the first array. + * @param array2 the second array. + * @param size the size of the arrays to be checked. + * @return whether the elements are the same. + */ + public static boolean equal(byte[] array1, byte[] array2, int size) + { + for (int index = 0; index < size; index++) + { + if (array1[index] != array2[index]) + { + return false; + } + } + + return true; + } + + + /** + * Returns whether the elements of the two given arrays are the same. + * @param array1 the first array. + * @param array2 the second array. + * @param size the size of the arrays to be checked. + * @return whether the elements are the same. + */ + public static boolean equal(short[] array1, short[] array2, int size) + { + for (int index = 0; index < size; index++) + { + if (array1[index] != array2[index]) + { + return false; + } + } + + return true; + } + + + /** + * Returns whether the elements of the two given arrays are the same. + * @param array1 the first array. + * @param array2 the second array. + * @param size the size of the arrays to be checked. + * @return whether the elements are the same. + */ + public static boolean equal(int[] array1, int[] array2, int size) + { + for (int index = 0; index < size; index++) + { + if (array1[index] != array2[index]) + { + return false; + } + } + + return true; + } + + + /** + * Returns whether the elements of the two given arrays are the same. + * @param array1 the first array. + * @param array2 the second array. + * @param size the size of the arrays to be checked. + * @return whether the elements are the same. + */ + public static boolean equal(Object[] array1, Object[] array2, int size) + { + for (int index = 0; index < size; index++) + { + if (!array1[index].equals(array2[index])) + { + return false; + } + } + + return true; + } + + + /** + * Returns a hash code for the elements of the given array. + * @param array the array. + * @param size the size of the array to be taken into account. + * @return a hash code. + */ + public static int hashCode(byte[] array, int size) + { + int hashCode = 0; + + for (int index = 0; index < size; index++) + { + hashCode ^= array[index]; + } + + return hashCode; + } + + + /** + * Returns a hash code for the elements of the given array. + * @param array the array. + * @param size the size of the array to be taken into account. + * @return a hash code. + */ + public static int hashCode(short[] array, int size) + { + int hashCode = 0; + + for (int index = 0; index < size; index++) + { + hashCode ^= array[index]; + } + + return hashCode; + } + + + /** + * Returns a hash code for the elements of the given array. + * @param array the array. + * @param size the size of the array to be taken into account. + * @return a hash code. + */ + public static int hashCode(int[] array, int size) + { + int hashCode = 0; + + for (int index = 0; index < size; index++) + { + hashCode ^= array[index]; + } + + return hashCode; + } + + + /** + * Returns a hash code for the elements of the given array. + * @param array the array. + * @param size the size of the array to be taken into account. + * @return a hash code. + */ + public static int hashCode(Object[] array, int size) + { + int hashCode = 0; + + for (int index = 0; index < size; index++) + { + hashCode ^= array[index].hashCode(); + } + + return hashCode; + } + + + /** + * Compares the elements of the two given arrays. + * @param array1 the first array. + * @param size1 the size of the first array. + * @param array2 the second array. + * @param size2 the size of the second array. + * @return 0 if all elements are the same, + * -1 if the first different element in the first array is smaller + * than the corresponding element in the second array, + * or 1 if it is larger. + */ + public static int compare(byte[] array1, int size1, + byte[] array2, int size2) + { + int minSize = Math.min(size1, size2); + + for (int index = 0; index < minSize; index++) + { + if (array1[index] < array2[index]) + { + return -1; + } + else if (array1[index] > array2[index]) + { + return 1; + } + } + + return size1 < size2 ? -1 : + size1 == size2 ? 0 : + 1; + } + + + /** + * Compares the elements of the two given arrays. + * @param array1 the first array. + * @param size1 the size of the first array. + * @param array2 the second array. + * @param size2 the size of the second array. + * @return 0 if all elements are the same, + * -1 if the first different element in the first array is smaller + * than the corresponding element in the second array, + * or 1 if it is larger. + */ + public static int compare(short[] array1, int size1, + short[] array2, int size2) + { + int minSize = Math.min(size1, size2); + + for (int index = 0; index < minSize; index++) + { + if (array1[index] < array2[index]) + { + return -1; + } + else if (array1[index] > array2[index]) + { + return 1; + } + } + + return size1 < size2 ? -1 : + size1 == size2 ? 0 : + 1; + } + + + /** + * Compares the elements of the two given arrays. + * @param array1 the first array. + * @param size1 the size of the first array. + * @param array2 the second array. + * @param size2 the size of the second array. + * @return 0 if all elements are the same, + * -1 if the first different element in the first array is smaller + * than the corresponding element in the second array, + * or 1 if it is larger. + */ + public static int compare(int[] array1, int size1, + int[] array2, int size2) + { + int minSize = Math.min(size1, size2); + + for (int index = 0; index < minSize; index++) + { + if (array1[index] < array2[index]) + { + return -1; + } + else if (array1[index] > array2[index]) + { + return 1; + } + } + + return size1 < size2 ? -1 : + size1 == size2 ? 0 : + 1; + } + + + /** + * Compares the elements of the two given arrays. + * @param array1 the first array. + * @param size1 the size of the first array. + * @param array2 the second array. + * @param size2 the size of the second array. + * @return 0 if all elements are the same, + * -1 if the first different element in the first array is smaller + * than the corresponding element in the second array, + * or 1 if it is larger. + */ + public static int compare(Comparable[] array1, int size1, + Comparable[] array2, int size2) + { + int minSize = Math.min(size1, size2); + + for (int index = 0; index < minSize; index++) + { + int comparison = ObjectUtil.compare(array1[index], array2[index]); + if (comparison != 0) + { + return comparison; + } + } + + return size1 < size2 ? -1 : + size1 == size2 ? 0 : + 1; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static boolean[] extendArray(boolean[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + boolean[] newArray = new boolean[size]; + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static boolean[] ensureArraySize(boolean[] array, + int size, + boolean initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = new boolean[size]; + + if (initialValue) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } + + + /** + * Adds the given element to the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static byte[] add(byte[] array, int size, byte element) + { + array = extendArray(array, size + 1); + + array[size] = element; + + return array; + } + + + /** + * Inserts the given element in the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param index the index at which the element is to be added. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static byte[] insert(byte[] array, int size, int index, byte element) + { + array = extendArray(array, size + 1); + + // Move the last part. + System.arraycopy(array, index, + array, index + 1, + size - index); + + array[index] = element; + + return array; + } + + + /** + * Removes the specified element from the given array. + * @param array the array. + * @param size the original size of the array. + * @param index the index of the element to be removed. + */ + public static void remove(byte[] array, int size, int index) + { + System.arraycopy(array, index + 1, + array, index, + array.length - index - 1); + + array[size - 1] = 0; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static byte[] extendArray(byte[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + byte[] newArray = new byte[size]; + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static byte[] ensureArraySize(byte[] array, + int size, + byte initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = new byte[size]; + + if (initialValue != 0) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } + + + /** + * Adds the given element to the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static short[] add(short[] array, int size, short element) + { + array = extendArray(array, size + 1); + + array[size] = element; + + return array; + } + + + /** + * Inserts the given element in the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param index the index at which the element is to be added. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static short[] insert(short[] array, int size, int index, short element) + { + array = extendArray(array, size + 1); + + // Move the last part. + System.arraycopy(array, index, + array, index + 1, + size - index); + + array[index] = element; + + return array; + } + + + /** + * Removes the specified element from the given array. + * @param array the array. + * @param size the original size of the array. + * @param index the index of the element to be removed. + */ + public static void remove(short[] array, int size, int index) + { + System.arraycopy(array, index + 1, + array, index, + array.length - index - 1); + + array[size - 1] = 0; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static short[] extendArray(short[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + short[] newArray = new short[size]; + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static short[] ensureArraySize(short[] array, + int size, + short initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = new short[size]; + + if (initialValue != 0) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } + + + /** + * Adds the given element to the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static int[] add(int[] array, int size, int element) + { + array = extendArray(array, size + 1); + + array[size] = element; + + return array; + } + + + /** + * Inserts the given element in the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param index the index at which the element is to be added. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static int[] insert(int[] array, int size, int index, int element) + { + array = extendArray(array, size + 1); + + // Move the last part. + System.arraycopy(array, index, + array, index + 1, + size - index); + + array[index] = element; + + return array; + } + + + /** + * Removes the specified element from the given array. + * @param array the array. + * @param size the original size of the array. + * @param index the index of the element to be removed. + */ + public static void remove(int[] array, int size, int index) + { + System.arraycopy(array, index + 1, + array, index, + array.length - index - 1); + + array[size - 1] = 0; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static int[] extendArray(int[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + int[] newArray = new int[size]; + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static int[] ensureArraySize(int[] array, + int size, + int initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = new int[size]; + + if (initialValue != 0) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } + + + /** + * Adds the given element to the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static long[] add(long[] array, int size, long element) + { + array = extendArray(array, size + 1); + + array[size] = element; + + return array; + } + + + /** + * Inserts the given element in the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param index the index at which the element is to be added. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static long[] insert(long[] array, int size, int index, long element) + { + array = extendArray(array, size + 1); + + // Move the last part. + System.arraycopy(array, index, + array, index + 1, + size - index); + + array[index] = element; + + return array; + } + + + /** + * Removes the specified element from the given array. + * @param array the array. + * @param size the original size of the array. + * @param index the index of the element to be removed. + */ + public static void remove(long[] array, int size, int index) + { + System.arraycopy(array, index + 1, + array, index, + array.length - index - 1); + + array[size - 1] = 0; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static long[] extendArray(long[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + long[] newArray = new long[size]; + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static long[] ensureArraySize(long[] array, + int size, + long initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = new long[size]; + + if (initialValue != 0L) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } + + + /** + * Adds the given element to the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static Object[] add(Object[] array, int size, Object element) + { + array = extendArray(array, size + 1); + + array[size] = element; + + return array; + } + + + /** + * Inserts the given element in the given array. + * The array is extended if necessary. + * @param array the array. + * @param size the original size of the array. + * @param index the index at which the element is to be added. + * @param element the element to be added. + * @return the original array, or a copy if it had to be extended. + */ + public static Object[] insert(Object[] array, int size, int index, Object element) + { + array = extendArray(array, size + 1); + + // Move the last part. + System.arraycopy(array, index, + array, index + 1, + size - index); + + array[index] = element; + + return array; + } + + + /** + * Removes the specified element from the given array. + * @param array the array. + * @param size the original size of the array. + * @param index the index of the element to be removed. + */ + public static void remove(Object[] array, int size, int index) + { + System.arraycopy(array, index + 1, + array, index, + array.length - index - 1); + + array[size - 1] = null; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @return the original array, or a copy if it had to be extended. + */ + public static Object[] extendArray(Object[] array, int size) + { + // Reuse the existing array if possible. + if (array.length >= size) + { + return array; + } + + // Otherwise create and initialize a new array. + Object[] newArray = (Object[])Array.newInstance(array.getClass().getComponentType(), size); + + System.arraycopy(array, 0, + newArray, 0, + array.length); + + return newArray; + } + + + /** + * Ensures the given array has a given size. + * @param array the array. + * @param size the target size of the array. + * @param initialValue the initial value of the elements. + * @return the original array, or a copy if it had to be + * extended. + */ + public static Object[] ensureArraySize(Object[] array, + int size, + Object initialValue) + { + // Is the existing array large enough? + if (array.length >= size) + { + // Reinitialize the existing array. + Arrays.fill(array, 0, size, initialValue); + } + else + { + // Otherwise create and initialize a new array. + array = (Object[])Array.newInstance(array.getClass().getComponentType(), size); + + if (initialValue != null) + { + Arrays.fill(array, 0, size, initialValue); + } + } + + return array; + } +} diff --git a/src/proguard/util/ClassNameParser.java b/src/proguard/util/ClassNameParser.java index ee972f0..22a0703 100644 --- a/src/proguard/util/ClassNameParser.java +++ b/src/proguard/util/ClassNameParser.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ConstantMatcher.java b/src/proguard/util/ConstantMatcher.java index 1764caa..8c0f1e1 100644 --- a/src/proguard/util/ConstantMatcher.java +++ b/src/proguard/util/ConstantMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/EmptyStringMatcher.java b/src/proguard/util/EmptyStringMatcher.java index 543f446..f07c666 100644 --- a/src/proguard/util/EmptyStringMatcher.java +++ b/src/proguard/util/EmptyStringMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ExtensionMatcher.java b/src/proguard/util/ExtensionMatcher.java index 5a9f658..eeb627a 100644 --- a/src/proguard/util/ExtensionMatcher.java +++ b/src/proguard/util/ExtensionMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/FileNameParser.java b/src/proguard/util/FileNameParser.java index 913f22d..9ec6d22 100644 --- a/src/proguard/util/FileNameParser.java +++ b/src/proguard/util/FileNameParser.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/FixedStringMatcher.java b/src/proguard/util/FixedStringMatcher.java index c1eb3f4..2f02271 100644 --- a/src/proguard/util/FixedStringMatcher.java +++ b/src/proguard/util/FixedStringMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ListMatcher.java b/src/proguard/util/ListMatcher.java index b2559c8..e07bff0 100644 --- a/src/proguard/util/ListMatcher.java +++ b/src/proguard/util/ListMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ListParser.java b/src/proguard/util/ListParser.java index cec803b..b3b4518 100644 --- a/src/proguard/util/ListParser.java +++ b/src/proguard/util/ListParser.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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 @@ public class ListParser implements StringParser // Loop over all simple regular expressions, backward, creating a // linked list of matchers. - for (int index = regularExpressions.size()-1; index >=0; index--) + for (int index = regularExpressions.size()-1; index >= 0; index--) { String regularExpression = (String)regularExpressions.get(index); diff --git a/src/proguard/util/ListUtil.java b/src/proguard/util/ListUtil.java index 570dbe8..18bdce2 100644 --- a/src/proguard/util/ListUtil.java +++ b/src/proguard/util/ListUtil.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is 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,7 +34,7 @@ public class ListUtil /** * Creates a comma-separated String from the given List of String objects. */ - public static String commaSeparatedString(List list) + public static String commaSeparatedString(List list, boolean quoteStrings) { if (list == null) { @@ -50,7 +50,14 @@ public class ListUtil buffer.append(','); } - buffer.append(quotedString((String)list.get(index))); + String string = (String)list.get(index); + + if (quoteStrings) + { + string = quotedString(string); + } + + buffer.append(string); } return buffer.toString(); @@ -165,7 +172,7 @@ public class ListUtil System.out.println("["+list.get(index)+"]"); } - String string = commaSeparatedString(list); + String string = commaSeparatedString(list, true); System.out.println("Resulting string: ["+string+"]"); } diff --git a/src/proguard/util/NameParser.java b/src/proguard/util/NameParser.java index e311fbf..f25d52e 100644 --- a/src/proguard/util/NameParser.java +++ b/src/proguard/util/NameParser.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/NotMatcher.java b/src/proguard/util/NotMatcher.java index f2a9a51..af539d0 100644 --- a/src/proguard/util/NotMatcher.java +++ b/src/proguard/util/NotMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/ObjectUtil.java b/src/proguard/util/ObjectUtil.java new file mode 100644 index 0000000..c5de36a --- /dev/null +++ b/src/proguard/util/ObjectUtil.java @@ -0,0 +1,67 @@ +/* + * 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.util; + +/** + * This class contains utility methods operating on objects. + */ +public class ObjectUtil +{ + /** + * Returns whether the given objects are the same. + * @param object1 the first object, may be null. + * @param object2 the second object, may be null. + * @return whether the objects are the same. + */ + public static boolean equal(Object object1, Object object2) + { + return object1 == null ? + object2 == null : + object1.equals(object2); + } + + + /** + * Returns the hash code of the given object, or 0 if it is null. + * @param object the object, may be null. + * @return the hash code. + */ + public static int hashCode(Object object) + { + return object == null ? 0 : object.hashCode(); + } + + + /** + * Returns a comparison of the two given objects. + * @param object1 the first object, may be null. + * @param object2 the second object, may be null. + * @return -1, 0, or 1. + * @see Comparable#compareTo(Object) + */ + public static int compare(Comparable object1, Comparable object2) + { + return object1 == null ? + object2 == null ? 0 : -1 : + object2 == null ? 1 : object1.compareTo(object2); + } +} diff --git a/src/proguard/util/OrMatcher.java b/src/proguard/util/OrMatcher.java index 097c6c6..7ad85c4 100644 --- a/src/proguard/util/OrMatcher.java +++ b/src/proguard/util/OrMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/SettableMatcher.java b/src/proguard/util/SettableMatcher.java index 9557f62..8650ccc 100644 --- a/src/proguard/util/SettableMatcher.java +++ b/src/proguard/util/SettableMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/StringMatcher.java b/src/proguard/util/StringMatcher.java index bd66dcc..146dbfc 100644 --- a/src/proguard/util/StringMatcher.java +++ b/src/proguard/util/StringMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/StringParser.java b/src/proguard/util/StringParser.java index 29f4f16..39d04d5 100644 --- a/src/proguard/util/StringParser.java +++ b/src/proguard/util/StringParser.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/util/VariableStringMatcher.java b/src/proguard/util/VariableStringMatcher.java index 1e41323..5a07c2a 100644 --- a/src/proguard/util/VariableStringMatcher.java +++ b/src/proguard/util/VariableStringMatcher.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/src/proguard/wtk/ProGuardObfuscator.java b/src/proguard/wtk/ProGuardObfuscator.java index 4618437..b6f9ace 100644 --- a/src/proguard/wtk/ProGuardObfuscator.java +++ b/src/proguard/wtk/ProGuardObfuscator.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -71,7 +71,8 @@ public class ProGuardObfuscator implements Obfuscator Configuration configuration = new Configuration(); // Parse the default configuration file. - ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION)); + ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION), + System.getProperties()); try { |