diff --git a/pom.xml b/pom.xml index 166d3df..a34a3dc 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,13 @@ 2.0.7 + + org.projectlombok + lombok + 1.18.26 + provided + + junit junit @@ -68,7 +75,7 @@ - haidnor.jvm.Main + haidnor.jvm.HaidnorJVM diff --git a/src/main/java/haidnor/jvm/HaidnorJVM.java b/src/main/java/haidnor/jvm/HaidnorJVM.java new file mode 100644 index 0000000..dd7d419 --- /dev/null +++ b/src/main/java/haidnor/jvm/HaidnorJVM.java @@ -0,0 +1,83 @@ +package haidnor.jvm; + +import haidnor.jvm.bcel.classfile.JavaClass; +import haidnor.jvm.classloader.JVMClassLoader; +import haidnor.jvm.core.JavaExecutionEngine; +import haidnor.jvm.rtda.Metaspace; +import haidnor.jvm.runtime.JVMThread; +import haidnor.jvm.util.JVMThreadHolder; +import lombok.SneakyThrows; +import org.apache.commons.cli.*; + +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * GitHub FranzHaidnor + */ +public class HaidnorJVM { + + @SneakyThrows + public static void main(String[] args) { + String banner = """ + ██╗ ██╗ █████╗ ██╗██████╗ ███╗ ██╗ ██████╗ ██████╗ ██╗██╗ ██╗███╗ ███╗ + ██║ ██║██╔══██╗██║██╔══██╗████╗ ██║██╔═══██╗██╔══██╗ ██║██║ ██║████╗ ████║ + ███████║███████║██║██║ ██║██╔██╗ ██║██║ ██║██████╔╝ ██║██║ ██║██╔████╔██║ + ██╔══██║██╔══██║██║██║ ██║██║╚██╗██║██║ ██║██╔══██╗ ██ ██║╚██╗ ██╔╝██║╚██╔╝██║ + ██║ ██║██║ ██║██║██████╔╝██║ ╚████║╚██████╔╝██║ ██║ ╚█████╔╝ ╚████╔╝ ██║ ╚═╝ ██║ + ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚════╝ ╚═══╝ ╚═╝ ╚═╝ + """; + System.out.println(banner); + + CommandLine cmd = initCommandLine(args); + + // 指定从 .jar 文件运行 + if (cmd.hasOption("jar")) { + String jarFilePath = cmd.getOptionValue("jar"); + try (JarFile jarFile = new JarFile(jarFilePath)) { + JVMClassLoader classLoader = new JVMClassLoader(jarFile, "ApplicationClassLoader"); + String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); + + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6); + if (className.equals(mainClass)) { + JVMThreadHolder.set(new JVMThread()); + JavaClass javaClass = classLoader.loadWithJar(jarFile, entry); + Metaspace.registerJavaClass(javaClass); + JavaExecutionEngine.callMainMethod(javaClass); + return; + } + } + } + } + } + + // 指定从 .class 文件运行 + if (cmd.hasOption("class")) { + JVMThreadHolder.set(new JVMThread()); + String path = cmd.getOptionValue("class"); + JVMClassLoader bootClassLoader = new JVMClassLoader("ApplicationClassLoader"); + JavaClass javaClass = bootClassLoader.loadWithAbsolutePath(path); + JavaExecutionEngine.callMainMethod(javaClass); + } + } + + private static CommandLine initCommandLine(String[] args) throws ParseException { + Option jarOption = new Option("jar", true, "运行 jar 程序"); + Option classOption = new Option("class", true, "运行 .class 字节码文件"); + + OptionGroup optionGroup = new OptionGroup(); + optionGroup.addOption(jarOption).addOption(classOption); + + Options options = new Options(); + options.addOptionGroup(optionGroup); + + CommandLineParser parser = new DefaultParser(); + return parser.parse(options, args); + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/bcel/Const.java b/src/main/java/haidnor/jvm/bcel/Const.java index 3abecf1..aaaa60f 100644 --- a/src/main/java/haidnor/jvm/bcel/Const.java +++ b/src/main/java/haidnor/jvm/bcel/Const.java @@ -30,7 +30,7 @@ public final class Const { * Java class file format Magic number (0xCAFEBABE) * * @see The ClassFile Structure - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final int JVM_CLASSFILE_MAGIC = 0xCAFEBABE; @@ -352,13 +352,13 @@ public final class Const { * One of the access flags for fields, methods, or classes. * * @see Flag definitions for - * Classes in the Java Virtual Machine Specification (Java SE 9 Edition). + * Classes in the Java Virtual Machine Specification (Java SE 9 Edition). * @see Flag definitions for Fields - * in the Java Virtual Machine Specification (Java SE 9 Edition). + * in the Java Virtual Machine Specification (Java SE 9 Edition). * @see Flag definitions for Methods - * in the Java Virtual Machine Specification (Java SE 9 Edition). + * in the Java Virtual Machine Specification (Java SE 9 Edition). * @see Flag - * definitions for Inner Classes in the Java Virtual Machine Specification (Java SE 9 Edition). + * definitions for Inner Classes in the Java Virtual Machine Specification (Java SE 9 Edition). */ public static final short ACC_PUBLIC = 0x0001; @@ -539,191 +539,150 @@ public final class Const { // 'volatile' is for fields, might be 'bridge' (if method) or 'static_phase' (if Module) // 'transient' is for fields, might be 'varargs' (if method) // 'module' is for classes, might be 'mandated' (if Module or MethodParameters) - /** - * The names of the access flags. - */ - private static final String[] ACCESS_NAMES = {"public", "private", "protected", "static", "final", "synchronized", "volatile", "transient", "native", - "interface", "abstract", "strictfp", "synthetic", "annotation", "enum", "module"}; - - /** @since 6.0 */ - public static final int ACCESS_NAMES_LENGTH = ACCESS_NAMES.length; - /** * Marks a constant pool entry as type UTF-8. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Utf8 = 1; + /** + * Marks a constant pool entry as type Integer. + * + * @see The Constant Pool in The + * Java Virtual Machine Specification + */ + public static final byte CONSTANT_Integer = 3; + /** + * Marks a constant pool entry as type Float. + * + * @see The Constant Pool in The + * Java Virtual Machine Specification + */ + public static final byte CONSTANT_Float = 4; /* * The description of the constant pool is at: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4 * References below are to the individual sections */ - - /** - * Marks a constant pool entry as type Integer. - * - * @see The Constant Pool in The - * Java Virtual Machine Specification - */ - public static final byte CONSTANT_Integer = 3; - - /** - * Marks a constant pool entry as type Float. - * - * @see The Constant Pool in The - * Java Virtual Machine Specification - */ - public static final byte CONSTANT_Float = 4; - /** * Marks a constant pool entry as type Long. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Long = 5; - /** * Marks a constant pool entry as type Double. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Double = 6; - /** * Marks a constant pool entry as a Class * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Class = 7; - /** * Marks a constant pool entry as a Field Reference. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Fieldref = 9; - /** * Marks a constant pool entry as type String * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_String = 8; - /** * Marks a constant pool entry as a Method Reference. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_Methodref = 10; - /** * Marks a constant pool entry as an Interface Method Reference. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_InterfaceMethodref = 11; - /** * Marks a constant pool entry as a name and type. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_NameAndType = 12; - /** * Marks a constant pool entry as a Method Handle. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_MethodHandle = 15; - /** * Marks a constant pool entry as a Method Type. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_MethodType = 16; - /** * Marks a constant pool entry as dynamically computed. * * @see Change request for JEP - * 309 + * 309 * @since 6.3 */ public static final byte CONSTANT_Dynamic = 17; - /** * Marks a constant pool entry as an Invoke Dynamic * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final byte CONSTANT_InvokeDynamic = 18; - /** * Marks a constant pool entry as a Module Reference. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification * @since 6.1 */ public static final byte CONSTANT_Module = 19; - /** * Marks a constant pool entry as a Package Reference. * * @see The Constant Pool in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification * @since 6.1 */ public static final byte CONSTANT_Package = 20; - - /** - * The names of the types of entries in a constant pool. Use getConstantName instead - */ - private static final String[] CONSTANT_NAMES = {"", "CONSTANT_Utf8", "", "CONSTANT_Integer", "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double", - "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref", "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref", "CONSTANT_NameAndType", "", "", - "CONSTANT_MethodHandle", "CONSTANT_MethodType", "CONSTANT_Dynamic", "CONSTANT_InvokeDynamic", "CONSTANT_Module", "CONSTANT_Package"}; - /** * The name of the static initializer, also called "class initialization method" or "interface * initialization method". This is "<clinit>". */ public static final String STATIC_INITIALIZER_NAME = ""; - /** * The name of every constructor method in a class, also called "instance initialization method". This is * "<init>". */ public static final String CONSTRUCTOR_NAME = ""; - - /** - * The names of the interfaces implemented by arrays - */ - private static final String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"}; - /** * Maximum Constant Pool entries. One of the limitations of the Java Virtual Machine. * * @see The Java Virtual - * Machine Specification, Java SE 8 Edition, page 330, chapter 4.11. + * Machine Specification, Java SE 8 Edition, page 330, chapter 4.11. */ public static final int MAX_CP_ENTRIES = 65535; - /** * Maximum code size (plus one; the code size must be LESS than this) One of the limitations of the Java Virtual * Machine. Note vmspec2 page 152 ("Limitations") says: "The amount of code per non-native, non-abstract method is @@ -734,2283 +693,1854 @@ public final class Const { * from later versions of the spec; it is not present in the Java SE 8 edition. * * @see The Java Virtual - * Machine Specification, Java SE 8 Edition, page 104, chapter 4.7. + * Machine Specification, Java SE 8 Edition, page 104, chapter 4.7. */ public static final int MAX_CODE_SIZE = 65536; // bytes - /** * The maximum number of dimensions in an array ({@value}). One of the limitations of the Java Virtual Machine. * * @see Field Descriptors in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final int MAX_ARRAY_DIMENSIONS = 255; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short NOP = 0; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short ACONST_NULL = 1; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_M1 = 2; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_0 = 3; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_1 = 4; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_2 = 5; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_3 = 6; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_4 = 7; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ICONST_5 = 8; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LCONST_0 = 9; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LCONST_1 = 10; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FCONST_0 = 11; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FCONST_1 = 12; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FCONST_2 = 13; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DCONST_0 = 14; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DCONST_1 = 15; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short BIPUSH = 16; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short SIPUSH = 17; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short LDC = 18; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LDC_W = 19; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LDC2_W = 20; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ILOAD = 21; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LLOAD = 22; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FLOAD = 23; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DLOAD = 24; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ALOAD = 25; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ILOAD_0 = 26; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ILOAD_1 = 27; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ILOAD_2 = 28; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ILOAD_3 = 29; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LLOAD_0 = 30; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LLOAD_1 = 31; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LLOAD_2 = 32; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LLOAD_3 = 33; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FLOAD_0 = 34; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FLOAD_1 = 35; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FLOAD_2 = 36; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FLOAD_3 = 37; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DLOAD_0 = 38; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DLOAD_1 = 39; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DLOAD_2 = 40; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DLOAD_3 = 41; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ALOAD_0 = 42; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ALOAD_1 = 43; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ALOAD_2 = 44; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ALOAD_3 = 45; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IALOAD = 46; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LALOAD = 47; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FALOAD = 48; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DALOAD = 49; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short AALOAD = 50; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short BALOAD = 51; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short CALOAD = 52; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short SALOAD = 53; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ISTORE = 54; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LSTORE = 55; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FSTORE = 56; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DSTORE = 57; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ASTORE = 58; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ISTORE_0 = 59; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ISTORE_1 = 60; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ISTORE_2 = 61; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ISTORE_3 = 62; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LSTORE_0 = 63; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LSTORE_1 = 64; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LSTORE_2 = 65; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short LSTORE_3 = 66; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FSTORE_0 = 67; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FSTORE_1 = 68; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FSTORE_2 = 69; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short FSTORE_3 = 70; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DSTORE_0 = 71; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DSTORE_1 = 72; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DSTORE_2 = 73; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short DSTORE_3 = 74; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ASTORE_0 = 75; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ASTORE_1 = 76; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ASTORE_2 = 77; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ASTORE_3 = 78; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IASTORE = 79; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LASTORE = 80; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FASTORE = 81; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DASTORE = 82; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short AASTORE = 83; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short BASTORE = 84; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short CASTORE = 85; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short SASTORE = 86; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short POP = 87; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short POP2 = 88; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short DUP = 89; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DUP_X1 = 90; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DUP_X2 = 91; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DUP2 = 92; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DUP2_X1 = 93; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DUP2_X2 = 94; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short SWAP = 95; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IADD = 96; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LADD = 97; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FADD = 98; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DADD = 99; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ISUB = 100; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LSUB = 101; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FSUB = 102; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DSUB = 103; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IMUL = 104; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LMUL = 105; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FMUL = 106; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DMUL = 107; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IDIV = 108; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LDIV = 109; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FDIV = 110; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DDIV = 111; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IREM = 112; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LREM = 113; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FREM = 114; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DREM = 115; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short INEG = 116; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LNEG = 117; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FNEG = 118; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DNEG = 119; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ISHL = 120; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LSHL = 121; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ISHR = 122; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LSHR = 123; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IUSHR = 124; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LUSHR = 125; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IAND = 126; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LAND = 127; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short IOR = 128; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short LOR = 129; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IXOR = 130; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LXOR = 131; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IINC = 132; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2L = 133; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2F = 134; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2D = 135; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short L2I = 136; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short L2F = 137; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short L2D = 138; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short F2I = 139; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short F2L = 140; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short F2D = 141; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short D2I = 142; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short D2L = 143; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short D2F = 144; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2B = 145; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short INT2BYTE = 145; // Old notation - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2C = 146; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short INT2CHAR = 146; // Old notation - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short I2S = 147; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short INT2SHORT = 147; // Old notation - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LCMP = 148; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FCMPL = 149; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FCMPG = 150; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DCMPL = 151; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DCMPG = 152; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFEQ = 153; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFNE = 154; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFLT = 155; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFGE = 156; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFGT = 157; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFLE = 158; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPEQ = 159; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPNE = 160; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPLT = 161; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPGE = 162; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPGT = 163; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPLE = 164; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ACMPEQ = 165; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short IF_ACMPNE = 166; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short GOTO = 167; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short JSR = 168; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short RET = 169; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short TABLESWITCH = 170; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short LOOKUPSWITCH = 171; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IRETURN = 172; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short LRETURN = 173; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short FRETURN = 174; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short DRETURN = 175; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ARETURN = 176; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short RETURN = 177; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short GETSTATIC = 178; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short PUTSTATIC = 179; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short GETFIELD = 180; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short PUTFIELD = 181; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short INVOKEVIRTUAL = 182; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short INVOKESPECIAL = 183; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short INVOKENONVIRTUAL = 183; // Old name in JDK 1.0 - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short INVOKESTATIC = 184; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short INVOKEINTERFACE = 185; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short INVOKEDYNAMIC = 186; - /** * Java VM opcode. * * @see Opcode definitions in The - * Java Virtual Machine Specification + * Java Virtual Machine Specification */ public static final short NEW = 187; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short NEWARRAY = 188; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short ANEWARRAY = 189; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short ARRAYLENGTH = 190; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short ATHROW = 191; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short CHECKCAST = 192; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short INSTANCEOF = 193; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short MONITORENTER = 194; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short MONITOREXIT = 195; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short WIDE = 196; - /** * Java VM opcode. * * @see Opcode - * definitions in The Java Virtual Machine Specification + * definitions in The Java Virtual Machine Specification */ public static final short MULTIANEWARRAY = 197; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short IFNULL = 198; - /** * Java VM opcode. * * @see Opcode definitions - * in The Java Virtual Machine Specification + * in The Java Virtual Machine Specification */ public static final short IFNONNULL = 199; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short GOTO_W = 200; - /** * Java VM opcode. * * @see Opcode definitions in - * The Java Virtual Machine Specification + * The Java Virtual Machine Specification */ public static final short JSR_W = 201; - /** * JVM internal opcode. * * @see Reserved opcodes in the Java - * Virtual Machine Specification + * Virtual Machine Specification */ public static final short BREAKPOINT = 202; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short LDC_QUICK = 203; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short LDC_W_QUICK = 204; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short LDC2_W_QUICK = 205; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short GETFIELD_QUICK = 206; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short PUTFIELD_QUICK = 207; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short GETFIELD2_QUICK = 208; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short PUTFIELD2_QUICK = 209; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short GETSTATIC_QUICK = 210; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short PUTSTATIC_QUICK = 211; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short GETSTATIC2_QUICK = 212; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short PUTSTATIC2_QUICK = 213; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKEVIRTUAL_QUICK = 214; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKENONVIRTUAL_QUICK = 215; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKESUPER_QUICK = 216; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKESTATIC_QUICK = 217; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKEINTERFACE_QUICK = 218; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKEVIRTUALOBJECT_QUICK = 219; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short NEW_QUICK = 221; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short ANEWARRAY_QUICK = 222; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short MULTIANEWARRAY_QUICK = 223; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short CHECKCAST_QUICK = 224; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INSTANCEOF_QUICK = 225; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short INVOKEVIRTUAL_QUICK_W = 226; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short GETFIELD_QUICK_W = 227; - /** * JVM internal opcode. * * @see - * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) + * "https://web.archive.org/web/20120108031230/http://java.sun.com/docs/books/jvms/first_edition/html/Quick.doc.html"> + * Specification of _quick opcodes in the Java Virtual Machine Specification (version 1) * @see Why the _quick - * opcodes were removed from the second version of the Java Virtual Machine Specification. + * opcodes were removed from the second version of the Java Virtual Machine Specification. */ public static final short PUTFIELD_QUICK_W = 228; - /** * JVM internal opcode. * * @see Reserved opcodes in the Java - * Virtual Machine Specification + * Virtual Machine Specification */ public static final short IMPDEP1 = 254; - /** * JVM internal opcode. * * @see Reserved opcodes in the Java - * Virtual Machine Specification + * Virtual Machine Specification */ public static final short IMPDEP2 = 255; - /** * BCEL virtual instruction for pushing an arbitrary data type onto the stack. Will be converted to the appropriate JVM * opcode when the class is dumped. */ public static final short PUSH = 4711; - /** * BCEL virtual instruction for either LOOKUPSWITCH or TABLESWITCH. Will be converted to the appropriate JVM opcode when * the class is dumped. */ public static final short SWITCH = 4712; - - /** Illegal opcode. */ + /** + * Illegal opcode. + */ public static final short UNDEFINED = -1; - - /** Illegal opcode. */ + /** + * Illegal opcode. + */ public static final short UNPREDICTABLE = -2; - - /** Illegal opcode. */ + /** + * Illegal opcode. + */ public static final short RESERVED = -3; - - /** Mnemonic for an illegal opcode. */ + /** + * Mnemonic for an illegal opcode. + */ public static final String ILLEGAL_OPCODE = ""; - - /** Mnemonic for an illegal type. */ + /** + * Mnemonic for an illegal type. + */ public static final String ILLEGAL_TYPE = ""; - /** * Boolean data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_BOOLEAN = 4; - /** * Char data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_CHAR = 5; - /** * Float data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_FLOAT = 6; - /** * Double data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_DOUBLE = 7; - /** * Byte data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_BYTE = 8; - /** * Short data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_SHORT = 9; - /** * Int data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_INT = 10; - /** * Long data type. * * @see Static Constraints in - * the Java Virtual Machine Specification + * the Java Virtual Machine Specification */ public static final byte T_LONG = 11; - - /** Void data type (non-standard). */ + /** + * Void data type (non-standard). + */ public static final byte T_VOID = 12; // Non-standard - - /** Array data type. */ + /** + * Array data type. + */ public static final byte T_ARRAY = 13; - - /** Object data type. */ + /** + * Object data type. + */ public static final byte T_OBJECT = 14; - - /** Reference data type (deprecated). */ + /** + * Reference data type (deprecated). + */ public static final byte T_REFERENCE = 14; // Deprecated - - /** Unknown data type. */ + /** + * Unknown data type. + */ public static final byte T_UNKNOWN = 15; - - /** Address data type. */ + /** + * Address data type. + */ public static final byte T_ADDRESS = 16; - - /** - * The primitive type names corresponding to the T_XX constants, e.g., TYPE_NAMES[T_INT] = "int" - */ - private static final String[] TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "boolean", "char", "float", "double", "byte", "short", - "int", "long", "void", "array", "object", "unknown", "address"}; - - /** - * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer" - */ - private static final String[] CLASS_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "java.lang.Boolean", "java.lang.Character", - "java.lang.Float", "java.lang.Double", "java.lang.Byte", "java.lang.Short", "java.lang.Integer", "java.lang.Long", "java.lang.Void", ILLEGAL_TYPE, - ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; - - /** - * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I" - */ - private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", - ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; - - /** - * Number of byte code operands for each opcode, i.e., number of bytes after the tag byte itself. Indexed by opcode, so - * NO_OF_OPERANDS[BIPUSH] = the number of operands for a bipush instruction. - */ - static final short[] NO_OF_OPERANDS = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */, - 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */, - 0/* dconst_1 */, 1/* bipush */, 2/* sipush */, 1/* ldc */, 2/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 1/* lload */, 1/* fload */, 1/* dload */, - 1/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */, - 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */, - 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 0/* iaload */, 0/* laload */, 0/* faload */, 0/* daload */, 0/* aaload */, 0/* baload */, 0/* caload */, - 0/* saload */, 1/* istore */, 1/* lstore */, 1/* fstore */, 1/* dstore */, 1/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */, - 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */, - 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */, - 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 0/* dup */, - 0/* dup_x1 */, 0/* dup_x2 */, 0/* dup2 */, 0/* dup2_x1 */, 0/* dup2_x2 */, 0/* swap */, 0/* iadd */, 0/* ladd */, 0/* fadd */, 0/* dadd */, 0/* isub */, - 0/* lsub */, 0/* fsub */, 0/* dsub */, 0/* imul */, 0/* lmul */, 0/* fmul */, 0/* dmul */, 0/* idiv */, 0/* ldiv */, 0/* fdiv */, 0/* ddiv */, - 0/* irem */, 0/* lrem */, 0/* frem */, 0/* drem */, 0/* ineg */, 0/* lneg */, 0/* fneg */, 0/* dneg */, 0/* ishl */, 0/* lshl */, 0/* ishr */, - 0/* lshr */, 0/* iushr */, 0/* lushr */, 0/* iand */, 0/* land */, 0/* ior */, 0/* lor */, 0/* ixor */, 0/* lxor */, 2/* iinc */, 0/* i2l */, - 0/* i2f */, 0/* i2d */, 0/* l2i */, 0/* l2f */, 0/* l2d */, 0/* f2i */, 0/* f2l */, 0/* f2d */, 0/* d2i */, 0/* d2l */, 0/* d2f */, 0/* i2b */, - 0/* i2c */, 0/* i2s */, 0/* lcmp */, 0/* fcmpl */, 0/* fcmpg */, 0/* dcmpl */, 0/* dcmpg */, 2/* ifeq */, 2/* ifne */, 2/* iflt */, 2/* ifge */, - 2/* ifgt */, 2/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2/* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */, - 2/* if_acmpne */, 2/* goto */, 2/* jsr */, 1/* ret */, UNPREDICTABLE/* tableswitch */, UNPREDICTABLE/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, - 0/* freturn */, 0/* dreturn */, 0/* areturn */, 0/* return */, 2/* getstatic */, 2/* putstatic */, 2/* getfield */, 2/* putfield */, - 2/* invokevirtual */, 2/* invokespecial */, 2/* invokestatic */, 4/* invokeinterface */, 4/* invokedynamic */, 2/* new */, 1/* newarray */, - 2/* anewarray */, 0/* arraylength */, 0/* athrow */, 2/* checkcast */, 2/* instanceof */, 0/* monitorenter */, 0/* monitorexit */, - UNPREDICTABLE/* wide */, 3/* multianewarray */, 2/* ifnull */, 2/* ifnonnull */, 4/* goto_w */, 4/* jsr_w */, 0/* breakpoint */, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, RESERVED/* impdep1 */, - RESERVED/* impdep2 */ - }; - - /** - * How the byte code operands are to be interpreted for each opcode. Indexed by opcode. TYPE_OF_OPERANDS[ILOAD] = an - * array of shorts describing the data types for the instruction. - */ - static final short[][] TYPE_OF_OPERANDS = {{}/* nop */, {}/* aconst_null */, {}/* iconst_m1 */, {}/* iconst_0 */, {}/* iconst_1 */, - {}/* iconst_2 */, {}/* iconst_3 */, {}/* iconst_4 */, {}/* iconst_5 */, {}/* lconst_0 */, {}/* lconst_1 */, {}/* fconst_0 */, {}/* fconst_1 */, - {}/* fconst_2 */, {}/* dconst_0 */, {}/* dconst_1 */, {T_BYTE}/* bipush */, {T_SHORT}/* sipush */, {T_BYTE}/* ldc */, {T_SHORT}/* ldc_w */, - {T_SHORT}/* ldc2_w */, {T_BYTE}/* iload */, {T_BYTE}/* lload */, {T_BYTE}/* fload */, {T_BYTE}/* dload */, {T_BYTE}/* aload */, {}/* iload_0 */, - {}/* iload_1 */, {}/* iload_2 */, {}/* iload_3 */, {}/* lload_0 */, {}/* lload_1 */, {}/* lload_2 */, {}/* lload_3 */, {}/* fload_0 */, {}/* fload_1 */, - {}/* fload_2 */, {}/* fload_3 */, {}/* dload_0 */, {}/* dload_1 */, {}/* dload_2 */, {}/* dload_3 */, {}/* aload_0 */, {}/* aload_1 */, {}/* aload_2 */, - {}/* aload_3 */, {}/* iaload */, {}/* laload */, {}/* faload */, {}/* daload */, {}/* aaload */, {}/* baload */, {}/* caload */, {}/* saload */, - {T_BYTE}/* istore */, {T_BYTE}/* lstore */, {T_BYTE}/* fstore */, {T_BYTE}/* dstore */, {T_BYTE}/* astore */, {}/* istore_0 */, {}/* istore_1 */, - {}/* istore_2 */, {}/* istore_3 */, {}/* lstore_0 */, {}/* lstore_1 */, {}/* lstore_2 */, {}/* lstore_3 */, {}/* fstore_0 */, {}/* fstore_1 */, - {}/* fstore_2 */, {}/* fstore_3 */, {}/* dstore_0 */, {}/* dstore_1 */, {}/* dstore_2 */, {}/* dstore_3 */, {}/* astore_0 */, {}/* astore_1 */, - {}/* astore_2 */, {}/* astore_3 */, {}/* iastore */, {}/* lastore */, {}/* fastore */, {}/* dastore */, {}/* aastore */, {}/* bastore */, - {}/* castore */, {}/* sastore */, {}/* pop */, {}/* pop2 */, {}/* dup */, {}/* dup_x1 */, {}/* dup_x2 */, {}/* dup2 */, {}/* dup2_x1 */, - {}/* dup2_x2 */, {}/* swap */, {}/* iadd */, {}/* ladd */, {}/* fadd */, {}/* dadd */, {}/* isub */, {}/* lsub */, {}/* fsub */, {}/* dsub */, - {}/* imul */, {}/* lmul */, {}/* fmul */, {}/* dmul */, {}/* idiv */, {}/* ldiv */, {}/* fdiv */, {}/* ddiv */, {}/* irem */, {}/* lrem */, - {}/* frem */, {}/* drem */, {}/* ineg */, {}/* lneg */, {}/* fneg */, {}/* dneg */, {}/* ishl */, {}/* lshl */, {}/* ishr */, {}/* lshr */, - {}/* iushr */, {}/* lushr */, {}/* iand */, {}/* land */, {}/* ior */, {}/* lor */, {}/* ixor */, {}/* lxor */, {T_BYTE, T_BYTE}/* iinc */, {}/* i2l */, - {}/* i2f */, {}/* i2d */, {}/* l2i */, {}/* l2f */, {}/* l2d */, {}/* f2i */, {}/* f2l */, {}/* f2d */, {}/* d2i */, {}/* d2l */, {}/* d2f */, - {}/* i2b */, {}/* i2c */, {}/* i2s */, {}/* lcmp */, {}/* fcmpl */, {}/* fcmpg */, {}/* dcmpl */, {}/* dcmpg */, {T_SHORT}/* ifeq */, - {T_SHORT}/* ifne */, {T_SHORT}/* iflt */, {T_SHORT}/* ifge */, {T_SHORT}/* ifgt */, {T_SHORT}/* ifle */, {T_SHORT}/* if_icmpeq */, - {T_SHORT}/* if_icmpne */, {T_SHORT}/* if_icmplt */, {T_SHORT}/* if_icmpge */, {T_SHORT}/* if_icmpgt */, {T_SHORT}/* if_icmple */, - {T_SHORT}/* if_acmpeq */, {T_SHORT}/* if_acmpne */, {T_SHORT}/* goto */, {T_SHORT}/* jsr */, {T_BYTE}/* ret */, {}/* tableswitch */, - {}/* lookupswitch */, {}/* ireturn */, {}/* lreturn */, {}/* freturn */, {}/* dreturn */, {}/* areturn */, {}/* return */, {T_SHORT}/* getstatic */, - {T_SHORT}/* putstatic */, {T_SHORT}/* getfield */, {T_SHORT}/* putfield */, {T_SHORT}/* invokevirtual */, {T_SHORT}/* invokespecial */, - {T_SHORT}/* invokestatic */, {T_SHORT, T_BYTE, T_BYTE}/* invokeinterface */, {T_SHORT, T_BYTE, T_BYTE}/* invokedynamic */, {T_SHORT}/* new */, - {T_BYTE}/* newarray */, {T_SHORT}/* anewarray */, {}/* arraylength */, {}/* athrow */, {T_SHORT}/* checkcast */, {T_SHORT}/* instanceof */, - {}/* monitorenter */, {}/* monitorexit */, {T_BYTE}/* wide */, {T_SHORT, T_BYTE}/* multianewarray */, {T_SHORT}/* ifnull */, {T_SHORT}/* ifnonnull */, - {T_INT}/* goto_w */, {T_INT}/* jsr_w */, {}/* breakpoint */, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, - {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}/* impdep1 */, {}/* impdep2 */ - }; - - /** - * Names of opcodes. Indexed by opcode. OPCODE_NAMES[ALOAD] = "aload". - */ - static final String[] OPCODE_NAMES = {"nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5", - "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload", - "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", - "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", - "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", - "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", - "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1", - "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", - "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", - "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", - "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", - "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", - "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", - "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", - "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, - ILLEGAL_OPCODE, ILLEGAL_OPCODE, "impdep1", "impdep2"}; - - /** - * @since 6.0 - */ - public static final int OPCODE_NAMES_LENGTH = OPCODE_NAMES.length; - - /** - * Number of words consumed on operand stack by instructions. Indexed by opcode. CONSUME_STACK[FALOAD] = number of words - * consumed from the stack by a faload instruction. - */ - static final int[] CONSUME_STACK = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */, - 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */, - 0/* dconst_1 */, 0/* bipush */, 0/* sipush */, 0/* ldc */, 0/* ldc_w */, 0/* ldc2_w */, 0/* iload */, 0/* lload */, 0/* fload */, 0/* dload */, - 0/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */, - 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */, - 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 2/* iaload */, 2/* laload */, 2/* faload */, 2/* daload */, 2/* aaload */, 2/* baload */, 2/* caload */, - 2/* saload */, 1/* istore */, 2/* lstore */, 1/* fstore */, 2/* dstore */, 1/* astore */, 1/* istore_0 */, 1/* istore_1 */, 1/* istore_2 */, - 1/* istore_3 */, 2/* lstore_0 */, 2/* lstore_1 */, 2/* lstore_2 */, 2/* lstore_3 */, 1/* fstore_0 */, 1/* fstore_1 */, 1/* fstore_2 */, 1/* fstore_3 */, - 2/* dstore_0 */, 2/* dstore_1 */, 2/* dstore_2 */, 2/* dstore_3 */, 1/* astore_0 */, 1/* astore_1 */, 1/* astore_2 */, 1/* astore_3 */, 3/* iastore */, - 4/* lastore */, 3/* fastore */, 4/* dastore */, 3/* aastore */, 3/* bastore */, 3/* castore */, 3/* sastore */, 1/* pop */, 2/* pop2 */, 1/* dup */, - 2/* dup_x1 */, 3/* dup_x2 */, 2/* dup2 */, 3/* dup2_x1 */, 4/* dup2_x2 */, 2/* swap */, 2/* iadd */, 4/* ladd */, 2/* fadd */, 4/* dadd */, 2/* isub */, - 4/* lsub */, 2/* fsub */, 4/* dsub */, 2/* imul */, 4/* lmul */, 2/* fmul */, 4/* dmul */, 2/* idiv */, 4/* ldiv */, 2/* fdiv */, 4/* ddiv */, - 2/* irem */, 4/* lrem */, 2/* frem */, 4/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 2/* ishl */, 3/* lshl */, 2/* ishr */, - 3/* lshr */, 2/* iushr */, 3/* lushr */, 2/* iand */, 4/* land */, 2/* ior */, 4/* lor */, 2/* ixor */, 4/* lxor */, 0/* iinc */, 1/* i2l */, - 1/* i2f */, 1/* i2d */, 2/* l2i */, 2/* l2f */, 2/* l2d */, 1/* f2i */, 1/* f2l */, 1/* f2d */, 2/* d2i */, 2/* d2l */, 2/* d2f */, 1/* i2b */, - 1/* i2c */, 1/* i2s */, 4/* lcmp */, 2/* fcmpl */, 2/* fcmpg */, 4/* dcmpl */, 4/* dcmpg */, 1/* ifeq */, 1/* ifne */, 1/* iflt */, 1/* ifge */, - 1/* ifgt */, 1/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2 /* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */, - 2/* if_acmpne */, 0/* goto */, 0/* jsr */, 0/* ret */, 1/* tableswitch */, 1/* lookupswitch */, 1/* ireturn */, 2/* lreturn */, 1/* freturn */, - 2/* dreturn */, 1/* areturn */, 0/* return */, 0/* getstatic */, UNPREDICTABLE/* putstatic */, 1/* getfield */, UNPREDICTABLE/* putfield */, - UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */, - UNPREDICTABLE/* invokedynamic */, 0/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */, - 1/* monitorenter */, 1/* monitorexit */, 0/* wide */, UNPREDICTABLE/* multianewarray */, 1/* ifnull */, 1/* ifnonnull */, 0/* goto_w */, 0/* jsr_w */, - 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */ - }; - - /** - * Number of words produced onto operand stack by instructions. Indexed by opcode. CONSUME_STACK[DALOAD] = number of - * words consumed from the stack by a daload instruction. - */ - static final int[] PRODUCE_STACK = {0/* nop */, 1/* aconst_null */, 1/* iconst_m1 */, 1/* iconst_0 */, 1/* iconst_1 */, 1/* iconst_2 */, - 1/* iconst_3 */, 1/* iconst_4 */, 1/* iconst_5 */, 2/* lconst_0 */, 2/* lconst_1 */, 1/* fconst_0 */, 1/* fconst_1 */, 1/* fconst_2 */, 2/* dconst_0 */, - 2/* dconst_1 */, 1/* bipush */, 1/* sipush */, 1/* ldc */, 1/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 2/* lload */, 1/* fload */, 2/* dload */, - 1/* aload */, 1/* iload_0 */, 1/* iload_1 */, 1/* iload_2 */, 1/* iload_3 */, 2/* lload_0 */, 2/* lload_1 */, 2/* lload_2 */, 2/* lload_3 */, - 1/* fload_0 */, 1/* fload_1 */, 1/* fload_2 */, 1/* fload_3 */, 2/* dload_0 */, 2/* dload_1 */, 2/* dload_2 */, 2/* dload_3 */, 1/* aload_0 */, - 1/* aload_1 */, 1/* aload_2 */, 1/* aload_3 */, 1/* iaload */, 2/* laload */, 1/* faload */, 2/* daload */, 1/* aaload */, 1/* baload */, 1/* caload */, - 1/* saload */, 0/* istore */, 0/* lstore */, 0/* fstore */, 0/* dstore */, 0/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */, - 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */, - 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */, - 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 2/* dup */, - 3/* dup_x1 */, 4/* dup_x2 */, 4/* dup2 */, 5/* dup2_x1 */, 6/* dup2_x2 */, 2/* swap */, 1/* iadd */, 2/* ladd */, 1/* fadd */, 2/* dadd */, 1/* isub */, - 2/* lsub */, 1/* fsub */, 2/* dsub */, 1/* imul */, 2/* lmul */, 1/* fmul */, 2/* dmul */, 1/* idiv */, 2/* ldiv */, 1/* fdiv */, 2/* ddiv */, - 1/* irem */, 2/* lrem */, 1/* frem */, 2/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 1/* ishl */, 2/* lshl */, 1/* ishr */, - 2/* lshr */, 1/* iushr */, 2/* lushr */, 1/* iand */, 2/* land */, 1/* ior */, 2/* lor */, 1/* ixor */, 2/* lxor */, 0/* iinc */, 2/* i2l */, - 1/* i2f */, 2/* i2d */, 1/* l2i */, 1/* l2f */, 2/* l2d */, 1/* f2i */, 2/* f2l */, 2/* f2d */, 1/* d2i */, 2/* d2l */, 1/* d2f */, 1/* i2b */, - 1/* i2c */, 1/* i2s */, 1/* lcmp */, 1/* fcmpl */, 1/* fcmpg */, 1/* dcmpl */, 1/* dcmpg */, 0/* ifeq */, 0/* ifne */, 0/* iflt */, 0/* ifge */, - 0/* ifgt */, 0/* ifle */, 0/* if_icmpeq */, 0/* if_icmpne */, 0/* if_icmplt */, 0/* if_icmpge */, 0/* if_icmpgt */, 0/* if_icmple */, 0/* if_acmpeq */, - 0/* if_acmpne */, 0/* goto */, 1/* jsr */, 0/* ret */, 0/* tableswitch */, 0/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, 0/* freturn */, - 0/* dreturn */, 0/* areturn */, 0/* return */, UNPREDICTABLE/* getstatic */, 0/* putstatic */, UNPREDICTABLE/* getfield */, 0/* putfield */, - UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */, - UNPREDICTABLE/* invokedynamic */, 1/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */, - 0/* monitorenter */, 0/* monitorexit */, 0/* wide */, 1/* multianewarray */, 0/* ifnull */, 0/* ifnonnull */, 0/* goto_w */, 1/* jsr_w */, - 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, - UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */ - }; - /** * Attributes and their corresponding names. */ public static final byte ATTR_UNKNOWN = -1; - public static final byte ATTR_SOURCE_FILE = 0; - public static final byte ATTR_CONSTANT_VALUE = 1; - public static final byte ATTR_CODE = 2; - public static final byte ATTR_EXCEPTIONS = 3; - public static final byte ATTR_LINE_NUMBER_TABLE = 4; - public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5; - public static final byte ATTR_INNER_CLASSES = 6; - public static final byte ATTR_SYNTHETIC = 7; - public static final byte ATTR_DEPRECATED = 8; - public static final byte ATTR_PMG = 9; - public static final byte ATTR_SIGNATURE = 10; - public static final byte ATTR_STACK_MAP = 11; public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS = 12; public static final byte ATTR_RUNTIME_INVISIBLE_ANNOTATIONS = 13; @@ -3028,10 +2558,6 @@ public final class Const { public static final byte ATTR_NEST_HOST = 25; public static final byte ATTR_NEST_MEMBERS = 26; public static final short KNOWN_ATTRIBUTES = 27; // count of attributes - private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", - "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", - "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", - "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"}; /** * Constants used in the StackMap attribute. */ @@ -3044,19 +2570,14 @@ public final class Const { public static final byte ITEM_InitObject = 6; public static final byte ITEM_Object = 7; public static final byte ITEM_NewObject = 8; - private static final String[] ITEM_NAMES = {"Bogus", "Integer", "Float", "Double", "Long", "Null", "InitObject", "Object", "NewObject"}; - /** * Constants used to identify StackMapEntry types. - * + *

* For those types which can specify a range, the constant names the lowest value. */ public static final int SAME_FRAME = 0; - public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; - public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; - public static final int CHOP_FRAME = 248; public static final int SAME_FRAME_EXTENDED = 251; public static final int APPEND_FRAME = 252; @@ -3070,22 +2591,219 @@ public final class Const { public static final int CHOP_FRAME_MAX = 250; public static final int APPEND_FRAME_MAX = 254; public static final byte REF_getField = 1; - public static final byte REF_getStatic = 2; - public static final byte REF_putField = 3; - public static final byte REF_putStatic = 4; public static final byte REF_invokeVirtual = 5; public static final byte REF_invokeStatic = 6; public static final byte REF_invokeSpecial = 7; public static final byte REF_newInvokeSpecial = 8; public static final byte REF_invokeInterface = 9; + /** + * Number of byte code operands for each opcode, i.e., number of bytes after the tag byte itself. Indexed by opcode, so + * NO_OF_OPERANDS[BIPUSH] = the number of operands for a bipush instruction. + */ + static final short[] NO_OF_OPERANDS = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */, + 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */, + 0/* dconst_1 */, 1/* bipush */, 2/* sipush */, 1/* ldc */, 2/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 1/* lload */, 1/* fload */, 1/* dload */, + 1/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */, + 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */, + 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 0/* iaload */, 0/* laload */, 0/* faload */, 0/* daload */, 0/* aaload */, 0/* baload */, 0/* caload */, + 0/* saload */, 1/* istore */, 1/* lstore */, 1/* fstore */, 1/* dstore */, 1/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */, + 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */, + 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */, + 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 0/* dup */, + 0/* dup_x1 */, 0/* dup_x2 */, 0/* dup2 */, 0/* dup2_x1 */, 0/* dup2_x2 */, 0/* swap */, 0/* iadd */, 0/* ladd */, 0/* fadd */, 0/* dadd */, 0/* isub */, + 0/* lsub */, 0/* fsub */, 0/* dsub */, 0/* imul */, 0/* lmul */, 0/* fmul */, 0/* dmul */, 0/* idiv */, 0/* ldiv */, 0/* fdiv */, 0/* ddiv */, + 0/* irem */, 0/* lrem */, 0/* frem */, 0/* drem */, 0/* ineg */, 0/* lneg */, 0/* fneg */, 0/* dneg */, 0/* ishl */, 0/* lshl */, 0/* ishr */, + 0/* lshr */, 0/* iushr */, 0/* lushr */, 0/* iand */, 0/* land */, 0/* ior */, 0/* lor */, 0/* ixor */, 0/* lxor */, 2/* iinc */, 0/* i2l */, + 0/* i2f */, 0/* i2d */, 0/* l2i */, 0/* l2f */, 0/* l2d */, 0/* f2i */, 0/* f2l */, 0/* f2d */, 0/* d2i */, 0/* d2l */, 0/* d2f */, 0/* i2b */, + 0/* i2c */, 0/* i2s */, 0/* lcmp */, 0/* fcmpl */, 0/* fcmpg */, 0/* dcmpl */, 0/* dcmpg */, 2/* ifeq */, 2/* ifne */, 2/* iflt */, 2/* ifge */, + 2/* ifgt */, 2/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2/* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */, + 2/* if_acmpne */, 2/* goto */, 2/* jsr */, 1/* ret */, UNPREDICTABLE/* tableswitch */, UNPREDICTABLE/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, + 0/* freturn */, 0/* dreturn */, 0/* areturn */, 0/* return */, 2/* getstatic */, 2/* putstatic */, 2/* getfield */, 2/* putfield */, + 2/* invokevirtual */, 2/* invokespecial */, 2/* invokestatic */, 4/* invokeinterface */, 4/* invokedynamic */, 2/* new */, 1/* newarray */, + 2/* anewarray */, 0/* arraylength */, 0/* athrow */, 2/* checkcast */, 2/* instanceof */, 0/* monitorenter */, 0/* monitorexit */, + UNPREDICTABLE/* wide */, 3/* multianewarray */, 2/* ifnull */, 2/* ifnonnull */, 4/* goto_w */, 4/* jsr_w */, 0/* breakpoint */, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, RESERVED/* impdep1 */, + RESERVED/* impdep2 */ + }; + /** + * How the byte code operands are to be interpreted for each opcode. Indexed by opcode. TYPE_OF_OPERANDS[ILOAD] = an + * array of shorts describing the data types for the instruction. + */ + static final short[][] TYPE_OF_OPERANDS = {{}/* nop */, {}/* aconst_null */, {}/* iconst_m1 */, {}/* iconst_0 */, {}/* iconst_1 */, + {}/* iconst_2 */, {}/* iconst_3 */, {}/* iconst_4 */, {}/* iconst_5 */, {}/* lconst_0 */, {}/* lconst_1 */, {}/* fconst_0 */, {}/* fconst_1 */, + {}/* fconst_2 */, {}/* dconst_0 */, {}/* dconst_1 */, {T_BYTE}/* bipush */, {T_SHORT}/* sipush */, {T_BYTE}/* ldc */, {T_SHORT}/* ldc_w */, + {T_SHORT}/* ldc2_w */, {T_BYTE}/* iload */, {T_BYTE}/* lload */, {T_BYTE}/* fload */, {T_BYTE}/* dload */, {T_BYTE}/* aload */, {}/* iload_0 */, + {}/* iload_1 */, {}/* iload_2 */, {}/* iload_3 */, {}/* lload_0 */, {}/* lload_1 */, {}/* lload_2 */, {}/* lload_3 */, {}/* fload_0 */, {}/* fload_1 */, + {}/* fload_2 */, {}/* fload_3 */, {}/* dload_0 */, {}/* dload_1 */, {}/* dload_2 */, {}/* dload_3 */, {}/* aload_0 */, {}/* aload_1 */, {}/* aload_2 */, + {}/* aload_3 */, {}/* iaload */, {}/* laload */, {}/* faload */, {}/* daload */, {}/* aaload */, {}/* baload */, {}/* caload */, {}/* saload */, + {T_BYTE}/* istore */, {T_BYTE}/* lstore */, {T_BYTE}/* fstore */, {T_BYTE}/* dstore */, {T_BYTE}/* astore */, {}/* istore_0 */, {}/* istore_1 */, + {}/* istore_2 */, {}/* istore_3 */, {}/* lstore_0 */, {}/* lstore_1 */, {}/* lstore_2 */, {}/* lstore_3 */, {}/* fstore_0 */, {}/* fstore_1 */, + {}/* fstore_2 */, {}/* fstore_3 */, {}/* dstore_0 */, {}/* dstore_1 */, {}/* dstore_2 */, {}/* dstore_3 */, {}/* astore_0 */, {}/* astore_1 */, + {}/* astore_2 */, {}/* astore_3 */, {}/* iastore */, {}/* lastore */, {}/* fastore */, {}/* dastore */, {}/* aastore */, {}/* bastore */, + {}/* castore */, {}/* sastore */, {}/* pop */, {}/* pop2 */, {}/* dup */, {}/* dup_x1 */, {}/* dup_x2 */, {}/* dup2 */, {}/* dup2_x1 */, + {}/* dup2_x2 */, {}/* swap */, {}/* iadd */, {}/* ladd */, {}/* fadd */, {}/* dadd */, {}/* isub */, {}/* lsub */, {}/* fsub */, {}/* dsub */, + {}/* imul */, {}/* lmul */, {}/* fmul */, {}/* dmul */, {}/* idiv */, {}/* ldiv */, {}/* fdiv */, {}/* ddiv */, {}/* irem */, {}/* lrem */, + {}/* frem */, {}/* drem */, {}/* ineg */, {}/* lneg */, {}/* fneg */, {}/* dneg */, {}/* ishl */, {}/* lshl */, {}/* ishr */, {}/* lshr */, + {}/* iushr */, {}/* lushr */, {}/* iand */, {}/* land */, {}/* ior */, {}/* lor */, {}/* ixor */, {}/* lxor */, {T_BYTE, T_BYTE}/* iinc */, {}/* i2l */, + {}/* i2f */, {}/* i2d */, {}/* l2i */, {}/* l2f */, {}/* l2d */, {}/* f2i */, {}/* f2l */, {}/* f2d */, {}/* d2i */, {}/* d2l */, {}/* d2f */, + {}/* i2b */, {}/* i2c */, {}/* i2s */, {}/* lcmp */, {}/* fcmpl */, {}/* fcmpg */, {}/* dcmpl */, {}/* dcmpg */, {T_SHORT}/* ifeq */, + {T_SHORT}/* ifne */, {T_SHORT}/* iflt */, {T_SHORT}/* ifge */, {T_SHORT}/* ifgt */, {T_SHORT}/* ifle */, {T_SHORT}/* if_icmpeq */, + {T_SHORT}/* if_icmpne */, {T_SHORT}/* if_icmplt */, {T_SHORT}/* if_icmpge */, {T_SHORT}/* if_icmpgt */, {T_SHORT}/* if_icmple */, + {T_SHORT}/* if_acmpeq */, {T_SHORT}/* if_acmpne */, {T_SHORT}/* goto */, {T_SHORT}/* jsr */, {T_BYTE}/* ret */, {}/* tableswitch */, + {}/* lookupswitch */, {}/* ireturn */, {}/* lreturn */, {}/* freturn */, {}/* dreturn */, {}/* areturn */, {}/* return */, {T_SHORT}/* getstatic */, + {T_SHORT}/* putstatic */, {T_SHORT}/* getfield */, {T_SHORT}/* putfield */, {T_SHORT}/* invokevirtual */, {T_SHORT}/* invokespecial */, + {T_SHORT}/* invokestatic */, {T_SHORT, T_BYTE, T_BYTE}/* invokeinterface */, {T_SHORT, T_BYTE, T_BYTE}/* invokedynamic */, {T_SHORT}/* new */, + {T_BYTE}/* newarray */, {T_SHORT}/* anewarray */, {}/* arraylength */, {}/* athrow */, {T_SHORT}/* checkcast */, {T_SHORT}/* instanceof */, + {}/* monitorenter */, {}/* monitorexit */, {T_BYTE}/* wide */, {T_SHORT, T_BYTE}/* multianewarray */, {T_SHORT}/* ifnull */, {T_SHORT}/* ifnonnull */, + {T_INT}/* goto_w */, {T_INT}/* jsr_w */, {}/* breakpoint */, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, + {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}/* impdep1 */, {}/* impdep2 */ + }; + /** + * Names of opcodes. Indexed by opcode. OPCODE_NAMES[ALOAD] = "aload". + */ + static final String[] OPCODE_NAMES = {"nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5", + "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload", + "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", + "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", + "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", + "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", + "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1", + "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", + "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", + "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", + "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", + "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", + "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", + "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", + "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, + ILLEGAL_OPCODE, ILLEGAL_OPCODE, "impdep1", "impdep2"}; + /** + * @since 6.0 + */ + public static final int OPCODE_NAMES_LENGTH = OPCODE_NAMES.length; + /** + * Number of words consumed on operand stack by instructions. Indexed by opcode. CONSUME_STACK[FALOAD] = number of words + * consumed from the stack by a faload instruction. + */ + static final int[] CONSUME_STACK = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */, + 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */, + 0/* dconst_1 */, 0/* bipush */, 0/* sipush */, 0/* ldc */, 0/* ldc_w */, 0/* ldc2_w */, 0/* iload */, 0/* lload */, 0/* fload */, 0/* dload */, + 0/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */, + 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */, + 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 2/* iaload */, 2/* laload */, 2/* faload */, 2/* daload */, 2/* aaload */, 2/* baload */, 2/* caload */, + 2/* saload */, 1/* istore */, 2/* lstore */, 1/* fstore */, 2/* dstore */, 1/* astore */, 1/* istore_0 */, 1/* istore_1 */, 1/* istore_2 */, + 1/* istore_3 */, 2/* lstore_0 */, 2/* lstore_1 */, 2/* lstore_2 */, 2/* lstore_3 */, 1/* fstore_0 */, 1/* fstore_1 */, 1/* fstore_2 */, 1/* fstore_3 */, + 2/* dstore_0 */, 2/* dstore_1 */, 2/* dstore_2 */, 2/* dstore_3 */, 1/* astore_0 */, 1/* astore_1 */, 1/* astore_2 */, 1/* astore_3 */, 3/* iastore */, + 4/* lastore */, 3/* fastore */, 4/* dastore */, 3/* aastore */, 3/* bastore */, 3/* castore */, 3/* sastore */, 1/* pop */, 2/* pop2 */, 1/* dup */, + 2/* dup_x1 */, 3/* dup_x2 */, 2/* dup2 */, 3/* dup2_x1 */, 4/* dup2_x2 */, 2/* swap */, 2/* iadd */, 4/* ladd */, 2/* fadd */, 4/* dadd */, 2/* isub */, + 4/* lsub */, 2/* fsub */, 4/* dsub */, 2/* imul */, 4/* lmul */, 2/* fmul */, 4/* dmul */, 2/* idiv */, 4/* ldiv */, 2/* fdiv */, 4/* ddiv */, + 2/* irem */, 4/* lrem */, 2/* frem */, 4/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 2/* ishl */, 3/* lshl */, 2/* ishr */, + 3/* lshr */, 2/* iushr */, 3/* lushr */, 2/* iand */, 4/* land */, 2/* ior */, 4/* lor */, 2/* ixor */, 4/* lxor */, 0/* iinc */, 1/* i2l */, + 1/* i2f */, 1/* i2d */, 2/* l2i */, 2/* l2f */, 2/* l2d */, 1/* f2i */, 1/* f2l */, 1/* f2d */, 2/* d2i */, 2/* d2l */, 2/* d2f */, 1/* i2b */, + 1/* i2c */, 1/* i2s */, 4/* lcmp */, 2/* fcmpl */, 2/* fcmpg */, 4/* dcmpl */, 4/* dcmpg */, 1/* ifeq */, 1/* ifne */, 1/* iflt */, 1/* ifge */, + 1/* ifgt */, 1/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2 /* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */, + 2/* if_acmpne */, 0/* goto */, 0/* jsr */, 0/* ret */, 1/* tableswitch */, 1/* lookupswitch */, 1/* ireturn */, 2/* lreturn */, 1/* freturn */, + 2/* dreturn */, 1/* areturn */, 0/* return */, 0/* getstatic */, UNPREDICTABLE/* putstatic */, 1/* getfield */, UNPREDICTABLE/* putfield */, + UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */, + UNPREDICTABLE/* invokedynamic */, 0/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */, + 1/* monitorenter */, 1/* monitorexit */, 0/* wide */, UNPREDICTABLE/* multianewarray */, 1/* ifnull */, 1/* ifnonnull */, 0/* goto_w */, 0/* jsr_w */, + 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */ + }; + /** + * Number of words produced onto operand stack by instructions. Indexed by opcode. CONSUME_STACK[DALOAD] = number of + * words consumed from the stack by a daload instruction. + */ + static final int[] PRODUCE_STACK = {0/* nop */, 1/* aconst_null */, 1/* iconst_m1 */, 1/* iconst_0 */, 1/* iconst_1 */, 1/* iconst_2 */, + 1/* iconst_3 */, 1/* iconst_4 */, 1/* iconst_5 */, 2/* lconst_0 */, 2/* lconst_1 */, 1/* fconst_0 */, 1/* fconst_1 */, 1/* fconst_2 */, 2/* dconst_0 */, + 2/* dconst_1 */, 1/* bipush */, 1/* sipush */, 1/* ldc */, 1/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 2/* lload */, 1/* fload */, 2/* dload */, + 1/* aload */, 1/* iload_0 */, 1/* iload_1 */, 1/* iload_2 */, 1/* iload_3 */, 2/* lload_0 */, 2/* lload_1 */, 2/* lload_2 */, 2/* lload_3 */, + 1/* fload_0 */, 1/* fload_1 */, 1/* fload_2 */, 1/* fload_3 */, 2/* dload_0 */, 2/* dload_1 */, 2/* dload_2 */, 2/* dload_3 */, 1/* aload_0 */, + 1/* aload_1 */, 1/* aload_2 */, 1/* aload_3 */, 1/* iaload */, 2/* laload */, 1/* faload */, 2/* daload */, 1/* aaload */, 1/* baload */, 1/* caload */, + 1/* saload */, 0/* istore */, 0/* lstore */, 0/* fstore */, 0/* dstore */, 0/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */, + 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */, + 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */, + 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 2/* dup */, + 3/* dup_x1 */, 4/* dup_x2 */, 4/* dup2 */, 5/* dup2_x1 */, 6/* dup2_x2 */, 2/* swap */, 1/* iadd */, 2/* ladd */, 1/* fadd */, 2/* dadd */, 1/* isub */, + 2/* lsub */, 1/* fsub */, 2/* dsub */, 1/* imul */, 2/* lmul */, 1/* fmul */, 2/* dmul */, 1/* idiv */, 2/* ldiv */, 1/* fdiv */, 2/* ddiv */, + 1/* irem */, 2/* lrem */, 1/* frem */, 2/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 1/* ishl */, 2/* lshl */, 1/* ishr */, + 2/* lshr */, 1/* iushr */, 2/* lushr */, 1/* iand */, 2/* land */, 1/* ior */, 2/* lor */, 1/* ixor */, 2/* lxor */, 0/* iinc */, 2/* i2l */, + 1/* i2f */, 2/* i2d */, 1/* l2i */, 1/* l2f */, 2/* l2d */, 1/* f2i */, 2/* f2l */, 2/* f2d */, 1/* d2i */, 2/* d2l */, 1/* d2f */, 1/* i2b */, + 1/* i2c */, 1/* i2s */, 1/* lcmp */, 1/* fcmpl */, 1/* fcmpg */, 1/* dcmpl */, 1/* dcmpg */, 0/* ifeq */, 0/* ifne */, 0/* iflt */, 0/* ifge */, + 0/* ifgt */, 0/* ifle */, 0/* if_icmpeq */, 0/* if_icmpne */, 0/* if_icmplt */, 0/* if_icmpge */, 0/* if_icmpgt */, 0/* if_icmple */, 0/* if_acmpeq */, + 0/* if_acmpne */, 0/* goto */, 1/* jsr */, 0/* ret */, 0/* tableswitch */, 0/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, 0/* freturn */, + 0/* dreturn */, 0/* areturn */, 0/* return */, UNPREDICTABLE/* getstatic */, 0/* putstatic */, UNPREDICTABLE/* getfield */, 0/* putfield */, + UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */, + UNPREDICTABLE/* invokedynamic */, 1/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */, + 0/* monitorenter */, 0/* monitorexit */, 0/* wide */, 1/* multianewarray */, 0/* ifnull */, 0/* ifnonnull */, 0/* goto_w */, 1/* jsr_w */, + 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, + UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */ + }; + /** + * The names of the access flags. + */ + private static final String[] ACCESS_NAMES = {"public", "private", "protected", "static", "final", "synchronized", "volatile", "transient", "native", + "interface", "abstract", "strictfp", "synthetic", "annotation", "enum", "module"}; + /** + * @since 6.0 + */ + public static final int ACCESS_NAMES_LENGTH = ACCESS_NAMES.length; + /** + * The names of the types of entries in a constant pool. Use getConstantName instead + */ + private static final String[] CONSTANT_NAMES = {"", "CONSTANT_Utf8", "", "CONSTANT_Integer", "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double", + "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref", "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref", "CONSTANT_NameAndType", "", "", + "CONSTANT_MethodHandle", "CONSTANT_MethodType", "CONSTANT_Dynamic", "CONSTANT_InvokeDynamic", "CONSTANT_Module", "CONSTANT_Package"}; + /** + * The names of the interfaces implemented by arrays + */ + private static final String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"}; + /** + * The primitive type names corresponding to the T_XX constants, e.g., TYPE_NAMES[T_INT] = "int" + */ + private static final String[] TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "boolean", "char", "float", "double", "byte", "short", + "int", "long", "void", "array", "object", "unknown", "address"}; + /** + * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer" + */ + private static final String[] CLASS_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "java.lang.Boolean", "java.lang.Character", + "java.lang.Float", "java.lang.Double", "java.lang.Byte", "java.lang.Short", "java.lang.Integer", "java.lang.Long", "java.lang.Void", ILLEGAL_TYPE, + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; + /** + * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I" + */ + private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", + ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; + private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", + "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", + "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", + "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"}; + private static final String[] ITEM_NAMES = {"Bogus", "Integer", "Float", "Double", "Long", "Null", "InitObject", "Object", "NewObject"}; /** * The names of the reference_kinds of a CONSTANT_MethodHandle_info. */ private static final String[] METHODHANDLE_NAMES = {"", "getField", "getStatic", "putField", "putStatic", "invokeVirtual", "invokeStatic", "invokeSpecial", - "newInvokeSpecial", "invokeInterface"}; + "newInvokeSpecial", "invokeInterface"}; + + private Const() { + } // not instantiable /** * @param index @@ -3097,7 +2815,6 @@ public final class Const { } /** - * * @param index * @return the attribute name * @since 6.0 @@ -3117,8 +2834,9 @@ public final class Const { return CLASS_TYPE_NAMES[index]; } + // Constants defining the behavior of the Method Handles (JVMS �5.4.3.5) + /** - * * @param index * @return the CONSTANT_NAMES entry at the given index * @since 6.0 @@ -3127,10 +2845,7 @@ public final class Const { return CONSTANT_NAMES[index]; } - // Constants defining the behavior of the Method Handles (JVMS �5.4.3.5) - /** - * * @param index * @return Number of words consumed on operand stack * @since 6.0 @@ -3147,7 +2862,6 @@ public final class Const { } /** - * * @param index * @return the item name * @since 6.0 @@ -3157,7 +2871,6 @@ public final class Const { } /** - * * @param index * @return the method handle name * @since 6.0 @@ -3167,7 +2880,6 @@ public final class Const { } /** - * * @param index * @return Number of byte code operands * @since 6.0 @@ -3198,7 +2910,6 @@ public final class Const { } /** - * * @param index * @return Number of words produced onto operand stack * @since 6.0 @@ -3208,7 +2919,6 @@ public final class Const { } /** - * * @param index * @return the short type name * @since 6.0 @@ -3228,7 +2938,4 @@ public final class Const { return TYPE_NAMES[index]; } - private Const() { - } // not instantiable - } diff --git a/src/main/java/haidnor/jvm/bcel/ExceptionConst.java b/src/main/java/haidnor/jvm/bcel/ExceptionConst.java index e9a96df..ba3b4d8 100644 --- a/src/main/java/haidnor/jvm/bcel/ExceptionConst.java +++ b/src/main/java/haidnor/jvm/bcel/ExceptionConst.java @@ -25,24 +25,14 @@ import org.apache.commons.lang3.ArrayUtils; */ public final class ExceptionConst { - /** - * Enum corresponding to the various Exception Class arrays, used by - * {@link ExceptionConst#createExceptions(EXCS, Class...)} - */ - public enum EXCS { - EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION, - } - /** * The mother of all exceptions */ public static final Class THROWABLE = Throwable.class; - /** * Super class of any run-time exception */ public static final Class RUNTIME_EXCEPTION = RuntimeException.class; - /** * Super class of any linking exception (aka Linkage Error) */ @@ -61,62 +51,56 @@ public final class ExceptionConst { public static final Class NO_SUCH_METHOD_ERROR = NoSuchMethodError.class; public static final Class NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class; public static final Class UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class; - public static final Class VERIFY_ERROR = VerifyError.class; - /* UnsupportedClassVersionError is new in JDK 1.2 */ -// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class; /** * Run-Time Exceptions */ public static final Class NULL_POINTER_EXCEPTION = NullPointerException.class; + /* UnsupportedClassVersionError is new in JDK 1.2 */ +// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class; public static final Class ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class; public static final Class ARITHMETIC_EXCEPTION = ArithmeticException.class; public static final Class NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class; public static final Class CLASS_CAST_EXCEPTION = ClassCastException.class; - public static final Class ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class; /** * Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual Machine Specification */ private static final Class[] EXCS_CLASS_AND_INTERFACE_RESOLUTION = {NO_CLASS_DEF_FOUND_ERROR, CLASS_FORMAT_ERROR, VERIFY_ERROR, ABSTRACT_METHOD_ERROR, - EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR}; // Chapter 5.1 - + EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR}; // Chapter 5.1 private static final Class[] EXCS_FIELD_AND_METHOD_RESOLUTION = {NO_SUCH_FIELD_ERROR, ILLEGAL_ACCESS_ERROR, NO_SUCH_METHOD_ERROR}; // Chapter 5.2 - /** * Empty array. */ private static final Class[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below) - /** * Empty array. */ private static final Class[] EXCS_STRING_RESOLUTION = new Class[0]; - // Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.) private static final Class[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION}; /** * Creates a copy of the specified Exception Class array combined with any additional Exception classes. * - * @param type the basic array type + * @param type the basic array type * @param extraClasses additional classes, if any * @return the merged array */ public static Class[] createExceptions(final EXCS type, final Class... extraClasses) { switch (type) { - case EXCS_CLASS_AND_INTERFACE_RESOLUTION: - return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses); - case EXCS_ARRAY_EXCEPTION: - return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses); - case EXCS_FIELD_AND_METHOD_RESOLUTION: - return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses); - case EXCS_INTERFACE_METHOD_RESOLUTION: - return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses); - case EXCS_STRING_RESOLUTION: - return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses); - default: - throw new AssertionError("Cannot happen; unexpected enum value: " + type); + case EXCS_CLASS_AND_INTERFACE_RESOLUTION: + return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses); + case EXCS_ARRAY_EXCEPTION: + return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses); + case EXCS_FIELD_AND_METHOD_RESOLUTION: + return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses); + case EXCS_INTERFACE_METHOD_RESOLUTION: + return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses); + case EXCS_STRING_RESOLUTION: + return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses); + default: + throw new AssertionError("Cannot happen; unexpected enum value: " + type); } } @@ -125,4 +109,12 @@ public final class ExceptionConst { return ArrayUtils.addAll(input, extraClasses); } + /** + * Enum corresponding to the various Exception Class arrays, used by + * {@link ExceptionConst#createExceptions(EXCS, Class...)} + */ + public enum EXCS { + EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION, + } + } diff --git a/src/main/java/haidnor/jvm/bcel/Repository.java b/src/main/java/haidnor/jvm/bcel/Repository.java index b05600d..881fbf5 100644 --- a/src/main/java/haidnor/jvm/bcel/Repository.java +++ b/src/main/java/haidnor/jvm/bcel/Repository.java @@ -53,7 +53,7 @@ public abstract class Repository { /** * @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend, - * and so on. (Some people call this a transitive hull). + * and so on. (Some people call this a transitive hull). * @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found */ public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException { @@ -62,9 +62,9 @@ public abstract class Repository { /** * @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces, - * and so on + * and so on * @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces - * can't be found + * can't be found */ public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException { return getInterfaces(lookupClass(className)); @@ -77,6 +77,13 @@ public abstract class Repository { return repository; } + /** + * Sets repository instance to be used for class loading + */ + public static void setRepository(final haidnor.jvm.bcel.util.Repository rep) { + repository = rep; + } + /** * @return list of super classes of clazz in ascending order, i.e., Object is always the last element * @throws ClassNotFoundException if any of the superclasses can't be found @@ -162,9 +169,9 @@ public abstract class Repository { /** * Tries to find class source using the internal repository instance. * - * @see Class * @return JavaClass object for given runtime class * @throws ClassNotFoundException if the class could not be found or parsed correctly + * @see Class */ public static JavaClass lookupClass(final Class clazz) throws ClassNotFoundException { return repository.loadClass(clazz); @@ -182,7 +189,7 @@ public abstract class Repository { /** * @return class file object for given Java class by looking on the system class path; returns null if the class file - * can't be found + * can't be found */ public static ClassPath.ClassFile lookupClassFile(final String className) { try (ClassPath path = repository.getClassPath()) { @@ -205,11 +212,4 @@ public abstract class Repository { public static void removeClass(final String clazz) { repository.removeClass(repository.findClass(clazz)); } - - /** - * Sets repository instance to be used for class loading - */ - public static void setRepository(final haidnor.jvm.bcel.util.Repository rep) { - repository = rep; - } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java b/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java index a631ad5..2e74ec6 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java @@ -46,6 +46,15 @@ public abstract class AccessFlags { return access_flags; } + /** + * Set access flags aka "modifiers". + * + * @param accessFlags Access flags of the object. + */ + public final void setAccessFlags(final int accessFlags) { + this.access_flags = accessFlags; + } + /** * @return Access flags of the object aka. "modifiers". */ @@ -53,6 +62,15 @@ public abstract class AccessFlags { return access_flags; } + /** + * Set access flags aka "modifiers". + * + * @param accessFlags Access flags of the object. + */ + public final void setModifiers(final int accessFlags) { + setAccessFlags(accessFlags); + } + public final boolean isAbstract() { return (access_flags & Const.ACC_ABSTRACT) != 0; } @@ -181,15 +199,6 @@ public abstract class AccessFlags { setFlag(Const.ACC_VOLATILE, flag); } - /** - * Set access flags aka "modifiers". - * - * @param accessFlags Access flags of the object. - */ - public final void setAccessFlags(final int accessFlags) { - this.access_flags = accessFlags; - } - private void setFlag(final int flag, final boolean set) { if ((access_flags & flag) != 0) { // Flag is set already if (!set) { @@ -199,13 +208,4 @@ public abstract class AccessFlags { access_flags |= flag; } } - - /** - * Set access flags aka "modifiers". - * - * @param accessFlags Access flags of the object. - */ - public final void setModifiers(final int accessFlags) { - setAccessFlags(accessFlags); - } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java index c28cb33..7a9f590 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java @@ -33,9 +33,9 @@ public class AnnotationDefault extends Attribute { private ElementValue defaultValue; /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants */ AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { @@ -44,8 +44,8 @@ public class AnnotationDefault extends Attribute { } /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes * @param defaultValue the annotation's default value * @param constantPool Array of constants */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java index f2776ac..c325942 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java @@ -31,11 +31,21 @@ import java.util.stream.Stream; public class AnnotationEntry implements Node { public static final AnnotationEntry[] EMPTY_ARRAY = {}; + private final int typeIndex; + private final ConstantPool constantPool; + private final boolean isRuntimeVisible; + private List elementValuePairs; + + public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) { + this.typeIndex = typeIndex; + this.constantPool = constantPool; + this.isRuntimeVisible = isRuntimeVisible; + } public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) { // Find attributes that contain annotation data return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) - .toArray(AnnotationEntry[]::new); + .toArray(AnnotationEntry[]::new); } /** @@ -53,25 +63,11 @@ public class AnnotationEntry implements Node { annotationEntry.elementValuePairs = new ArrayList<>(); for (int i = 0; i < numElementValuePairs; i++) { annotationEntry.elementValuePairs - .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool)); + .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool)); } return annotationEntry; } - private final int typeIndex; - - private final ConstantPool constantPool; - - private final boolean isRuntimeVisible; - - private List elementValuePairs; - - public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) { - this.typeIndex = typeIndex; - this.constantPool = constantPool; - this.isRuntimeVisible = isRuntimeVisible; - } - /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java b/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java index a2fe3c4..27eec58 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java @@ -31,8 +31,8 @@ import java.util.stream.Stream; */ public abstract class Annotations extends Attribute implements Iterable { - private AnnotationEntry[] annotationTable; private final boolean isRuntimeVisible; + private AnnotationEntry[] annotationTable; /** * Constructs an instance. @@ -45,7 +45,7 @@ public abstract class Annotations extends Attribute implements Iterable READERS = new HashMap<>(); - /** * Empty array. * * @since 6.6.0 */ public static final Attribute[] EMPTY_ARRAY = {}; + private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off + private static final Map READERS = new HashMap<>(); + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter) + /** + * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected int length; // Content length of attribute field TODO make private (has getter & setter) + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected ConstantPool constant_pool; // TODO make private (has getter & setter) + + /** + * Constructs an instance. + * + *

+     * attribute_info {
+     *   u2 attribute_name_index;
+     *   u4 attribute_length;
+     *   u1 info[attribute_length];
+     * }
+     * 
+ * + * @param tag tag. + * @param nameIndex u2 name index. + * @param length u4 length. + * @param constantPool constant pool. + */ + protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) { + this.tag = tag; + this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index"); + this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length"); + this.constant_pool = constantPool; + } /** * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the * standard attributes such as "LineNumberTable", because those are handled internally. * - * @param name the name of the attribute as stored in the class file + * @param name the name of the attribute as stored in the class file * @param unknownAttributeReader the reader object */ public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) { @@ -85,13 +126,12 @@ public abstract class Attribute implements Cloneable, Node { * Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It * is called by the Field and Method constructor methods. * - * @see JavaField - * @see JavaMethod - * - * @param dataInput Input stream + * @param dataInput Input stream * @param constantPool Array of constants * @return Attribute * @throws IOException if an I/O error occurs. + * @see JavaField + * @see JavaMethod * @since 6.0 */ public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException { @@ -113,74 +153,74 @@ public abstract class Attribute implements Cloneable, Node { // Call proper constructor, depending on 'tag' switch (tag) { - case Const.ATTR_UNKNOWN: - final Object r = READERS.get(name); - if (r instanceof UnknownAttributeReader) { - return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool); - } - return new Unknown(nameIndex, length, dataInput, constantPool); - case Const.ATTR_CONSTANT_VALUE: - return new ConstantValue(nameIndex, length, dataInput, constantPool); - case Const.ATTR_SOURCE_FILE: - return new SourceFile(nameIndex, length, dataInput, constantPool); - case Const.ATTR_CODE: - return new Code(nameIndex, length, dataInput, constantPool); - case Const.ATTR_EXCEPTIONS: - return new ExceptionTable(nameIndex, length, dataInput, constantPool); - case Const.ATTR_LINE_NUMBER_TABLE: - return new LineNumberTable(nameIndex, length, dataInput, constantPool); - case Const.ATTR_LOCAL_VARIABLE_TABLE: - return new LocalVariableTable(nameIndex, length, dataInput, constantPool); - case Const.ATTR_INNER_CLASSES: - return new InnerClasses(nameIndex, length, dataInput, constantPool); - case Const.ATTR_SYNTHETIC: - return new Synthetic(nameIndex, length, dataInput, constantPool); - case Const.ATTR_DEPRECATED: - return new Deprecated(nameIndex, length, dataInput, constantPool); - case Const.ATTR_PMG: - return new PMGClass(nameIndex, length, dataInput, constantPool); - case Const.ATTR_SIGNATURE: - return new Signature(nameIndex, length, dataInput, constantPool); - case Const.ATTR_STACK_MAP: - // old style stack map: unneeded for JDK5 and below; - // illegal(?) for JDK6 and above. So just delete with a warning. - println("Warning: Obsolete StackMap attribute ignored."); - return new Unknown(nameIndex, length, dataInput, constantPool); - case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: - return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool); - case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: - return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool); - case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: - return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); - case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: - return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); - case Const.ATTR_ANNOTATION_DEFAULT: - return new AnnotationDefault(nameIndex, length, dataInput, constantPool); - case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE: - return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool); - case Const.ATTR_ENCLOSING_METHOD: - return new EnclosingMethod(nameIndex, length, dataInput, constantPool); - case Const.ATTR_STACK_MAP_TABLE: - // read new style stack map: StackMapTable. The rest of the code - // calls this a StackMap for historical reasons. - return new StackMap(nameIndex, length, dataInput, constantPool); - case Const.ATTR_BOOTSTRAP_METHODS: - return new BootstrapMethods(nameIndex, length, dataInput, constantPool); - case Const.ATTR_METHOD_PARAMETERS: - return new MethodParameters(nameIndex, length, dataInput, constantPool); - case Const.ATTR_MODULE: - return new Module(nameIndex, length, dataInput, constantPool); - case Const.ATTR_MODULE_PACKAGES: - return new ModulePackages(nameIndex, length, dataInput, constantPool); - case Const.ATTR_MODULE_MAIN_CLASS: - return new ModuleMainClass(nameIndex, length, dataInput, constantPool); - case Const.ATTR_NEST_HOST: - return new NestHost(nameIndex, length, dataInput, constantPool); - case Const.ATTR_NEST_MEMBERS: - return new NestMembers(nameIndex, length, dataInput, constantPool); - default: - // Never reached - throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); + case Const.ATTR_UNKNOWN: + final Object r = READERS.get(name); + if (r instanceof UnknownAttributeReader) { + return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool); + } + return new Unknown(nameIndex, length, dataInput, constantPool); + case Const.ATTR_CONSTANT_VALUE: + return new ConstantValue(nameIndex, length, dataInput, constantPool); + case Const.ATTR_SOURCE_FILE: + return new SourceFile(nameIndex, length, dataInput, constantPool); + case Const.ATTR_CODE: + return new Code(nameIndex, length, dataInput, constantPool); + case Const.ATTR_EXCEPTIONS: + return new ExceptionTable(nameIndex, length, dataInput, constantPool); + case Const.ATTR_LINE_NUMBER_TABLE: + return new LineNumberTable(nameIndex, length, dataInput, constantPool); + case Const.ATTR_LOCAL_VARIABLE_TABLE: + return new LocalVariableTable(nameIndex, length, dataInput, constantPool); + case Const.ATTR_INNER_CLASSES: + return new InnerClasses(nameIndex, length, dataInput, constantPool); + case Const.ATTR_SYNTHETIC: + return new Synthetic(nameIndex, length, dataInput, constantPool); + case Const.ATTR_DEPRECATED: + return new Deprecated(nameIndex, length, dataInput, constantPool); + case Const.ATTR_PMG: + return new PMGClass(nameIndex, length, dataInput, constantPool); + case Const.ATTR_SIGNATURE: + return new Signature(nameIndex, length, dataInput, constantPool); + case Const.ATTR_STACK_MAP: + // old style stack map: unneeded for JDK5 and below; + // illegal(?) for JDK6 and above. So just delete with a warning. + println("Warning: Obsolete StackMap attribute ignored."); + return new Unknown(nameIndex, length, dataInput, constantPool); + case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: + return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool); + case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: + return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool); + case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: + return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); + case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: + return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); + case Const.ATTR_ANNOTATION_DEFAULT: + return new AnnotationDefault(nameIndex, length, dataInput, constantPool); + case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE: + return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool); + case Const.ATTR_ENCLOSING_METHOD: + return new EnclosingMethod(nameIndex, length, dataInput, constantPool); + case Const.ATTR_STACK_MAP_TABLE: + // read new style stack map: StackMapTable. The rest of the code + // calls this a StackMap for historical reasons. + return new StackMap(nameIndex, length, dataInput, constantPool); + case Const.ATTR_BOOTSTRAP_METHODS: + return new BootstrapMethods(nameIndex, length, dataInput, constantPool); + case Const.ATTR_METHOD_PARAMETERS: + return new MethodParameters(nameIndex, length, dataInput, constantPool); + case Const.ATTR_MODULE: + return new Module(nameIndex, length, dataInput, constantPool); + case Const.ATTR_MODULE_PACKAGES: + return new ModulePackages(nameIndex, length, dataInput, constantPool); + case Const.ATTR_MODULE_MAIN_CLASS: + return new ModuleMainClass(nameIndex, length, dataInput, constantPool); + case Const.ATTR_NEST_HOST: + return new NestHost(nameIndex, length, dataInput, constantPool); + case Const.ATTR_NEST_MEMBERS: + return new NestMembers(nameIndex, length, dataInput, constantPool); + default: + // Never reached + throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); } } @@ -188,13 +228,12 @@ public abstract class Attribute implements Cloneable, Node { * Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It * is called by the Field and Method constructor methods. * - * @see JavaField - * @see JavaMethod - * * @param dataInputStream Input stream - * @param constantPool Array of constants + * @param constantPool Array of constants * @return Attribute * @throws IOException if an I/O error occurs. + * @see JavaField + * @see JavaMethod */ public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException { return readAttribute((DataInput) dataInputStream, constantPool); @@ -209,53 +248,6 @@ public abstract class Attribute implements Cloneable, Node { READERS.remove(name); } - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter) - - /** - * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected int length; // Content length of attribute field TODO make private (has getter & setter) - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected ConstantPool constant_pool; // TODO make private (has getter & setter) - - /** - * Constructs an instance. - * - *
-     * attribute_info {
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *   u1 info[attribute_length];
-     * }
-     * 
- * - * @param tag tag. - * @param nameIndex u2 name index. - * @param length u4 length. - * @param constantPool constant pool. - */ - protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) { - this.tag = tag; - this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index"); - this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length"); - this.constant_pool = constantPool; - } - /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. @@ -306,6 +298,14 @@ public abstract class Attribute implements Cloneable, Node { return constant_pool; } + /** + * @param constantPool Constant pool to be used for this object. + * @see ConstantPool + */ + public final void setConstantPool(final ConstantPool constantPool) { + this.constant_pool = constantPool; + } + /** * @return Length of attribute field in bytes. */ @@ -313,6 +313,13 @@ public abstract class Attribute implements Cloneable, Node { return length; } + /** + * @param length length in bytes. + */ + public final void setLength(final int length) { + this.length = length; + } + /** * @return Name of attribute * @since 6.0 @@ -328,28 +335,6 @@ public abstract class Attribute implements Cloneable, Node { return name_index; } - /** - * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method. - */ - public final byte getTag() { - return tag; - } - - /** - * @param constantPool Constant pool to be used for this object. - * @see ConstantPool - */ - public final void setConstantPool(final ConstantPool constantPool) { - this.constant_pool = constantPool; - } - - /** - * @param length length in bytes. - */ - public final void setLength(final int length) { - this.length = length; - } - /** * @param nameIndex of attribute. */ @@ -357,6 +342,13 @@ public abstract class Attribute implements Cloneable, Node { this.name_index = nameIndex; } + /** + * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method. + */ + public final byte getTag() { + return tag; + } + /** * @return attribute name. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java index d310548..9c8761e 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java @@ -29,15 +29,19 @@ import java.util.Arrays; * and an array of the bootstrap arguments. * * @see The class File Format : - * The BootstrapMethods Attribute + * The BootstrapMethods Attribute * @since 6.0 */ public class BootstrapMethod implements Cloneable { - /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ + /** + * Index of the CONSTANT_MethodHandle_info structure in the constant_pool table + */ private int bootstrapMethodRef; - /** Array of references to the constant_pool table */ + /** + * Array of references to the constant_pool table + */ private int[] bootstrapArguments; /** @@ -110,20 +114,6 @@ public class BootstrapMethod implements Cloneable { return bootstrapArguments; } - /** - * @return index into constant_pool of bootstrap_method - */ - public int getBootstrapMethodRef() { - return bootstrapMethodRef; - } - - /** - * @return count of number of boostrap arguments - */ - public int getNumBootstrapArguments() { - return bootstrapArguments.length; - } - /** * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info */ @@ -131,6 +121,13 @@ public class BootstrapMethod implements Cloneable { this.bootstrapArguments = bootstrapArguments; } + /** + * @return index into constant_pool of bootstrap_method + */ + public int getBootstrapMethodRef() { + return bootstrapMethodRef; + } + /** * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle */ @@ -138,6 +135,13 @@ public class BootstrapMethod implements Cloneable { this.bootstrapMethodRef = bootstrapMethodRef; } + /** + * @return count of number of boostrap arguments + */ + public int getNumBootstrapArguments() { + return bootstrapArguments.length; + } + /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java index fa94a19..3cda9eb 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java @@ -29,7 +29,7 @@ import java.util.stream.Stream; * This class represents a BootstrapMethods attribute. * * @see The class File Format : - * The BootstrapMethods Attribute + * The BootstrapMethods Attribute * @since 6.0 */ public class BootstrapMethods extends Attribute implements Iterable { @@ -47,10 +47,10 @@ public class BootstrapMethods extends Attribute implements Iterable iterator() { - return Stream.of(bootstrapMethods).iterator(); - } - /** * @param bootstrapMethods the array of bootstrap methods */ @@ -134,6 +129,11 @@ public class BootstrapMethods extends Attribute implements Iterable iterator() { + return Stream.of(bootstrapMethods).iterator(); + } + /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java b/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java index e1b7cc3..5b7fb1e 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java @@ -26,7 +26,7 @@ import java.util.zip.ZipFile; * Wrapper class that parses a given Java .class file. The method parse returns a * JavaClass object on success. When an I/O error or an inconsistency occurs an * appropriate exception is propagated back to the caller. - * + *

* The structure and the names comply, except for a few conveniences, exactly with the * JVM specification 1.0. See this paper for further details about * the structure of a bytecode file. @@ -34,9 +34,10 @@ import java.util.zip.ZipFile; public final class ClassParser { private static final int BUFSIZE = 8192; - private DataInputStream dataInputStream; private final boolean fileOwned; private final String fileName; + private final boolean isZip; // Loaded from zip file + private DataInputStream dataInputStream; private String zipFile; private int classNameIndex; private int superclassNameIndex; @@ -48,13 +49,12 @@ public final class ClassParser { private JavaField[] fields; // class fields, i.e., its variables private JavaMethod[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class - private final boolean isZip; // Loaded from zip file /** * Parses class from the given stream. * * @param inputStream Input stream - * @param fileName File name + * @param fileName File name */ public ClassParser(final InputStream inputStream, final String fileName) { this.fileName = fileName; @@ -82,7 +82,7 @@ public final class ClassParser { /** * Parses class from given .class file in a ZIP-archive * - * @param zipFile zip file name + * @param zipFile zip file name * @param fileName file name */ public ClassParser(final String zipFile, final String fileName) { @@ -98,7 +98,7 @@ public final class ClassParser { * not include verification of the byte code as it is performed by the java interpreter). * * @return Class object representing the parsed class file - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ public JavaClass parse() throws IOException, ClassFormatException { @@ -172,13 +172,13 @@ public final class ClassParser { } // Return the information we have gathered in a new object return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes, - isZip ? JavaClass.ZIP : JavaClass.FILE); + isZip ? JavaClass.ZIP : JavaClass.FILE); } /** * Reads information about the attributes of the class. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readAttributes() throws IOException, ClassFormatException { @@ -192,7 +192,7 @@ public final class ClassParser { /** * Reads information about the class and its super class. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readClassInfo() throws IOException, ClassFormatException { @@ -213,7 +213,7 @@ public final class ClassParser { /** * Reads constant pool entries. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readConstantPool() throws IOException, ClassFormatException { @@ -223,7 +223,7 @@ public final class ClassParser { /** * Reads information about the fields of the class, i.e., its variables. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readFields() throws IOException, ClassFormatException { @@ -238,7 +238,7 @@ public final class ClassParser { /** * Checks whether the header of the file is ok. Of course, this has to be the first action on successive file reads. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readID() throws IOException, ClassFormatException { @@ -250,7 +250,7 @@ public final class ClassParser { /** * Reads information about the interfaces implemented by this class. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readInterfaces() throws IOException, ClassFormatException { @@ -264,7 +264,7 @@ public final class ClassParser { /** * Reads information about the methods of the class. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readMethods() throws IOException { @@ -278,7 +278,7 @@ public final class ClassParser { /** * Reads major and minor version of compiler which created the file. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ private void readVersion() throws IOException, ClassFormatException { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Code.java b/src/main/java/haidnor/jvm/bcel/classfile/Code.java index ef0d913..7df31f1 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Code.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Code.java @@ -29,7 +29,7 @@ import java.util.Arrays; * This class represents a chunk of Java byte code contained in a method. It is instantiated by the * Attribute.readAttribute() method. A Code attribute contains informations about operand stack, local * variables, byte code and the exceptions handled within this method. - * + *

* This attribute has attributes itself, namely LineNumberTable which is used for debugging purposes and * LocalVariableTable which contains information about the local variables. * @@ -52,6 +52,7 @@ import java.util.Arrays; * attribute_info attributes[attributes_count]; * } * + * * @see Attribute * @see CodeException * @see LineNumberTable @@ -77,9 +78,9 @@ public final class Code extends Attribute { } /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param file Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param file Input stream * @param constantPool Array of constants */ Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException { @@ -113,17 +114,17 @@ public final class Code extends Attribute { } /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param maxStack Maximum size of stack - * @param maxLocals Number of local variables - * @param code Actual byte code + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param maxStack Maximum size of stack + * @param maxLocals Number of local variables + * @param code Actual byte code * @param exceptionTable of handled exceptions - * @param attributes Attributes of code: LineNumber or LocalVariable - * @param constantPool Array of constants + * @param attributes Attributes of code: LineNumber or LocalVariable + * @param constantPool Array of constants */ public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable, - final Attribute[] attributes, final ConstantPool constantPool) { + final Attribute[] attributes, final ConstantPool constantPool) { super(Const.ATTR_CODE, nameIndex, length, constantPool); this.maxStack = Args.requireU2(maxStack, "maxStack"); this.maxLocals = Args.requireU2(maxLocals, "maxLocals"); @@ -147,7 +148,7 @@ public final class Code extends Attribute { /** * @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained - * attributes + * attributes */ private int calculateLength() { int len = 0; @@ -160,9 +161,8 @@ public final class Code extends Attribute { } /** - * @return deep copy of this attribute - * * @param constantPool the constant pool to duplicate + * @return deep copy of this attribute */ @Override public Attribute copy(final ConstantPool constantPool) { @@ -209,6 +209,14 @@ public final class Code extends Attribute { return attributes; } + /** + * @param attributes the attributes to set for this Code + */ + public void setAttributes(final Attribute[] attributes) { + this.attributes = attributes != null ? attributes : EMPTY_ARRAY; + super.setLength(calculateLength()); // Adjust length + } + /** * @return Actual byte code of the method. */ @@ -216,6 +224,14 @@ public final class Code extends Attribute { return code; } + /** + * @param code byte code + */ + public void setCode(final byte[] code) { + this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY; + super.setLength(calculateLength()); // Adjust length + } + /** * @return Table of handled exceptions. * @see CodeException @@ -224,15 +240,23 @@ public final class Code extends Attribute { return exceptionTable; } + /** + * @param exceptionTable exception table + */ + public void setExceptionTable(final CodeException[] exceptionTable) { + this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; + super.setLength(calculateLength()); // Adjust length + } + /** * @return the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes */ private int getInternalLength() { return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */ - + code.length /* byte-code */ - + 2 /* exception-table length */ - + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */ - + 2 /* attributes count */; + + code.length /* byte-code */ + + 2 /* exception-table length */ + + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */ + + 2 /* attributes count */; } /** @@ -266,37 +290,6 @@ public final class Code extends Attribute { return maxLocals; } - /** - * @return Maximum size of stack used by this method. - */ - public int getMaxStack() { - return maxStack; - } - - /** - * @param attributes the attributes to set for this Code - */ - public void setAttributes(final Attribute[] attributes) { - this.attributes = attributes != null ? attributes : EMPTY_ARRAY; - super.setLength(calculateLength()); // Adjust length - } - - /** - * @param code byte code - */ - public void setCode(final byte[] code) { - this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY; - super.setLength(calculateLength()); // Adjust length - } - - /** - * @param exceptionTable exception table - */ - public void setExceptionTable(final CodeException[] exceptionTable) { - this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; - super.setLength(calculateLength()); // Adjust length - } - /** * @param maxLocals maximum number of local variables */ @@ -304,6 +297,13 @@ public final class Code extends Attribute { this.maxLocals = maxLocals; } + /** + * @return Maximum size of stack used by this method. + */ + public int getMaxStack() { + return maxStack; + } + /** * @param maxStack maximum stack size */ @@ -328,7 +328,7 @@ public final class Code extends Attribute { public String toString(final boolean verbose) { final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n") - .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose)); + .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose)); if (exceptionTable.length > 0) { buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n"); for (final CodeException exception : exceptionTable) { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java b/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java index 2588343..e8e9fde 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java @@ -154,27 +154,6 @@ public final class CodeException implements Cloneable, Node { return catchType; } - /** - * @return Exclusive end index of the region where the handler is active. - */ - public int getEndPC() { - return endPc; - } - - /** - * @return Starting address of exception handler, relative to the code. - */ - public int getHandlerPC() { - return handlerPc; - } - - /** - * @return Inclusive start index of the region where the handler is active. - */ - public int getStartPC() { - return startPc; - } - /** * @param catchType the type of exception that is caught */ @@ -182,6 +161,13 @@ public final class CodeException implements Cloneable, Node { this.catchType = catchType; } + /** + * @return Exclusive end index of the region where the handler is active. + */ + public int getEndPC() { + return endPc; + } + /** * @param endPc end of handled block */ @@ -189,6 +175,13 @@ public final class CodeException implements Cloneable, Node { this.endPc = endPc; } + /** + * @return Starting address of exception handler, relative to the code. + */ + public int getHandlerPC() { + return handlerPc; + } + /** * @param handlerPc where the actual code is */ @@ -196,6 +189,13 @@ public final class CodeException implements Cloneable, Node { this.handlerPc = handlerPc; } + /** + * @return Inclusive start index of the region where the handler is active. + */ + public int getStartPC() { + return startPc; + } + /** * @param startPc start of handled block */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Constant.java b/src/main/java/haidnor/jvm/bcel/classfile/Constant.java index bb899b5..41baeab 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Constant.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Constant.java @@ -45,6 +45,15 @@ public abstract class Constant implements Cloneable, Node { return THIS.toString().hashCode(); } }; + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @java.lang.Deprecated + protected byte tag; // TODO should be private & final + + Constant(final byte tag) { + this.tag = tag; + } /** * @return Comparison strategy object @@ -53,64 +62,6 @@ public abstract class Constant implements Cloneable, Node { return bcelComparator; } - /** - * Reads one constant from the given input, the type depends on a tag byte. - * - * @param dataInput Input stream - * @return Constant object - * @throws IOException if an I/O error occurs reading from the given {@code dataInput}. - * @throws ClassFormatException if the next byte is not recognized - * @since 6.0 made public - */ - public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException { - final byte b = dataInput.readByte(); // Read tag byte - switch (b) { - case Const.CONSTANT_Class: - return new ConstantClass(dataInput); - case Const.CONSTANT_Fieldref: - return new ConstantFieldref(dataInput); - case Const.CONSTANT_Methodref: - return new ConstantMethodref(dataInput); - case Const.CONSTANT_InterfaceMethodref: - return new ConstantInterfaceMethodref(dataInput); - case Const.CONSTANT_String: - return new ConstantString(dataInput); - case Const.CONSTANT_Integer: - return new ConstantInteger(dataInput); - case Const.CONSTANT_Float: - return new ConstantFloat(dataInput); - case Const.CONSTANT_Long: - return new ConstantLong(dataInput); - case Const.CONSTANT_Double: - return new ConstantDouble(dataInput); - case Const.CONSTANT_NameAndType: - return new ConstantNameAndType(dataInput); - case Const.CONSTANT_Utf8: - return ConstantUtf8.getInstance(dataInput); - case Const.CONSTANT_MethodHandle: - return new ConstantMethodHandle(dataInput); - case Const.CONSTANT_MethodType: - return new ConstantMethodType(dataInput); - case Const.CONSTANT_Dynamic: - return new ConstantDynamic(dataInput); - case Const.CONSTANT_InvokeDynamic: - return new ConstantInvokeDynamic(dataInput); - case Const.CONSTANT_Module: - return new ConstantModule(dataInput); - case Const.CONSTANT_Package: - return new ConstantPackage(dataInput); - default: - throw new ClassFormatException("Invalid byte tag in constant pool: " + b); - } - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - /* * In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via * 'instanceof'. In some places we will use the tag for switch()es anyway. @@ -118,14 +69,63 @@ public abstract class Constant implements Cloneable, Node { * First, we want match the specification as closely as possible. Second we need the tag as an index to select the * corresponding class name from the 'CONSTANT_NAMES' array. */ - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @java.lang.Deprecated - protected byte tag; // TODO should be private & final - Constant(final byte tag) { - this.tag = tag; + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + + /** + * Reads one constant from the given input, the type depends on a tag byte. + * + * @param dataInput Input stream + * @return Constant object + * @throws IOException if an I/O error occurs reading from the given {@code dataInput}. + * @throws ClassFormatException if the next byte is not recognized + * @since 6.0 made public + */ + public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException { + final byte b = dataInput.readByte(); // Read tag byte + switch (b) { + case Const.CONSTANT_Class: + return new ConstantClass(dataInput); + case Const.CONSTANT_Fieldref: + return new ConstantFieldref(dataInput); + case Const.CONSTANT_Methodref: + return new ConstantMethodref(dataInput); + case Const.CONSTANT_InterfaceMethodref: + return new ConstantInterfaceMethodref(dataInput); + case Const.CONSTANT_String: + return new ConstantString(dataInput); + case Const.CONSTANT_Integer: + return new ConstantInteger(dataInput); + case Const.CONSTANT_Float: + return new ConstantFloat(dataInput); + case Const.CONSTANT_Long: + return new ConstantLong(dataInput); + case Const.CONSTANT_Double: + return new ConstantDouble(dataInput); + case Const.CONSTANT_NameAndType: + return new ConstantNameAndType(dataInput); + case Const.CONSTANT_Utf8: + return ConstantUtf8.getInstance(dataInput); + case Const.CONSTANT_MethodHandle: + return new ConstantMethodHandle(dataInput); + case Const.CONSTANT_MethodType: + return new ConstantMethodType(dataInput); + case Const.CONSTANT_Dynamic: + return new ConstantDynamic(dataInput); + case Const.CONSTANT_InvokeDynamic: + return new ConstantInvokeDynamic(dataInput); + case Const.CONSTANT_Module: + return new ConstantModule(dataInput); + case Const.CONSTANT_Package: + return new ConstantPackage(dataInput); + default: + throw new ClassFormatException("Invalid byte tag in constant pool: " + b); + } } /** diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java index 8f6a266..86c28fe 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java @@ -53,7 +53,7 @@ public abstract class ConstantCP extends Constant { /** * Initialize instance from file data. * - * @param tag Constant type tag + * @param tag Constant type tag * @param file Input stream * @throws IOException if an I/O error occurs. */ @@ -62,7 +62,7 @@ public abstract class ConstantCP extends Constant { } /** - * @param classIndex Reference to the class containing the field + * @param classIndex Reference to the class containing the field * @param nameAndTypeIndex and the field signature */ protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) { @@ -107,13 +107,6 @@ public abstract class ConstantCP extends Constant { return class_index; } - /** - * @return Reference (index) to signature of the field. - */ - public final int getNameAndTypeIndex() { - return name_and_type_index; - } - /** * @param classIndex points to Constant_class */ @@ -121,6 +114,13 @@ public abstract class ConstantCP extends Constant { this.class_index = classIndex; } + /** + * @return Reference (index) to signature of the field. + */ + public final int getNameAndTypeIndex() { + return name_and_type_index; + } + /** * @param nameAndTypeIndex points to Constant_NameAndType */ @@ -130,8 +130,8 @@ public abstract class ConstantCP extends Constant { /** * @return String representation. - * - * not final as ConstantInvokeDynamic needs to modify + *

+ * not final as ConstantInvokeDynamic needs to modify */ @Override public String toString() { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java index 745f9c3..82db2c4 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java @@ -88,6 +88,13 @@ public final class ConstantDouble extends Constant implements ConstantObject { return bytes; } + /** + * @param bytes the raw bytes that represent the double value + */ + public void setBytes(final double bytes) { + this.bytes = bytes; + } + /** * @return Double object */ @@ -96,13 +103,6 @@ public final class ConstantDouble extends Constant implements ConstantObject { return Double.valueOf(bytes); } - /** - * @param bytes the raw bytes that represent the double value - */ - public void setBytes(final double bytes) { - this.bytes = bytes; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java index bea3381..1700154 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java @@ -27,7 +27,7 @@ import java.io.IOException; * * @see Constant * @see Change request for JEP - * 309 + * 309 * @since 6.3 */ public final class ConstantDynamic extends ConstantCP { @@ -68,8 +68,8 @@ public final class ConstantDynamic extends ConstantCP { /** * @return Reference (index) to bootstrap method this constant refers to. - * - * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic. + *

+ * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic. * @since 6.0 */ public int getBootstrapMethodAttrIndex() { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java index dfaffc2..a21edd0 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java @@ -46,7 +46,7 @@ public final class ConstantFieldref extends ConstantCP { } /** - * @param classIndex Reference to the class containing the Field + * @param classIndex Reference to the class containing the Field * @param nameAndTypeIndex and the Field signature */ public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java index 5b2ece3..83a63e8 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java @@ -89,6 +89,13 @@ public final class ConstantFloat extends Constant implements ConstantObject { return bytes; } + /** + * @param bytes the raw bytes that represent this float + */ + public void setBytes(final float bytes) { + this.bytes = bytes; + } + /** * @return Float object */ @@ -97,13 +104,6 @@ public final class ConstantFloat extends Constant implements ConstantObject { return Float.valueOf(bytes); } - /** - * @param bytes the raw bytes that represent this float - */ - public void setBytes(final float bytes) { - this.bytes = bytes; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java index 2540969..3d5cdcc 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java @@ -88,6 +88,13 @@ public final class ConstantInteger extends Constant implements ConstantObject { return bytes; } + /** + * @param bytes the raw bytes that represent this integer + */ + public void setBytes(final int bytes) { + this.bytes = bytes; + } + /** * @return Integer object */ @@ -96,13 +103,6 @@ public final class ConstantInteger extends Constant implements ConstantObject { return Integer.valueOf(bytes); } - /** - * @param bytes the raw bytes that represent this integer - */ - public void setBytes(final int bytes) { - this.bytes = bytes; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java index 28521c3..1f3e1d5 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java @@ -46,7 +46,7 @@ public final class ConstantInterfaceMethodref extends ConstantCP { } /** - * @param classIndex Reference to the class containing the method + * @param classIndex Reference to the class containing the method * @param nameAndTypeIndex and the method signature */ public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java index 3cb848a..84f7065 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java @@ -26,7 +26,7 @@ import java.io.IOException; * * @see Constant * @see The - * CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification + * CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification * @since 6.0 */ public final class ConstantInvokeDynamic extends ConstantCP { @@ -67,8 +67,8 @@ public final class ConstantInvokeDynamic extends ConstantCP { /** * @return Reference (index) to bootstrap method this constant refers to. - * - * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic. + *

+ * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic. * @since 6.0 */ public int getBootstrapMethodAttrIndex() { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java index 7c57f20..48ef892 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java @@ -88,6 +88,13 @@ public final class ConstantLong extends Constant implements ConstantObject { return bytes; } + /** + * @param bytes the raw bytes that represent this long + */ + public void setBytes(final long bytes) { + this.bytes = bytes; + } + /** * @return Long object */ @@ -96,13 +103,6 @@ public final class ConstantLong extends Constant implements ConstantObject { return Long.valueOf(bytes); } - /** - * @param bytes the raw bytes that represent this long - */ - public void setBytes(final long bytes) { - this.bytes = bytes; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java index 98891fe..fe554a6 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java @@ -86,14 +86,14 @@ public final class ConstantMethodHandle extends Constant { return referenceIndex; } - public int getReferenceKind() { - return referenceKind; - } - public void setReferenceIndex(final int referenceIndex) { this.referenceIndex = referenceIndex; } + public int getReferenceKind() { + return referenceKind; + } + public void setReferenceKind(final int referenceKind) { this.referenceKind = referenceKind; } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java index e9b02b3..322848d 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java @@ -46,7 +46,7 @@ public final class ConstantMethodref extends ConstantCP { } /** - * @param classIndex Reference to the class containing the method + * @param classIndex Reference to the class containing the method * @param nameAndTypeIndex and the method signature */ public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java index 547e4cd..be69787 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java @@ -53,7 +53,7 @@ public final class ConstantNameAndType extends Constant { } /** - * @param nameIndex Name of field/method + * @param nameIndex Name of field/method * @param signatureIndex and its signature */ public ConstantNameAndType(final int nameIndex, final int signatureIndex) { @@ -100,6 +100,13 @@ public final class ConstantNameAndType extends Constant { return nameIndex; } + /** + * @param nameIndex the name index of this constant + */ + public void setNameIndex(final int nameIndex) { + this.nameIndex = nameIndex; + } + /** * @return signature */ @@ -114,13 +121,6 @@ public final class ConstantNameAndType extends Constant { return signatureIndex; } - /** - * @param nameIndex the name index of this constant - */ - public void setNameIndex(final int nameIndex) { - this.nameIndex = nameIndex; - } - /** * @param signatureIndex the signature index in the constant pool of this type */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java index 29a8082..c453949 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java @@ -35,34 +35,6 @@ import java.util.Iterator; */ public class ConstantPool implements Cloneable, Node, Iterable { - private static String escape(final String str) { - final int len = str.length(); - final StringBuilder buf = new StringBuilder(len + 5); - final char[] ch = str.toCharArray(); - for (int i = 0; i < len; i++) { - switch (ch[i]) { - case '\n': - buf.append("\\n"); - break; - case '\r': - buf.append("\\r"); - break; - case '\t': - buf.append("\\t"); - break; - case '\b': - buf.append("\\b"); - break; - case '"': - buf.append("\\\""); - break; - default: - buf.append(ch[i]); - } - } - return buf.toString(); - } - private Constant[] constantPool; /** @@ -100,6 +72,34 @@ public class ConstantPool implements Cloneable, Node, Iterable { } } + private static String escape(final String str) { + final int len = str.length(); + final StringBuilder buf = new StringBuilder(len + 5); + final char[] ch = str.toCharArray(); + for (int i = 0; i < len; i++) { + switch (ch[i]) { + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + case '\t': + buf.append("\\t"); + break; + case '\b': + buf.append("\\b"); + break; + case '"': + buf.append("\\\""); + break; + default: + buf.append(ch[i]); + } + } + return buf.toString(); + } + /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e., the hierarchy of methods, fields, * attributes, etc. spawns a tree of objects. @@ -123,72 +123,72 @@ public class ConstantPool implements Cloneable, Node, Iterable { int i; final byte tag = c.getTag(); switch (tag) { - case Const.CONSTANT_Class: - i = ((ConstantClass) c).getNameIndex(); - c = getConstantUtf8(i); - str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); - break; - case Const.CONSTANT_String: - i = ((ConstantString) c).getStringIndex(); - c = getConstantUtf8(i); - str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; - break; - case Const.CONSTANT_Utf8: - str = ((ConstantUtf8) c).getBytes(); - break; - case Const.CONSTANT_Double: - str = String.valueOf(((ConstantDouble) c).getBytes()); - break; - case Const.CONSTANT_Float: - str = String.valueOf(((ConstantFloat) c).getBytes()); - break; - case Const.CONSTANT_Long: - str = String.valueOf(((ConstantLong) c).getBytes()); - break; - case Const.CONSTANT_Integer: - str = String.valueOf(((ConstantInteger) c).getBytes()); - break; - case Const.CONSTANT_NameAndType: - str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " " - + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8); - break; - case Const.CONSTANT_InterfaceMethodref: - case Const.CONSTANT_Methodref: - case Const.CONSTANT_Fieldref: - str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "." - + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType); - break; - case Const.CONSTANT_MethodHandle: - // Note that the ReferenceIndex may point to a Fieldref, Methodref or - // InterfaceMethodref - so we need to peek ahead to get the actual type. - final ConstantMethodHandle cmh = (ConstantMethodHandle) c; - str = Const.getMethodHandleName(cmh.getReferenceKind()) + " " - + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag()); - break; - case Const.CONSTANT_MethodType: - final ConstantMethodType cmt = (ConstantMethodType) c; - str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); - break; - case Const.CONSTANT_InvokeDynamic: - final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; - str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); - break; - case Const.CONSTANT_Dynamic: - final ConstantDynamic cd = (ConstantDynamic) c; - str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); - break; - case Const.CONSTANT_Module: - i = ((ConstantModule) c).getNameIndex(); - c = getConstantUtf8(i); - str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); - break; - case Const.CONSTANT_Package: - i = ((ConstantPackage) c).getNameIndex(); - c = getConstantUtf8(i); - str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); - break; - default: // Never reached - throw new IllegalArgumentException("Unknown constant type " + tag); + case Const.CONSTANT_Class: + i = ((ConstantClass) c).getNameIndex(); + c = getConstantUtf8(i); + str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); + break; + case Const.CONSTANT_String: + i = ((ConstantString) c).getStringIndex(); + c = getConstantUtf8(i); + str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; + break; + case Const.CONSTANT_Utf8: + str = ((ConstantUtf8) c).getBytes(); + break; + case Const.CONSTANT_Double: + str = String.valueOf(((ConstantDouble) c).getBytes()); + break; + case Const.CONSTANT_Float: + str = String.valueOf(((ConstantFloat) c).getBytes()); + break; + case Const.CONSTANT_Long: + str = String.valueOf(((ConstantLong) c).getBytes()); + break; + case Const.CONSTANT_Integer: + str = String.valueOf(((ConstantInteger) c).getBytes()); + break; + case Const.CONSTANT_NameAndType: + str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " " + + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8); + break; + case Const.CONSTANT_InterfaceMethodref: + case Const.CONSTANT_Methodref: + case Const.CONSTANT_Fieldref: + str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "." + + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType); + break; + case Const.CONSTANT_MethodHandle: + // Note that the ReferenceIndex may point to a Fieldref, Methodref or + // InterfaceMethodref - so we need to peek ahead to get the actual type. + final ConstantMethodHandle cmh = (ConstantMethodHandle) c; + str = Const.getMethodHandleName(cmh.getReferenceKind()) + " " + + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag()); + break; + case Const.CONSTANT_MethodType: + final ConstantMethodType cmt = (ConstantMethodType) c; + str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); + break; + case Const.CONSTANT_InvokeDynamic: + final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; + str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); + break; + case Const.CONSTANT_Dynamic: + final ConstantDynamic cd = (ConstantDynamic) c; + str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); + break; + case Const.CONSTANT_Module: + i = ((ConstantModule) c).getNameIndex(); + c = getConstantUtf8(i); + str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); + break; + case Const.CONSTANT_Package: + i = ((ConstantPackage) c).getNameIndex(); + c = getConstantUtf8(i); + str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); + break; + default: // Never reached + throw new IllegalArgumentException("Unknown constant type " + tag); } return str; } @@ -249,8 +249,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { * * @param index Index in constant pool * @return Constant value - * @see Constant * @throws ClassFormatException if index is invalid + * @see Constant */ @SuppressWarnings("unchecked") public T getConstant(final int index) throws ClassFormatException { @@ -263,8 +263,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @param index Index in constant pool * @param tag Tag of expected constant, i.e., its type * @return Constant value - * @see Constant * @throws ClassFormatException if constant type does not match tag + * @see Constant */ @SuppressWarnings("unchecked") public T getConstant(final int index, final byte tag) throws ClassFormatException { @@ -277,8 +277,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @param index Index in constant pool * @param tag Tag of expected constant, i.e., its type * @return Constant value - * @see Constant * @throws ClassFormatException if constant type does not match tag + * @see Constant * @since 6.6.0 */ public T getConstant(final int index, final byte tag, final Class castTo) throws ClassFormatException { @@ -292,12 +292,12 @@ public class ConstantPool implements Cloneable, Node, Iterable { /** * Gets constant from constant pool. * - * @param A {@link Constant} subclass - * @param index Index in constant pool + * @param A {@link Constant} subclass + * @param index Index in constant pool * @param castTo The {@link Constant} subclass to cast to. * @return Constant value - * @see Constant * @throws ClassFormatException if index is invalid + * @see Constant * @since 6.6.0 */ public T getConstant(final int index, final Class castTo) throws ClassFormatException { @@ -311,8 +311,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { // Previous check ensures this won't throw a ClassCastException final T c = castTo.cast(constantPool[index]); if (c == null - // the 0th element is always null - && index != 0) { + // the 0th element is always null + && index != 0) { final Constant prev = constantPool[index - 1]; if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) { throw new ClassFormatException("Constant pool at index " + index + " is null."); @@ -326,8 +326,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { * * @param index Index in constant pool * @return ConstantInteger value - * @see ConstantInteger * @throws ClassFormatException if constant type does not match tag + * @see ConstantInteger */ public ConstantInteger getConstantInteger(final int index) { return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class); @@ -341,6 +341,13 @@ public class ConstantPool implements Cloneable, Node, Iterable { return constantPool; } + /** + * @param constantPool + */ + public void setConstantPool(final Constant[] constantPool) { + this.constantPool = constantPool; + } + /** * Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that * points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data. @@ -348,9 +355,9 @@ public class ConstantPool implements Cloneable, Node, Iterable { * @param index Index in constant pool * @param tag Tag of expected constant, either ConstantClass or ConstantString * @return Contents of string reference + * @throws IllegalArgumentException if tag is invalid * @see ConstantClass * @see ConstantString - * @throws IllegalArgumentException if tag is invalid */ public String getConstantString(final int index, final byte tag) throws IllegalArgumentException { int i; @@ -360,22 +367,22 @@ public class ConstantPool implements Cloneable, Node, Iterable { * subclassing. */ switch (tag) { - case Const.CONSTANT_Class: - i = getConstant(index, ConstantClass.class).getNameIndex(); - break; - case Const.CONSTANT_String: - i = getConstant(index, ConstantString.class).getStringIndex(); - break; - case Const.CONSTANT_Module: - i = getConstant(index, ConstantModule.class).getNameIndex(); - break; - case Const.CONSTANT_Package: - i = getConstant(index, ConstantPackage.class).getNameIndex(); - break; - case Const.CONSTANT_Utf8: - return getConstantUtf8(index).getBytes(); - default: - throw new IllegalArgumentException("getConstantString called with illegal tag " + tag); + case Const.CONSTANT_Class: + i = getConstant(index, ConstantClass.class).getNameIndex(); + break; + case Const.CONSTANT_String: + i = getConstant(index, ConstantString.class).getStringIndex(); + break; + case Const.CONSTANT_Module: + i = getConstant(index, ConstantModule.class).getNameIndex(); + break; + case Const.CONSTANT_Package: + i = getConstant(index, ConstantPackage.class).getNameIndex(); + break; + case Const.CONSTANT_Utf8: + return getConstantUtf8(index).getBytes(); + default: + throw new IllegalArgumentException("getConstantString called with illegal tag " + tag); } // Finally get the string from the constant pool return getConstantUtf8(i).getBytes(); @@ -386,8 +393,8 @@ public class ConstantPool implements Cloneable, Node, Iterable { * * @param index Index in constant pool * @return ConstantUtf8 value - * @see ConstantUtf8 * @throws ClassFormatException if constant type does not match tag + * @see ConstantUtf8 */ public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException { return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class); @@ -412,13 +419,6 @@ public class ConstantPool implements Cloneable, Node, Iterable { constantPool[index] = constant; } - /** - * @param constantPool - */ - public void setConstantPool(final Constant[] constantPool) { - this.constantPool = constantPool; - } - /** * @return String representation. */ @@ -430,4 +430,164 @@ public class ConstantPool implements Cloneable, Node, Iterable { } return buf.toString(); } + + + // ---------------------------------------------- haidnorJVM + + public ConstantFieldref getConstantFieldref(int constantFieldrefIndex) { + return getConstant(constantFieldrefIndex); + } + + public ConstantMethodref getConstantMethodref(int constantMethodrefIndex) { + return getConstant(constantMethodrefIndex); + } + + public ConstantClass getConstantClass(int constantClassIndex) { + return getConstant(constantClassIndex); + } + + public ConstantNameAndType getConstantNameAndType(int constantNameAndTypeIndex) { + return getConstant(constantNameAndTypeIndex); + } + + + // ConstantClass --------------------------------------------------------------------------------------------------- + + /** + * 获取长类名, 例如 java/lang/String + */ + public String constantClass_ClassName(final ConstantClass constantClass) { + ConstantUtf8 constantUtf8 = getConstant(constantClass.getNameIndex()); + return constantUtf8.getBytes(); + } + + /** + * 获取长类名, 例如 java/lang/String + */ + public String constantClass_ClassName(int constantClassIndex) { + ConstantClass constantClass = getConstant(constantClassIndex); + return constantClass_ClassName(constantClass); + } + + + // ConstantFieldref ------------------------------------------------------------------------------------------------ + + /** + * 获取字段所处于Java类的类名, 例如 java/lang/String + */ + public String constantFieldref_ClassName(final ConstantFieldref constantFieldref) { + ConstantClass constClass = getConstant(constantFieldref.getClassIndex()); + return (String) constClass.getConstantValue(this); + } + + /** + * 获取字段所处于Java类的类名, 例如 java/lang/String + */ + public String constantFieldref_ClassName(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return constantFieldref_ClassName(constantFieldref); + } + + /** + * 获取字段名称 + */ + public String getFieldName(final ConstantFieldref constantFieldref) { + ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex()); + return constNameAndType.getName(this); + } + + /** + * 获取字段名称 + */ + public String getFieldName(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return getFieldName(constantFieldref); + } + + /** + * 获取字段类型签名 + */ + public String getFieldSignature(final ConstantFieldref constantFieldref) { + ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex()); + return constNameAndType.getSignature(this); + } + + /** + * 获取字段类型签名 + */ + public String getFieldSignature(int constantFieldrefIndex) { + ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex); + return getFieldSignature(constantFieldref); + } + + // ConstantMethodref ----------------------------------------------------------------------------------------------- + + /** + * 获取方法所处于Java类的类名 + * 名称使用/分割,例如 haidnor/jvm/test/instruction/references/NEW + */ + public String constantMethodref_ClassName(final ConstantMethodref methodref) { + ConstantClass constClass = getConstant(methodref.getClassIndex()); + return (String) constClass.getConstantValue(this); + } + + /** + * 获取方法名 + */ + public String constantMethodref_MethodName(final ConstantMethodref methodref) { + ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getName(this); + } + + /** + * 获取方法签名 + */ + public String constantMethodref_MethodSignature(final ConstantMethodref methodref) { + ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getSignature(this); + } + + // ConstantInterfaceMethodref ----------------------------------------------------------------------------------------------- + + public String constantInterfaceMethodref_ClassName(final ConstantInterfaceMethodref methodref) { + ConstantClass constClass = getConstant(methodref.getClassIndex()); + return (String) constClass.getConstantValue(this); + } + + /** + * 获取方法名 + */ + public String constantInterfaceMethodref_MethodName(final ConstantInterfaceMethodref methodref) { + ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getName(this); + } + + /** + * 获取方法签名 + */ + public String constantInterfaceMethodref_MethodSignature(final ConstantInterfaceMethodref methodref) { + ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex()); + return constNameAndType.getSignature(this); + } + + + // ConstantNameAndType ----------------------------------------------------------------------------------------------- + + /** + * ConstantNameAndType + */ + public ConstantNameAndType constantNameAndType(int constantNameAndTypeIndex) { + return getConstant(constantNameAndTypeIndex); + } + + public String constantNameAndType_name(int constantNameAndTypeIndex) { + ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex); + return constantNameAndType.getName(this); + } + + public String constantNameAndType_signature(int constantNameAndTypeIndex) { + ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex); + return constantNameAndType.getSignature(this); + } + } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java index 555a23e..5461ddc 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java @@ -57,47 +57,53 @@ import java.util.Objects; */ public final class ConstantUtf8 extends Constant { - private static class Cache { - - private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS); - private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue(); - private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75); - - private static final HashMap CACHE = new LinkedHashMap(INITIAL_CAPACITY, 0.75f, true) { - - private static final long serialVersionUID = -8506975356158971766L; - - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > MAX_ENTRIES; - } - }; - - // Set the size to 0 or below to skip caching entirely - private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue(); - - static boolean isEnabled() { - return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; - } - - } - + private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached"; + private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size"; + private static final String SYS_PROP_STATISTICS = "bcel.statistics"; // TODO these should perhaps be AtomicInt? private static volatile int considered; private static volatile int created; private static volatile int hits; private static volatile int skipped; - private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached"; - private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size"; - private static final String SYS_PROP_STATISTICS = "bcel.statistics"; - static { if (Cache.BCEL_STATISTICS) { Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats)); } } + private final String value; + + /** + * Initializes from another object. + * + * @param constantUtf8 the value. + */ + public ConstantUtf8(final ConstantUtf8 constantUtf8) { + this(constantUtf8.getBytes()); + } + + /** + * Initializes instance from file data. + * + * @param dataInput Input stream + * @throws IOException if an I/O error occurs. + */ + ConstantUtf8(final DataInput dataInput) throws IOException { + super(Const.CONSTANT_Utf8); + value = dataInput.readUTF(); + created++; + } + + /** + * @param value Data + */ + public ConstantUtf8(final String value) { + super(Const.CONSTANT_Utf8); + this.value = Objects.requireNonNull(value, "value"); + created++; + } + /** * Clears the cache. * @@ -175,39 +181,7 @@ public final class ConstantUtf8 extends Constant { System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped); System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created); System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE, - Cache.MAX_ENTRY_SIZE); - } - - private final String value; - - /** - * Initializes from another object. - * - * @param constantUtf8 the value. - */ - public ConstantUtf8(final ConstantUtf8 constantUtf8) { - this(constantUtf8.getBytes()); - } - - /** - * Initializes instance from file data. - * - * @param dataInput Input stream - * @throws IOException if an I/O error occurs. - */ - ConstantUtf8(final DataInput dataInput) throws IOException { - super(Const.CONSTANT_Utf8); - value = dataInput.readUTF(); - created++; - } - - /** - * @param value Data - */ - public ConstantUtf8(final String value) { - super(Const.CONSTANT_Utf8); - this.value = Objects.requireNonNull(value, "value"); - created++; + Cache.MAX_ENTRY_SIZE); } /** @@ -256,4 +230,29 @@ public final class ConstantUtf8 extends Constant { public String toString() { return super.toString() + "(\"" + Utility.replace(value, "\n", "\\n") + "\")"; } + + private static class Cache { + + private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS); + private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue(); + private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75); + + private static final HashMap CACHE = new LinkedHashMap(INITIAL_CAPACITY, 0.75f, true) { + + private static final long serialVersionUID = -8506975356158971766L; + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > MAX_ENTRIES; + } + }; + + // Set the size to 0 or below to skip caching entirely + private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue(); + + static boolean isEnabled() { + return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; + } + + } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java index b5c2278..3c6737e 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java @@ -34,6 +34,7 @@ import java.io.IOException; * u2 constantvalue_index; * } * + * * @see Attribute */ public final class ConstantValue extends Attribute { @@ -53,9 +54,9 @@ public final class ConstantValue extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Name index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Name index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -64,10 +65,10 @@ public final class ConstantValue extends Attribute { } /** - * @param nameIndex Name index in constant pool - * @param length Content length in bytes + * @param nameIndex Name index in constant pool + * @param length Content length in bytes * @param constantValueIndex Index in constant pool - * @param constantPool Array of constants + * @param constantPool Array of constants */ public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) { super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool); @@ -131,25 +132,25 @@ public final class ConstantValue extends Attribute { int i; // Print constant to string depending on its type switch (c.getTag()) { - case Const.CONSTANT_Long: - buf = String.valueOf(((ConstantLong) c).getBytes()); - break; - case Const.CONSTANT_Float: - buf = String.valueOf(((ConstantFloat) c).getBytes()); - break; - case Const.CONSTANT_Double: - buf = String.valueOf(((ConstantDouble) c).getBytes()); - break; - case Const.CONSTANT_Integer: - buf = String.valueOf(((ConstantInteger) c).getBytes()); - break; - case Const.CONSTANT_String: - i = ((ConstantString) c).getStringIndex(); - c = super.getConstantPool().getConstantUtf8(i); - buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\""; - break; - default: - throw new IllegalStateException("Type of ConstValue invalid: " + c); + case Const.CONSTANT_Long: + buf = String.valueOf(((ConstantLong) c).getBytes()); + break; + case Const.CONSTANT_Float: + buf = String.valueOf(((ConstantFloat) c).getBytes()); + break; + case Const.CONSTANT_Double: + buf = String.valueOf(((ConstantDouble) c).getBytes()); + break; + case Const.CONSTANT_Integer: + buf = String.valueOf(((ConstantInteger) c).getBytes()); + break; + case Const.CONSTANT_String: + i = ((ConstantString) c).getStringIndex(); + c = super.getConstantPool().getConstantUtf8(i); + buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\""; + break; + default: + throw new IllegalStateException("Type of ConstValue invalid: " + c); } return buf; } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java b/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java index fc2024c..50d188b 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java @@ -44,9 +44,9 @@ public final class Deprecated extends Attribute { } /** - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param bytes Attribute contents + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param bytes Attribute contents * @param constantPool Array of constants */ public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { @@ -57,9 +57,9 @@ public final class Deprecated extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java b/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java index 355da57..19a8329 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java @@ -32,7 +32,7 @@ public class DescendingVisitor implements Visitor { private final Stack stack = new Stack<>(); /** - * @param clazz Class to traverse + * @param clazz Class to traverse * @param visitor visitor object to apply to all components */ public DescendingVisitor(final JavaClass clazz, final Visitor visitor) { @@ -153,7 +153,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.3 */ + /** + * @since 6.3 + */ @Override public void visitConstantDynamic(final ConstantDynamic obj) { stack.push(obj); @@ -206,7 +208,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.0 */ + /** + * @since 6.0 + */ @Override public void visitConstantMethodHandle(final ConstantMethodHandle obj) { stack.push(obj); @@ -221,7 +225,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.0 */ + /** + * @since 6.0 + */ @Override public void visitConstantMethodType(final ConstantMethodType obj) { stack.push(obj); @@ -229,7 +235,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.1 */ + /** + * @since 6.1 + */ @Override public void visitConstantModule(final ConstantModule obj) { stack.push(obj); @@ -244,7 +252,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.1 */ + /** + * @since 6.1 + */ @Override public void visitConstantPackage(final ConstantPackage obj) { stack.push(obj); @@ -408,7 +418,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModule(final Module obj) { stack.push(obj); @@ -420,7 +432,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleExports(final ModuleExports obj) { stack.push(obj); @@ -428,7 +442,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleMainClass(final ModuleMainClass obj) { stack.push(obj); @@ -436,7 +452,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleOpens(final ModuleOpens obj) { stack.push(obj); @@ -444,7 +462,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModulePackages(final ModulePackages obj) { stack.push(obj); @@ -452,7 +472,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleProvides(final ModuleProvides obj) { stack.push(obj); @@ -460,7 +482,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleRequires(final ModuleRequires obj) { stack.push(obj); @@ -468,7 +492,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitNestHost(final NestHost obj) { stack.push(obj); @@ -476,7 +502,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitNestMembers(final NestMembers obj) { stack.push(obj); @@ -494,7 +522,9 @@ public class DescendingVisitor implements Visitor { stack.pop(); } - /** @since 6.0 */ + /** + * @since 6.0 + */ @Override public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) { stack.push(obj); diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java b/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java index fe950f5..aa55c07 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java @@ -44,8 +44,9 @@ import java.io.IOException; * element_value values[num_values]; * } array_value; * } value; - *} - * + * } + * + * * @since 6.0 */ public abstract class ElementValue { @@ -63,72 +64,6 @@ public abstract class ElementValue { public static final byte PRIMITIVE_LONG = 'J'; public static final byte PRIMITIVE_SHORT = 'S'; public static final byte PRIMITIVE_BOOLEAN = 'Z'; - - /** - * Reads an {@code element_value} as an {@code ElementValue}. - * - * @param input Raw data input. - * @param cpool Constant pool. - * @return a new ElementValue. - * @throws IOException if an I/O error occurs. - */ - public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException { - return readElementValue(input, cpool, 0); - } - - /** - * Reads an {@code element_value} as an {@code ElementValue}. - * - * @param input Raw data input. - * @param cpool Constant pool. - * @param arrayNesting level of current array nesting. - * @return a new ElementValue. - * @throws IOException if an I/O error occurs. - * @since 6.7.0 - */ - public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting) - throws IOException { - final byte tag = input.readByte(); - switch (tag) { - case PRIMITIVE_BYTE: - case PRIMITIVE_CHAR: - case PRIMITIVE_DOUBLE: - case PRIMITIVE_FLOAT: - case PRIMITIVE_INT: - case PRIMITIVE_LONG: - case PRIMITIVE_SHORT: - case PRIMITIVE_BOOLEAN: - case STRING: - return new SimpleElementValue(tag, input.readUnsignedShort(), cpool); - - case ENUM_CONSTANT: - return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool); - - case CLASS: - return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool); - - case ANNOTATION: - // TODO isRuntimeVisible - return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool); - - case ARRAY: - arrayNesting++; - if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) { - // JVM spec 4.4.1 - throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS)); - } - final int numArrayVals = input.readUnsignedShort(); - final ElementValue[] evalues = new ElementValue[numArrayVals]; - for (int j = 0; j < numArrayVals; j++) { - evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting); - } - return new ArrayElementValue(ARRAY, evalues, cpool); - - default: - throw new ClassFormatException("Unexpected element value tag in annotation: " + tag); - } - } - /** * @deprecated (since 6.0) will be made private and final; do not access directly, use getter */ @@ -145,9 +80,76 @@ public abstract class ElementValue { this.cpool = cpool; } + /** + * Reads an {@code element_value} as an {@code ElementValue}. + * + * @param input Raw data input. + * @param cpool Constant pool. + * @return a new ElementValue. + * @throws IOException if an I/O error occurs. + */ + public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException { + return readElementValue(input, cpool, 0); + } + + /** + * Reads an {@code element_value} as an {@code ElementValue}. + * + * @param input Raw data input. + * @param cpool Constant pool. + * @param arrayNesting level of current array nesting. + * @return a new ElementValue. + * @throws IOException if an I/O error occurs. + * @since 6.7.0 + */ + public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting) + throws IOException { + final byte tag = input.readByte(); + switch (tag) { + case PRIMITIVE_BYTE: + case PRIMITIVE_CHAR: + case PRIMITIVE_DOUBLE: + case PRIMITIVE_FLOAT: + case PRIMITIVE_INT: + case PRIMITIVE_LONG: + case PRIMITIVE_SHORT: + case PRIMITIVE_BOOLEAN: + case STRING: + return new SimpleElementValue(tag, input.readUnsignedShort(), cpool); + + case ENUM_CONSTANT: + return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool); + + case CLASS: + return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool); + + case ANNOTATION: + // TODO isRuntimeVisible + return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool); + + case ARRAY: + arrayNesting++; + if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) { + // JVM spec 4.4.1 + throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS)); + } + final int numArrayVals = input.readUnsignedShort(); + final ElementValue[] evalues = new ElementValue[numArrayVals]; + for (int j = 0; j < numArrayVals; j++) { + evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting); + } + return new ArrayElementValue(ARRAY, evalues, cpool); + + default: + throw new ClassFormatException("Unexpected element value tag in annotation: " + tag); + } + } + public abstract void dump(DataOutputStream dos) throws IOException; - /** @since 6.0 */ + /** + * @since 6.0 + */ final ConstantPool getConstantPool() { return cpool; } @@ -156,7 +158,9 @@ public abstract class ElementValue { return type; } - /** @since 6.0 */ + /** + * @since 6.0 + */ final int getType() { return type; } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java b/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java index 2763aed..61eea60 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java @@ -235,47 +235,65 @@ public class EmptyVisitor implements Visitor { public void visitMethodParameters(final MethodParameters obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModule(final Module obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleExports(final ModuleExports obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleMainClass(final ModuleMainClass obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleOpens(final ModuleOpens obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModulePackages(final ModulePackages obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleProvides(final ModuleProvides obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitModuleRequires(final ModuleRequires obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitNestHost(final NestHost obj) { } - /** @since 6.4.0 */ + /** + * @since 6.4.0 + */ @Override public void visitNestMembers(final NestMembers obj) { } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java index c81d27d..0cf7791 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java @@ -1,18 +1,18 @@ /** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package haidnor.jvm.bcel.classfile; @@ -81,6 +81,10 @@ public class EnclosingMethod extends Attribute { return classIndex; } + public final void setEnclosingClassIndex(final int idx) { + classIndex = idx; + } + public final ConstantNameAndType getEnclosingMethod() { if (methodIndex == 0) { return null; @@ -92,10 +96,6 @@ public class EnclosingMethod extends Attribute { return methodIndex; } - public final void setEnclosingClassIndex(final int idx) { - classIndex = idx; - } - public final void setEnclosingMethodIndex(final int idx) { methodIndex = idx; } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java b/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java index 51385bc..4b22ab8 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java @@ -40,6 +40,7 @@ import java.util.Arrays; * u2 exception_index_table[number_of_exceptions]; * } * + * * @see Code */ public final class ExceptionTable extends Attribute { @@ -59,9 +60,9 @@ public final class ExceptionTable extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -75,10 +76,10 @@ public final class ExceptionTable extends Attribute { } /** - * @param nameIndex Index in constant pool - * @param length Content length in bytes + * @param nameIndex Index in constant pool + * @param length Content length in bytes * @param exceptionIndexTable Table of indices in constant pool - * @param constantPool Array of constants + * @param constantPool Array of constants */ public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); @@ -132,6 +133,14 @@ public final class ExceptionTable extends Attribute { return exceptionIndexTable; } + /** + * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table + * length. + */ + public void setExceptionIndexTable(final int[] exceptionIndexTable) { + this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY; + } + /** * @return class names of thrown exceptions */ @@ -148,14 +157,6 @@ public final class ExceptionTable extends Attribute { return exceptionIndexTable == null ? 0 : exceptionIndexTable.length; } - /** - * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table - * length. - */ - public void setExceptionIndexTable(final int[] exceptionIndexTable) { - this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY; - } - /** * @return String representation, i.e., a list of thrown exceptions. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java index e1da2e5..59018b9 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java @@ -50,16 +50,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No */ @java.lang.Deprecated protected int attributes_count; // No. of attributes - - // @since 6.0 - private AnnotationEntry[] annotationEntries; // annotations defined on the field or method - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @java.lang.Deprecated protected ConstantPool constant_pool; - + // @since 6.0 + private AnnotationEntry[] annotationEntries; // annotations defined on the field or method private String signatureAttributeString; private boolean searchedForSignatureAttribute; @@ -105,14 +102,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No } /** - * @param accessFlags Access rights of method - * @param nameIndex Points to field name in constant pool + * @param accessFlags Access rights of method + * @param nameIndex Points to field name in constant pool * @param signatureIndex Points to encoded signature - * @param attributes Collection of attributes - * @param constantPool Array of constants + * @param attributes Collection of attributes + * @param constantPool Array of constants */ protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, - final ConstantPool constantPool) { + final ConstantPool constantPool) { super(accessFlags); this.name_index = nameIndex; this.signature_index = signatureIndex; @@ -173,6 +170,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No return attributes; } + /** + * @param attributes Collection of object attributes. + */ + public final void setAttributes(final Attribute[] attributes) { + this.attributes = attributes; + this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field + } + /** * @return Constant pool used by this object. */ @@ -180,6 +185,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No return constant_pool; } + /** + * @param constantPool Constant pool to be used for this object. + */ + public final void setConstantPool(final ConstantPool constantPool) { + this.constant_pool = constantPool; + } + /** * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for @@ -215,6 +227,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No return name_index; } + /** + * @param nameIndex Index in constant pool of object's name. + */ + public final void setNameIndex(final int nameIndex) { + this.name_index = nameIndex; + } + /** * @return String representation of object's type signature (java style) */ @@ -229,28 +248,6 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No return signature_index; } - /** - * @param attributes Collection of object attributes. - */ - public final void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; - this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field - } - - /** - * @param constantPool Constant pool to be used for this object. - */ - public final void setConstantPool(final ConstantPool constantPool) { - this.constant_pool = constantPool; - } - - /** - * @param nameIndex Index in constant pool of object's name. - */ - public final void setNameIndex(final int nameIndex) { - this.name_index = nameIndex; - } - /** * @param signatureIndex Index in constant pool of field signature. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java b/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java index 719e8ba..edf3529 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java @@ -55,9 +55,9 @@ public final class InnerClass implements Cloneable, Node { } /** - * @param innerClassIndex Class index in constant pool of inner class - * @param outerClassIndex Class index in constant pool of outer class - * @param innerNameIndex Name index in constant pool of inner class + * @param innerClassIndex Class index in constant pool of inner class + * @param outerClassIndex Class index in constant pool of outer class + * @param innerNameIndex Name index in constant pool of inner class * @param innerAccessFlags Access flags of inner class */ public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) { @@ -110,27 +110,6 @@ public final class InnerClass implements Cloneable, Node { return innerAccessFlags; } - /** - * @return class index of inner class. - */ - public int getInnerClassIndex() { - return innerClassIndex; - } - - /** - * @return name index of inner class. - */ - public int getInnerNameIndex() { - return innerNameIndex; - } - - /** - * @return class index of outer class. - */ - public int getOuterClassIndex() { - return outerClassIndex; - } - /** * @param innerAccessFlags access flags for this inner class */ @@ -138,6 +117,13 @@ public final class InnerClass implements Cloneable, Node { this.innerAccessFlags = innerAccessFlags; } + /** + * @return class index of inner class. + */ + public int getInnerClassIndex() { + return innerClassIndex; + } + /** * @param innerClassIndex index into the constant pool for this class */ @@ -145,6 +131,13 @@ public final class InnerClass implements Cloneable, Node { this.innerClassIndex = innerClassIndex; } + /** + * @return name index of inner class. + */ + public int getInnerNameIndex() { + return innerNameIndex; + } + /** * @param innerNameIndex index into the constant pool for this class's name */ @@ -152,6 +145,13 @@ public final class InnerClass implements Cloneable, Node { this.innerNameIndex = innerNameIndex; } + /** + * @return class index of outer class. + */ + public int getOuterClassIndex() { + return outerClassIndex; + } + /** * @param outerClassIndex index into the constant pool for the owning class */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java b/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java index 398d2c1..b3b7b33 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java @@ -54,9 +54,9 @@ public final class InnerClasses extends Attribute implements Iterable iterator() { - return Stream.of(innerClasses).iterator(); - } - /** * @param innerClasses the array of inner classes */ @@ -139,6 +134,11 @@ public final class InnerClasses extends Attribute implements Iterable iterator() { + return Stream.of(innerClasses).iterator(); + } + /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java index c0076b8..0150703 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java @@ -23,6 +23,9 @@ import haidnor.jvm.bcel.util.BCELComparator; import haidnor.jvm.bcel.util.ClassQueue; import haidnor.jvm.bcel.util.Repository; import haidnor.jvm.bcel.util.SyntheticRepository; +import haidnor.jvm.classloader.JVMClassLoader; +import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.ArrayUtils; import java.io.*; @@ -71,41 +74,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return THIS.getClassName().hashCode(); } }; - - /* - * Print debug information depending on 'JavaClass.debug' - */ - static void Debug(final String str) { - if (debug) { - System.out.println(str); - } - } - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - private static String indent(final Object obj) { - final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n"); - final StringBuilder buf = new StringBuilder(); - while (tokenizer.hasMoreTokens()) { - buf.append("\t").append(tokenizer.nextToken()).append("\n"); - } - return buf.toString(); - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - - private String fileName; private final String packageName; + @Getter + private final Map staticJavaFieldMap = new HashMap<>(); + private String fileName; private String sourceFileName = ""; private int classNameIndex; private int superclassNameIndex; @@ -119,36 +91,38 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl private JavaField[] fields; // Fields, i.e., variables of class private JavaMethod[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class - private AnnotationEntry[] annotations; // annotations defined on the class private byte source = HEAP; // Generated in memory - private boolean isAnonymous; - private boolean isNested; - private boolean computedNestedTypeStatus; + // ---------------------------------------------- haidnorJVM > /** * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any * better. */ private transient Repository repository = SyntheticRepository.getInstance(); + @Getter + @Setter + private JVMClassLoader JVMClassLoader; + + // ---------------------------------------------- haidnorJVM < /** * Constructor gets all contents as arguments. * - * @param classNameIndex Class name + * @param classNameIndex Class name * @param superclassNameIndex Superclass name - * @param fileName File name - * @param major Major compiler version - * @param minor Minor compiler version - * @param accessFlags Access rights defined by bit flags - * @param constantPool Array of constants - * @param interfaces Implemented interfaces - * @param fields Class fields - * @param methods Class methods - * @param attributes Class attributes + * @param fileName File name + * @param major Major compiler version + * @param minor Minor compiler version + * @param accessFlags Access rights defined by bit flags + * @param constantPool Array of constants + * @param interfaces Implemented interfaces + * @param fields Class fields + * @param methods Class methods + * @param attributes Class attributes */ public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, final ConstantPool constantPool, final int[] interfaces, final JavaField[] fields, final JavaMethod[] methods, final Attribute[] attributes) { @@ -158,19 +132,19 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl /** * Constructor gets all contents as arguments. * - * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class. + * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class. * @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's - * superclass. - * @param fileName File name - * @param major Major compiler version - * @param minor Minor compiler version - * @param accessFlags Access rights defined by bit flags - * @param constantPool Array of constants - * @param interfaces Implemented interfaces - * @param fields Class fields - * @param methods Class methods - * @param attributes Class attributes - * @param source Read from file or generated in memory? + * superclass. + * @param fileName File name + * @param major Major compiler version + * @param minor Minor compiler version + * @param accessFlags Access rights defined by bit flags + * @param constantPool Array of constants + * @param interfaces Implemented interfaces + * @param fields Class fields + * @param methods Class methods + * @param attributes Class attributes + * @param source Read from file or generated in memory? */ public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, final ConstantPool constantPool, int[] interfaces, JavaField[] fields, JavaMethod[] methods, Attribute[] attributes, final byte source) { @@ -229,6 +203,45 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class); interfaceNames[i] = Utility.compactClassName(str, false); } + + // 初始化静态字段 + for (JavaField field : getFields()) { + if (field.isStatic()) { + staticJavaFieldMap.put(field.getName(), field); + } + } + } + + /* + * Print debug information depending on 'JavaClass.debug' + */ + static void Debug(final String str) { + if (debug) { + System.out.println(str); + } + } + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + + private static String indent(final Object obj) { + final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n"); + final StringBuilder buf = new StringBuilder(); + while (tokenizer.hasMoreTokens()) { + buf.append("\t").append(tokenizer.nextToken()).append("\n"); + } + return buf.toString(); } /** @@ -258,7 +271,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } for (final Attribute attribute : this.attributes) { if (attribute instanceof InnerClasses) { - ((InnerClasses) attribute).forEach(innerClass -> { + ((InnerClasses) attribute).forEach(innerClass -> { boolean innerClassAttributeRefersToMe = false; String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class); innerClassName = Utility.compactClassName(innerClassName, false); @@ -429,6 +442,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return attributes; } + /** + * @param attributes . + */ + public void setAttributes(final Attribute[] attributes) { + this.attributes = attributes; + } + /** * @return class in binary format */ @@ -449,6 +469,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return className; } + /** + * @param className . + */ + public void setClassName(final String className) { + this.className = className; + } + /** * @return Class name index. */ @@ -456,6 +483,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return classNameIndex; } + /** + * @param classNameIndex . + */ + public void setClassNameIndex(final int classNameIndex) { + this.classNameIndex = classNameIndex; + } + /** * @return Constant pool. */ @@ -463,14 +497,28 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return constantPool; } + /** + * @param constantPool . + */ + public void setConstantPool(final ConstantPool constantPool) { + this.constantPool = constantPool; + } + /** * @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are - * those specific to this class, and not those of the superclass or superinterfaces. + * those specific to this class, and not those of the superclass or superinterfaces. */ public JavaField[] getFields() { return fields; } + /** + * @param fields . + */ + public void setFields(final JavaField[] fields) { + this.fields = fields; + } + /** * @return File name of class, aka SourceFile attribute value */ @@ -478,6 +526,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return fileName; } + /** + * Set File name of class, aka SourceFile attribute value + */ + public void setFileName(final String fileName) { + this.fileName = fileName; + } + /** * @return Indices in constant pool of implemented interfaces. */ @@ -492,6 +547,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return interfaceNames; } + /** + * @param interfaceNames . + */ + public void setInterfaceNames(final String[] interfaceNames) { + this.interfaceNames = interfaceNames; + } + /** * Get interfaces directly implemented by this JavaClass. * @@ -506,6 +568,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return classes; } + /** + * @param interfaces . + */ + public void setInterfaces(final int[] interfaces) { + this.interfaces = interfaces; + } + /** * @return Major number of class file version. */ @@ -513,6 +582,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return major; } + /** + * @param major . + */ + public void setMajor(final int major) { + this.major = major; + } + /** * @return A {@link JavaMethod} corresponding to java.lang.reflect.Method if any */ @@ -532,6 +608,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return methods; } + /** + * @param methods . + */ + public void setMethods(final JavaMethod[] methods) { + this.methods = methods; + } + /** * @return Minor number of class file version. */ @@ -539,6 +622,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return minor; } + /** + * @param minor . + */ + public void setMinor(final int minor) { + this.minor = minor; + } + /** * @return Package name. */ @@ -554,6 +644,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return repository; } + /** + * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done. + */ + public void setRepository(final Repository repository) { // TODO make protected? + this.repository = repository; + } + /** * @return returns either HEAP (generated), FILE, or ZIP */ @@ -568,6 +665,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return sourceFileName; } + /** + * Set absolute path to file this class was read from. + */ + public void setSourceFileName(final String sourceFileName) { + this.sourceFileName = sourceFileName; + } + /** * Gets the source file path including the package path. * @@ -618,6 +722,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return superclassName; } + /** + * @param superclassName . + */ + public void setSuperclassName(final String superclassName) { + this.superclassName = superclassName; + } + /** * @return Class name index. */ @@ -625,6 +736,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return superclassNameIndex; } + /** + * @param superclassNameIndex . + */ + public void setSuperclassNameIndex(final int superclassNameIndex) { + this.superclassNameIndex = superclassNameIndex; + } + + public JavaField getStaticField(String filedName) { + return staticJavaFieldMap.get(filedName); + } + /** * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. * @@ -700,111 +822,6 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl return (super.getAccessFlags() & Const.ACC_SUPER) != 0; } - /** - * @param attributes . - */ - public void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; - } - - /** - * @param className . - */ - public void setClassName(final String className) { - this.className = className; - } - - /** - * @param classNameIndex . - */ - public void setClassNameIndex(final int classNameIndex) { - this.classNameIndex = classNameIndex; - } - - /** - * @param constantPool . - */ - public void setConstantPool(final ConstantPool constantPool) { - this.constantPool = constantPool; - } - - /** - * @param fields . - */ - public void setFields(final JavaField[] fields) { - this.fields = fields; - } - - /** - * Set File name of class, aka SourceFile attribute value - */ - public void setFileName(final String fileName) { - this.fileName = fileName; - } - - /** - * @param interfaceNames . - */ - public void setInterfaceNames(final String[] interfaceNames) { - this.interfaceNames = interfaceNames; - } - - /** - * @param interfaces . - */ - public void setInterfaces(final int[] interfaces) { - this.interfaces = interfaces; - } - - /** - * @param major . - */ - public void setMajor(final int major) { - this.major = major; - } - - /** - * @param methods . - */ - public void setMethods(final JavaMethod[] methods) { - this.methods = methods; - } - - /** - * @param minor . - */ - public void setMinor(final int minor) { - this.minor = minor; - } - - /** - * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done. - */ - public void setRepository(final Repository repository) { // TODO make protected? - this.repository = repository; - } - - /** - * Set absolute path to file this class was read from. - */ - public void setSourceFileName(final String sourceFileName) { - this.sourceFileName = sourceFileName; - } - - /** - * @param superclassName . - */ - public void setSuperclassName(final String superclassName) { - this.superclassName = superclassName; - } - - /** - * @param superclassNameIndex . - */ - public void setSuperclassNameIndex(final int superclassNameIndex) { - this.superclassNameIndex = superclassNameIndex; - } - /** * @return String representing class contents. */ @@ -814,7 +831,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl access = access.isEmpty() ? "" : access + " "; final StringBuilder buf = new StringBuilder(128); buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(className).append(" extends ") - .append(Utility.compactClassName(superclassName, false)).append('\n'); + .append(Utility.compactClassName(superclassName, false)).append('\n'); final int size = interfaces.length; if (size > 0) { buf.append("implements\t\t"); @@ -859,4 +876,20 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl } return buf.toString(); } + + // ---------------------------------------------- haidnorJVM + + /** + * 获取 main 方法 + */ + public JavaMethod getMainMethod() { + for (JavaMethod javaMethod : getMethods()) { + if (javaMethod.toString().startsWith("public static void main(String[] args)")) { + return javaMethod; + } + } + return null; + } + + } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java index cf1f7fd..71d326c 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java @@ -28,7 +28,7 @@ import java.util.Objects; * This class represents the field info structure, i.e., the representation for a variable in the class. See JVM * specification for details. */ -public final class JavaField extends FieldOrMethod { +public class JavaField extends FieldOrMethod { /** * Empty array constant. @@ -36,7 +36,10 @@ public final class JavaField extends FieldOrMethod { * @since 6.6.0 */ public static final JavaField[] EMPTY_ARRAY = {}; - + /** + * Empty array. + */ + static final JavaField[] EMPTY_FIELD_ARRAY = {}; private static BCELComparator bcelComparator = new BCELComparator() { @Override @@ -52,25 +55,14 @@ public final class JavaField extends FieldOrMethod { return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; - /** - * Empty array. + * 值类型 */ - static final JavaField[] EMPTY_FIELD_ARRAY = {}; - + private int valueType; /** - * @return Comparison strategy object + * 值 */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } + private Object value; /** * Construct object from file stream. @@ -92,16 +84,30 @@ public final class JavaField extends FieldOrMethod { } /** - * @param accessFlags Access rights of field - * @param nameIndex Points to field name in constant pool + * @param accessFlags Access rights of field + * @param nameIndex Points to field name in constant pool * @param signatureIndex Points to encoded signature - * @param attributes Collection of attributes - * @param constantPool Array of constants + * @param attributes Collection of attributes + * @param constantPool Array of constants */ public JavaField(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); } + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. @@ -150,6 +156,22 @@ public final class JavaField extends FieldOrMethod { return Type.getReturnType(getSignature()); } + public int getValueType() { + return valueType; + } + + public void setValueType(int valueType) { + this.valueType = valueType; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + /** * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR * signature. diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java index d83f245..4f2e62d 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java @@ -27,7 +27,7 @@ import java.util.Objects; * This class represents the method info structure, i.e., the representation for a method in the class. See JVM * specification for details. A method has access flags, a name, a signature and a number of attributes. */ -public final class JavaMethod extends FieldOrMethod { +public class JavaMethod extends FieldOrMethod { /** * Empty array constant. @@ -35,7 +35,10 @@ public final class JavaMethod extends FieldOrMethod { * @since 6.6.0 */ public static final JavaMethod[] EMPTY_ARRAY = {}; - + /** + * Empty array. + */ + static final JavaMethod[] EMPTY_METHOD_ARRAY = {}; private static BCELComparator bcelComparator = new BCELComparator() { @Override @@ -51,26 +54,6 @@ public final class JavaMethod extends FieldOrMethod { return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; - - /** - * Empty array. - */ - static final JavaMethod[] EMPTY_METHOD_ARRAY = {}; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - // annotations defined on the parameters of a method private ParameterAnnotationEntry[] parameterAnnotationEntries; @@ -84,7 +67,7 @@ public final class JavaMethod extends FieldOrMethod { * Construct object from file stream. * * @param file Input stream - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ JavaMethod(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { @@ -92,11 +75,11 @@ public final class JavaMethod extends FieldOrMethod { } /** - * @param accessFlags Access rights of method - * @param nameIndex Points to field name in constant pool + * @param accessFlags Access rights of method + * @param nameIndex Points to field name in constant pool * @param signatureIndex Points to encoded signature - * @param attributes Collection of attributes - * @param constantPool Array of constants + * @param attributes Collection of attributes + * @param constantPool Array of constants */ public JavaMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); @@ -112,6 +95,20 @@ public final class JavaMethod extends FieldOrMethod { super(c); } + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. @@ -162,7 +159,7 @@ public final class JavaMethod extends FieldOrMethod { /** * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception - * handlers! + * handlers! */ public ExceptionTable getExceptionTable() { for (final Attribute attribute : super.getAttributes()) { diff --git a/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java b/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java index 8f45505..7be245d 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java @@ -32,10 +32,14 @@ public final class LineNumber implements Cloneable, Node { static final LineNumber[] EMPTY_ARRAY = {}; - /** Program Counter (PC) corresponds to line */ + /** + * Program Counter (PC) corresponds to line + */ private int startPc; - /** number in source file */ + /** + * number in source file + */ private int lineNumber; /** @@ -49,7 +53,7 @@ public final class LineNumber implements Cloneable, Node { } /** - * @param startPc Program Counter (PC) corresponds to + * @param startPc Program Counter (PC) corresponds to * @param lineNumber line number in source file */ public LineNumber(final int startPc, final int lineNumber) { @@ -107,13 +111,6 @@ public final class LineNumber implements Cloneable, Node { return lineNumber & 0xffff; } - /** - * @return PC in code - */ - public int getStartPC() { - return startPc & 0xffff; - } - /** * @param lineNumber the source line number */ @@ -121,6 +118,13 @@ public final class LineNumber implements Cloneable, Node { this.lineNumber = (short) lineNumber; } + /** + * @return PC in code + */ + public int getStartPC() { + return startPc & 0xffff; + } + /** * @param startPc the pc for this line number */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java b/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java index 28ec9f9..702e0b6 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java @@ -41,9 +41,9 @@ public final class LineNumberTable extends Attribute implements Iterable + * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package haidnor.jvm.bcel.classfile; diff --git a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java index 0b0e9ca..c49446a 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java @@ -27,15 +27,19 @@ import java.io.IOException; * Entry of the parameters table. * * @see The class File Format : - * The MethodParameters Attribute + * The MethodParameters Attribute * @since 6.0 */ public class MethodParameter implements Cloneable, Node { - /** Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter */ + /** + * Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter + */ private int nameIndex; - /** The access flags */ + /** + * The access flags + */ private int accessFlags; public MethodParameter() { @@ -45,7 +49,7 @@ public class MethodParameter implements Cloneable, Node { * Construct object from input stream. * * @param input Input stream - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ MethodParameter(final DataInput input) throws IOException { @@ -85,10 +89,18 @@ public class MethodParameter implements Cloneable, Node { return accessFlags; } + public void setAccessFlags(final int accessFlags) { + this.accessFlags = accessFlags; + } + public int getNameIndex() { return nameIndex; } + public void setNameIndex(final int nameIndex) { + this.nameIndex = nameIndex; + } + /** * Returns the name of the parameter. */ @@ -110,12 +122,4 @@ public class MethodParameter implements Cloneable, Node { public boolean isSynthetic() { return (accessFlags & Const.ACC_SYNTHETIC) != 0; } - - public void setAccessFlags(final int accessFlags) { - this.accessFlags = accessFlags; - } - - public void setNameIndex(final int nameIndex) { - this.nameIndex = nameIndex; - } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java index 86b6337..0ca62b1 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java @@ -30,7 +30,7 @@ import java.util.stream.Stream; * This class represents a MethodParameters attribute. * * @see The class File Format : - * The MethodParameters Attribute + * The MethodParameters Attribute * @since 6.0 */ public class MethodParameters extends Attribute implements Iterable { @@ -86,12 +86,12 @@ public class MethodParameters extends Attribute implements Iterable iterator() { return Stream.of(parameters).iterator(); } - - public void setParameters(final MethodParameter[] parameters) { - this.parameters = parameters; - } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Module.java b/src/main/java/haidnor/jvm/bcel/classfile/Module.java index b4379ca..19f22cf 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Module.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Module.java @@ -43,20 +43,19 @@ public final class Module extends Attribute { private final int moduleNameIndex; private final int moduleFlags; private final int moduleVersionIndex; - + private final int usesCount; + private final int[] usesIndex; private ModuleRequires[] requiresTable; private ModuleExports[] exportsTable; private ModuleOpens[] opensTable; - private final int usesCount; - private final int[] usesIndex; private ModuleProvides[] providesTable; /** * Construct object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java b/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java index 37c3d8b..8e39f59 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java @@ -37,9 +37,9 @@ public final class ModuleMainClass extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -49,10 +49,10 @@ public final class ModuleMainClass extends Attribute { } /** - * @param nameIndex Index in constant pool - * @param length Content length in bytes + * @param nameIndex Index in constant pool + * @param length Content length in bytes * @param mainClassIndex Host class index - * @param constantPool Array of constants + * @param constantPool Array of constants */ public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) { super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java b/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java index 2bce0ba..66b5af3 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java @@ -39,9 +39,9 @@ public final class ModulePackages extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -55,10 +55,10 @@ public final class ModulePackages extends Attribute { } /** - * @param nameIndex Index in constant pool - * @param length Content length in bytes + * @param nameIndex Index in constant pool + * @param length Content length in bytes * @param packageIndexTable Table of indices in constant pool - * @param constantPool Array of constants + * @param constantPool Array of constants */ public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) { super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool); @@ -129,6 +129,13 @@ public final class ModulePackages extends Attribute { return packageIndexTable; } + /** + * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length. + */ + public void setPackageIndexTable(final int[] packageIndexTable) { + this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY; + } + /** * @return string array of package names */ @@ -138,13 +145,6 @@ public final class ModulePackages extends Attribute { return names; } - /** - * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length. - */ - public void setPackageIndexTable(final int[] packageIndexTable) { - this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY; - } - /** * @return String representation, i.e., a list of packages. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java b/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java index 6f3e654..c62c73b 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java @@ -37,9 +37,9 @@ public final class NestHost extends Attribute { /** * Constructs object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -49,10 +49,10 @@ public final class NestHost extends Attribute { } /** - * @param nameIndex Index in constant pool - * @param length Content length in bytes + * @param nameIndex Index in constant pool + * @param length Content length in bytes * @param hostClassIndex Host class index - * @param constantPool Array of constants + * @param constantPool Array of constants */ public NestHost(final int nameIndex, final int length, final int hostClassIndex, final ConstantPool constantPool) { super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); diff --git a/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java b/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java index 1019688..479e69a 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java @@ -40,9 +40,9 @@ public final class NestMembers extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -56,9 +56,9 @@ public final class NestMembers extends Attribute { } /** - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param classes Table of indices in constant pool + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param classes Table of indices in constant pool * @param constantPool Array of constants */ public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) { @@ -123,6 +123,13 @@ public final class NestMembers extends Attribute { return classes; } + /** + * @param classes the list of class indexes Also redefines number_of_classes according to table length. + */ + public void setClasses(final int[] classes) { + this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY; + } + /** * @return string array of class names */ @@ -139,13 +146,6 @@ public final class NestMembers extends Attribute { return classes.length; } - /** - * @param classes the list of class indexes Also redefines number_of_classes according to table length. - */ - public void setClasses(final int[] classes) { - this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY; - } - /** * @return String representation, i.e., a list of classes. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java b/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java index 87ecb31..bba4af8 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java @@ -35,9 +35,9 @@ public final class PMGClass extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -46,11 +46,11 @@ public final class PMGClass extends Attribute { } /** - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param pmgIndex index in constant pool for source file name + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param pmgIndex index in constant pool for source file name * @param pmgClassIndex Index in constant pool to CONSTANT_Utf8 - * @param constantPool Array of constants + * @param constantPool Array of constants */ public PMGClass(final int nameIndex, final int length, final int pmgIndex, final int pmgClassIndex, final ConstantPool constantPool) { super(Const.ATTR_PMG, nameIndex, length, constantPool); @@ -107,6 +107,13 @@ public final class PMGClass extends Attribute { return pmgClassIndex; } + /** + * @param pmgClassIndex + */ + public void setPMGClassIndex(final int pmgClassIndex) { + this.pmgClassIndex = pmgClassIndex; + } + /** * @return PMG class name. */ @@ -121,20 +128,6 @@ public final class PMGClass extends Attribute { return pmgIndex; } - /** - * @return PMG name. - */ - public String getPMGName() { - return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes(); - } - - /** - * @param pmgClassIndex - */ - public void setPMGClassIndex(final int pmgClassIndex) { - this.pmgClassIndex = pmgClassIndex; - } - /** * @param pmgIndex */ @@ -142,6 +135,13 @@ public final class PMGClass extends Attribute { this.pmgIndex = pmgIndex; } + /** + * @return PMG name. + */ + public String getPMGName() { + return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes(); + } + /** * @return String representation */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java index 99b1397..f236066 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java @@ -31,19 +31,6 @@ import java.util.List; public class ParameterAnnotationEntry implements Node { static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; - - public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) { - // Find attributes that contain parameter annotation data - final List accumulatedAnnotations = new ArrayList<>(attrs.length); - for (final Attribute attribute : attrs) { - if (attribute instanceof ParameterAnnotations) { - final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute; - Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries()); - } - } - return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY); - } - private final AnnotationEntry[] annotationTable; /** @@ -61,6 +48,18 @@ public class ParameterAnnotationEntry implements Node { } } + public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) { + // Find attributes that contain parameter annotation data + final List accumulatedAnnotations = new ArrayList<>(attrs.length); + for (final Attribute attribute : attrs) { + if (attribute instanceof ParameterAnnotations) { + final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute; + Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries()); + } + } + return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY); + } + /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java index 8b3071c..15c61af 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java @@ -29,18 +29,20 @@ import java.util.stream.Stream; */ public abstract class ParameterAnnotations extends Attribute implements Iterable { - /** Table of parameter annotations */ + /** + * Table of parameter annotations + */ private ParameterAnnotationEntry[] parameterAnnotationTable; /** * @param parameterAnnotationType the subclass type of the parameter annotation - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream - * @param constantPool Array of constants + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream + * @param constantPool Array of constants */ ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) - throws IOException { + throws IOException { this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool); final int numParameters = input.readUnsignedByte(); parameterAnnotationTable = new ParameterAnnotationEntry[numParameters]; @@ -50,14 +52,14 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable } /** - * @param parameterAnnotationType the subclass type of the parameter annotation - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes + * @param parameterAnnotationType the subclass type of the parameter annotation + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes * @param parameterAnnotationTable the actual parameter annotations - * @param constantPool Array of constants + * @param constantPool Array of constants */ public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, - final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) { + final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) { super(parameterAnnotationType, nameIndex, length, constantPool); this.parameterAnnotationTable = parameterAnnotationTable; } @@ -106,15 +108,15 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable return parameterAnnotationTable; } - @Override - public Iterator iterator() { - return Stream.of(parameterAnnotationTable).iterator(); - } - /** * @param parameterAnnotationTable the entries to set in this parameter annotation */ public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) { this.parameterAnnotationTable = parameterAnnotationTable; } + + @Override + public Iterator iterator() { + return Stream.of(parameterAnnotationTable).iterator(); + } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java index 4120d07..7f80e3b 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java @@ -30,9 +30,9 @@ import java.io.IOException; public class RuntimeInvisibleAnnotations extends Annotations { /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException Thrown when an I/O exception of some sort has occurred. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java index cd799b5..4cfdd42 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java @@ -29,14 +29,14 @@ import java.io.IOException; public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations { /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException Thrown when an I/O exception of some sort has occurred. */ public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) - throws IOException { + throws IOException { super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool); } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java index b523905..5a4049d 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java @@ -30,9 +30,9 @@ import java.io.IOException; public class RuntimeVisibleAnnotations extends Annotations { /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException Thrown when an I/O exception of some sort has occurred. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java index 2e311cd..b3a0800 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java @@ -29,14 +29,14 @@ import java.io.IOException; public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations { /** - * @param nameIndex Index pointing to the name Code - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index pointing to the name Code + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException Thrown when an I/O exception of some sort has occurred. */ public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) - throws IOException { + throws IOException { super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool); } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Signature.java b/src/main/java/haidnor/jvm/bcel/classfile/Signature.java index ca0b000..d47bfd6 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Signature.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Signature.java @@ -33,24 +33,42 @@ import java.util.Objects; */ public final class Signature extends Attribute { + private int signatureIndex; + /** - * Extends ByteArrayInputStream to make 'unreading' chars possible. + * Construct object from file stream. + * + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param input Input stream + * @param constantPool Array of constants + * @throws IOException if an I/O error occurs. */ - private static final class MyByteArrayInputStream extends ByteArrayInputStream { + Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { + this(nameIndex, length, input.readUnsignedShort(), constantPool); + } - MyByteArrayInputStream(final String data) { - super(data.getBytes(StandardCharsets.UTF_8)); - } + /** + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param signatureIndex Index in constant pool to CONSTANT_Utf8 + * @param constantPool Array of constants + */ + public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) { + super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool); + this.signatureIndex = signatureIndex; + // validate: + Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)"); + } - String getData() { - return new String(buf, StandardCharsets.UTF_8); - } - - void unread() { - if (pos > 0) { - pos--; - } - } + /** + * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a + * physical copy. + * + * @param c Source to copy. + */ + public Signature(final Signature c) { + this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); } private static boolean identStart(final int ch) { @@ -152,44 +170,6 @@ public final class Signature extends Attribute { return buf.toString(); } - private int signatureIndex; - - /** - * Construct object from file stream. - * - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param input Input stream - * @param constantPool Array of constants - * @throws IOException if an I/O error occurs. - */ - Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { - this(nameIndex, length, input.readUnsignedShort(), constantPool); - } - - /** - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param signatureIndex Index in constant pool to CONSTANT_Utf8 - * @param constantPool Array of constants - */ - public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) { - super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool); - this.signatureIndex = signatureIndex; - // validate: - Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)"); - } - - /** - * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a - * physical copy. - * - * @param c Source to copy. - */ - public Signature(final Signature c) { - this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); - } - /** * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. @@ -250,4 +230,24 @@ public final class Signature extends Attribute { public String toString() { return "Signature: " + getSignature(); } + + /** + * Extends ByteArrayInputStream to make 'unreading' chars possible. + */ + private static final class MyByteArrayInputStream extends ByteArrayInputStream { + + MyByteArrayInputStream(final String data) { + super(data.getBytes(StandardCharsets.UTF_8)); + } + + String getData() { + return new String(buf, StandardCharsets.UTF_8); + } + + void unread() { + if (pos > 0) { + pos--; + } + } + } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java b/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java index 892c35b..6a94d4c 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java @@ -37,19 +37,19 @@ public class SimpleElementValue extends ElementValue { final int type = super.getType(); dos.writeByte(type); // u1 kind of value switch (type) { - case PRIMITIVE_INT: - case PRIMITIVE_BYTE: - case PRIMITIVE_CHAR: - case PRIMITIVE_FLOAT: - case PRIMITIVE_LONG: - case PRIMITIVE_BOOLEAN: - case PRIMITIVE_SHORT: - case PRIMITIVE_DOUBLE: - case STRING: - dos.writeShort(getIndex()); - break; - default: - throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type); + case PRIMITIVE_INT: + case PRIMITIVE_BYTE: + case PRIMITIVE_CHAR: + case PRIMITIVE_FLOAT: + case PRIMITIVE_LONG: + case PRIMITIVE_BOOLEAN: + case PRIMITIVE_SHORT: + case PRIMITIVE_DOUBLE: + case STRING: + dos.writeShort(getIndex()); + break; + default: + throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type); } } @@ -60,6 +60,10 @@ public class SimpleElementValue extends ElementValue { return index; } + public void setIndex(final int index) { + this.index = index; + } + public boolean getValueBoolean() { if (super.getType() != PRIMITIVE_BOOLEAN) { throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); @@ -128,46 +132,42 @@ public class SimpleElementValue extends ElementValue { return super.getConstantPool().getConstantUtf8(getIndex()).getBytes(); } - public void setIndex(final int index) { - this.index = index; - } - // Whatever kind of value it is, return it as a string @Override public String stringifyValue() { final ConstantPool cpool = super.getConstantPool(); final int type = super.getType(); switch (type) { - case PRIMITIVE_INT: - return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes()); - case PRIMITIVE_LONG: - final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class); - return Long.toString(j.getBytes()); - case PRIMITIVE_DOUBLE: - final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class); - return Double.toString(d.getBytes()); - case PRIMITIVE_FLOAT: - final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class); - return Float.toString(f.getBytes()); - case PRIMITIVE_SHORT: - final ConstantInteger s = cpool.getConstantInteger(getIndex()); - return Integer.toString(s.getBytes()); - case PRIMITIVE_BYTE: - final ConstantInteger b = cpool.getConstantInteger(getIndex()); - return Integer.toString(b.getBytes()); - case PRIMITIVE_CHAR: - final ConstantInteger ch = cpool.getConstantInteger(getIndex()); - return String.valueOf((char) ch.getBytes()); - case PRIMITIVE_BOOLEAN: - final ConstantInteger bo = cpool.getConstantInteger(getIndex()); - if (bo.getBytes() == 0) { - return "false"; - } - return "true"; - case STRING: - return cpool.getConstantUtf8(getIndex()).getBytes(); - default: - throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type); + case PRIMITIVE_INT: + return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes()); + case PRIMITIVE_LONG: + final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class); + return Long.toString(j.getBytes()); + case PRIMITIVE_DOUBLE: + final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class); + return Double.toString(d.getBytes()); + case PRIMITIVE_FLOAT: + final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class); + return Float.toString(f.getBytes()); + case PRIMITIVE_SHORT: + final ConstantInteger s = cpool.getConstantInteger(getIndex()); + return Integer.toString(s.getBytes()); + case PRIMITIVE_BYTE: + final ConstantInteger b = cpool.getConstantInteger(getIndex()); + return Integer.toString(b.getBytes()); + case PRIMITIVE_CHAR: + final ConstantInteger ch = cpool.getConstantInteger(getIndex()); + return String.valueOf((char) ch.getBytes()); + case PRIMITIVE_BOOLEAN: + final ConstantInteger bo = cpool.getConstantInteger(getIndex()); + if (bo.getBytes() == 0) { + return "false"; + } + return "true"; + case STRING: + return cpool.getConstantUtf8(getIndex()).getBytes(); + default: + throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type); } } diff --git a/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java b/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java index c61f9ed..6e2e1a2 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java @@ -37,9 +37,9 @@ public final class SourceFile extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -48,13 +48,13 @@ public final class SourceFile extends Attribute { } /** - * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile". - * @param length Content length in bytes, the value should be 2. - * @param constantPool The constant pool that this attribute is associated with. + * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile". + * @param length Content length in bytes, the value should be 2. + * @param constantPool The constant pool that this attribute is associated with. * @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the - * file from which this class was compiled. It will not be interpreted as indicating the name of the directory - * contqining the file or an absolute path; this information has to be supplied the consumer of this attribute - - * in many cases, the JVM. + * file from which this class was compiled. It will not be interpreted as indicating the name of the directory + * contqining the file or an absolute path; this information has to be supplied the consumer of this attribute - + * in many cases, the JVM. */ public SourceFile(final int nameIndex, final int length, final int sourceFileIndex, final ConstantPool constantPool) { super(Const.ATTR_SOURCE_FILE, nameIndex, Args.require(length, 2, "SourceFile length attribute"), constantPool); @@ -109,13 +109,6 @@ public final class SourceFile extends Attribute { return sourceFileIndex; } - /** - * @return Source file name. - */ - public String getSourceFileName() { - return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes(); - } - /** * @param sourceFileIndex */ @@ -123,6 +116,13 @@ public final class SourceFile extends Attribute { this.sourceFileIndex = sourceFileIndex; } + /** + * @return Source file name. + */ + public String getSourceFileName() { + return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes(); + } + /** * @return String representation */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java index 543db9f..e6f7ef4 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java @@ -50,9 +50,9 @@ public final class StackMap extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index of name - * @param length Content length in bytes - * @param dataInput Input stream + * @param nameIndex Index of name + * @param length Content length in bytes + * @param dataInput Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java index 58413c7..65be1aa 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java @@ -27,7 +27,7 @@ import java.util.Arrays; /** * This class represents a stack map entry recording the types of local variables and the of stack items at a given * byte code offset. See CLDC specification 5.3.1.2. - * + *

* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4 * *

@@ -41,6 +41,7 @@ import java.util.Arrays;
  *   full_frame;
  * }
  * 
+ * * @see StackMap * @see StackMapType */ @@ -67,10 +68,10 @@ public final class StackMapEntry implements Node, Cloneable { byteCodeOffset = frameType - Const.SAME_FRAME; } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; - typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) }; + typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)}; } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { byteCodeOffset = dataInput.readUnsignedShort(); - typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) }; + typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)}; } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) { byteCodeOffset = dataInput.readUnsignedShort(); } else if (frameType == Const.SAME_FRAME_EXTENDED) { @@ -104,16 +105,16 @@ public final class StackMapEntry implements Node, Cloneable { * DO NOT USE * * @param byteCodeOffset - * @param numberOfLocals NOT USED - * @param typesOfLocals array of {@link StackMapType}s of locals + * @param numberOfLocals NOT USED + * @param typesOfLocals array of {@link StackMapType}s of locals * @param numberOfStackItems NOT USED - * @param typesOfStackItems array ot {@link StackMapType}s of stack items - * @param constantPool the constant pool + * @param typesOfStackItems array ot {@link StackMapType}s of stack items + * @param constantPool the constant pool * @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead */ @java.lang.Deprecated public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems, - final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { + final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { this.byteCodeOffset = byteCodeOffset; this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY; this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY; @@ -129,14 +130,14 @@ public final class StackMapEntry implements Node, Cloneable { /** * Create an instance * - * @param tag the frameType to use + * @param tag the frameType to use * @param byteCodeOffset - * @param typesOfLocals array of {@link StackMapType}s of locals + * @param typesOfLocals array of {@link StackMapType}s of locals * @param typesOfStackItems array ot {@link StackMapType}s of stack items - * @param constantPool the constant pool + * @param constantPool the constant pool */ public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems, - final ConstantPool constantPool) { + final ConstantPool constantPool) { this.frameType = tag; this.byteCodeOffset = byteCodeOffset; this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY; @@ -215,6 +216,29 @@ public final class StackMapEntry implements Node, Cloneable { return byteCodeOffset; } + public void setByteCodeOffset(final int newOffset) { + if (newOffset < 0 || newOffset > 32767) { + throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset); + } + + if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) { + if (newOffset > Const.SAME_FRAME_MAX) { + frameType = Const.SAME_FRAME_EXTENDED; + } else { + frameType = newOffset; + } + } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { + if (newOffset > Const.SAME_FRAME_MAX) { + frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; + } else { + frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset; + } + } else if (invalidFrameType(frameType)) { + throw new IllegalStateException("Invalid StackMap frameType: " + frameType); + } + byteCodeOffset = newOffset; + } + /** * @return Constant pool used by this object. */ @@ -222,13 +246,30 @@ public final class StackMapEntry implements Node, Cloneable { return constantPool; } + /** + * @param constantPool Constant pool to be used for this object. + */ + public void setConstantPool(final ConstantPool constantPool) { + this.constantPool = constantPool; + } + public int getFrameType() { return frameType; } + public void setFrameType(final int ft) { + if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) { + byteCodeOffset = ft - Const.SAME_FRAME; + } else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { + byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; + } else if (invalidFrameType(ft)) { + throw new IllegalArgumentException("Invalid StackMap frameType"); + } + frameType = ft; + } + /** * Calculate stack map entry size - * */ int getMapEntrySize() { if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) { @@ -267,18 +308,40 @@ public final class StackMapEntry implements Node, Cloneable { return typesOfLocals.length; } + /** + * @deprecated since 6.0 + */ + @java.lang.Deprecated + public void setNumberOfLocals(final int n) { // TODO unused + } + public int getNumberOfStackItems() { return typesOfStackItems.length; } + /** + * @deprecated since 6.0 + */ + @java.lang.Deprecated + public void setNumberOfStackItems(final int n) { // TODO unused + } + public StackMapType[] getTypesOfLocals() { return typesOfLocals; } + public void setTypesOfLocals(final StackMapType[] types) { + typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY; + } + public StackMapType[] getTypesOfStackItems() { return typesOfStackItems; } + public void setTypesOfStackItems(final StackMapType[] types) { + typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY; + } + private boolean invalidFrameType(final int f) { // @formatter:off return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED @@ -289,71 +352,6 @@ public final class StackMapEntry implements Node, Cloneable { // @formatter:on } - public void setByteCodeOffset(final int newOffset) { - if (newOffset < 0 || newOffset > 32767) { - throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset); - } - - if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) { - if (newOffset > Const.SAME_FRAME_MAX) { - frameType = Const.SAME_FRAME_EXTENDED; - } else { - frameType = newOffset; - } - } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { - if (newOffset > Const.SAME_FRAME_MAX) { - frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; - } else { - frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset; - } - } else if (invalidFrameType(frameType)) { - throw new IllegalStateException("Invalid StackMap frameType: " + frameType); - } - byteCodeOffset = newOffset; - } - - /** - * @param constantPool Constant pool to be used for this object. - */ - public void setConstantPool(final ConstantPool constantPool) { - this.constantPool = constantPool; - } - - public void setFrameType(final int ft) { - if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) { - byteCodeOffset = ft - Const.SAME_FRAME; - } else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { - byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; - } else if (invalidFrameType(ft)) { - throw new IllegalArgumentException("Invalid StackMap frameType"); - } - frameType = ft; - } - - /** - * - * @deprecated since 6.0 - */ - @java.lang.Deprecated - public void setNumberOfLocals(final int n) { // TODO unused - } - - /** - * - * @deprecated since 6.0 - */ - @java.lang.Deprecated - public void setNumberOfStackItems(final int n) { // TODO unused - } - - public void setTypesOfLocals(final StackMapType[] types) { - typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY; - } - - public void setTypesOfStackItems(final StackMapType[] types) { - typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java index 6d3b61e..9033842 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java @@ -38,7 +38,7 @@ public final class StackMapType implements Cloneable { private ConstantPool constantPool; /** - * @param type type tag as defined in the Constants interface + * @param type type tag as defined in the Constants interface * @param index index to constant pool, or byte code offset */ public StackMapType(final byte type, final int index, final ConstantPool constantPool) { @@ -100,18 +100,33 @@ public final class StackMapType implements Cloneable { return constantPool; } + /** + * @param constantPool Constant pool to be used for this object. + */ + public void setConstantPool(final ConstantPool constantPool) { + this.constantPool = constantPool; + } + /** * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1 - * otherwise + * otherwise */ public int getIndex() { return index; } + public void setIndex(final int index) { + this.index = index; + } + public byte getType() { return type; } + public void setType(final byte type) { + this.type = checkType(type); + } + /** * @return true, if type is either ITEM_Object or ITEM_NewObject */ @@ -132,21 +147,6 @@ public final class StackMapType implements Cloneable { return ""; } - /** - * @param constantPool Constant pool to be used for this object. - */ - public void setConstantPool(final ConstantPool constantPool) { - this.constantPool = constantPool; - } - - public void setIndex(final int index) { - this.index = index; - } - - public void setType(final byte type) { - this.type = checkType(type); - } - /** * @return String representation */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java b/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java index f2e8864..9b74b4c 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java @@ -36,9 +36,9 @@ public final class Synthetic extends Attribute { private byte[] bytes; /** - * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic". - * @param length Content length in bytes - should be zero. - * @param bytes Attribute contents + * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic". + * @param length Content length in bytes - should be zero. + * @param bytes Attribute contents * @param constantPool The constant pool this attribute is associated with. */ public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { @@ -49,9 +49,9 @@ public final class Synthetic extends Attribute { /** * Construct object from input stream. * - * @param nameIndex Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java b/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java index 84e59dc..9dbc3a1 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java @@ -34,16 +34,15 @@ import java.util.Arrays; */ public final class Unknown extends Attribute { - private byte[] bytes; - private final String name; + private byte[] bytes; /** * Constructs a new instance for a non-standard attribute. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param bytes Attribute contents + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param bytes Attribute contents * @param constantPool Array of constants */ public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { @@ -55,9 +54,9 @@ public final class Unknown extends Attribute { /** * Constructs a new instance from an input stream. * - * @param nameIndex Index in constant pool - * @param length Content length in bytes - * @param input Input stream + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream * @param constantPool Array of constants * @throws IOException if an I/O error occurs. */ @@ -123,6 +122,13 @@ public final class Unknown extends Attribute { return bytes; } + /** + * @param bytes the bytes to set + */ + public void setBytes(final byte[] bytes) { + this.bytes = bytes; + } + /** * @return name of attribute. */ @@ -131,13 +137,6 @@ public final class Unknown extends Attribute { return name; } - /** - * @param bytes the bytes to set - */ - public void setBytes(final byte[] bytes) { - this.bytes = bytes; - } - /** * @return String representation. */ diff --git a/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java b/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java index 7822992..eab6e14 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java @@ -31,15 +31,13 @@ public interface UnknownAttributeReader { * associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the * name of the attributes it is constructing. * - * @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute. - * @param length The length of the data contained in the attribute. This is written into the constant pool and should - * agree with what the factory expects the length to be. - * @param file This is the data input that the factory needs to read its data from. + * @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute. + * @param length The length of the data contained in the attribute. This is written into the constant pool and should + * agree with what the factory expects the length to be. + * @param file This is the data input that the factory needs to read its data from. * @param constantPool This is the constant pool associated with the Attribute that we are constructing. - * * @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of - * errors, a null can be returned which will cause the parsing of the class file to fail. - * + * errors, a null can be returned which will cause the parsing of the class file to fail. * @see Attribute#addAttributeReader(String, UnknownAttributeReader) */ Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool); diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Utility.java b/src/main/java/haidnor/jvm/bcel/classfile/Utility.java index 07db873..a0ff788 100644 --- a/src/main/java/haidnor/jvm/bcel/classfile/Utility.java +++ b/src/main/java/haidnor/jvm/bcel/classfile/Utility.java @@ -35,96 +35,16 @@ import java.util.zip.GZIPOutputStream; // @since 6.0 methods are no longer final public abstract class Utility { - /** - * Decode characters into bytes. Used by decode() - */ - private static class JavaReader extends FilterReader { - - public JavaReader(final Reader in) { - super(in); - } - - @Override - public int read() throws IOException { - final int b = in.read(); - if (b != ESCAPE_CHAR) { - return b; - } - final int i = in.read(); - if (i < 0) { - return -1; - } - if (i >= '0' && i <= '9' || i >= 'a' && i <= 'f') { // Normal escape - final int j = in.read(); - if (j < 0) { - return -1; - } - final char[] tmp = {(char) i, (char) j}; - return Integer.parseInt(new String(tmp), 16); - } - return MAP_CHAR[i]; - } - - @Override - public int read(final char[] cbuf, final int off, final int len) throws IOException { - for (int i = 0; i < len; i++) { - cbuf[off + i] = (char) read(); - } - return len; - } - } - - /** - * Encode bytes into valid java identifier characters. Used by - * encode() - */ - private static class JavaWriter extends FilterWriter { - - public JavaWriter(final Writer out) { - super(out); - } - - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - for (int i = 0; i < len; i++) { - write(cbuf[off + i]); - } - } - - @Override - public void write(final int b) throws IOException { - if (isJavaIdentifierPart((char) b) && b != ESCAPE_CHAR) { - out.write(b); - } else { - out.write(ESCAPE_CHAR); // Escape character - // Special escape - if (b >= 0 && b < FREE_CHARS) { - out.write(CHAR_MAP[b]); - } else { // Normal escape - final char[] tmp = Integer.toHexString(b).toCharArray(); - if (tmp.length == 1) { - out.write('0'); - out.write(tmp[0]); - } else { - out.write(tmp[0]); - out.write(tmp[1]); - } - } - } - } - - @Override - public void write(final String str, final int off, final int len) throws IOException { - write(str.toCharArray(), off, len); - } - } - /* * How many chars have been consumed during parsing in typeSignatureToString(). Read by methodSignatureToString(). Set * by side effect, but only internally. */ private static final ThreadLocal CONSUMER_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0)); - + // A-Z, g-z, _, $ + private static final int FREE_CHARS = 48; + private static final int[] CHAR_MAP = new int[FREE_CHARS]; + private static final int[] MAP_CHAR = new int[256]; // Reverse map + private static final char ESCAPE_CHAR = '$'; /* * The 'WIDE' instruction is used in the byte code to allow 16-bit wide indices for local variables. This opcode * precedes an 'ILOAD', e.g.. The opcode immediately following takes an extra byte which is combined with the following @@ -132,15 +52,6 @@ public abstract class Utility { */ private static boolean wide; - // A-Z, g-z, _, $ - private static final int FREE_CHARS = 48; - - private static final int[] CHAR_MAP = new int[FREE_CHARS]; - - private static final int[] MAP_CHAR = new int[256]; // Reverse map - - private static final char ESCAPE_CHAR = '$'; - static { int j = 0; for (int i = 'A'; i <= 'Z'; i++) { @@ -172,12 +83,12 @@ public abstract class Utility { /** * Convert bit field of flags into string such as 'static final'. - * + *

* Special case: Classes compiled with new compilers and with the 'ACC_SUPER' flag would be said to be "synchronized". * This is because SUN used the same value for the flags 'ACC_SUPER' and 'ACC_SYNCHRONIZED'. * * @param accessFlags Access flags - * @param forClass access flags are for class qualifiers ? + * @param forClass access flags are for class qualifiers ? * @return String representation of flags */ public static String accessToString(final int accessFlags, final boolean forClass) { @@ -208,7 +119,6 @@ public abstract class Utility { /** * @param accessFlags the class flags - * * @return "class" or "interface", depending on the ACC_INTERFACE flag */ public static String classOrInterface(final int accessFlags) { @@ -231,11 +141,11 @@ public abstract class Utility { * Disassemble a byte array of JVM byte codes starting from code line 'index' and return the disassembled string * representation. Decode only 'num' opcodes (including their operands), use -1 if you want to decompile everything. * - * @param code byte code array + * @param code byte code array * @param constantPool Array of constants - * @param index offset in 'code' array (number of opcodes, not bytes!) - * @param length number of opcodes to decompile, -1 for all - * @param verbose be verbose, e.g. print constant pool index + * @param index offset in 'code' array (number of opcodes, not bytes!) + * @param length number of opcodes to decompile, -1 for all + * @param verbose be verbose, e.g. print constant pool index * @return String representation of byte codes */ public static String codeToString(final byte[] code, final ConstantPool constantPool, final int index, final int length, final boolean verbose) { @@ -263,11 +173,10 @@ public abstract class Utility { /** * Disassemble a stream of byte codes and return the string representation. * - * @param bytes stream of bytes + * @param bytes stream of bytes * @param constantPool Array of constants - * @param verbose be verbose, e.g. print constant pool index + * @param verbose be verbose, e.g. print constant pool index * @return String representation of byte code - * * @throws IOException if a failure from reading from the bytes argument occurs */ public static String codeToString(final ByteSequence bytes, final ConstantPool constantPool, final boolean verbose) throws IOException { @@ -300,225 +209,225 @@ public abstract class Utility { defaultOffset = bytes.readInt(); } switch (opcode) { - /* - * Table switch has variable length arguments. - */ - case Const.TABLESWITCH: - low = bytes.readInt(); - high = bytes.readInt(); - offset = bytes.getIndex() - 12 - noPadBytes - 1; - defaultOffset += offset; - buf.append("\tdefault = ").append(defaultOffset).append(", low = ").append(low).append(", high = ").append(high).append("("); - jumpTable = new int[high - low + 1]; - for (int i = 0; i < jumpTable.length; i++) { - jumpTable[i] = offset + bytes.readInt(); - buf.append(jumpTable[i]); - if (i < jumpTable.length - 1) { - buf.append(", "); - } - } - buf.append(")"); - break; - /* - * Lookup switch has variable length arguments. - */ - case Const.LOOKUPSWITCH: { - npairs = bytes.readInt(); - offset = bytes.getIndex() - 8 - noPadBytes - 1; - match = new int[npairs]; - jumpTable = new int[npairs]; - defaultOffset += offset; - buf.append("\tdefault = ").append(defaultOffset).append(", npairs = ").append(npairs).append(" ("); - for (int i = 0; i < npairs; i++) { - match[i] = bytes.readInt(); - jumpTable[i] = offset + bytes.readInt(); - buf.append("(").append(match[i]).append(", ").append(jumpTable[i]).append(")"); - if (i < npairs - 1) { - buf.append(", "); - } - } - buf.append(")"); - } - break; - /* - * Two address bytes + offset from start of byte stream form the jump target - */ - case Const.GOTO: - case Const.IFEQ: - case Const.IFGE: - case Const.IFGT: - case Const.IFLE: - case Const.IFLT: - case Const.JSR: - case Const.IFNE: - case Const.IFNONNULL: - case Const.IFNULL: - case Const.IF_ACMPEQ: - case Const.IF_ACMPNE: - case Const.IF_ICMPEQ: - case Const.IF_ICMPGE: - case Const.IF_ICMPGT: - case Const.IF_ICMPLE: - case Const.IF_ICMPLT: - case Const.IF_ICMPNE: - buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readShort()); - break; - /* - * 32-bit wide jumps - */ - case Const.GOTO_W: - case Const.JSR_W: - buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readInt()); - break; - /* - * Index byte references local variable (register) - */ - case Const.ALOAD: - case Const.ASTORE: - case Const.DLOAD: - case Const.DSTORE: - case Const.FLOAD: - case Const.FSTORE: - case Const.ILOAD: - case Const.ISTORE: - case Const.LLOAD: - case Const.LSTORE: - case Const.RET: - if (wide) { - vindex = bytes.readUnsignedShort(); - wide = false; // Clear flag - } else { - vindex = bytes.readUnsignedByte(); - } - buf.append("\t\t%").append(vindex); - break; - /* - * Remember wide byte which is used to form a 16-bit address in the following instruction. Relies on that the method is - * called again with the following opcode. - */ - case Const.WIDE: - wide = true; - buf.append("\t(wide)"); - break; - /* - * Array of basic type. - */ - case Const.NEWARRAY: - buf.append("\t\t<").append(Const.getTypeName(bytes.readByte())).append(">"); - break; - /* - * Access object/class fields. - */ - case Const.GETFIELD: - case Const.GETSTATIC: - case Const.PUTFIELD: - case Const.PUTSTATIC: - index = bytes.readUnsignedShort(); - buf.append("\t\t").append(constantPool.constantToString(index, Const.CONSTANT_Fieldref)).append(verbose ? " (" + index + ")" : ""); - break; - /* - * Operands are references to classes in constant pool - */ - case Const.NEW: - case Const.CHECKCAST: - buf.append("\t"); - //$FALL-THROUGH$ - case Const.INSTANCEOF: - index = bytes.readUnsignedShort(); - buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : ""); - break; - /* - * Operands are references to methods in constant pool - */ - case Const.INVOKESPECIAL: - case Const.INVOKESTATIC: - index = bytes.readUnsignedShort(); - final Constant c = constantPool.getConstant(index); - // With Java8 operand may be either a CONSTANT_Methodref - // or a CONSTANT_InterfaceMethodref. (markro) - buf.append("\t").append(constantPool.constantToString(index, c.getTag())).append(verbose ? " (" + index + ")" : ""); - break; - case Const.INVOKEVIRTUAL: - index = bytes.readUnsignedShort(); - buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_Methodref)).append(verbose ? " (" + index + ")" : ""); - break; - case Const.INVOKEINTERFACE: - index = bytes.readUnsignedShort(); - final int nargs = bytes.readUnsignedByte(); // historical, redundant - buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InterfaceMethodref)).append(verbose ? " (" + index + ")\t" : "") - .append(nargs).append("\t").append(bytes.readUnsignedByte()); // Last byte is a reserved space - break; - case Const.INVOKEDYNAMIC: - index = bytes.readUnsignedShort(); - buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InvokeDynamic)).append(verbose ? " (" + index + ")\t" : "") - .append(bytes.readUnsignedByte()) // Thrid byte is a reserved space - .append(bytes.readUnsignedByte()); // Last byte is a reserved space - break; - /* - * Operands are references to items in constant pool - */ - case Const.LDC_W: - case Const.LDC2_W: - index = bytes.readUnsignedShort(); - buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag())) - .append(verbose ? " (" + index + ")" : ""); - break; - case Const.LDC: - index = bytes.readUnsignedByte(); - buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag())) - .append(verbose ? " (" + index + ")" : ""); - break; - /* - * Array of references. - */ - case Const.ANEWARRAY: - index = bytes.readUnsignedShort(); - buf.append("\t\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">") - .append(verbose ? " (" + index + ")" : ""); - break; - /* - * Multidimensional array of references. - */ - case Const.MULTIANEWARRAY: { - index = bytes.readUnsignedShort(); - final int dimensions = bytes.readUnsignedByte(); - buf.append("\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">\t").append(dimensions) - .append(verbose ? " (" + index + ")" : ""); - } - break; - /* - * Increment local variable. - */ - case Const.IINC: - if (wide) { - vindex = bytes.readUnsignedShort(); - constant = bytes.readShort(); - wide = false; - } else { - vindex = bytes.readUnsignedByte(); - constant = bytes.readByte(); - } - buf.append("\t\t%").append(vindex).append("\t").append(constant); - break; - default: - if (Const.getNoOfOperands(opcode) > 0) { - for (int i = 0; i < Const.getOperandTypeCount(opcode); i++) { - buf.append("\t\t"); - switch (Const.getOperandType(opcode, i)) { - case Const.T_BYTE: - buf.append(bytes.readByte()); - break; - case Const.T_SHORT: - buf.append(bytes.readShort()); - break; - case Const.T_INT: - buf.append(bytes.readInt()); - break; - default: // Never reached - throw new IllegalStateException("Unreachable default case reached!"); + /* + * Table switch has variable length arguments. + */ + case Const.TABLESWITCH: + low = bytes.readInt(); + high = bytes.readInt(); + offset = bytes.getIndex() - 12 - noPadBytes - 1; + defaultOffset += offset; + buf.append("\tdefault = ").append(defaultOffset).append(", low = ").append(low).append(", high = ").append(high).append("("); + jumpTable = new int[high - low + 1]; + for (int i = 0; i < jumpTable.length; i++) { + jumpTable[i] = offset + bytes.readInt(); + buf.append(jumpTable[i]); + if (i < jumpTable.length - 1) { + buf.append(", "); } } + buf.append(")"); + break; + /* + * Lookup switch has variable length arguments. + */ + case Const.LOOKUPSWITCH: { + npairs = bytes.readInt(); + offset = bytes.getIndex() - 8 - noPadBytes - 1; + match = new int[npairs]; + jumpTable = new int[npairs]; + defaultOffset += offset; + buf.append("\tdefault = ").append(defaultOffset).append(", npairs = ").append(npairs).append(" ("); + for (int i = 0; i < npairs; i++) { + match[i] = bytes.readInt(); + jumpTable[i] = offset + bytes.readInt(); + buf.append("(").append(match[i]).append(", ").append(jumpTable[i]).append(")"); + if (i < npairs - 1) { + buf.append(", "); + } + } + buf.append(")"); } + break; + /* + * Two address bytes + offset from start of byte stream form the jump target + */ + case Const.GOTO: + case Const.IFEQ: + case Const.IFGE: + case Const.IFGT: + case Const.IFLE: + case Const.IFLT: + case Const.JSR: + case Const.IFNE: + case Const.IFNONNULL: + case Const.IFNULL: + case Const.IF_ACMPEQ: + case Const.IF_ACMPNE: + case Const.IF_ICMPEQ: + case Const.IF_ICMPGE: + case Const.IF_ICMPGT: + case Const.IF_ICMPLE: + case Const.IF_ICMPLT: + case Const.IF_ICMPNE: + buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readShort()); + break; + /* + * 32-bit wide jumps + */ + case Const.GOTO_W: + case Const.JSR_W: + buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readInt()); + break; + /* + * Index byte references local variable (register) + */ + case Const.ALOAD: + case Const.ASTORE: + case Const.DLOAD: + case Const.DSTORE: + case Const.FLOAD: + case Const.FSTORE: + case Const.ILOAD: + case Const.ISTORE: + case Const.LLOAD: + case Const.LSTORE: + case Const.RET: + if (wide) { + vindex = bytes.readUnsignedShort(); + wide = false; // Clear flag + } else { + vindex = bytes.readUnsignedByte(); + } + buf.append("\t\t%").append(vindex); + break; + /* + * Remember wide byte which is used to form a 16-bit address in the following instruction. Relies on that the method is + * called again with the following opcode. + */ + case Const.WIDE: + wide = true; + buf.append("\t(wide)"); + break; + /* + * Array of basic type. + */ + case Const.NEWARRAY: + buf.append("\t\t<").append(Const.getTypeName(bytes.readByte())).append(">"); + break; + /* + * Access object/class fields. + */ + case Const.GETFIELD: + case Const.GETSTATIC: + case Const.PUTFIELD: + case Const.PUTSTATIC: + index = bytes.readUnsignedShort(); + buf.append("\t\t").append(constantPool.constantToString(index, Const.CONSTANT_Fieldref)).append(verbose ? " (" + index + ")" : ""); + break; + /* + * Operands are references to classes in constant pool + */ + case Const.NEW: + case Const.CHECKCAST: + buf.append("\t"); + //$FALL-THROUGH$ + case Const.INSTANCEOF: + index = bytes.readUnsignedShort(); + buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : ""); + break; + /* + * Operands are references to methods in constant pool + */ + case Const.INVOKESPECIAL: + case Const.INVOKESTATIC: + index = bytes.readUnsignedShort(); + final Constant c = constantPool.getConstant(index); + // With Java8 operand may be either a CONSTANT_Methodref + // or a CONSTANT_InterfaceMethodref. (markro) + buf.append("\t").append(constantPool.constantToString(index, c.getTag())).append(verbose ? " (" + index + ")" : ""); + break; + case Const.INVOKEVIRTUAL: + index = bytes.readUnsignedShort(); + buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_Methodref)).append(verbose ? " (" + index + ")" : ""); + break; + case Const.INVOKEINTERFACE: + index = bytes.readUnsignedShort(); + final int nargs = bytes.readUnsignedByte(); // historical, redundant + buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InterfaceMethodref)).append(verbose ? " (" + index + ")\t" : "") + .append(nargs).append("\t").append(bytes.readUnsignedByte()); // Last byte is a reserved space + break; + case Const.INVOKEDYNAMIC: + index = bytes.readUnsignedShort(); + buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InvokeDynamic)).append(verbose ? " (" + index + ")\t" : "") + .append(bytes.readUnsignedByte()) // Thrid byte is a reserved space + .append(bytes.readUnsignedByte()); // Last byte is a reserved space + break; + /* + * Operands are references to items in constant pool + */ + case Const.LDC_W: + case Const.LDC2_W: + index = bytes.readUnsignedShort(); + buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag())) + .append(verbose ? " (" + index + ")" : ""); + break; + case Const.LDC: + index = bytes.readUnsignedByte(); + buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag())) + .append(verbose ? " (" + index + ")" : ""); + break; + /* + * Array of references. + */ + case Const.ANEWARRAY: + index = bytes.readUnsignedShort(); + buf.append("\t\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">") + .append(verbose ? " (" + index + ")" : ""); + break; + /* + * Multidimensional array of references. + */ + case Const.MULTIANEWARRAY: { + index = bytes.readUnsignedShort(); + final int dimensions = bytes.readUnsignedByte(); + buf.append("\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">\t").append(dimensions) + .append(verbose ? " (" + index + ")" : ""); + } + break; + /* + * Increment local variable. + */ + case Const.IINC: + if (wide) { + vindex = bytes.readUnsignedShort(); + constant = bytes.readShort(); + wide = false; + } else { + vindex = bytes.readUnsignedByte(); + constant = bytes.readByte(); + } + buf.append("\t\t%").append(vindex).append("\t").append(constant); + break; + default: + if (Const.getNoOfOperands(opcode) > 0) { + for (int i = 0; i < Const.getOperandTypeCount(opcode); i++) { + buf.append("\t\t"); + switch (Const.getOperandType(opcode, i)) { + case Const.T_BYTE: + buf.append(bytes.readByte()); + break; + case Const.T_SHORT: + buf.append(bytes.readShort()); + break; + case Const.T_INT: + buf.append(bytes.readInt()); + break; + default: // Never reached + throw new IllegalStateException("Unreachable default case reached!"); + } + } + } } return buf.toString(); } @@ -537,7 +446,7 @@ public abstract class Utility { * Shorten long class names, java/lang/String becomes java.lang.String, e.g.. If chopit is * true the prefix java.lang is also removed. * - * @param str The long class name + * @param str The long class name * @param chopit flag that determines whether chopping is executed or not * @return Compacted class name */ @@ -549,7 +458,7 @@ public abstract class Utility { * Shorten long class name str, i.e., chop off the prefix, if the class name starts with this string * and the flag chopit is true. Slashes / are converted to dots .. * - * @param str The long class name + * @param str The long class name * @param prefix The prefix the get rid off * @param chopit flag that determines whether chopping is executed or not * @return Compacted class name @@ -572,24 +481,24 @@ public abstract class Utility { final StringBuilder buf = new StringBuilder(); for (final char element : ch) { switch (element) { - case '\n': - buf.append("\\n"); - break; - case '\r': - buf.append("\\r"); - break; - case '\"': - buf.append("\\\""); - break; - case '\'': - buf.append("\\'"); - break; - case '\\': - buf.append("\\\\"); - break; - default: - buf.append(element); - break; + case '\n': + buf.append("\\n"); + break; + case '\r': + buf.append("\\r"); + break; + case '\"': + buf.append("\\\""); + break; + case '\'': + buf.append("\\'"); + break; + case '\\': + buf.append("\\\\"); + break; + default: + buf.append(element); + break; } } return buf.toString(); @@ -601,22 +510,22 @@ public abstract class Utility { boolean open = false; for (final char c : chars) { switch (c) { - case '[': - if (open) { - throw new IllegalArgumentException("Illegally nested brackets:" + brackets); - } - open = true; - break; - case ']': - if (!open) { - throw new IllegalArgumentException("Illegally nested brackets:" + brackets); - } - open = false; - count++; - break; - default: - // Don't care - break; + case '[': + if (open) { + throw new IllegalArgumentException("Illegally nested brackets:" + brackets); + } + open = true; + break; + case ']': + if (!open) { + throw new IllegalArgumentException("Illegally nested brackets:" + brackets); + } + open = false; + count++; + break; + default: + // Don't care + break; } } if (open) { @@ -628,9 +537,8 @@ public abstract class Utility { /** * Decode a string back to a byte array. * - * @param s the string to convert + * @param s the string to convert * @param uncompress use gzip to uncompress the stream of bytes - * * @throws IOException if there's a gzip exception */ public static byte[] decode(final String s, final boolean uncompress) throws IOException { @@ -669,9 +577,8 @@ public abstract class Utility { * This operation inflates the original byte array by roughly 40-50% *

* - * @param bytes the byte array to convert + * @param bytes the byte array to convert * @param compress use gzip to minimize string - * * @throws IOException if there's a gzip exception */ public static String encode(byte[] bytes, final boolean compress) throws IOException { @@ -695,10 +602,10 @@ public abstract class Utility { /** * Fillup char with up to length characters with char 'fill' and justify it left or right. * - * @param str string to format - * @param length length of desired string + * @param str string to format + * @param length length of desired string * @param leftJustify format left or right - * @param fill fill character + * @param fill fill character * @return formatted string */ public static String fillup(final String str, final int length, final boolean leftJustify, final char fill) { @@ -714,16 +621,84 @@ public abstract class Utility { /** * Return a string for an integer justified left or right and filled up with 'fill' characters if necessary. * - * @param i integer to format - * @param length length of desired string + * @param i integer to format + * @param length length of desired string * @param leftJustify format left or right - * @param fill fill character + * @param fill fill character * @return formatted int */ public static String format(final int i, final int length, final boolean leftJustify, final char fill) { return fillup(Integer.toString(i), length, leftJustify, fill); } + /** + * Parse Java type such as "char", or "java.lang.String[]" and return the signature in byte code format, e.g. "C" or + * "[Ljava/lang/String;" respectively. + * + * @param type Java type + * @return byte code signature + */ + public static String getSignature(String type) { + final StringBuilder buf = new StringBuilder(); + final char[] chars = type.toCharArray(); + boolean charFound = false; + boolean delim = false; + int index = -1; + loop: + for (int i = 0; i < chars.length; i++) { + switch (chars[i]) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + if (charFound) { + delim = true; + } + break; + case '[': + if (!charFound) { + throw new IllegalArgumentException("Illegal type: " + type); + } + index = i; + break loop; + default: + charFound = true; + if (!delim) { + buf.append(chars[i]); + } + } + } + int brackets = 0; + if (index > 0) { + brackets = countBrackets(type.substring(index)); + } + type = buf.toString(); + buf.setLength(0); + for (int i = 0; i < brackets; i++) { + buf.append('['); + } + boolean found = false; + for (int i = Const.T_BOOLEAN; i <= Const.T_VOID && !found; i++) { + if (Const.getTypeName(i).equals(type)) { + found = true; + buf.append(Const.getShortTypeName(i)); + } + } + if (!found) { + buf.append('L').append(packageToPath(type)).append(';'); + } + return buf.toString(); + } + + /** + * @param ch the character to test if it's part of an identifier + * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _) + */ + public static boolean isJavaIdentifierPart(final char ch) { + return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_'; + } + /** * WARNING: * @@ -748,74 +723,6 @@ public abstract class Utility { * you should call typeSignatureToString directly. */ - /** - * Parse Java type such as "char", or "java.lang.String[]" and return the signature in byte code format, e.g. "C" or - * "[Ljava/lang/String;" respectively. - * - * @param type Java type - * @return byte code signature - */ - public static String getSignature(String type) { - final StringBuilder buf = new StringBuilder(); - final char[] chars = type.toCharArray(); - boolean charFound = false; - boolean delim = false; - int index = -1; - loop: for (int i = 0; i < chars.length; i++) { - switch (chars[i]) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - if (charFound) { - delim = true; - } - break; - case '[': - if (!charFound) { - throw new IllegalArgumentException("Illegal type: " + type); - } - index = i; - break loop; - default: - charFound = true; - if (!delim) { - buf.append(chars[i]); - } - } - } - int brackets = 0; - if (index > 0) { - brackets = countBrackets(type.substring(index)); - } - type = buf.toString(); - buf.setLength(0); - for (int i = 0; i < brackets; i++) { - buf.append('['); - } - boolean found = false; - for (int i = Const.T_BOOLEAN; i <= Const.T_VOID && !found; i++) { - if (Const.getTypeName(i).equals(type)) { - found = true; - buf.append(Const.getShortTypeName(i)); - } - } - if (!found) { - buf.append('L').append(packageToPath(type)).append(';'); - } - return buf.toString(); - } - - /** - * @param ch the character to test if it's part of an identifier - * - * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _) - */ - public static boolean isJavaIdentifierPart(final char ch) { - return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_'; - } - /** * @return true, if bit 'i' in 'flag' is set */ @@ -838,7 +745,7 @@ public abstract class Utility { * Converts argument list portion of method signature to string. * * @param signature Method signature - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return String Array of argument types * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ @@ -877,7 +784,7 @@ public abstract class Utility { * Converts return type portion of method signature to string. * * @param signature Method signature - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return String representation of method return type * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ @@ -901,8 +808,8 @@ public abstract class Utility { * Converts method signature to string with all class names compacted. * * @param signature to convert - * @param name of method - * @param access flags of method + * @param name of method + * @param access flags of method * @return Human readable signature */ public static String methodSignatureToString(final String signature, final String name, final String access) { @@ -913,9 +820,9 @@ public abstract class Utility { * Converts method signature to string. * * @param signature to convert - * @param name of method - * @param access flags of method - * @param chopit flag that determines whether chopping is executed or not + * @param name of method + * @param access flags of method + * @param chopit flag that determines whether chopping is executed or not * @return Human readable signature */ public static String methodSignatureToString(final String signature, final String name, final String access, final boolean chopit) { @@ -927,15 +834,15 @@ public abstract class Utility { * 'ClassFormatException' when the parsed type is invalid. * * @param signature Method signature - * @param name Method name - * @param access Method access rights - * @param chopit flag that determines whether chopping is executed or not - * @param vars the LocalVariableTable for the method + * @param name Method name + * @param access Method access rights + * @param chopit flag that determines whether chopping is executed or not + * @param vars the LocalVariableTable for the method * @return Java type declaration * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file */ public static String methodSignatureToString(final String signature, final String name, final String access, final boolean chopit, - final LocalVariableTable vars) throws ClassFormatException { + final LocalVariableTable vars) throws ClassFormatException { final StringBuilder buf = new StringBuilder("("); String type; int index; @@ -978,16 +885,15 @@ public abstract class Utility { } buf.append(")"); return access + (!access.isEmpty() ? " " : "") + // May be an empty string - type + " " + name + buf.toString(); + type + " " + name + buf.toString(); } /** * Converts string containing the method return and argument types to a byte code method signature. * - * @param ret Return type of method + * @param ret Return type of method * @param argv Types of method arguments * @return Byte code representation of method signature - * * @throws ClassFormatException if the signature is for Void */ public static String methodTypeToSignature(final String ret, final String[] argv) throws ClassFormatException { @@ -1076,8 +982,8 @@ public abstract class Utility { /** * Replace all occurrences of old in str with new. * - * @param str String to permute - * @param old String to be replaced + * @param str String to permute + * @param old String to be replaced * @param new_ Replacement string * @return new String object */ @@ -1139,7 +1045,7 @@ public abstract class Utility { * not supported. * * @param signature signature to convert - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return String containg human readable signature */ public static String signatureToString(final String signature, final boolean chopit) { @@ -1190,7 +1096,6 @@ public abstract class Utility { * Convert bytes into hexadecimal string * * @param bytes an array of bytes to convert to hexadecimal - * * @return bytes as hexadecimal string, e.g. 00 fa 12 ... */ public static String toHexString(final byte[] bytes) { @@ -1214,9 +1119,8 @@ public abstract class Utility { * * @param signature in format described above * @return type of method signature - * @see Const - * * @throws ClassFormatException if signature is not a method signature + * @see Const */ public static byte typeOfMethodSignature(final String signature) throws ClassFormatException { int index; @@ -1236,42 +1140,41 @@ public abstract class Utility { * * @param signature in format described above * @return type of signature - * @see Const - * * @throws ClassFormatException if signature isn't a known type + * @see Const */ public static byte typeOfSignature(final String signature) throws ClassFormatException { try { switch (signature.charAt(0)) { - case 'B': - return Const.T_BYTE; - case 'C': - return Const.T_CHAR; - case 'D': - return Const.T_DOUBLE; - case 'F': - return Const.T_FLOAT; - case 'I': - return Const.T_INT; - case 'J': - return Const.T_LONG; - case 'L': - case 'T': - return Const.T_REFERENCE; - case '[': - return Const.T_ARRAY; - case 'V': - return Const.T_VOID; - case 'Z': - return Const.T_BOOLEAN; - case 'S': - return Const.T_SHORT; - case '!': - case '+': - case '*': - return typeOfSignature(signature.substring(1)); - default: - throw new ClassFormatException("Invalid method signature: " + signature); + case 'B': + return Const.T_BYTE; + case 'C': + return Const.T_CHAR; + case 'D': + return Const.T_DOUBLE; + case 'F': + return Const.T_FLOAT; + case 'I': + return Const.T_INT; + case 'J': + return Const.T_LONG; + case 'L': + case 'T': + return Const.T_REFERENCE; + case '[': + return Const.T_ARRAY; + case 'V': + return Const.T_VOID; + case 'Z': + return Const.T_BOOLEAN; + case 'S': + return Const.T_SHORT; + case '!': + case '+': + case '*': + return typeOfSignature(signature.substring(1)); + default: + throw new ClassFormatException("Invalid method signature: " + signature); } } catch (final StringIndexOutOfBoundsException e) { throw new ClassFormatException("Invalid method signature: " + signature, e); @@ -1282,7 +1185,7 @@ public abstract class Utility { * Converts a type parameter list signature to a string. * * @param signature signature to convert - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return String containg human readable signature */ private static String typeParamTypesToString(final String signature, final boolean chopit) { @@ -1306,7 +1209,7 @@ public abstract class Utility { * Converts a type parameter signature to a string. * * @param signature signature to convert - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return String containg human readable signature */ private static String typeParamTypeToString(final String signature, final boolean chopit) { @@ -1338,8 +1241,8 @@ public abstract class Utility { * Converts a list of type signatures to a string. * * @param signature signature to convert - * @param chopit flag that determines whether chopping is executed or not - * @param term character indicating the end of the list + * @param chopit flag that determines whether chopping is executed or not + * @param term character indicating the end of the list * @return String containg human readable signature */ private static String typeSignaturesToString(final String signature, final boolean chopit, final char term) { @@ -1362,12 +1265,11 @@ public abstract class Utility { } /** - * * This method converts a type signature string into a Java type declaration such as 'String[]' and throws a * 'ClassFormatException' when the parsed type is invalid. * * @param signature type signature - * @param chopit flag that determines whether chopping is executed or not + * @param chopit flag that determines whether chopping is executed or not * @return string containing human readable type signature * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @since 6.4.0 @@ -1377,90 +1279,67 @@ public abstract class Utility { wrap(CONSUMER_CHARS, 1); // This is the default, read just one char like 'B' try { switch (signature.charAt(0)) { - case 'B': - return "byte"; - case 'C': - return "char"; - case 'D': - return "double"; - case 'F': - return "float"; - case 'I': - return "int"; - case 'J': - return "long"; - case 'T': { // TypeVariableSignature - final int index = signature.indexOf(';'); // Look for closing ';' - if (index < 0) { - throw new ClassFormatException("Invalid type variable signature: " + signature); + case 'B': + return "byte"; + case 'C': + return "char"; + case 'D': + return "double"; + case 'F': + return "float"; + case 'I': + return "int"; + case 'J': + return "long"; + case 'T': { // TypeVariableSignature + final int index = signature.indexOf(';'); // Look for closing ';' + if (index < 0) { + throw new ClassFormatException("Invalid type variable signature: " + signature); + } + // corrected concurrent private static field acess + wrap(CONSUMER_CHARS, index + 1); // "Tblabla;" 'T' and ';' are removed + return compactClassName(signature.substring(1, index), chopit); } - // corrected concurrent private static field acess - wrap(CONSUMER_CHARS, index + 1); // "Tblabla;" 'T' and ';' are removed - return compactClassName(signature.substring(1, index), chopit); - } - case 'L': { // Full class name - // should this be a while loop? can there be more than - // one generic clause? (markro) - int fromIndex = signature.indexOf('<'); // generic type? - if (fromIndex < 0) { - fromIndex = 0; - } else { - fromIndex = signature.indexOf('>', fromIndex); + case 'L': { // Full class name + // should this be a while loop? can there be more than + // one generic clause? (markro) + int fromIndex = signature.indexOf('<'); // generic type? + if (fromIndex < 0) { + fromIndex = 0; + } else { + fromIndex = signature.indexOf('>', fromIndex); + if (fromIndex < 0) { + throw new ClassFormatException("Invalid signature: " + signature); + } + } + final int index = signature.indexOf(';', fromIndex); // Look for closing ';' + if (index < 0) { + throw new ClassFormatException("Invalid signature: " + signature); + } + + // check to see if there are any TypeArguments + final int bracketIndex = signature.substring(0, index).indexOf('<'); + if (bracketIndex < 0) { + // just a class identifier + wrap(CONSUMER_CHARS, index + 1); // "Lblabla;" 'L' and ';' are removed + return compactClassName(signature.substring(1, index), chopit); + } + // but make sure we are not looking past the end of the current item + fromIndex = signature.indexOf(';'); if (fromIndex < 0) { throw new ClassFormatException("Invalid signature: " + signature); } - } - final int index = signature.indexOf(';', fromIndex); // Look for closing ';' - if (index < 0) { - throw new ClassFormatException("Invalid signature: " + signature); - } + if (fromIndex < bracketIndex) { + // just a class identifier + wrap(CONSUMER_CHARS, fromIndex + 1); // "Lblabla;" 'L' and ';' are removed + return compactClassName(signature.substring(1, fromIndex), chopit); + } - // check to see if there are any TypeArguments - final int bracketIndex = signature.substring(0, index).indexOf('<'); - if (bracketIndex < 0) { - // just a class identifier - wrap(CONSUMER_CHARS, index + 1); // "Lblabla;" 'L' and ';' are removed - return compactClassName(signature.substring(1, index), chopit); - } - // but make sure we are not looking past the end of the current item - fromIndex = signature.indexOf(';'); - if (fromIndex < 0) { - throw new ClassFormatException("Invalid signature: " + signature); - } - if (fromIndex < bracketIndex) { - // just a class identifier - wrap(CONSUMER_CHARS, fromIndex + 1); // "Lblabla;" 'L' and ';' are removed - return compactClassName(signature.substring(1, fromIndex), chopit); - } + // we have TypeArguments; build up partial result + // as we recurse for each TypeArgument + final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<"); + int consumedChars = bracketIndex + 1; // Shadows global var - // we have TypeArguments; build up partial result - // as we recurse for each TypeArgument - final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<"); - int consumedChars = bracketIndex + 1; // Shadows global var - - // check for wildcards - if (signature.charAt(consumedChars) == '+') { - type.append("? extends "); - consumedChars++; - } else if (signature.charAt(consumedChars) == '-') { - type.append("? super "); - consumedChars++; - } - - // get the first TypeArgument - if (signature.charAt(consumedChars) == '*') { - type.append("?"); - consumedChars++; - } else { - type.append(typeSignatureToString(signature.substring(consumedChars), chopit)); - // update our consumed count by the number of characters the for type argument - consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars; - wrap(Utility.CONSUMER_CHARS, consumedChars); - } - - // are there more TypeArguments? - while (signature.charAt(consumedChars) != '>') { - type.append(", "); // check for wildcards if (signature.charAt(consumedChars) == '+') { type.append("? extends "); @@ -1469,6 +1348,8 @@ public abstract class Utility { type.append("? super "); consumedChars++; } + + // get the first TypeArgument if (signature.charAt(consumedChars) == '*') { type.append("?"); consumedChars++; @@ -1478,58 +1359,79 @@ public abstract class Utility { consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars; wrap(Utility.CONSUMER_CHARS, consumedChars); } - } - // process the closing ">" - consumedChars++; - type.append(">"); + // are there more TypeArguments? + while (signature.charAt(consumedChars) != '>') { + type.append(", "); + // check for wildcards + if (signature.charAt(consumedChars) == '+') { + type.append("? extends "); + consumedChars++; + } else if (signature.charAt(consumedChars) == '-') { + type.append("? super "); + consumedChars++; + } + if (signature.charAt(consumedChars) == '*') { + type.append("?"); + consumedChars++; + } else { + type.append(typeSignatureToString(signature.substring(consumedChars), chopit)); + // update our consumed count by the number of characters the for type argument + consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars; + wrap(Utility.CONSUMER_CHARS, consumedChars); + } + } - if (signature.charAt(consumedChars) == '.') { - // we have a ClassTypeSignatureSuffix - type.append("."); - // convert SimpleClassTypeSignature to fake ClassTypeSignature - // and then recurse to parse it - type.append(typeSignatureToString("L" + signature.substring(consumedChars + 1), chopit)); - // update our consumed count by the number of characters the for type argument - // note that this count includes the "L" we added, but that is ok - // as it accounts for the "." we didn't consume - consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars; - wrap(Utility.CONSUMER_CHARS, consumedChars); + // process the closing ">" + consumedChars++; + type.append(">"); + + if (signature.charAt(consumedChars) == '.') { + // we have a ClassTypeSignatureSuffix + type.append("."); + // convert SimpleClassTypeSignature to fake ClassTypeSignature + // and then recurse to parse it + type.append(typeSignatureToString("L" + signature.substring(consumedChars + 1), chopit)); + // update our consumed count by the number of characters the for type argument + // note that this count includes the "L" we added, but that is ok + // as it accounts for the "." we didn't consume + consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars; + wrap(Utility.CONSUMER_CHARS, consumedChars); + return type.toString(); + } + if (signature.charAt(consumedChars) != ';') { + throw new ClassFormatException("Invalid signature: " + signature); + } + wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";" return type.toString(); } - if (signature.charAt(consumedChars) != ';') { - throw new ClassFormatException("Invalid signature: " + signature); + case 'S': + return "short"; + case 'Z': + return "boolean"; + case '[': { // Array declaration + int n; + StringBuilder brackets; + String type; + int consumedChars; // Shadows global var + brackets = new StringBuilder(); // Accumulate []'s + // Count opening brackets and look for optional size argument + for (n = 0; signature.charAt(n) == '['; n++) { + brackets.append("[]"); + } + consumedChars = n; // Remember value + // The rest of the string denotes a '' + type = typeSignatureToString(signature.substring(n), chopit); + // corrected concurrent private static field acess + // Utility.consumed_chars += consumed_chars; is replaced by: + final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars; + wrap(Utility.CONSUMER_CHARS, temp); + return type + brackets.toString(); } - wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";" - return type.toString(); - } - case 'S': - return "short"; - case 'Z': - return "boolean"; - case '[': { // Array declaration - int n; - StringBuilder brackets; - String type; - int consumedChars; // Shadows global var - brackets = new StringBuilder(); // Accumulate []'s - // Count opening brackets and look for optional size argument - for (n = 0; signature.charAt(n) == '['; n++) { - brackets.append("[]"); - } - consumedChars = n; // Remember value - // The rest of the string denotes a '' - type = typeSignatureToString(signature.substring(n), chopit); - // corrected concurrent private static field acess - // Utility.consumed_chars += consumed_chars; is replaced by: - final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars; - wrap(Utility.CONSUMER_CHARS, temp); - return type + brackets.toString(); - } - case 'V': - return "void"; - default: - throw new ClassFormatException("Invalid signature: '" + signature + "'"); + case 'V': + return "void"; + default: + throw new ClassFormatException("Invalid signature: '" + signature + "'"); } } catch (final StringIndexOutOfBoundsException e) { // Should never occur throw new ClassFormatException("Invalid signature: " + signature, e); @@ -1544,4 +1446,88 @@ public abstract class Utility { tl.set(Integer.valueOf(value)); } + /** + * Decode characters into bytes. Used by decode() + */ + private static class JavaReader extends FilterReader { + + public JavaReader(final Reader in) { + super(in); + } + + @Override + public int read() throws IOException { + final int b = in.read(); + if (b != ESCAPE_CHAR) { + return b; + } + final int i = in.read(); + if (i < 0) { + return -1; + } + if (i >= '0' && i <= '9' || i >= 'a' && i <= 'f') { // Normal escape + final int j = in.read(); + if (j < 0) { + return -1; + } + final char[] tmp = {(char) i, (char) j}; + return Integer.parseInt(new String(tmp), 16); + } + return MAP_CHAR[i]; + } + + @Override + public int read(final char[] cbuf, final int off, final int len) throws IOException { + for (int i = 0; i < len; i++) { + cbuf[off + i] = (char) read(); + } + return len; + } + } + + /** + * Encode bytes into valid java identifier characters. Used by + * encode() + */ + private static class JavaWriter extends FilterWriter { + + public JavaWriter(final Writer out) { + super(out); + } + + @Override + public void write(final char[] cbuf, final int off, final int len) throws IOException { + for (int i = 0; i < len; i++) { + write(cbuf[off + i]); + } + } + + @Override + public void write(final int b) throws IOException { + if (isJavaIdentifierPart((char) b) && b != ESCAPE_CHAR) { + out.write(b); + } else { + out.write(ESCAPE_CHAR); // Escape character + // Special escape + if (b >= 0 && b < FREE_CHARS) { + out.write(CHAR_MAP[b]); + } else { // Normal escape + final char[] tmp = Integer.toHexString(b).toCharArray(); + if (tmp.length == 1) { + out.write('0'); + out.write(tmp[0]); + } else { + out.write(tmp[0]); + out.write(tmp[1]); + } + } + } + } + + @Override + public void write(final String str, final int off, final int len) throws IOException { + write(str.toCharArray(), off, len); + } + } + } diff --git a/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java b/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java index 6852dc9..5e486b4 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java @@ -53,6 +53,6 @@ public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackP */ @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION}; + return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java b/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java index 053123e..3652c89 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java @@ -53,6 +53,6 @@ public class ATHROW extends Instruction implements UnconditionalBranch, Exceptio */ @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.THROWABLE}; + return new Class[]{ExceptionConst.THROWABLE}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java b/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java index efeafb6..9bd080b 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java @@ -28,11 +28,43 @@ import java.util.List; public class AnnotationEntryGen { static final AnnotationEntryGen[] EMPTY_ARRAY = {}; + private final ConstantPoolGen cpool; + private int typeIndex; + private List evs; + private boolean isRuntimeVisible; + + /** + * Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool + * passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us + * to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name + * value pairs and the visibility. + */ + public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) { + this.cpool = cpool; + if (copyPoolEntries) { + typeIndex = cpool.addUtf8(a.getAnnotationType()); + } else { + typeIndex = a.getAnnotationTypeIndex(); + } + isRuntimeVisible = a.isRuntimeVisible(); + evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries); + } + + private AnnotationEntryGen(final ConstantPoolGen cpool) { + this.cpool = cpool; + } + + public AnnotationEntryGen(final ObjectType type, final List elements, final boolean vis, final ConstantPoolGen cpool) { + this.cpool = cpool; + this.typeIndex = cpool.addUtf8(type.getSignature()); + evs = elements; + isRuntimeVisible = vis; + } /** * Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file. * - * @param cp The constant pool gen where we can create the necessary name refs + * @param cp The constant pool gen where we can create the necessary name refs * @param annotationEntryGens An array of AnnotationGen objects */ static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) { @@ -86,11 +118,11 @@ public class AnnotationEntryGen { final List newAttributes = new ArrayList<>(); if (rvaData.length > 2) { newAttributes - .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool())); + .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool())); } if (riaData.length > 2) { newAttributes.add( - new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool())); + new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool())); } return newAttributes.toArray(Attribute.EMPTY_ARRAY); @@ -106,7 +138,7 @@ public class AnnotationEntryGen { * RuntimeInvisibleParameterAnnotations */ static Attribute[] getParameterAnnotationAttributes(final ConstantPoolGen cp, - final List[] /* Array of lists, array size depends on #params */ vec) { + final List[] /* Array of lists, array size depends on #params */ vec) { final int[] visCount = new int[vec.length]; int totalVisCount = 0; final int[] invisCount = new int[vec.length]; @@ -168,11 +200,11 @@ public class AnnotationEntryGen { final List newAttributes = new ArrayList<>(); if (totalVisCount > 0) { newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), - cp.getConstantPool())); + cp.getConstantPool())); } if (totalInvisCount > 0) { newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), - cp.getConstantPool())); + cp.getConstantPool())); } return newAttributes.toArray(Attribute.EMPTY_ARRAY); } catch (final IOException e) { @@ -194,42 +226,6 @@ public class AnnotationEntryGen { return a; } - private int typeIndex; - - private List evs; - - private final ConstantPoolGen cpool; - - private boolean isRuntimeVisible; - - /** - * Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool - * passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us - * to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name - * value pairs and the visibility. - */ - public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) { - this.cpool = cpool; - if (copyPoolEntries) { - typeIndex = cpool.addUtf8(a.getAnnotationType()); - } else { - typeIndex = a.getAnnotationTypeIndex(); - } - isRuntimeVisible = a.isRuntimeVisible(); - evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries); - } - - private AnnotationEntryGen(final ConstantPoolGen cpool) { - this.cpool = cpool; - } - - public AnnotationEntryGen(final ObjectType type, final List elements, final boolean vis, final ConstantPoolGen cpool) { - this.cpool = cpool; - this.typeIndex = cpool.addUtf8(type.getSignature()); - evs = elements; - isRuntimeVisible = vis; - } - public void addElementNameValuePair(final ElementValuePairGen evp) { if (evs == null) { evs = new ArrayList<>(); diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java index 4743eb4..5c39975 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java @@ -43,48 +43,48 @@ public abstract class ArithmeticInstruction extends Instruction implements Typed public Type getType(final ConstantPoolGen cp) { final short opcode = super.getOpcode(); switch (opcode) { - case Const.DADD: - case Const.DDIV: - case Const.DMUL: - case Const.DNEG: - case Const.DREM: - case Const.DSUB: - return Type.DOUBLE; - case Const.FADD: - case Const.FDIV: - case Const.FMUL: - case Const.FNEG: - case Const.FREM: - case Const.FSUB: - return Type.FLOAT; - case Const.IADD: - case Const.IAND: - case Const.IDIV: - case Const.IMUL: - case Const.INEG: - case Const.IOR: - case Const.IREM: - case Const.ISHL: - case Const.ISHR: - case Const.ISUB: - case Const.IUSHR: - case Const.IXOR: - return Type.INT; - case Const.LADD: - case Const.LAND: - case Const.LDIV: - case Const.LMUL: - case Const.LNEG: - case Const.LOR: - case Const.LREM: - case Const.LSHL: - case Const.LSHR: - case Const.LSUB: - case Const.LUSHR: - case Const.LXOR: - return Type.LONG; - default: // Never reached - throw new ClassGenException("Unknown type " + opcode); + case Const.DADD: + case Const.DDIV: + case Const.DMUL: + case Const.DNEG: + case Const.DREM: + case Const.DSUB: + return Type.DOUBLE; + case Const.FADD: + case Const.FDIV: + case Const.FMUL: + case Const.FNEG: + case Const.FREM: + case Const.FSUB: + return Type.FLOAT; + case Const.IADD: + case Const.IAND: + case Const.IDIV: + case Const.IMUL: + case Const.INEG: + case Const.IOR: + case Const.IREM: + case Const.ISHL: + case Const.ISHR: + case Const.ISUB: + case Const.IUSHR: + case Const.IXOR: + return Type.INT; + case Const.LADD: + case Const.LAND: + case Const.LDIV: + case Const.LMUL: + case Const.LNEG: + case Const.LOR: + case Const.LREM: + case Const.LSHL: + case Const.LSHR: + case Const.LSUB: + case Const.LUSHR: + case Const.LXOR: + return Type.LONG; + default: // Never reached + throw new ClassGenException("Unknown type " + opcode); } } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java index fdb7803..307e1ba 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java @@ -49,32 +49,32 @@ public abstract class ArrayInstruction extends Instruction implements ExceptionT public Type getType(final ConstantPoolGen cp) { final short opcode = super.getOpcode(); switch (opcode) { - case Const.IALOAD: - case Const.IASTORE: - return Type.INT; - case Const.CALOAD: - case Const.CASTORE: - return Type.CHAR; - case Const.BALOAD: - case Const.BASTORE: - return Type.BYTE; - case Const.SALOAD: - case Const.SASTORE: - return Type.SHORT; - case Const.LALOAD: - case Const.LASTORE: - return Type.LONG; - case Const.DALOAD: - case Const.DASTORE: - return Type.DOUBLE; - case Const.FALOAD: - case Const.FASTORE: - return Type.FLOAT; - case Const.AALOAD: - case Const.AASTORE: - return Type.OBJECT; - default: - throw new ClassGenException("Unknown case in switch" + opcode); + case Const.IALOAD: + case Const.IASTORE: + return Type.INT; + case Const.CALOAD: + case Const.CASTORE: + return Type.CHAR; + case Const.BALOAD: + case Const.BASTORE: + return Type.BYTE; + case Const.SALOAD: + case Const.SASTORE: + return Type.SHORT; + case Const.LALOAD: + case Const.LASTORE: + return Type.LONG; + case Const.DALOAD: + case Const.DASTORE: + return Type.DOUBLE; + case Const.FALOAD: + case Const.FASTORE: + return Type.FLOAT; + case Const.AALOAD: + case Const.AASTORE: + return Type.OBJECT; + default: + throw new ClassGenException("Unknown case in switch" + opcode); } } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java b/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java index 5f8f746..19caf4d 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java @@ -29,7 +29,7 @@ public final class ArrayType extends ReferenceType { /** * Convenience constructor for array type, e.g. int[] * - * @param type array type, e.g. T_INT + * @param type array type, e.g. T_INT * @param dimensions array dimensions */ public ArrayType(final byte type, final int dimensions) { @@ -39,7 +39,7 @@ public final class ArrayType extends ReferenceType { /** * Convenience constructor for reference array type, e.g. Object[] * - * @param className complete name of class (java.lang.String, e.g.) + * @param className complete name of class (java.lang.String, e.g.) * @param dimensions array dimensions */ public ArrayType(final String className, final int dimensions) { @@ -49,7 +49,7 @@ public final class ArrayType extends ReferenceType { /** * Constructor for array of given type * - * @param type type of array (may be an array itself) + * @param type type of array (may be an array itself) * @param dimensions array dimensions */ public ArrayType(final Type type, final int dimensions) { @@ -58,17 +58,17 @@ public final class ArrayType extends ReferenceType { throw new ClassGenException("Invalid number of dimensions: " + dimensions); } switch (type.getType()) { - case Const.T_ARRAY: - final ArrayType array = (ArrayType) type; - this.dimensions = dimensions + array.dimensions; - basicType = array.basicType; - break; - case Const.T_VOID: - throw new ClassGenException("Invalid type: void[]"); - default: // Basic type or reference - this.dimensions = dimensions; - basicType = type; - break; + case Const.T_ARRAY: + final ArrayType array = (ArrayType) type; + this.dimensions = dimensions + array.dimensions; + basicType = array.basicType; + break; + case Const.T_VOID: + throw new ClassGenException("Invalid type: void[]"); + default: // Basic type or reference + this.dimensions = dimensions; + basicType = type; + break; } final StringBuilder buf = new StringBuilder(); for (int i = 0; i < this.dimensions; i++) { diff --git a/src/main/java/haidnor/jvm/bcel/generic/BasicType.java b/src/main/java/haidnor/jvm/bcel/generic/BasicType.java index 5af9a28..1a3e8a5 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/BasicType.java +++ b/src/main/java/haidnor/jvm/bcel/generic/BasicType.java @@ -23,32 +23,6 @@ import haidnor.jvm.bcel.Const; */ public final class BasicType extends Type { - // @since 6.0 no longer final - public static BasicType getType(final byte type) { - switch (type) { - case Const.T_VOID: - return VOID; - case Const.T_BOOLEAN: - return BOOLEAN; - case Const.T_BYTE: - return BYTE; - case Const.T_SHORT: - return SHORT; - case Const.T_CHAR: - return CHAR; - case Const.T_INT: - return INT; - case Const.T_LONG: - return LONG; - case Const.T_DOUBLE: - return DOUBLE; - case Const.T_FLOAT: - return FLOAT; - default: - throw new ClassGenException("Invalid type: " + type); - } - } - /** * Constructor for basic types such as int, long, 'void' * @@ -62,6 +36,32 @@ public final class BasicType extends Type { } } + // @since 6.0 no longer final + public static BasicType getType(final byte type) { + switch (type) { + case Const.T_VOID: + return VOID; + case Const.T_BOOLEAN: + return BOOLEAN; + case Const.T_BYTE: + return BYTE; + case Const.T_SHORT: + return SHORT; + case Const.T_CHAR: + return CHAR; + case Const.T_INT: + return INT; + case Const.T_LONG: + return LONG; + case Const.T_DOUBLE: + return DOUBLE; + case Const.T_FLOAT: + return FLOAT; + default: + throw new ClassGenException("Invalid type: " + type); + } + } + /** * @return true if both type objects refer to the same type */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java b/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java index deb8a97..61a24aa 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java +++ b/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java @@ -26,13 +26,6 @@ package haidnor.jvm.bcel.generic; */ public final class BranchHandle extends InstructionHandle { - /** - * Factory method. - */ - static BranchHandle getBranchHandle(final BranchInstruction i) { - return new BranchHandle(i); - } - // This is also a cache in case the InstructionHandle#swapInstruction() method is used // See BCEL-273 private BranchInstruction bi; // An alias in fact, but saves lots of casts @@ -42,6 +35,13 @@ public final class BranchHandle extends InstructionHandle { bi = i; } + /** + * Factory method. + */ + static BranchHandle getBranchHandle(final BranchInstruction i) { + return new BranchHandle(i); + } + /* * Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private * i_position field should be prevented. @@ -51,6 +51,13 @@ public final class BranchHandle extends InstructionHandle { return bi.getPosition(); } + @Override + void setPosition(final int pos) { + // Original code: i_position = bi.position = pos; + bi.setPosition(pos); + super.setPosition(pos); + } + /** * @return target of instruction. */ @@ -58,6 +65,13 @@ public final class BranchHandle extends InstructionHandle { return bi.getTarget(); } + /** + * Pass new target to instruction. + */ + public void setTarget(final InstructionHandle ih) { + bi.setTarget(ih); + } + /** * Set new contents. Old instruction is disposed and may not be used anymore. */ @@ -70,20 +84,6 @@ public final class BranchHandle extends InstructionHandle { bi = (BranchInstruction) i; } - @Override - void setPosition(final int pos) { - // Original code: i_position = bi.position = pos; - bi.setPosition(pos); - super.setPosition(pos); - } - - /** - * Pass new target to instruction. - */ - public void setTarget(final InstructionHandle ih) { - bi.setTarget(ih); - } - @Override protected int updatePosition(final int offset, final int maxOffset) { final int x = bi.updatePosition(offset, maxOffset); diff --git a/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java index e27d21a..3babe3b 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java @@ -29,30 +29,16 @@ import java.io.IOException; */ public abstract class BranchInstruction extends Instruction implements InstructionTargeter { - /** - * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen - */ - static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) { - if (oldIh != null) { - oldIh.removeTargeter(t); - } - if (newIh != null) { - newIh.addTargeter(t); - } - } - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected int index; // Branch target relative to this instruction - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected InstructionHandle target; // Target object in instruction list - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @@ -76,6 +62,18 @@ public abstract class BranchInstruction extends Instruction implements Instructi setTarget(target); } + /** + * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen + */ + static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) { + if (oldIh != null) { + oldIh.removeTargeter(t); + } + if (newIh != null) { + newIh.addTargeter(t); + } + } + /** * @return true, if ih is target of this instruction */ @@ -116,6 +114,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi return index; } + /** + * @param index the index to set + * @since 6.0 + */ + protected void setIndex(final int index) { + this.index = index; + } + /** * @return the position * @since 6.0 @@ -124,6 +130,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi return position; } + /** + * @param position the position to set + * @since 6.0 + */ + protected void setPosition(final int position) { + this.position = position; + } + /** * @return target of branch instruction */ @@ -131,6 +145,16 @@ public abstract class BranchInstruction extends Instruction implements Instructi return target; } + /** + * Set branch target + * + * @param target branch target + */ + public void setTarget(final InstructionHandle target) { + notifyTarget(this.target, target, this); + this.target = target; + } + /** * @return the offset to this instruction's target */ @@ -157,7 +181,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi * Read needed data (e.g. index) from file. Conversion to a InstructionHandle is done in InstructionList(byte[]). * * @param bytes input stream - * @param wide wide prefix? + * @param wide wide prefix? * @see InstructionList */ @Override @@ -166,35 +190,9 @@ public abstract class BranchInstruction extends Instruction implements Instructi index = bytes.readShort(); } - /** - * @param index the index to set - * @since 6.0 - */ - protected void setIndex(final int index) { - this.index = index; - } - - /** - * @param position the position to set - * @since 6.0 - */ - protected void setPosition(final int position) { - this.position = position; - } - - /** - * Set branch target - * - * @param target branch target - */ - public void setTarget(final InstructionHandle target) { - notifyTarget(this.target, target, this); - this.target = target; - } - /** * Long output format: - * + *

* <position in byte code> <name of opcode> "["<opcode number>"]" "("<length of instruction>")" * "<"<target instruction>">" "@"<branch target offset> * @@ -232,7 +230,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi * length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte) * positions and offsets by calling this function. * - * @param offset additional offset caused by preceding (variable length) instructions + * @param offset additional offset caused by preceding (variable length) instructions * @param maxOffset the maximum offset that may be caused by these instructions * @return additional offset caused by possible change of this instruction's length */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java index 44ad35d..ffac216 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java @@ -74,6 +74,19 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct return index; } + /** + * Set the index to constant pool. + * + * @param index in constant pool. + */ + @Override + public void setIndex(final int index) { // TODO could be package-protected? + if (index < 0) { + throw new ClassGenException("Negative index value: " + index); + } + this.index = index; + } + /** * @return type related with this instruction. */ @@ -91,7 +104,7 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct * Read needed data (i.e., index) from file. * * @param bytes input stream - * @param wide wide prefix? + * @param wide wide prefix? */ @Override protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { @@ -99,22 +112,9 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct super.setLength(3); } - /** - * Set the index to constant pool. - * - * @param index in constant pool. - */ - @Override - public void setIndex(final int index) { // TODO could be package-protected? - if (index < 0) { - throw new ClassGenException("Negative index value: " + index); - } - this.index = index; - } - /** * Long output format: - * + *

* <name of opcode> "["<opcode number>"]" "("<length of instruction>")" "<"< constant pool * index>">" * diff --git a/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java b/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java index 1a5e1ad..10fcb78 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java @@ -45,42 +45,23 @@ public class ClassGen extends AccessFlags implements Cloneable { return THIS.getClassName().hashCode(); } }; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - + private final String fileName; + // ArrayLists instead of arrays to gather fields, methods, etc. + private final List fieldList = new ArrayList<>(); + private final List methodList = new ArrayList<>(); + private final List attributeList = new ArrayList<>(); + private final List interfaceList = new ArrayList<>(); + private final List annotationList = new ArrayList<>(); /* * Corresponds to the fields found in a JavaClass object. */ private String className; private String superClassName; - private final String fileName; private int classNameIndex = -1; private int superclassNameIndex = -1; private int major = Const.MAJOR_1_1; private int minor = Const.MINOR_1_1; private ConstantPoolGen cp; // Template for building up constant pool - // ArrayLists instead of arrays to gather fields, methods, etc. - private final List fieldList = new ArrayList<>(); - private final List methodList = new ArrayList<>(); - - private final List attributeList = new ArrayList<>(); - - private final List interfaceList = new ArrayList<>(); - - private final List annotationList = new ArrayList<>(); - private List observers; /** @@ -115,11 +96,11 @@ public class ClassGen extends AccessFlags implements Cloneable { /** * Convenience constructor to set up some important values initially. * - * @param className fully qualified class name + * @param className fully qualified class name * @param superClassName fully qualified superclass name - * @param fileName source file name - * @param accessFlags access qualifiers - * @param interfaces implemented interfaces + * @param fileName source file name + * @param accessFlags access qualifiers + * @param interfaces implemented interfaces */ public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces) { this(className, superClassName, fileName, accessFlags, interfaces, new ConstantPoolGen()); @@ -128,15 +109,15 @@ public class ClassGen extends AccessFlags implements Cloneable { /** * Convenience constructor to set up some important values initially. * - * @param className fully qualified class name + * @param className fully qualified class name * @param superClassName fully qualified superclass name - * @param fileName source file name - * @param accessFlags access qualifiers - * @param interfaces implemented interfaces - * @param cp constant pool to use + * @param fileName source file name + * @param accessFlags access qualifiers + * @param interfaces implemented interfaces + * @param cp constant pool to use */ public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces, - final ConstantPoolGen cp) { + final ConstantPoolGen cp) { super(accessFlags); this.className = className; this.superClassName = superClassName; @@ -153,6 +134,20 @@ public class ClassGen extends AccessFlags implements Cloneable { } } + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + public void addAnnotationEntry(final AnnotationEntryGen a) { annotationList.add(a); } @@ -168,7 +163,7 @@ public class ClassGen extends AccessFlags implements Cloneable { /** * Convenience method. - * + *

* Add an empty constructor to this class that does nothing but calling super(). * * @param accessFlags rights for constructor @@ -281,14 +276,28 @@ public class ClassGen extends AccessFlags implements Cloneable { return className; } + public void setClassName(final String name) { + className = Utility.pathToPackage(name); + classNameIndex = cp.addClass(name); + } + public int getClassNameIndex() { return classNameIndex; } + public void setClassNameIndex(final int classNameIndex) { + this.classNameIndex = classNameIndex; + this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class)); + } + public ConstantPoolGen getConstantPool() { return cp; } + public void setConstantPool(final ConstantPoolGen constantPool) { + cp = constantPool; + } + public JavaField[] getFields() { return fieldList.toArray(JavaField.EMPTY_ARRAY); } @@ -328,7 +337,7 @@ public class ClassGen extends AccessFlags implements Cloneable { // Must be last since the above calls may still add something to it final ConstantPool cp = this.cp.getFinalConstantPool(); return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, super.getAccessFlags(), cp, interfaces, fields, methods, - attributes); + attributes); } /** @@ -338,6 +347,15 @@ public class ClassGen extends AccessFlags implements Cloneable { return major; } + /** + * Set major version number of class file, default value is 45 (JDK 1.1) + * + * @param major major version number + */ + public void setMajor(final int major) { // TODO could be package-protected - only called by test code + this.major = major; + } + public JavaMethod getMethodAt(final int pos) { return methodList.get(pos); } @@ -346,6 +364,11 @@ public class ClassGen extends AccessFlags implements Cloneable { return methodList.toArray(JavaMethod.EMPTY_ARRAY); } + public void setMethods(final JavaMethod[] methods) { + methodList.clear(); + Collections.addAll(methodList, methods); + } + /** * @return minor version number of class file */ @@ -353,14 +376,33 @@ public class ClassGen extends AccessFlags implements Cloneable { return minor; } + /** + * Set minor version number of class file, default value is 3 (JDK 1.1) + * + * @param minor minor version number + */ + public void setMinor(final int minor) { // TODO could be package-protected - only called by test code + this.minor = minor; + } + public String getSuperclassName() { return superClassName; } + public void setSuperclassName(final String name) { + superClassName = Utility.pathToPackage(name); + superclassNameIndex = cp.addClass(name); + } + public int getSuperclassNameIndex() { return superclassNameIndex; } + public void setSuperclassNameIndex(final int superclassNameIndex) { + this.superclassNameIndex = superclassNameIndex; + superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class)); + } + /** * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. * @@ -446,57 +488,10 @@ public class ClassGen extends AccessFlags implements Cloneable { } } - public void setClassName(final String name) { - className = Utility.pathToPackage(name); - classNameIndex = cp.addClass(name); - } - - public void setClassNameIndex(final int classNameIndex) { - this.classNameIndex = classNameIndex; - this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class)); - } - - public void setConstantPool(final ConstantPoolGen constantPool) { - cp = constantPool; - } - - /** - * Set major version number of class file, default value is 45 (JDK 1.1) - * - * @param major major version number - */ - public void setMajor(final int major) { // TODO could be package-protected - only called by test code - this.major = major; - } - public void setMethodAt(final JavaMethod method, final int pos) { methodList.set(pos, method); } - public void setMethods(final JavaMethod[] methods) { - methodList.clear(); - Collections.addAll(methodList, methods); - } - - /** - * Set minor version number of class file, default value is 3 (JDK 1.1) - * - * @param minor minor version number - */ - public void setMinor(final int minor) { // TODO could be package-protected - only called by test code - this.minor = minor; - } - - public void setSuperclassName(final String name) { - superClassName = Utility.pathToPackage(name); - superclassNameIndex = cp.addClass(name); - } - - public void setSuperclassNameIndex(final int superclassNameIndex) { - this.superclassNameIndex = superclassNameIndex; - superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class)); - } - /** * Look for attributes representing annotations and unpack them. */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java b/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java index f9a65f9..e55dba0 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java @@ -42,8 +42,8 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling * is done. * - * @param startPc Start of handled region (inclusive) - * @param endPc End of handled region (inclusive) + * @param startPc Start of handled region (inclusive) + * @param endPc End of handled region (inclusive) * @param handlerPc Where handling is done * @param catchType which exception is handled, null for ANY */ @@ -71,14 +71,23 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { return startPc == ih || endPc == ih || handlerPc == ih; } - /** Gets the type of the Exception to catch, 'null' for ANY. */ + /** + * Gets the type of the Exception to catch, 'null' for ANY. + */ public ObjectType getCatchType() { return catchType; } + /** + * Sets the type of the Exception to catch. Set 'null' for ANY. + */ + public void setCatchType(final ObjectType catchType) { + this.catchType = catchType; + } + /** * Get CodeException object.
- * + *

* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. * @@ -86,7 +95,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { */ public CodeException getCodeException(final ConstantPoolGen cp) { return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(), - catchType == null ? 0 : cp.addClass(catchType)); + catchType == null ? 0 : cp.addClass(catchType)); } /** @@ -96,25 +105,6 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { return endPc; } - /** - * @return start of handler - */ - public InstructionHandle getHandlerPC() { - return handlerPc; - } - - /** - * @return start of handled region (inclusive) - */ - public InstructionHandle getStartPC() { - return startPc; - } - - /** Sets the type of the Exception to catch. Set 'null' for ANY. */ - public void setCatchType(final ObjectType catchType) { - this.catchType = catchType; - } - /* * Set end of handler * @@ -125,6 +115,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { this.endPc = endPc; } + /** + * @return start of handler + */ + public InstructionHandle getHandlerPC() { + return handlerPc; + } + /* * Set handler code * @@ -135,6 +132,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable { this.handlerPc = handlerPc; } + /** + * @return start of handled region (inclusive) + */ + public InstructionHandle getStartPC() { + return startPc; + } + /* * Set start of handler * diff --git a/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java index 104d96e..bc6a910 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java @@ -21,7 +21,7 @@ package haidnor.jvm.bcel.generic; * meaning. For example, the (virtual) PUSH instruction takes an arbitrary argument and produces the appropriate code at * dump time (ICONST, LDC, BIPUSH, ...). Also you can use the SWITCH instruction as a useful template for either * LOOKUPSWITCH or TABLESWITCH. - * + *

* The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns. * * @see PUSH diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java b/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java index cf7cdd2..8c7b40f 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java @@ -44,35 +44,27 @@ public class ConstantPoolGen { private static final String FIELDREF_DELIM = "&"; private static final String NAT_DELIM = "%"; // Name and Type - + private final Map stringTable = new HashMap<>(); + private final Map classTable = new HashMap<>(); + private final Map utf8Table = new HashMap<>(); + private final Map natTable = new HashMap<>(); + private final Map cpTable = new HashMap<>(); /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected int size; - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected Constant[] constants; - /** * @deprecated (since 6.0) will be made private; do not access directly, use getSize() */ @Deprecated protected int index = 1; // First entry (0) used by JVM - private final Map stringTable = new HashMap<>(); - - private final Map classTable = new HashMap<>(); - - private final Map utf8Table = new HashMap<>(); - - private final Map natTable = new HashMap<>(); - - private final Map cpTable = new HashMap<>(); - /** * Constructs a new empty constant pool. */ @@ -255,63 +247,63 @@ public class ConstantPoolGen { * Adds a constant from another ConstantPool and returns the new index. * * @param constant The constant to add. - * @param cpGen Source pool. + * @param cpGen Source pool. * @return index of entry */ public int addConstant(final Constant constant, final ConstantPoolGen cpGen) { final Constant[] constants = cpGen.getConstantPool().getConstantPool(); switch (constant.getTag()) { - case Const.CONSTANT_String: { - final ConstantString s = (ConstantString) constant; - final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; - return addString(u8.getBytes()); - } - case Const.CONSTANT_Class: { - final ConstantClass s = (ConstantClass) constant; - final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; - return addClass(u8.getBytes()); - } - case Const.CONSTANT_NameAndType: { - final ConstantNameAndType n = (ConstantNameAndType) constant; - final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; - final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; - return addNameAndType(u8.getBytes(), u8_2.getBytes()); - } - case Const.CONSTANT_Utf8: - return addUtf8(((ConstantUtf8) constant).getBytes()); - case Const.CONSTANT_Double: - return addDouble(((ConstantDouble) constant).getBytes()); - case Const.CONSTANT_Float: - return addFloat(((ConstantFloat) constant).getBytes()); - case Const.CONSTANT_Long: - return addLong(((ConstantLong) constant).getBytes()); - case Const.CONSTANT_Integer: - return addInteger(((ConstantInteger) constant).getBytes()); - case Const.CONSTANT_InterfaceMethodref: - case Const.CONSTANT_Methodref: - case Const.CONSTANT_Fieldref: { - final ConstantCP m = (ConstantCP) constant; - final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()]; - final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()]; - ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()]; - final String className = Utility.pathToPackage(u8.getBytes()); - u8 = (ConstantUtf8) constants[n.getNameIndex()]; - final String name = u8.getBytes(); - u8 = (ConstantUtf8) constants[n.getSignatureIndex()]; - final String signature = u8.getBytes(); - switch (constant.getTag()) { + case Const.CONSTANT_String: { + final ConstantString s = (ConstantString) constant; + final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; + return addString(u8.getBytes()); + } + case Const.CONSTANT_Class: { + final ConstantClass s = (ConstantClass) constant; + final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; + return addClass(u8.getBytes()); + } + case Const.CONSTANT_NameAndType: { + final ConstantNameAndType n = (ConstantNameAndType) constant; + final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; + final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; + return addNameAndType(u8.getBytes(), u8_2.getBytes()); + } + case Const.CONSTANT_Utf8: + return addUtf8(((ConstantUtf8) constant).getBytes()); + case Const.CONSTANT_Double: + return addDouble(((ConstantDouble) constant).getBytes()); + case Const.CONSTANT_Float: + return addFloat(((ConstantFloat) constant).getBytes()); + case Const.CONSTANT_Long: + return addLong(((ConstantLong) constant).getBytes()); + case Const.CONSTANT_Integer: + return addInteger(((ConstantInteger) constant).getBytes()); case Const.CONSTANT_InterfaceMethodref: - return addInterfaceMethodref(className, name, signature); case Const.CONSTANT_Methodref: - return addMethodref(className, name, signature); - case Const.CONSTANT_Fieldref: - return addFieldref(className, name, signature); + case Const.CONSTANT_Fieldref: { + final ConstantCP m = (ConstantCP) constant; + final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()]; + final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()]; + ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()]; + final String className = Utility.pathToPackage(u8.getBytes()); + u8 = (ConstantUtf8) constants[n.getNameIndex()]; + final String name = u8.getBytes(); + u8 = (ConstantUtf8) constants[n.getSignatureIndex()]; + final String signature = u8.getBytes(); + switch (constant.getTag()) { + case Const.CONSTANT_InterfaceMethodref: + return addInterfaceMethodref(className, name, signature); + case Const.CONSTANT_Methodref: + return addMethodref(className, name, signature); + case Const.CONSTANT_Fieldref: + return addFieldref(className, name, signature); + default: // Never reached + throw new IllegalArgumentException("Unknown constant type " + constant); + } + } default: // Never reached throw new IllegalArgumentException("Unknown constant type " + constant); - } - } - default: // Never reached - throw new IllegalArgumentException("Unknown constant type " + constant); } } @@ -395,9 +387,9 @@ public class ConstantPoolGen { /** * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there. * - * @param className class name string to add + * @param className class name string to add * @param methodName method name string to add - * @param signature signature string to add + * @param signature signature string to add * @return index of entry */ public int addInterfaceMethodref(final String className, final String methodName, final String signature) { @@ -430,6 +422,7 @@ public class ConstantPoolGen { index += 2; // Wastes one entry according to spec return ret; } + public int addMethodref(final MethodGen method) { return addMethodref(method.getClassName(), method.getName(), method.getSignature()); } @@ -437,9 +430,9 @@ public class ConstantPoolGen { /** * Add a new Methodref constant to the ConstantPool, if it is not already in there. * - * @param className class name string to add + * @param className class name string to add * @param methodName method name string to add - * @param signature method signature string to add + * @param signature method signature string to add * @return index of entry */ public int addMethodref(final String className, final String methodName, final String signature) { @@ -458,7 +451,7 @@ public class ConstantPoolGen { /** * Add a new NameAndType constant to the ConstantPool if it is not already in there. * - * @param name Name string to add + * @param name Name string to add * @param signature signature string to add * @return index of entry */ @@ -654,9 +647,9 @@ public class ConstantPoolGen { /** * Look for ConstantInterfaceMethodref in ConstantPool. * - * @param className Where to find method + * @param className Where to find method * @param methodName Guess what - * @param signature return and argument types + * @param signature return and argument types * @return index on success, -1 otherwise */ public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) { @@ -688,9 +681,9 @@ public class ConstantPoolGen { /** * Look for ConstantMethodref in ConstantPool. * - * @param className Where to find method + * @param className Where to find method * @param methodName Guess what - * @param signature return and argument types + * @param signature return and argument types * @return index on success, -1 otherwise */ public int lookupMethodref(final String className, final String methodName, final String signature) { @@ -700,7 +693,7 @@ public class ConstantPoolGen { /** * Look for ConstantNameAndType in ConstantPool. * - * @param name of variable/method + * @param name of variable/method * @param signature of variable/method * @return index on success, -1 otherwise */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java index 9112c60..bdf8d2b 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java @@ -19,7 +19,6 @@ package haidnor.jvm.bcel.generic; /** * Denotes a push instruction that produces a literal on the stack such as SIPUSH, BIPUSH, ICONST, etc. * - * * @see ICONST * @see SIPUSH */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java index abfbd19..d6f00d8 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java @@ -43,30 +43,30 @@ public abstract class ConversionInstruction extends Instruction implements Typed public Type getType(final ConstantPoolGen cp) { final short opcode = super.getOpcode(); switch (opcode) { - case Const.D2I: - case Const.F2I: - case Const.L2I: - return Type.INT; - case Const.D2F: - case Const.I2F: - case Const.L2F: - return Type.FLOAT; - case Const.D2L: - case Const.F2L: - case Const.I2L: - return Type.LONG; - case Const.F2D: - case Const.I2D: - case Const.L2D: - return Type.DOUBLE; - case Const.I2B: - return Type.BYTE; - case Const.I2C: - return Type.CHAR; - case Const.I2S: - return Type.SHORT; - default: // Never reached - throw new ClassGenException("Unknown type " + opcode); + case Const.D2I: + case Const.F2I: + case Const.L2I: + return Type.INT; + case Const.D2F: + case Const.I2F: + case Const.L2F: + return Type.FLOAT; + case Const.D2L: + case Const.F2L: + case Const.I2L: + return Type.LONG; + case Const.F2D: + case Const.I2D: + case Const.L2D: + return Type.DOUBLE; + case Const.I2B: + return Type.BYTE; + case Const.I2C: + return Type.CHAR; + case Const.I2S: + return Type.SHORT; + default: // Never reached + throw new ClassGenException("Unknown type " + opcode); } } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/DADD.java b/src/main/java/haidnor/jvm/bcel/generic/DADD.java index eb51578..0ed4336 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/DADD.java +++ b/src/main/java/haidnor/jvm/bcel/generic/DADD.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result1.word2 */ public class DADD extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/DDIV.java b/src/main/java/haidnor/jvm/bcel/generic/DDIV.java index fedb009..e419b58 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/DDIV.java +++ b/src/main/java/haidnor/jvm/bcel/generic/DDIV.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class DDIV extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/DMUL.java b/src/main/java/haidnor/jvm/bcel/generic/DMUL.java index cc0b95f..d33ef96 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/DMUL.java +++ b/src/main/java/haidnor/jvm/bcel/generic/DMUL.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class DMUL extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/DREM.java b/src/main/java/haidnor/jvm/bcel/generic/DREM.java index 78c87a3..f1531de 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/DREM.java +++ b/src/main/java/haidnor/jvm/bcel/generic/DREM.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class DREM extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/DSUB.java b/src/main/java/haidnor/jvm/bcel/generic/DSUB.java index 9742bb9..9f47378 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/DSUB.java +++ b/src/main/java/haidnor/jvm/bcel/generic/DSUB.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class DSUB extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java index 489730b..29fe1b8 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java @@ -52,83 +52,11 @@ public abstract class ElementValueGen { public static final int PRIMITIVE_SHORT = 'S'; public static final int PRIMITIVE_BOOLEAN = 'Z'; - - /** - * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct. - */ - public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) { - switch (value.getElementValueType()) { - case 'B': // byte - case 'C': // char - case 'D': // double - case 'F': // float - case 'I': // int - case 'J': // long - case 'S': // short - case 'Z': // boolean - case 's': // String - return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries); - case 'e': // Enum constant - return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries); - case '@': // Annotation - return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries); - case '[': // Array - return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries); - case 'c': // Class - return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries); - default: - throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")"); - } - } - - public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException { - final int type = dis.readUnsignedByte(); - switch (type) { - case 'B': // byte - return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen); - case 'C': // char - return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen); - case 'D': // double - return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen); - case 'F': // float - return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen); - case 'I': // int - return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen); - case 'J': // long - return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen); - case 'S': // short - return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen); - case 'Z': // boolean - return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen); - case 's': // String - return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen); - case 'e': // Enum constant - return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen); - case 'c': // Class - return new ClassElementValueGen(dis.readUnsignedShort(), cpGen); - case '@': // Annotation - // TODO: isRuntimeVisible ?????????? - // FIXME - return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false), - cpGen); - case '[': // Array - final int numArrayVals = dis.readUnsignedShort(); - final ElementValue[] evalues = new ElementValue[numArrayVals]; - for (int j = 0; j < numArrayVals; j++) { - evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool()); - } - return new ArrayElementValueGen(ARRAY, evalues, cpGen); - default: - throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type); - } - } - /** * @deprecated (since 6.0) will be made private and final; do not access directly, use getter */ @Deprecated protected int type; - /** * @deprecated (since 6.0) will be made private and final; do not access directly, use getter */ @@ -140,6 +68,76 @@ public abstract class ElementValueGen { this.cpGen = cpGen; } + /** + * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct. + */ + public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) { + switch (value.getElementValueType()) { + case 'B': // byte + case 'C': // char + case 'D': // double + case 'F': // float + case 'I': // int + case 'J': // long + case 'S': // short + case 'Z': // boolean + case 's': // String + return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries); + case 'e': // Enum constant + return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries); + case '@': // Annotation + return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries); + case '[': // Array + return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries); + case 'c': // Class + return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries); + default: + throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")"); + } + } + + public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException { + final int type = dis.readUnsignedByte(); + switch (type) { + case 'B': // byte + return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen); + case 'C': // char + return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen); + case 'D': // double + return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen); + case 'F': // float + return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen); + case 'I': // int + return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen); + case 'J': // long + return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen); + case 'S': // short + return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen); + case 'Z': // boolean + return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen); + case 's': // String + return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen); + case 'e': // Enum constant + return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen); + case 'c': // Class + return new ClassElementValueGen(dis.readUnsignedShort(), cpGen); + case '@': // Annotation + // TODO: isRuntimeVisible ?????????? + // FIXME + return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false), + cpGen); + case '[': // Array + final int numArrayVals = dis.readUnsignedShort(); + final ElementValue[] evalues = new ElementValue[numArrayVals]; + for (int j = 0; j < numArrayVals; j++) { + evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool()); + } + return new ArrayElementValueGen(ARRAY, evalues, cpGen); + default: + throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type); + } + } + public abstract void dump(DataOutputStream dos) throws IOException; protected ConstantPoolGen getConstantPool() { diff --git a/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java index 87c6c67..d4e2e08 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java @@ -36,9 +36,9 @@ public class EnumElementValueGen extends ElementValueGen { super(ENUM_CONSTANT, cpool); if (copyPoolEntries) { typeIdx = cpool.addUtf8(value.getEnumTypeString());// was - // addClass(value.getEnumTypeString()); + // addClass(value.getEnumTypeString()); valueIdx = cpool.addUtf8(value.getEnumValueString()); // was - // addString(value.getEnumValueString()); + // addString(value.getEnumValueString()); } else { typeIdx = value.getTypeIndex(); valueIdx = value.getValueIndex(); diff --git a/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java b/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java index 923064e..7b7a249 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java @@ -19,11 +19,11 @@ package haidnor.jvm.bcel.generic; /** * Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite * the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted. - * + *

* The Lava Language Specification specifies exactly which RUN-TIME and which LINKING exceptions each * instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may * be possible that an Instruction implementing this interface returns a Class[] of size 0. - * + *

* Please note that we speak of an "exception" here when we mean any "Throwable" object; so this term is equally used * for "Exception" and "Error" objects. */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java b/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java index 1e26b51..cbffaf6 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java @@ -48,30 +48,14 @@ public class FieldGen extends FieldGenOrMethodGen { return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - private Object value; - private List observers; /** * Instantiate from existing field. * * @param field Field object - * @param cp constant pool (must contain the same entries as the field's constant pool) + * @param cp constant pool (must contain the same entries as the field's constant pool) */ public FieldGen(final JavaField field, final ConstantPoolGen cp) { this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); @@ -93,9 +77,9 @@ public class FieldGen extends FieldGenOrMethodGen { * value associated with it as defined by setInitValue(). * * @param accessFlags access qualifiers - * @param type field type - * @param name field name - * @param cp constant pool + * @param type field type + * @param name field name + * @param cp constant pool */ public FieldGen(final int accessFlags, final Type type, final String name, final ConstantPoolGen cp) { super(accessFlags); @@ -104,28 +88,42 @@ public class FieldGen extends FieldGenOrMethodGen { setConstantPool(cp); } + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + private void addAnnotationsAsAttribute(final ConstantPoolGen cp) { Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute); } private int addConstant() { switch (super.getType().getType()) { // sic - case Const.T_INT: - case Const.T_CHAR: - case Const.T_BYTE: - case Const.T_BOOLEAN: - case Const.T_SHORT: - return super.getConstantPool().addInteger(((Integer) value).intValue()); - case Const.T_FLOAT: - return super.getConstantPool().addFloat(((Float) value).floatValue()); - case Const.T_DOUBLE: - return super.getConstantPool().addDouble(((Double) value).doubleValue()); - case Const.T_LONG: - return super.getConstantPool().addLong(((Long) value).longValue()); - case Const.T_REFERENCE: - return super.getConstantPool().addString((String) value); - default: - throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic + case Const.T_INT: + case Const.T_CHAR: + case Const.T_BYTE: + case Const.T_BOOLEAN: + case Const.T_SHORT: + return super.getConstantPool().addInteger(((Integer) value).intValue()); + case Const.T_FLOAT: + return super.getConstantPool().addFloat(((Float) value).floatValue()); + case Const.T_DOUBLE: + return super.getConstantPool().addDouble(((Double) value).doubleValue()); + case Const.T_LONG: + return super.getConstantPool().addLong(((Long) value).longValue()); + case Const.T_REFERENCE: + return super.getConstantPool().addString((String) value); + default: + throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic } } @@ -202,31 +200,6 @@ public class FieldGen extends FieldGenOrMethodGen { return null; } - @Override - public String getSignature() { - return super.getType().getSignature(); - } - - /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR - * signature. - * - * @see Object#hashCode() - */ - @Override - public int hashCode() { - return bcelComparator.hashCode(this); - } - - /** - * Remove observer for this object. - */ - public void removeObserver(final FieldObserver o) { - if (observers != null) { - observers.remove(o); - } - } - public void setInitValue(final boolean b) { checkType(Type.BOOLEAN); if (b) { @@ -293,6 +266,31 @@ public class FieldGen extends FieldGenOrMethodGen { } } + @Override + public String getSignature() { + return super.getType().getSignature(); + } + + /** + * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR + * signature. + * + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return bcelComparator.hashCode(this); + } + + /** + * Remove observer for this object. + */ + public void removeObserver(final FieldObserver o) { + if (observers != null) { + observers.remove(o); + } + } + private void setValue(final int index) { final ConstantPool cp = super.getConstantPool().getConstantPool(); final Constant c = cp.getConstant(index); diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java b/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java index 4f2ba9d..8a23e84 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java @@ -29,29 +29,25 @@ import java.util.List; */ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable { + private final List attributeList = new ArrayList<>(); + // @since 6.0 + private final List annotationList = new ArrayList<>(); /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected String name; - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected Type type; - /** * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter */ @Deprecated protected ConstantPoolGen cp; - private final List attributeList = new ArrayList<>(); - - // @since 6.0 - private final List annotationList = new ArrayList<>(); - protected FieldGenOrMethodGen() { } @@ -107,6 +103,10 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn return cp; } + public void setConstantPool(final ConstantPoolGen cp) { // TODO could be package-protected? + this.cp = cp; + } + /** * @return name of method/field. */ @@ -115,6 +115,11 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn return name; } + @Override + public void setName(final String name) { // TODO could be package-protected? + this.name = name; + } + /** * @return signature of method/field. */ @@ -125,6 +130,14 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn return type; } + @Override + public void setType(final Type type) { // TODO could be package-protected? + if (type.getType() == Const.T_ADDRESS) { + throw new IllegalArgumentException("Type can not be " + type); + } + this.type = type; + } + /** * @since 6.0 */ @@ -152,21 +165,4 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn public void removeAttributes() { attributeList.clear(); } - - public void setConstantPool(final ConstantPoolGen cp) { // TODO could be package-protected? - this.cp = cp; - } - - @Override - public void setName(final String name) { // TODO could be package-protected? - this.name = name; - } - - @Override - public void setType(final Type type) { // TODO could be package-protected? - if (type.getType() == Const.T_ADDRESS) { - throw new IllegalArgumentException("Type can not be " + type); - } - this.type = type; - } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java b/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java index b0fc8ac..dc26e42 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java +++ b/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java @@ -43,10 +43,9 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass { /** * @return name of the referenced class/interface * @deprecated If the instruction references an array class, this method will return "java.lang.Object". For code - * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an - * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly - * distinguishes between class types and array types. - * + * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an + * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly + * distinguishes between class types and array types. */ @Deprecated public String getClassName(final ConstantPoolGen cpg) { @@ -63,7 +62,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass { /** * @return type of the referenced class/interface * @deprecated If the instruction references an array class, the ObjectType returned will be invalid. Use - * getReferenceType() instead. + * getReferenceType() instead. */ @Deprecated public ObjectType getClassType(final ConstantPoolGen cpg) { @@ -100,7 +99,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass { * * @param cpg the ConstantPoolGen used to create the instruction * @return an ObjectType (if the referenced class type is a class or interface), or an ArrayType (if the referenced - * class type is an array class) + * class type is an array class) */ public ReferenceType getReferenceType(final ConstantPoolGen cpg) { final ConstantPool cp = cpg.getConstantPool(); diff --git a/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java b/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java index 0df16c2..baa1a96 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java +++ b/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java @@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst; *

  * Stack: ..., objectref -> ..., value
  * 
- * + *

* OR * *

@@ -66,7 +66,7 @@ public class GETFIELD extends FieldInstruction implements ExceptionThrower, Stac
     @Override
     public Class[] getExceptions() {
         return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
-            ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+                ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
     }
 
     @Override
diff --git a/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
index 699b656..b097020 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
  * 
  * Stack: ..., -> ..., value
  * 
- * + *

* OR * *

diff --git a/src/main/java/haidnor/jvm/bcel/generic/GOTO.java b/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
index 76b117b..a599e3f 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
@@ -73,7 +73,7 @@ public class GOTO extends GotoInstruction implements VariableLengthInstruction {
      * Called in pass 2 of InstructionList.setPositions() in order to update the branch target, that may shift due to
      * variable length instructions.
      *
-     * @param offset additional offset caused by preceding (variable length) instructions
+     * @param offset    additional offset caused by preceding (variable length) instructions
      * @param maxOffset the maximum offset that may be caused by these instructions
      * @return additional offset caused by possible change of this instruction's length
      */
diff --git a/src/main/java/haidnor/jvm/bcel/generic/IDIV.java b/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
index a3806b7..2831efe 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
@@ -56,6 +56,6 @@ public class IDIV extends ArithmeticInstruction implements ExceptionThrower {
      */
     @Override
     public Class[] getExceptions() {
-        return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION};
+        return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
     }
 }
diff --git a/src/main/java/haidnor/jvm/bcel/generic/IINC.java b/src/main/java/haidnor/jvm/bcel/generic/IINC.java
index 8ea16d4..a114dda 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/IINC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/IINC.java
@@ -87,6 +87,14 @@ public class IINC extends LocalVariableInstruction {
         return c;
     }
 
+    /**
+     * Sets increment factor.
+     */
+    public final void setIncrement(final int c) {
+        this.c = c;
+        setWide();
+    }
+
     /**
      * @return int type
      */
@@ -112,14 +120,6 @@ public class IINC extends LocalVariableInstruction {
         }
     }
 
-    /**
-     * Sets increment factor.
-     */
-    public final void setIncrement(final int c) {
-        this.c = c;
-        setWide();
-    }
-
     /**
      * Sets index of local variable.
      */
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
index 133657e..ee5fcf7 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
@@ -31,7 +31,7 @@ import java.io.IOException;
  * of the method. Ignores the bootstrap mechanism entirely.
  *
  * @see  The
- *      invokedynamic instruction in The Java Virtual Machine Specification
+ * invokedynamic instruction in The Java Virtual Machine Specification
  * @since 6.0
  */
 public class INVOKEDYNAMIC extends InvokeInstruction {
@@ -80,7 +80,7 @@ public class INVOKEDYNAMIC extends InvokeInstruction {
 
     /**
      * Override the parent method because our class name is held elsewhere.
-     *
+     * 

* Note: Contrary to this method's name it does not return the class name of the invoke target; rather it returns the * name of the method that will be used to invoke the Lambda method generated by this invoke dynamic instruction. */ @@ -94,7 +94,7 @@ public class INVOKEDYNAMIC extends InvokeInstruction { @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR, - ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); + ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); } /** diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java index 8cf9d47..d888c94 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java +++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java @@ -32,7 +32,7 @@ import java.io.IOException; *

* * @see The - * invokeinterface instruction in The Java Virtual Machine Specification + * invokeinterface instruction in The Java Virtual Machine Specification */ public final class INVOKEINTERFACE extends InvokeInstruction { @@ -100,7 +100,7 @@ public final class INVOKEINTERFACE extends InvokeInstruction { @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR, - ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); + ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); } /** diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java index 1ab8998..ff029d4 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java +++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java @@ -31,7 +31,7 @@ import java.io.IOException; *
* * @see The - * invokespecial instruction in The Java Virtual Machine Specification + * invokespecial instruction in The Java Virtual Machine Specification */ public class INVOKESPECIAL extends InvokeInstruction { @@ -78,6 +78,6 @@ public class INVOKESPECIAL extends InvokeInstruction { @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION, - ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR); + ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR); } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java index 1890895..b24faf4 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java +++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java @@ -30,7 +30,7 @@ import java.io.IOException; * * * @see The invokestatic - * instruction in The Java Virtual Machine Specification + * instruction in The Java Virtual Machine Specification */ public class INVOKESTATIC extends InvokeInstruction { @@ -77,6 +77,6 @@ public class INVOKESTATIC extends InvokeInstruction { @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR, - ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); + ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java index ddbd29d..8774156 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java +++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java @@ -30,7 +30,7 @@ import java.io.IOException; * * * @see The - * invokevirtual instruction in The Java Virtual Machine Specification + * invokevirtual instruction in The Java Virtual Machine Specification */ public class INVOKEVIRTUAL extends InvokeInstruction { @@ -77,6 +77,6 @@ public class INVOKEVIRTUAL extends InvokeInstruction { @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION, - ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR); + ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR); } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/IREM.java b/src/main/java/haidnor/jvm/bcel/generic/IREM.java index c1262bc..2556efe 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/IREM.java +++ b/src/main/java/haidnor/jvm/bcel/generic/IREM.java @@ -56,6 +56,6 @@ public class IREM extends ArithmeticInstruction implements ExceptionThrower { */ @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; + return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/Instruction.java b/src/main/java/haidnor/jvm/bcel/generic/Instruction.java index 92cc653..4b25748 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/Instruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/Instruction.java @@ -31,6 +31,27 @@ public abstract class Instruction implements Cloneable { static final Instruction[] EMPTY_ARRAY = {}; private static InstructionComparator cmp = InstructionComparator.DEFAULT; + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected short length = 1; // Length of instruction in bytes + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected short opcode = -1; // Opcode number + + /** + * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. + */ + Instruction() { + } + + public Instruction(final short opcode, final short length) { + this.length = length; + this.opcode = opcode; + } /** * Gets Comparator object used in the equals() method to determine equality of instructions. @@ -43,6 +64,16 @@ public abstract class Instruction implements Cloneable { return cmp; } + /** + * Sets comparator to be used for equals(). + * + * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods + */ + @Deprecated + public static void setComparator(final InstructionComparator c) { + cmp = c; + } + /** * Tests if the value can fit in a byte (signed) * @@ -70,6 +101,7 @@ public abstract class Instruction implements Cloneable { *

* If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned. *

+ * * @param bytes input stream bytes * @return instruction object being read * @throws IOException Thrown when an I/O exception of some sort has occurred. @@ -90,299 +122,299 @@ public abstract class Instruction implements Cloneable { } switch (opcode) { - case Const.BIPUSH: - obj = new BIPUSH(); - break; - case Const.SIPUSH: - obj = new SIPUSH(); - break; - case Const.LDC: - obj = new LDC(); - break; - case Const.LDC_W: - obj = new LDC_W(); - break; - case Const.LDC2_W: - obj = new LDC2_W(); - break; - case Const.ILOAD: - obj = new ILOAD(); - break; - case Const.LLOAD: - obj = new LLOAD(); - break; - case Const.FLOAD: - obj = new FLOAD(); - break; - case Const.DLOAD: - obj = new DLOAD(); - break; - case Const.ALOAD: - obj = new ALOAD(); - break; - case Const.ILOAD_0: - obj = new ILOAD(0); - break; - case Const.ILOAD_1: - obj = new ILOAD(1); - break; - case Const.ILOAD_2: - obj = new ILOAD(2); - break; - case Const.ILOAD_3: - obj = new ILOAD(3); - break; - case Const.LLOAD_0: - obj = new LLOAD(0); - break; - case Const.LLOAD_1: - obj = new LLOAD(1); - break; - case Const.LLOAD_2: - obj = new LLOAD(2); - break; - case Const.LLOAD_3: - obj = new LLOAD(3); - break; - case Const.FLOAD_0: - obj = new FLOAD(0); - break; - case Const.FLOAD_1: - obj = new FLOAD(1); - break; - case Const.FLOAD_2: - obj = new FLOAD(2); - break; - case Const.FLOAD_3: - obj = new FLOAD(3); - break; - case Const.DLOAD_0: - obj = new DLOAD(0); - break; - case Const.DLOAD_1: - obj = new DLOAD(1); - break; - case Const.DLOAD_2: - obj = new DLOAD(2); - break; - case Const.DLOAD_3: - obj = new DLOAD(3); - break; - case Const.ALOAD_0: - obj = new ALOAD(0); - break; - case Const.ALOAD_1: - obj = new ALOAD(1); - break; - case Const.ALOAD_2: - obj = new ALOAD(2); - break; - case Const.ALOAD_3: - obj = new ALOAD(3); - break; - case Const.ISTORE: - obj = new ISTORE(); - break; - case Const.LSTORE: - obj = new LSTORE(); - break; - case Const.FSTORE: - obj = new FSTORE(); - break; - case Const.DSTORE: - obj = new DSTORE(); - break; - case Const.ASTORE: - obj = new ASTORE(); - break; - case Const.ISTORE_0: - obj = new ISTORE(0); - break; - case Const.ISTORE_1: - obj = new ISTORE(1); - break; - case Const.ISTORE_2: - obj = new ISTORE(2); - break; - case Const.ISTORE_3: - obj = new ISTORE(3); - break; - case Const.LSTORE_0: - obj = new LSTORE(0); - break; - case Const.LSTORE_1: - obj = new LSTORE(1); - break; - case Const.LSTORE_2: - obj = new LSTORE(2); - break; - case Const.LSTORE_3: - obj = new LSTORE(3); - break; - case Const.FSTORE_0: - obj = new FSTORE(0); - break; - case Const.FSTORE_1: - obj = new FSTORE(1); - break; - case Const.FSTORE_2: - obj = new FSTORE(2); - break; - case Const.FSTORE_3: - obj = new FSTORE(3); - break; - case Const.DSTORE_0: - obj = new DSTORE(0); - break; - case Const.DSTORE_1: - obj = new DSTORE(1); - break; - case Const.DSTORE_2: - obj = new DSTORE(2); - break; - case Const.DSTORE_3: - obj = new DSTORE(3); - break; - case Const.ASTORE_0: - obj = new ASTORE(0); - break; - case Const.ASTORE_1: - obj = new ASTORE(1); - break; - case Const.ASTORE_2: - obj = new ASTORE(2); - break; - case Const.ASTORE_3: - obj = new ASTORE(3); - break; - case Const.IINC: - obj = new IINC(); - break; - case Const.IFEQ: - obj = new IFEQ(); - break; - case Const.IFNE: - obj = new IFNE(); - break; - case Const.IFLT: - obj = new IFLT(); - break; - case Const.IFGE: - obj = new IFGE(); - break; - case Const.IFGT: - obj = new IFGT(); - break; - case Const.IFLE: - obj = new IFLE(); - break; - case Const.IF_ICMPEQ: - obj = new IF_ICMPEQ(); - break; - case Const.IF_ICMPNE: - obj = new IF_ICMPNE(); - break; - case Const.IF_ICMPLT: - obj = new IF_ICMPLT(); - break; - case Const.IF_ICMPGE: - obj = new IF_ICMPGE(); - break; - case Const.IF_ICMPGT: - obj = new IF_ICMPGT(); - break; - case Const.IF_ICMPLE: - obj = new IF_ICMPLE(); - break; - case Const.IF_ACMPEQ: - obj = new IF_ACMPEQ(); - break; - case Const.IF_ACMPNE: - obj = new IF_ACMPNE(); - break; - case Const.GOTO: - obj = new GOTO(); - break; - case Const.JSR: - obj = new JSR(); - break; - case Const.RET: - obj = new RET(); - break; - case Const.TABLESWITCH: - obj = new TABLESWITCH(); - break; - case Const.LOOKUPSWITCH: - obj = new LOOKUPSWITCH(); - break; - case Const.GETSTATIC: - obj = new GETSTATIC(); - break; - case Const.PUTSTATIC: - obj = new PUTSTATIC(); - break; - case Const.GETFIELD: - obj = new GETFIELD(); - break; - case Const.PUTFIELD: - obj = new PUTFIELD(); - break; - case Const.INVOKEVIRTUAL: - obj = new INVOKEVIRTUAL(); - break; - case Const.INVOKESPECIAL: - obj = new INVOKESPECIAL(); - break; - case Const.INVOKESTATIC: - obj = new INVOKESTATIC(); - break; - case Const.INVOKEINTERFACE: - obj = new INVOKEINTERFACE(); - break; - case Const.INVOKEDYNAMIC: - obj = new INVOKEDYNAMIC(); - break; - case Const.NEW: - obj = new NEW(); - break; - case Const.NEWARRAY: - obj = new NEWARRAY(); - break; - case Const.ANEWARRAY: - obj = new ANEWARRAY(); - break; - case Const.CHECKCAST: - obj = new CHECKCAST(); - break; - case Const.INSTANCEOF: - obj = new INSTANCEOF(); - break; - case Const.MULTIANEWARRAY: - obj = new MULTIANEWARRAY(); - break; - case Const.IFNULL: - obj = new IFNULL(); - break; - case Const.IFNONNULL: - obj = new IFNONNULL(); - break; - case Const.GOTO_W: - obj = new GOTO_W(); - break; - case Const.JSR_W: - obj = new JSR_W(); - break; - case Const.BREAKPOINT: - obj = new BREAKPOINT(); - break; - case Const.IMPDEP1: - obj = new IMPDEP1(); - break; - case Const.IMPDEP2: - obj = new IMPDEP2(); - break; - default: - throw new ClassGenException("Illegal opcode detected: " + opcode); + case Const.BIPUSH: + obj = new BIPUSH(); + break; + case Const.SIPUSH: + obj = new SIPUSH(); + break; + case Const.LDC: + obj = new LDC(); + break; + case Const.LDC_W: + obj = new LDC_W(); + break; + case Const.LDC2_W: + obj = new LDC2_W(); + break; + case Const.ILOAD: + obj = new ILOAD(); + break; + case Const.LLOAD: + obj = new LLOAD(); + break; + case Const.FLOAD: + obj = new FLOAD(); + break; + case Const.DLOAD: + obj = new DLOAD(); + break; + case Const.ALOAD: + obj = new ALOAD(); + break; + case Const.ILOAD_0: + obj = new ILOAD(0); + break; + case Const.ILOAD_1: + obj = new ILOAD(1); + break; + case Const.ILOAD_2: + obj = new ILOAD(2); + break; + case Const.ILOAD_3: + obj = new ILOAD(3); + break; + case Const.LLOAD_0: + obj = new LLOAD(0); + break; + case Const.LLOAD_1: + obj = new LLOAD(1); + break; + case Const.LLOAD_2: + obj = new LLOAD(2); + break; + case Const.LLOAD_3: + obj = new LLOAD(3); + break; + case Const.FLOAD_0: + obj = new FLOAD(0); + break; + case Const.FLOAD_1: + obj = new FLOAD(1); + break; + case Const.FLOAD_2: + obj = new FLOAD(2); + break; + case Const.FLOAD_3: + obj = new FLOAD(3); + break; + case Const.DLOAD_0: + obj = new DLOAD(0); + break; + case Const.DLOAD_1: + obj = new DLOAD(1); + break; + case Const.DLOAD_2: + obj = new DLOAD(2); + break; + case Const.DLOAD_3: + obj = new DLOAD(3); + break; + case Const.ALOAD_0: + obj = new ALOAD(0); + break; + case Const.ALOAD_1: + obj = new ALOAD(1); + break; + case Const.ALOAD_2: + obj = new ALOAD(2); + break; + case Const.ALOAD_3: + obj = new ALOAD(3); + break; + case Const.ISTORE: + obj = new ISTORE(); + break; + case Const.LSTORE: + obj = new LSTORE(); + break; + case Const.FSTORE: + obj = new FSTORE(); + break; + case Const.DSTORE: + obj = new DSTORE(); + break; + case Const.ASTORE: + obj = new ASTORE(); + break; + case Const.ISTORE_0: + obj = new ISTORE(0); + break; + case Const.ISTORE_1: + obj = new ISTORE(1); + break; + case Const.ISTORE_2: + obj = new ISTORE(2); + break; + case Const.ISTORE_3: + obj = new ISTORE(3); + break; + case Const.LSTORE_0: + obj = new LSTORE(0); + break; + case Const.LSTORE_1: + obj = new LSTORE(1); + break; + case Const.LSTORE_2: + obj = new LSTORE(2); + break; + case Const.LSTORE_3: + obj = new LSTORE(3); + break; + case Const.FSTORE_0: + obj = new FSTORE(0); + break; + case Const.FSTORE_1: + obj = new FSTORE(1); + break; + case Const.FSTORE_2: + obj = new FSTORE(2); + break; + case Const.FSTORE_3: + obj = new FSTORE(3); + break; + case Const.DSTORE_0: + obj = new DSTORE(0); + break; + case Const.DSTORE_1: + obj = new DSTORE(1); + break; + case Const.DSTORE_2: + obj = new DSTORE(2); + break; + case Const.DSTORE_3: + obj = new DSTORE(3); + break; + case Const.ASTORE_0: + obj = new ASTORE(0); + break; + case Const.ASTORE_1: + obj = new ASTORE(1); + break; + case Const.ASTORE_2: + obj = new ASTORE(2); + break; + case Const.ASTORE_3: + obj = new ASTORE(3); + break; + case Const.IINC: + obj = new IINC(); + break; + case Const.IFEQ: + obj = new IFEQ(); + break; + case Const.IFNE: + obj = new IFNE(); + break; + case Const.IFLT: + obj = new IFLT(); + break; + case Const.IFGE: + obj = new IFGE(); + break; + case Const.IFGT: + obj = new IFGT(); + break; + case Const.IFLE: + obj = new IFLE(); + break; + case Const.IF_ICMPEQ: + obj = new IF_ICMPEQ(); + break; + case Const.IF_ICMPNE: + obj = new IF_ICMPNE(); + break; + case Const.IF_ICMPLT: + obj = new IF_ICMPLT(); + break; + case Const.IF_ICMPGE: + obj = new IF_ICMPGE(); + break; + case Const.IF_ICMPGT: + obj = new IF_ICMPGT(); + break; + case Const.IF_ICMPLE: + obj = new IF_ICMPLE(); + break; + case Const.IF_ACMPEQ: + obj = new IF_ACMPEQ(); + break; + case Const.IF_ACMPNE: + obj = new IF_ACMPNE(); + break; + case Const.GOTO: + obj = new GOTO(); + break; + case Const.JSR: + obj = new JSR(); + break; + case Const.RET: + obj = new RET(); + break; + case Const.TABLESWITCH: + obj = new TABLESWITCH(); + break; + case Const.LOOKUPSWITCH: + obj = new LOOKUPSWITCH(); + break; + case Const.GETSTATIC: + obj = new GETSTATIC(); + break; + case Const.PUTSTATIC: + obj = new PUTSTATIC(); + break; + case Const.GETFIELD: + obj = new GETFIELD(); + break; + case Const.PUTFIELD: + obj = new PUTFIELD(); + break; + case Const.INVOKEVIRTUAL: + obj = new INVOKEVIRTUAL(); + break; + case Const.INVOKESPECIAL: + obj = new INVOKESPECIAL(); + break; + case Const.INVOKESTATIC: + obj = new INVOKESTATIC(); + break; + case Const.INVOKEINTERFACE: + obj = new INVOKEINTERFACE(); + break; + case Const.INVOKEDYNAMIC: + obj = new INVOKEDYNAMIC(); + break; + case Const.NEW: + obj = new NEW(); + break; + case Const.NEWARRAY: + obj = new NEWARRAY(); + break; + case Const.ANEWARRAY: + obj = new ANEWARRAY(); + break; + case Const.CHECKCAST: + obj = new CHECKCAST(); + break; + case Const.INSTANCEOF: + obj = new INSTANCEOF(); + break; + case Const.MULTIANEWARRAY: + obj = new MULTIANEWARRAY(); + break; + case Const.IFNULL: + obj = new IFNULL(); + break; + case Const.IFNONNULL: + obj = new IFNONNULL(); + break; + case Const.GOTO_W: + obj = new GOTO_W(); + break; + case Const.JSR_W: + obj = new JSR_W(); + break; + case Const.BREAKPOINT: + obj = new BREAKPOINT(); + break; + case Const.IMPDEP1: + obj = new IMPDEP1(); + break; + case Const.IMPDEP2: + obj = new IMPDEP2(); + break; + default: + throw new ClassGenException("Illegal opcode detected: " + opcode); } @@ -394,39 +426,6 @@ public abstract class Instruction implements Cloneable { return obj; } - /** - * Sets comparator to be used for equals(). - * - * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods - */ - @Deprecated - public static void setComparator(final InstructionComparator c) { - cmp = c; - } - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected short length = 1; // Length of instruction in bytes - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected short opcode = -1; // Opcode number - - /** - * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. - */ - Instruction() { - } - - public Instruction(final short opcode, final short length) { - this.length = length; - this.opcode = opcode; - } - /** * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call * methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last. @@ -440,7 +439,7 @@ public abstract class Instruction implements Cloneable { * they reference. * * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be - * computed statically + * computed statically */ public int consumeStack(final ConstantPoolGen cpg) { return Const.getConsumeStack(opcode); @@ -450,8 +449,8 @@ public abstract class Instruction implements Cloneable { * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic * types are). This also applies for 'Select' instructions with their multiple branch targets. * - * @see BranchInstruction * @return (shallow) copy of an instruction + * @see BranchInstruction */ public Instruction copy() { Instruction i = null; @@ -501,6 +500,15 @@ public abstract class Instruction implements Cloneable { return length; } + /** + * Needed in readInstruction and subclasses in this package + * + * @since 6.0 + */ + final void setLength(final int length) { + this.length = (short) length; // TODO check range? + } + /** * @return name of instruction, i.e., opcode name */ @@ -515,6 +523,13 @@ public abstract class Instruction implements Cloneable { return opcode; } + /** + * Needed in readInstruction and subclasses in this package + */ + final void setOpcode(final short opcode) { + this.opcode = opcode; + } + /** * Gets the hashCode of this object. * @@ -530,7 +545,7 @@ public abstract class Instruction implements Cloneable { * Reads needed data (e.g. index) from file. * * @param bytes byte sequence to read from - * @param wide "wide" instruction flag + * @param wide "wide" instruction flag * @throws IOException may be thrown if the implementation needs to read data from the file */ @SuppressWarnings("unused") // thrown by subclasses @@ -542,28 +557,12 @@ public abstract class Instruction implements Cloneable { * they reference. * * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this can not be - * computed statically + * computed statically */ public int produceStack(final ConstantPoolGen cpg) { return Const.getProduceStack(opcode); } - /** - * Needed in readInstruction and subclasses in this package - * - * @since 6.0 - */ - final void setLength(final int length) { - this.length = (short) length; // TODO check range? - } - - /** - * Needed in readInstruction and subclasses in this package - */ - final void setOpcode(final short opcode) { - this.opcode = opcode; - } - /** * @return mnemonic for instruction in verbose format */ @@ -574,7 +573,7 @@ public abstract class Instruction implements Cloneable { /** * Long output format: - * + *

* <name of opcode> "["<opcode number>"]" "("<length of instruction>")" * * @param verbose long/short format switch diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java index 3e3834a..d90ba86 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java +++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java @@ -35,7 +35,7 @@ public final class InstructionConst { /** * Predefined instruction objects. - * + *

* NOTE these are not currently immutable, because Instruction has mutable protected fields opcode and length. */ public static final Instruction NOP = new NOP(); @@ -279,6 +279,9 @@ public final class InstructionConst { INSTRUCTIONS[Const.MONITOREXIT] = MONITOREXIT; } + private InstructionConst() { + } // non-instantiable + /** * Gets the Instruction. * @@ -288,7 +291,4 @@ public final class InstructionConst { public static Instruction getInstruction(final int index) { return INSTRUCTIONS[index]; } - - private InstructionConst() { - } // non-instantiable } diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java index bd1e4b6..ab279ac 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java +++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java @@ -30,28 +30,10 @@ import haidnor.jvm.bcel.Const; */ public class InstructionFactory { - private static class MethodObject { - - final Type[] argTypes; - final Type resultType; - final String className; - final String name; - - MethodObject(final String c, final String n, final Type r, final Type[] a) { - this.className = c; - this.name = n; - this.resultType = r; - this.argTypes = a; - } - } - private static final String APPEND = "append"; - private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer"; - // N.N. These must agree with the order of Constants.T_CHAR through T_LONG private static final String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"}; - private static final MethodObject[] appendMethodObjects = { new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.STRING}), new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.OBJECT}), null, null, // indices 2, 3 @@ -63,6 +45,35 @@ public class InstructionFactory { new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.INT}), // No append(byte) new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.INT}), // No append(short) new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.LONG})}; + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected ClassGen cg; + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected ConstantPoolGen cp; + + /** + * Initialize with ClassGen object + */ + public InstructionFactory(final ClassGen cg) { + this(cg, cg.getConstantPool()); + } + + public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) { + this.cg = cg; + this.cp = cp; + } + + /** + * Initialize just with ConstantPoolGen object + */ + public InstructionFactory(final ConstantPoolGen cp) { + this(null, cp); + } /** * @param type type of elements of array, i.e., array.getElementType() @@ -445,37 +456,6 @@ public class InstructionFactory { return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String"); } - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected ClassGen cg; - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected ConstantPoolGen cp; - - /** - * Initialize with ClassGen object - */ - public InstructionFactory(final ClassGen cg) { - this(cg, cg.getConstantPool()); - } - - public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) { - this.cg = cg; - this.cp = cp; - } - - /** - * Initialize just with ConstantPoolGen object - */ - public InstructionFactory(final ConstantPoolGen cp) { - this(null, cp); - } - public Instruction createAppend(final Type type) { final byte t = type.getType(); if (isString(type)) { @@ -720,15 +700,30 @@ public class InstructionFactory { return cg; } - public ConstantPoolGen getConstantPool() { - return cp; - } - public void setClassGen(final ClassGen c) { cg = c; } + public ConstantPoolGen getConstantPool() { + return cp; + } + public void setConstantPool(final ConstantPoolGen c) { cp = c; } + + private static class MethodObject { + + final Type[] argTypes; + final Type resultType; + final String className; + final String name; + + MethodObject(final String c, final String n, final Type r, final Type[] a) { + this.className = c; + this.name = n; + this.resultType = r; + this.argTypes = a; + } + } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java index 1602de7..8c19c87 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java +++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java @@ -23,7 +23,7 @@ import java.util.*; /** * Instances of this class give users a handle to the instructions contained in an InstructionList. Instruction objects * may be used more than once within a list, this is useful because it saves memory and may be much faster. - * + *

* Within an InstructionList an InstructionHandle object is wrapped around all instructions, i.e., it implements a cell * in a doubly-linked list. From the outside only the next and the previous instruction (handle) are accessible. One can * traverse the list via an Enumeration returned by InstructionList.elements(). @@ -45,6 +45,21 @@ public class InstructionHandle { * Empty array. */ static final InstructionTargeter[] EMPTY_INSTRUCTION_TARGETER_ARRAY = {}; + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected int i_position = -1; // byte code offset of instruction + private InstructionHandle next; + private InstructionHandle prev; + + private Instruction instruction; + private Set targeters; + private Map attributes; + + protected InstructionHandle(final Instruction i) { + setInstruction(i); + } /** * Factory method. @@ -53,24 +68,6 @@ public class InstructionHandle { return new InstructionHandle(i); } - private InstructionHandle next; - private InstructionHandle prev; - - private Instruction instruction; - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected int i_position = -1; // byte code offset of instruction - private Set targeters; - - private Map attributes; - - protected InstructionHandle(final Instruction i) { - setInstruction(i); - } - /** * Convenience method, simply calls accept() on the contained instruction. * @@ -83,7 +80,7 @@ public class InstructionHandle { /** * Add an attribute to an instruction handle. * - * @param key the key object to store/retrieve the attribute + * @param key the key object to store/retrieve the attribute * @param attr the attribute to associate with this handle */ public void addAttribute(final Object key, final Object attr) { @@ -152,22 +149,63 @@ public class InstructionHandle { return instruction; } + /** + * Replace current instruction contained in this handle. Old instruction is disposed using Instruction.dispose(). + */ + public void setInstruction(final Instruction i) { // Overridden in BranchHandle TODO could be package-protected? + if (i == null) { + throw new ClassGenException("Assigning null to handle"); + } + if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) { + throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); + } + if (instruction != null) { + instruction.dispose(); + } + instruction = i; + } + public final InstructionHandle getNext() { return next; } + /** + * @param next the next to set + * @since 6.0 + */ + final InstructionHandle setNext(final InstructionHandle next) { + this.next = next; + return next; + } + /** * @return the position, i.e., the byte code offset of the contained instruction. This is accurate only after - * InstructionList.setPositions() has been called. + * InstructionList.setPositions() has been called. */ public int getPosition() { return i_position; } + /** + * Set the position, i.e., the byte code offset of the contained instruction. + */ + void setPosition(final int pos) { + i_position = pos; + } + public final InstructionHandle getPrev() { return prev; } + /** + * @param prev the prev to set + * @since 6.0 + */ + final InstructionHandle setPrev(final InstructionHandle prev) { + this.prev = prev; + return prev; + } + /** * @return null, if there are no targeters */ @@ -213,47 +251,6 @@ public class InstructionHandle { } } - /** - * Replace current instruction contained in this handle. Old instruction is disposed using Instruction.dispose(). - */ - public void setInstruction(final Instruction i) { // Overridden in BranchHandle TODO could be package-protected? - if (i == null) { - throw new ClassGenException("Assigning null to handle"); - } - if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) { - throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); - } - if (instruction != null) { - instruction.dispose(); - } - instruction = i; - } - - /** - * @param next the next to set - * @since 6.0 - */ - final InstructionHandle setNext(final InstructionHandle next) { - this.next = next; - return next; - } - - /** - * Set the position, i.e., the byte code offset of the contained instruction. - */ - void setPosition(final int pos) { - i_position = pos; - } - - /** - * @param prev the prev to set - * @since 6.0 - */ - final InstructionHandle setPrev(final InstructionHandle prev) { - this.prev = prev; - return prev; - } - /** * Temporarily swap the current instruction, without disturbing anything. Meant to be used by a debugger, implementing * breakpoints. Current instruction is returned. @@ -289,7 +286,7 @@ public class InstructionHandle { * length instructions 'setPositions()' performs multiple passes over the instruction list to calculate the correct * (byte) positions and offsets by calling this function. * - * @param offset additional offset caused by preceding (variable length) instructions + * @param offset additional offset caused by preceding (variable length) instructions * @param maxOffset the maximum offset that may be caused by these instructions * @return additional offset caused by possible change of this instruction's length */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java index 92a14d3..2642714 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java +++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java @@ -32,7 +32,7 @@ import java.util.*; * InstructionHandles objects that are returned upon append/insert operations. They * give the user (read only) access to the list structure, such that it can be traversed and manipulated in a controlled * way. - * + *

* A list is finally dumped to a byte code array with getByteCode. * * @see Instruction @@ -41,42 +41,10 @@ import java.util.*; */ public class InstructionList implements Iterable { - /** - * Find the target instruction (handle) that corresponds to the given target position (byte code offset). - * - * @param ihs array of instruction handles, i.e. il.getInstructionHandles() - * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions() - * @param count length of arrays - * @param target target position to search for - * @return target position's instruction handle if available - */ - public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) { - int l = 0; - int r = count - 1; - /* - * Do a binary search since the pos array is orderd. - */ - do { - final int i = l + r >>> 1; - final int j = pos[i]; - if (j == target) { - return ihs[i]; - } - if (target < j) { - r = i - 1; - } else { - l = i + 1; - } - } while (l <= r); - return null; - } - private InstructionHandle start; private InstructionHandle end; private int length; // number of elements in list - private int[] bytePositions; // byte code offsets corresponding to instructions - private List observers; /** @@ -138,8 +106,8 @@ public class InstructionList implements Iterable { if (ihs[i] instanceof BranchHandle) { final BranchInstruction bi = (BranchInstruction) ihs[i].getInstruction(); int target = bi.getPosition() + bi.getIndex(); /* - * Byte code position: relative -> absolute. - */ + * Byte code position: relative -> absolute. + */ // Search for target position InstructionHandle ih = findHandle(ihs, pos, count, target); if (ih == null) { @@ -181,6 +149,36 @@ public class InstructionList implements Iterable { append(i); } + /** + * Find the target instruction (handle) that corresponds to the given target position (byte code offset). + * + * @param ihs array of instruction handles, i.e. il.getInstructionHandles() + * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions() + * @param count length of arrays + * @param target target position to search for + * @return target position's instruction handle if available + */ + public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) { + int l = 0; + int r = count - 1; + /* + * Do a binary search since the pos array is orderd. + */ + do { + final int i = l + r >>> 1; + final int j = pos[i]; + if (j == target) { + return ihs[i]; + } + if (target < j) { + r = i - 1; + } else { + l = i + 1; + } + } while (l <= r); + return null; + } + /** * Add observer for this object. */ @@ -250,7 +248,7 @@ public class InstructionList implements Iterable { /** * Append another list after instruction i contained in this list. Consumes argument list, i.e., it becomes empty. * - * @param i where to append the instruction list + * @param i where to append the instruction list * @param il Instruction list to append to this one * @return instruction handle pointing to the first appended instruction */ @@ -284,7 +282,7 @@ public class InstructionList implements Iterable { * Append an instruction after instruction (handle) ih contained in this list. * * @param ih where to append the instruction list - * @param i Instruction to append + * @param i Instruction to append * @return instruction handle pointing to the first appended instruction */ public BranchHandle append(final InstructionHandle ih, final BranchInstruction i) { @@ -299,7 +297,7 @@ public class InstructionList implements Iterable { * Append a compound instruction. * * @param ih where to append the instruction list - * @param c The composite instruction (containing an InstructionList) + * @param c The composite instruction (containing an InstructionList) * @return instruction handle of the first appended instruction */ public InstructionHandle append(final InstructionHandle ih, final CompoundInstruction c) { @@ -310,7 +308,7 @@ public class InstructionList implements Iterable { * Append an instruction after instruction (handle) ih contained in this list. * * @param ih where to append the instruction list - * @param i Instruction to append + * @param i Instruction to append * @return instruction handle pointing to the first appended instruction */ public InstructionHandle append(final InstructionHandle ih, final Instruction i) { @@ -456,7 +454,7 @@ public class InstructionList implements Iterable { * 'from' is an instruction before 'to', or risk havoc. The corresponding Instruction handles must not be reused! * * @param from where to start deleting (inclusive) - * @param to where to end deleting (inclusive) + * @param to where to end deleting (inclusive) */ public void delete(final Instruction from, final Instruction to) throws TargetLostException { InstructionHandle fromIh; @@ -484,7 +482,7 @@ public class InstructionList implements Iterable { * 'from' is an instruction before 'to', or risk havoc. The corresponding Instruction handles must not be reused! * * @param from where to start deleting (inclusive) - * @param to where to end deleting (inclusive) + * @param to where to end deleting (inclusive) */ public void delete(final InstructionHandle from, final InstructionHandle to) throws TargetLostException { remove(from.getPrev(), to.getNext()); @@ -693,7 +691,7 @@ public class InstructionList implements Iterable { /** * Insert another list before Instruction i contained in this list. Consumes argument list, i.e., it becomes empty. * - * @param i where to append the instruction list + * @param i where to append the instruction list * @param il Instruction list to insert * @return instruction handle pointing to the first inserted instruction, i.e., il.getStart() */ @@ -727,7 +725,7 @@ public class InstructionList implements Iterable { * Insert an instruction before instruction (handle) ih contained in this list. * * @param ih where to insert to the instruction list - * @param i Instruction to insert + * @param i Instruction to insert * @return instruction handle of the first inserted instruction */ public BranchHandle insert(final InstructionHandle ih, final BranchInstruction i) { @@ -742,7 +740,7 @@ public class InstructionList implements Iterable { * Insert a compound instruction. * * @param ih where to insert the instruction list - * @param c The composite instruction (containing an InstructionList) + * @param c The composite instruction (containing an InstructionList) * @return instruction handle of the first inserted instruction */ public InstructionHandle insert(final InstructionHandle ih, final CompoundInstruction c) { @@ -753,7 +751,7 @@ public class InstructionList implements Iterable { * Insert an instruction before instruction (handle) ih contained in this list. * * @param ih where to insert to the instruction list - * @param i Instruction to insert + * @param i Instruction to insert * @return instruction handle of the first inserted instruction */ public InstructionHandle insert(final InstructionHandle ih, final Instruction i) { @@ -845,7 +843,7 @@ public class InstructionList implements Iterable { /** * Move a single instruction (handle) to a new location. * - * @param ih moved instruction + * @param ih moved instruction * @param target new location of moved instruction */ public void move(final InstructionHandle ih, final InstructionHandle target) { @@ -860,8 +858,8 @@ public class InstructionList implements Iterable { * Any instruction targeters pointing to handles within the block, keep their targets. *

* - * @param start of moved block - * @param end of moved block + * @param start of moved block + * @param end of moved block * @param target of moved block */ public void move(final InstructionHandle start, final InstructionHandle end, final InstructionHandle target) { @@ -945,8 +943,8 @@ public class InstructionList implements Iterable { * Redirect all references of exception handlers from oldTarget to newTarget. * * @param exceptions array of exception handlers - * @param oldTarget the old target instruction handle - * @param newTarget the new target instruction handle + * @param oldTarget the old target instruction handle + * @param newTarget the new target instruction handle * @see MethodGen */ public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) { @@ -966,7 +964,7 @@ public class InstructionList implements Iterable { /** * Redirect all references of local variables from oldTarget to newTarget. * - * @param lg array of local variables + * @param lg array of local variables * @param oldTarget the old target instruction handle * @param newTarget the new target instruction handle * @see MethodGen @@ -1098,7 +1096,7 @@ public class InstructionList implements Iterable { } if (!(ih instanceof BranchHandle)) { throw new ClassGenException( - "Branch instruction " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not contained in BranchHandle."); + "Branch instruction " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not contained in BranchHandle."); } } } @@ -1115,14 +1113,14 @@ public class InstructionList implements Iterable { * depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH). */ switch (i.getOpcode()) { - case Const.JSR: - case Const.GOTO: - maxAdditionalBytes += 2; - break; - case Const.TABLESWITCH: - case Const.LOOKUPSWITCH: - maxAdditionalBytes += 3; - break; + case Const.JSR: + case Const.GOTO: + maxAdditionalBytes += 2; + break; + case Const.TABLESWITCH: + case Const.LOOKUPSWITCH: + maxAdditionalBytes += 3; + break; } index += i.getLength(); } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LADD.java b/src/main/java/haidnor/jvm/bcel/generic/LADD.java index a633bfb..6d8e809 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LADD.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LADD.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *
  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class LADD extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/LAND.java b/src/main/java/haidnor/jvm/bcel/generic/LAND.java index 8c11081..7676850 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LAND.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LAND.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class LAND extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/LCMP.java b/src/main/java/haidnor/jvm/bcel/generic/LCMP.java index 487bf67..ac233a2 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LCMP.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LCMP.java @@ -24,7 +24,6 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -> ..., result <= -1, 0, 1>
  * 
- * */ public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer { diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDC.java b/src/main/java/haidnor/jvm/bcel/generic/LDC.java index 1b1fa6d..eb772e2 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LDC.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LDC.java @@ -83,36 +83,36 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro @Override public Type getType(final ConstantPoolGen cpg) { switch (cpg.getConstantPool().getConstant(super.getIndex()).getTag()) { - case Const.CONSTANT_String: - return Type.STRING; - case Const.CONSTANT_Float: - return Type.FLOAT; - case Const.CONSTANT_Integer: - return Type.INT; - case Const.CONSTANT_Class: - return Type.CLASS; - default: // Never reached - throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); + case Const.CONSTANT_String: + return Type.STRING; + case Const.CONSTANT_Float: + return Type.FLOAT; + case Const.CONSTANT_Integer: + return Type.INT; + case Const.CONSTANT_Class: + return Type.CLASS; + default: // Never reached + throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } } public Object getValue(final ConstantPoolGen cpg) { Constant c = cpg.getConstantPool().getConstant(super.getIndex()); switch (c.getTag()) { - case Const.CONSTANT_String: - final int i = ((ConstantString) c).getStringIndex(); - c = cpg.getConstantPool().getConstant(i); - return ((ConstantUtf8) c).getBytes(); - case Const.CONSTANT_Float: - return Float.valueOf(((ConstantFloat) c).getBytes()); - case Const.CONSTANT_Integer: - return Integer.valueOf(((ConstantInteger) c).getBytes()); - case Const.CONSTANT_Class: - final int nameIndex = ((ConstantClass) c).getNameIndex(); - c = cpg.getConstantPool().getConstant(nameIndex); - return Type.getType(((ConstantUtf8) c).getBytes()); - default: // Never reached - throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); + case Const.CONSTANT_String: + final int i = ((ConstantString) c).getStringIndex(); + c = cpg.getConstantPool().getConstant(i); + return ((ConstantUtf8) c).getBytes(); + case Const.CONSTANT_Float: + return Float.valueOf(((ConstantFloat) c).getBytes()); + case Const.CONSTANT_Integer: + return Integer.valueOf(((ConstantInteger) c).getBytes()); + case Const.CONSTANT_Class: + final int nameIndex = ((ConstantClass) c).getNameIndex(); + c = cpg.getConstantPool().getConstant(nameIndex); + return Type.getType(((ConstantUtf8) c).getBytes()); + default: // Never reached + throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java b/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java index 579b0ab..2450be0 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java @@ -58,24 +58,24 @@ public class LDC2_W extends CPInstruction implements PushInstruction { @Override public Type getType(final ConstantPoolGen cpg) { switch (cpg.getConstantPool().getConstant(super.getIndex()).getTag()) { - case Const.CONSTANT_Long: - return Type.LONG; - case Const.CONSTANT_Double: - return Type.DOUBLE; - default: // Never reached - throw new IllegalArgumentException("Unknown constant type " + super.getOpcode()); + case Const.CONSTANT_Long: + return Type.LONG; + case Const.CONSTANT_Double: + return Type.DOUBLE; + default: // Never reached + throw new IllegalArgumentException("Unknown constant type " + super.getOpcode()); } } public Number getValue(final ConstantPoolGen cpg) { final Constant c = cpg.getConstantPool().getConstant(super.getIndex()); switch (c.getTag()) { - case Const.CONSTANT_Long: - return Long.valueOf(((ConstantLong) c).getBytes()); - case Const.CONSTANT_Double: - return Double.valueOf(((ConstantDouble) c).getBytes()); - default: // Never reached - throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); + case Const.CONSTANT_Long: + return Long.valueOf(((ConstantLong) c).getBytes()); + case Const.CONSTANT_Double: + return Double.valueOf(((ConstantDouble) c).getBytes()); + default: // Never reached + throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDIV.java b/src/main/java/haidnor/jvm/bcel/generic/LDIV.java index be20296..4781b00 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LDIV.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LDIV.java @@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst; *
  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class LDIV extends ArithmeticInstruction implements ExceptionThrower { @@ -52,6 +52,6 @@ public class LDIV extends ArithmeticInstruction implements ExceptionThrower { @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; + return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LMUL.java b/src/main/java/haidnor/jvm/bcel/generic/LMUL.java index 4b60c17..a2f9a1a 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LMUL.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LMUL.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class LMUL extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/LREM.java b/src/main/java/haidnor/jvm/bcel/generic/LREM.java index 22f164e..cfba075 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LREM.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LREM.java @@ -50,6 +50,6 @@ public class LREM extends ArithmeticInstruction implements ExceptionThrower { @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; + return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LSUB.java b/src/main/java/haidnor/jvm/bcel/generic/LSUB.java index e81bcdd..9e947cc 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LSUB.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LSUB.java @@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const; *

  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
  * 
- * + *

* ..., result.word1, result.word2 */ public class LSUB extends ArithmeticInstruction { diff --git a/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java b/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java index 4376c5d..e7d2c88 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java @@ -65,9 +65,15 @@ public class LineNumberGen implements InstructionTargeter, Cloneable { return ih; } + public void setInstruction(final InstructionHandle instructionHandle) { // TODO could be package-protected? + Objects.requireNonNull(instructionHandle, "instructionHandle"); + BranchInstruction.notifyTarget(this.ih, instructionHandle, this); + this.ih = instructionHandle; + } + /** * Get LineNumber attribute. - * + *

* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. */ @@ -79,12 +85,6 @@ public class LineNumberGen implements InstructionTargeter, Cloneable { return srcLine; } - public void setInstruction(final InstructionHandle instructionHandle) { // TODO could be package-protected? - Objects.requireNonNull(instructionHandle, "instructionHandle"); - BranchInstruction.notifyTarget(this.ih, instructionHandle, this); - this.ih = instructionHandle; - } - public void setSourceLine(final int srcLine) { // TODO could be package-protected? this.srcLine = srcLine; } diff --git a/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java index f79c968..9c97372 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java @@ -31,8 +31,8 @@ public abstract class LoadInstruction extends LocalVariableInstruction implement /** * @param opcode Instruction opcode - * @param cTag Instruction number for compact version, ALOAD_0, e.g. - * @param n local variable index (unsigned short) + * @param cTag Instruction number for compact version, ALOAD_0, e.g. + * @param n local variable index (unsigned short) */ protected LoadInstruction(final short opcode, final short cTag, final int n) { super(opcode, cTag, n); diff --git a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java index 0c6bcb1..a5c2a37 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java @@ -41,10 +41,10 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo * have to be provided by the user. * * @param index index of local variable - * @param name its name - * @param type its type + * @param name its name + * @param type its type * @param start from where the instruction is valid (null means from the start) - * @param end until where the instruction is valid (null means to the end) + * @param end until where the instruction is valid (null means to the end) */ public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end) { if (index < 0 || index > Const.MAX_SHORT) { @@ -63,15 +63,15 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo * Generates a local variable that with index 'index'. Note that double and long variables need two indexs. Index * indices have to be provided by the user. * - * @param index index of local variable - * @param name its name - * @param type its type - * @param start from where the instruction is valid (null means from the start) - * @param end until where the instruction is valid (null means to the end) + * @param index index of local variable + * @param name its name + * @param type its type + * @param start from where the instruction is valid (null means from the start) + * @param end until where the instruction is valid (null means to the end) * @param origIndex index of local variable prior to any changes to index */ public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end, - final int origIndex) { + final int origIndex) { this(index, name, type, start, end); this.origIndex = origIndex; } @@ -117,20 +117,33 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo return end; } + public void setEnd(final InstructionHandle end) { // TODO could be package-protected? + BranchInstruction.notifyTarget(this.end, end, this); + this.end = end; + } + public int getIndex() { return index; } + public void setIndex(final int index) { + this.index = index; + } + public boolean getLiveToEnd() { return liveToEnd; } + public void setLiveToEnd(final boolean liveToEnd) { + this.liveToEnd = liveToEnd; + } + /** * Gets LocalVariable object. - * + *

* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. - * + *

* Note that due to the conversion from byte code offset to InstructionHandle, it is impossible to tell the difference * between a live range that ends BEFORE the last insturction of the method or a live range that ends AFTER the last * instruction of the method. Hence the liveToEnd flag to differentiate between these two cases. @@ -157,6 +170,11 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo return name; } + @Override + public void setName(final String name) { + this.name = name; + } + public int getOrigIndex() { return origIndex; } @@ -165,11 +183,21 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo return start; } + public void setStart(final InstructionHandle start) { // TODO could be package-protected? + BranchInstruction.notifyTarget(this.start, start, this); + this.start = start; + } + @Override public Type getType() { return type; } + @Override + public void setType(final Type type) { + this.type = type; + } + @Override public int hashCode() { // If the user changes the name or type, problems with the targeter hashmap will occur. @@ -177,34 +205,6 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo return name.hashCode() ^ type.hashCode(); } - public void setEnd(final InstructionHandle end) { // TODO could be package-protected? - BranchInstruction.notifyTarget(this.end, end, this); - this.end = end; - } - - public void setIndex(final int index) { - this.index = index; - } - - public void setLiveToEnd(final boolean liveToEnd) { - this.liveToEnd = liveToEnd; - } - - @Override - public void setName(final String name) { - this.name = name; - } - - public void setStart(final InstructionHandle start) { // TODO could be package-protected? - BranchInstruction.notifyTarget(this.start, start, this); - this.start = start; - } - - @Override - public void setType(final Type type) { - this.type = type; - } - @Override public String toString() { return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; diff --git a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java index cde6f91..6f29232 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java @@ -53,8 +53,8 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty /** * @param opcode Instruction opcode - * @param cTag Instruction number for compact version, ALOAD_0, e.g. - * @param n local variable index (unsigned short) + * @param cTag Instruction number for compact version, ALOAD_0, e.g. + * @param n local variable index (unsigned short) */ protected LocalVariableInstruction(final short opcode, final short cTag, final int n) { super(opcode, (short) 2); @@ -98,6 +98,31 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty return n; } + /** + * Set the local variable index. also updates opcode and length TODO Why? + * + * @see #setIndexOnly(int) + */ + @Override + public void setIndex(final int n) { // TODO could be package-protected? + if (n < 0 || n > Const.MAX_SHORT) { + throw new ClassGenException("Illegal value: " + n); + } + this.n = n; + // Cannot be < 0 as this is checked above + if (n <= 3) { // Use more compact instruction xLOAD_n + super.setOpcode((short) (cTag + n)); + super.setLength(1); + } else { + super.setOpcode(canonTag); + if (wide()) { + super.setLength(4); + } else { + super.setLength(2); + } + } + } + /** * Returns the type associated with the instruction - in case of ALOAD or ASTORE Type.OBJECT is returned. This is just a * bit incorrect, because ALOAD and ASTORE may work on every ReferenceType (including Type.NULL) and ASTORE may even @@ -108,23 +133,23 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty @Override public Type getType(final ConstantPoolGen cp) { switch (canonTag) { - case Const.ILOAD: - case Const.ISTORE: - return Type.INT; - case Const.LLOAD: - case Const.LSTORE: - return Type.LONG; - case Const.DLOAD: - case Const.DSTORE: - return Type.DOUBLE; - case Const.FLOAD: - case Const.FSTORE: - return Type.FLOAT; - case Const.ALOAD: - case Const.ASTORE: - return Type.OBJECT; - default: - throw new ClassGenException("Unknown case in switch" + canonTag); + case Const.ILOAD: + case Const.ISTORE: + return Type.INT; + case Const.LLOAD: + case Const.LSTORE: + return Type.LONG; + case Const.DLOAD: + case Const.DSTORE: + return Type.DOUBLE; + case Const.FLOAD: + case Const.FSTORE: + return Type.FLOAT; + case Const.ALOAD: + case Const.ASTORE: + return Type.OBJECT; + default: + throw new ClassGenException("Unknown case in switch" + canonTag); } } @@ -156,36 +181,11 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty } } - /** - * Set the local variable index. also updates opcode and length TODO Why? - * - * @see #setIndexOnly(int) - */ - @Override - public void setIndex(final int n) { // TODO could be package-protected? - if (n < 0 || n > Const.MAX_SHORT) { - throw new ClassGenException("Illegal value: " + n); - } - this.n = n; - // Cannot be < 0 as this is checked above - if (n <= 3) { // Use more compact instruction xLOAD_n - super.setOpcode((short) (cTag + n)); - super.setLength(1); - } else { - super.setOpcode(canonTag); - if (wide()) { - super.setLength(4); - } else { - super.setLength(2); - } - } - } - /** * Sets the index of the referenced variable (n) only * - * @since 6.0 * @see #setIndex(int) + * @since 6.0 */ final void setIndexOnly(final int n) { this.n = n; @@ -193,7 +193,7 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty /** * Long output format: - * + *

* <name of opcode> "["<opcode number>"]" "("<length of instruction>")" "<"< local variable * index>">" * diff --git a/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java b/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java index 6c801f0..a8527ef 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java +++ b/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java @@ -47,6 +47,6 @@ public class MONITORENTER extends Instruction implements ExceptionThrower, Stack @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION}; + return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java b/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java index 543ca18..437e72a 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java +++ b/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java @@ -47,6 +47,6 @@ public class MONITOREXIT extends Instruction implements ExceptionThrower, StackC @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION}; + return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION}; } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java b/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java index 9cb0658..c535d2c 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java +++ b/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java @@ -98,7 +98,7 @@ public class MULTIANEWARRAY extends CPInstruction implements LoadClass, Allocati @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION, ExceptionConst.ILLEGAL_ACCESS_ERROR, - ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION); + ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION); } @Override diff --git a/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java b/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java index 20a278a..79180e5 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java @@ -27,7 +27,7 @@ import java.util.*; * Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local * variables and attributes, whereas the 'LocalVariableTable' and 'LineNumberTable' attributes will be set automatically * for the code. Use stripAttributes() if you don't like this. - * + *

* While generating code it may be necessary to insert NOP operations. You can use the 'removeNOPs' method to get rid * off them. The resulting method object can be obtained via the 'getMethod()' method. * @@ -36,47 +36,6 @@ import java.util.*; */ public class MethodGen extends FieldGenOrMethodGen { - static final class BranchStack { - - private final Stack branchTargets = new Stack<>(); - private final Hashtable visitedTargets = new Hashtable<>(); - - public BranchTarget pop() { - if (!branchTargets.empty()) { - return branchTargets.pop(); - } - return null; - } - - public void push(final InstructionHandle target, final int stackDepth) { - if (visited(target)) { - return; - } - branchTargets.push(visit(target, stackDepth)); - } - - private BranchTarget visit(final InstructionHandle target, final int stackDepth) { - final BranchTarget bt = new BranchTarget(target, stackDepth); - visitedTargets.put(target, bt); - return bt; - } - - private boolean visited(final InstructionHandle target) { - return visitedTargets.get(target) != null; - } - } - - static final class BranchTarget { - - final InstructionHandle target; - final int stackDepth; - - BranchTarget(final InstructionHandle target, final int stackDepth) { - this.target = target; - this.stackDepth = stackDepth; - } - } - private static BCELComparator bcelComparator = new BCELComparator() { @Override @@ -92,147 +51,43 @@ public class MethodGen extends FieldGenOrMethodGen { return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; - - private static byte[] getByteCodes(final JavaMethod method) { - final Code code = method.getCode(); - if (code == null) { - throw new IllegalStateException(String.format("The method '%s' has no code.", method)); - } - return code.getCode(); - } - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { - return bcelComparator; - } - - /** - * Computes stack usage of an instruction list by performing control flow analysis. - * - * @return maximum stack depth used by method - */ - public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) { - final BranchStack branchTargets = new BranchStack(); - /* - * Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to - * explicitly. in each case, the stack will have depth 1, containing the exception object. - */ - for (final CodeExceptionGen element : et) { - final InstructionHandle handlerPc = element.getHandlerPC(); - if (handlerPc != null) { - branchTargets.push(handlerPc, 1); - } - } - int stackDepth = 0; - int maxStackDepth = 0; - InstructionHandle ih = il.getStart(); - while (ih != null) { - final Instruction instruction = ih.getInstruction(); - final short opcode = instruction.getOpcode(); - final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp); - stackDepth += delta; - if (stackDepth > maxStackDepth) { - maxStackDepth = stackDepth; - } - // choose the next instruction based on whether current is a branch. - if (instruction instanceof BranchInstruction) { - final BranchInstruction branch = (BranchInstruction) instruction; - if (instruction instanceof Select) { - // explore all of the select's targets. the default target is handled below. - final Select select = (Select) branch; - final InstructionHandle[] targets = select.getTargets(); - for (final InstructionHandle target : targets) { - branchTargets.push(target, stackDepth); - } - // nothing to fall through to. - ih = null; - } else if (!(branch instanceof IfInstruction)) { - // if an instruction that comes back to following PC, - // push next instruction, with stack depth reduced by 1. - if (opcode == Const.JSR || opcode == Const.JSR_W) { - branchTargets.push(ih.getNext(), stackDepth - 1); - } - ih = null; - } - // for all branches, the target of the branch is pushed on the branch stack. - // conditional branches have a fall through case, selects don't, and - // jsr/jsr_w return to the next instruction. - branchTargets.push(branch.getTarget(), stackDepth); - } else // check for instructions that terminate the method. - if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) { - ih = null; - } - // normal case, go to the next instruction. - if (ih != null) { - ih = ih.getNext(); - } - // if we have no more instructions, see if there are any deferred branches to explore. - if (ih == null) { - final BranchTarget bt = branchTargets.pop(); - if (bt != null) { - ih = bt.target; - stackDepth = bt.stackDepth; - } - } - } - return maxStackDepth; - } - - /** - * @param comparator Comparison strategy object - */ - public static void setComparator(final BCELComparator comparator) { - bcelComparator = comparator; - } - + private final List variableList = new ArrayList<>(); + private final List lineNumberList = new ArrayList<>(); + private final List exceptionList = new ArrayList<>(); + private final List throwsList = new ArrayList<>(); + private final List codeAttrsList = new ArrayList<>(); private String className; private Type[] argTypes; private String[] argNames; private int maxLocals; private int maxStack; private InstructionList il; - private boolean stripAttributes; private LocalVariableTypeTable localVariableTypeTable; - private final List variableList = new ArrayList<>(); - - private final List lineNumberList = new ArrayList<>(); - - private final List exceptionList = new ArrayList<>(); - - private final List throwsList = new ArrayList<>(); - - private final List codeAttrsList = new ArrayList<>(); - private List[] paramAnnotations; // Array of lists containing AnnotationGen objects - private boolean hasParameterAnnotations; - private boolean haveUnpackedParameterAnnotations; - private List observers; /** * Declare method. If the method is non-static the constructor automatically declares a local variable '$this' in slot * 0. The actual code is contained in the 'il' parameter, which may further manipulated by the user. But they must take * care not to remove any instruction (handles) that are still referenced from this object. - * + *

* For example one may not add a local variable and later remove the instructions it refers to without causing havoc. It * is safe however if you remove that local variable, too. * * @param accessFlags access qualifiers - * @param returnType method type - * @param argTypes argument types - * @param argNames argument names (if this is null, default names will be provided for them) - * @param methodName name of method - * @param className class name containing this method (may be null, if you don't care) - * @param il instruction list associated with this method, may be null only for abstract or native methods - * @param cp constant pool + * @param returnType method type + * @param argTypes argument types + * @param argNames argument names (if this is null, default names will be provided for them) + * @param methodName name of method + * @param className class name containing this method (may be null, if you don't care) + * @param il instruction list associated with this method, may be null only for abstract or native methods + * @param cp constant pool */ public MethodGen(final int accessFlags, final Type returnType, final Type[] argTypes, String[] argNames, final String methodName, final String className, - final InstructionList il, final ConstantPoolGen cp) { + final InstructionList il, final ConstantPoolGen cp) { super(accessFlags); setType(returnType); setArgumentTypes(argTypes); @@ -283,15 +138,15 @@ public class MethodGen extends FieldGenOrMethodGen { /** * Instantiate from existing method. * - * @param method method + * @param method method * @param className class name containing this method - * @param cp constant pool + * @param cp constant pool */ public MethodGen(final JavaMethod method, final String className, final ConstantPoolGen cp) { this(method.getAccessFlags(), Type.getReturnType(method.getSignature()), Type.getArgumentTypes(method.getSignature()), - null /* may be overridden anyway */ - , method.getName(), className, - (method.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0 ? new InstructionList(getByteCodes(method)) : null, cp); + null /* may be overridden anyway */ + , method.getName(), className, + (method.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0 ? new InstructionList(getByteCodes(method)) : null, cp); final Attribute[] attributes = method.getAttributes(); for (final Attribute attribute : attributes) { Attribute a = attribute; @@ -349,6 +204,100 @@ public class MethodGen extends FieldGenOrMethodGen { } } + private static byte[] getByteCodes(final JavaMethod method) { + final Code code = method.getCode(); + if (code == null) { + throw new IllegalStateException(String.format("The method '%s' has no code.", method)); + } + return code.getCode(); + } + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + + /** + * Computes stack usage of an instruction list by performing control flow analysis. + * + * @return maximum stack depth used by method + */ + public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) { + final BranchStack branchTargets = new BranchStack(); + /* + * Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to + * explicitly. in each case, the stack will have depth 1, containing the exception object. + */ + for (final CodeExceptionGen element : et) { + final InstructionHandle handlerPc = element.getHandlerPC(); + if (handlerPc != null) { + branchTargets.push(handlerPc, 1); + } + } + int stackDepth = 0; + int maxStackDepth = 0; + InstructionHandle ih = il.getStart(); + while (ih != null) { + final Instruction instruction = ih.getInstruction(); + final short opcode = instruction.getOpcode(); + final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp); + stackDepth += delta; + if (stackDepth > maxStackDepth) { + maxStackDepth = stackDepth; + } + // choose the next instruction based on whether current is a branch. + if (instruction instanceof BranchInstruction) { + final BranchInstruction branch = (BranchInstruction) instruction; + if (instruction instanceof Select) { + // explore all of the select's targets. the default target is handled below. + final Select select = (Select) branch; + final InstructionHandle[] targets = select.getTargets(); + for (final InstructionHandle target : targets) { + branchTargets.push(target, stackDepth); + } + // nothing to fall through to. + ih = null; + } else if (!(branch instanceof IfInstruction)) { + // if an instruction that comes back to following PC, + // push next instruction, with stack depth reduced by 1. + if (opcode == Const.JSR || opcode == Const.JSR_W) { + branchTargets.push(ih.getNext(), stackDepth - 1); + } + ih = null; + } + // for all branches, the target of the branch is pushed on the branch stack. + // conditional branches have a fall through case, selects don't, and + // jsr/jsr_w return to the next instruction. + branchTargets.push(branch.getTarget(), stackDepth); + } else // check for instructions that terminate the method. + if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) { + ih = null; + } + // normal case, go to the next instruction. + if (ih != null) { + ih = ih.getNext(); + } + // if we have no more instructions, see if there are any deferred branches to explore. + if (ih == null) { + final BranchTarget bt = branchTargets.pop(); + if (bt != null) { + ih = bt.target; + stackDepth = bt.stackDepth; + } + } + } + return maxStackDepth; + } + /** * @since 6.0 */ @@ -380,14 +329,14 @@ public class MethodGen extends FieldGenOrMethodGen { * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling * is done. * - * @param startPc Start of region (inclusive) - * @param endPc End of region (inclusive) + * @param startPc Start of region (inclusive) + * @param endPc End of region (inclusive) * @param handlerPc Where handling is done * @param catchType class type of handled exception or null if any exception is handled * @return new exception handler object */ public CodeExceptionGen addExceptionHandler(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc, - final ObjectType catchType) { + final ObjectType catchType) { if (startPc == null || endPc == null || handlerPc == null) { throw new ClassGenException("Exception handler target is null instruction"); } @@ -412,10 +361,10 @@ public class MethodGen extends FieldGenOrMethodGen { /** * Adds a local variable to this method and assigns an index automatically. * - * @param name variable name - * @param type variable type + * @param name variable name + * @param type variable type * @param start from where the variable is valid, if this is null, it is valid from the start - * @param end until where the variable is valid, if this is null, it is valid to the end + * @param end until where the variable is valid, if this is null, it is valid to the end * @return new local variable object * @see LocalVariable */ @@ -426,11 +375,11 @@ public class MethodGen extends FieldGenOrMethodGen { /** * Adds a local variable to this method. * - * @param name variable name - * @param type variable type - * @param slot the index of the local variable, if type is long or double, the next available index is slot+2 + * @param name variable name + * @param type variable type + * @param slot the index of the local variable, if type is long or double, the next available index is slot+2 * @param start from where the variable is valid - * @param end until where the variable is valid + * @param end until where the variable is valid * @return new local variable object * @see LocalVariable */ @@ -441,17 +390,17 @@ public class MethodGen extends FieldGenOrMethodGen { /** * Adds a local variable to this method. * - * @param name variable name - * @param type variable type - * @param slot the index of the local variable, if type is long or double, the next available index is slot+2 - * @param start from where the variable is valid - * @param end until where the variable is valid + * @param name variable name + * @param type variable type + * @param slot the index of the local variable, if type is long or double, the next available index is slot+2 + * @param start from where the variable is valid + * @param end until where the variable is valid * @param origIndex the index of the local variable prior to any modifications * @return new local variable object * @see LocalVariable */ public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, final InstructionHandle start, final InstructionHandle end, - final int origIndex) { + final int origIndex) { final byte t = type.getType(); if (t != Const.T_ADDRESS) { final int add = type.getSize(); @@ -614,8 +563,6 @@ public class MethodGen extends FieldGenOrMethodGen { return bcelComparator.equals(this, obj); } - // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this - // is more likely to suggest to the caller it is readonly (which a List does not). /** * Return a list of AnnotationGen objects representing parameter annotations * @@ -633,10 +580,17 @@ public class MethodGen extends FieldGenOrMethodGen { return argNames[i]; } + // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this + // is more likely to suggest to the caller it is readonly (which a List does not). + public String[] getArgumentNames() { return argNames.clone(); } + public void setArgumentNames(final String[] argNames) { + this.argNames = argNames; + } + public Type getArgumentType(final int i) { return argTypes[i]; } @@ -645,6 +599,10 @@ public class MethodGen extends FieldGenOrMethodGen { return argTypes.clone(); } + public void setArgumentTypes(final Type[] argTypes) { + this.argTypes = argTypes; + } + /** * @return class that contains this method */ @@ -652,6 +610,10 @@ public class MethodGen extends FieldGenOrMethodGen { return className; } + public void setClassName(final String className) { // TODO could be package-protected? + this.className = className; + } + /** * @return all attributes of this method. */ @@ -697,6 +659,10 @@ public class MethodGen extends FieldGenOrMethodGen { return il; } + public void setInstructionList(final InstructionList il) { // TODO could be package-protected? + this.il = il; + } + /* * @return array of line numbers */ @@ -760,10 +726,24 @@ public class MethodGen extends FieldGenOrMethodGen { return maxLocals; } + /** + * Set maximum number of local variables. + */ + public void setMaxLocals(final int m) { + maxLocals = m; + } + public int getMaxStack() { return maxStack; } + /** + * Set maximum stack size for this method. + */ + public void setMaxStack(final int m) { // TODO could be package-protected? + maxStack = m; + } + /** * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method * (the same applies for max locals). @@ -819,9 +799,9 @@ public class MethodGen extends FieldGenOrMethodGen { } } code = new Code(cp.addUtf8("Code"), 8 + byteCode.length + // prologue byte code - 2 + excLen + // exceptions - 2 + attrsLen, // attributes - maxStack, maxLocals, byteCode, cExc, codeAttrs, cp.getConstantPool()); + 2 + excLen + // exceptions + 2 + attrsLen, // attributes + maxStack, maxLocals, byteCode, cExc, codeAttrs, cp.getConstantPool()); addAttribute(code); } final Attribute[] annotations = addRuntimeAnnotationsAsAttribute(cp); @@ -857,6 +837,10 @@ public class MethodGen extends FieldGenOrMethodGen { return getType(); } + public void setReturnType(final Type returnType) { + setType(returnType); + } + @Override public String getSignature() { return Type.getMethodSignature(super.getType(), argTypes); @@ -1014,26 +998,10 @@ public class MethodGen extends FieldGenOrMethodGen { argNames[i] = name; } - public void setArgumentNames(final String[] argNames) { - this.argNames = argNames; - } - public void setArgumentType(final int i, final Type type) { argTypes[i] = type; } - public void setArgumentTypes(final Type[] argTypes) { - this.argTypes = argTypes; - } - - public void setClassName(final String className) { // TODO could be package-protected? - this.className = className; - } - - public void setInstructionList(final InstructionList il) { // TODO could be package-protected? - this.il = il; - } - /** * Compute maximum number of local variables. */ @@ -1060,13 +1028,6 @@ public class MethodGen extends FieldGenOrMethodGen { } } - /** - * Set maximum number of local variables. - */ - public void setMaxLocals(final int m) { - maxLocals = m; - } - /** * Computes max. stack size by performing control flow analysis. */ @@ -1078,17 +1039,6 @@ public class MethodGen extends FieldGenOrMethodGen { } } - /** - * Set maximum stack size for this method. - */ - public void setMaxStack(final int m) { // TODO could be package-protected? - maxStack = m; - } - - public void setReturnType(final Type returnType) { - setType(returnType); - } - /** * Do not/Do produce attributes code attributesLineNumberTable and LocalVariableTable, like javac -O */ @@ -1149,4 +1099,45 @@ public class MethodGen extends FieldGenOrMethodGen { addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end, l.getOrigIndex()); } } + + static final class BranchStack { + + private final Stack branchTargets = new Stack<>(); + private final Hashtable visitedTargets = new Hashtable<>(); + + public BranchTarget pop() { + if (!branchTargets.empty()) { + return branchTargets.pop(); + } + return null; + } + + public void push(final InstructionHandle target, final int stackDepth) { + if (visited(target)) { + return; + } + branchTargets.push(visit(target, stackDepth)); + } + + private BranchTarget visit(final InstructionHandle target, final int stackDepth) { + final BranchTarget bt = new BranchTarget(target, stackDepth); + visitedTargets.put(target, bt); + return bt; + } + + private boolean visited(final InstructionHandle target) { + return visitedTargets.get(target) != null; + } + } + + static final class BranchTarget { + + final InstructionHandle target; + final int stackDepth; + + BranchTarget(final InstructionHandle target, final int stackDepth) { + this.target = target; + this.stackDepth = stackDepth; + } + } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/NEW.java b/src/main/java/haidnor/jvm/bcel/generic/NEW.java index 9c7d0e8..6ee2b72 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/NEW.java +++ b/src/main/java/haidnor/jvm/bcel/generic/NEW.java @@ -58,7 +58,7 @@ public class NEW extends CPInstruction implements LoadClass, AllocationInstructi @Override public Class[] getExceptions() { return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION, ExceptionConst.ILLEGAL_ACCESS_ERROR, - ExceptionConst.INSTANTIATION_ERROR); + ExceptionConst.INSTANTIATION_ERROR); } @Override diff --git a/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java b/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java index 4e8514a..1c520c0 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java +++ b/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java @@ -29,7 +29,7 @@ import java.io.IOException; *

  * Stack: ..., count -> ..., arrayref
  * 
- * + *

* type must be one of T_INT, T_SHORT, ... */ public class NEWARRAY extends Instruction implements AllocationInstruction, ExceptionThrower, StackProducer { @@ -78,7 +78,7 @@ public class NEWARRAY extends Instruction implements AllocationInstruction, Exce @Override public Class[] getExceptions() { - return new Class[] {ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION}; + return new Class[]{ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION}; } /** diff --git a/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java b/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java index dd76de8..b567ab1 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java +++ b/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java @@ -23,9 +23,9 @@ public interface NamedAndTyped { String getName(); - Type getType(); - void setName(String name); + Type getType(); + void setType(Type type); } diff --git a/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java b/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java index 0ccb1d8..3d535a6 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java +++ b/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java @@ -26,17 +26,6 @@ import haidnor.jvm.bcel.classfile.Utility; */ public class ObjectType extends ReferenceType { - /** - * Constructs a new instance. - * - * @param className fully qualified class name, e.g. java.lang.String - * @return a new instance. - * @since 6.0 - */ - public static ObjectType getInstance(final String className) { - return new ObjectType(className); - } - private final String className; // Class name of type /** @@ -49,6 +38,17 @@ public class ObjectType extends ReferenceType { this.className = Utility.pathToPackage(className); } + /** + * Constructs a new instance. + * + * @param className fully qualified class name, e.g. java.lang.String + * @return a new instance. + * @since 6.0 + */ + public static ObjectType getInstance(final String className) { + return new ObjectType(className); + } + /** * Java Virtual Machine Specification edition 2, � 5.4.4 Access Control * @@ -89,8 +89,9 @@ public class ObjectType extends ReferenceType { /** * If "this" doesn't reference a class, it references an interface or a non-existant entity. + * * @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be - * found: use referencesClassExact() instead + * found: use referencesClassExact() instead */ @Deprecated public boolean referencesClass() { @@ -117,7 +118,7 @@ public class ObjectType extends ReferenceType { * If "this" doesn't reference an interface, it references a class or a non-existant entity. * * @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be - * found: use referencesInterfaceExact() instead + * found: use referencesInterfaceExact() instead */ @Deprecated public boolean referencesInterface() { diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUSH.java b/src/main/java/haidnor/jvm/bcel/generic/PUSH.java index 86dcd09..bc86caa 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/PUSH.java +++ b/src/main/java/haidnor/jvm/bcel/generic/PUSH.java @@ -30,7 +30,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio /** * Pushes an array type constant, for example {@code int[].class}, {@code String[].class}, and so on. * - * @param cp generated constant pool. + * @param cp generated constant pool. * @param value to be pushed. * @since 6.7.0 */ @@ -42,8 +42,8 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } } - /** - * @param cp Constant pool + /** + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final boolean value) { @@ -52,7 +52,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final Boolean value) { @@ -63,7 +63,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio * creates a push object from a Character value. Warning: Make sure not to attempt to allow autoboxing to create this * value parameter, as an alternative constructor will be called * - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final Character value) { @@ -71,7 +71,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final double value) { @@ -85,7 +85,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final float value) { @@ -103,7 +103,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio /** * This constructor also applies for values of type short, char, byte * - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final int value) { @@ -119,7 +119,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final long value) { @@ -133,7 +133,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final Number value) { @@ -151,7 +151,6 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * * @param cp * @param value * @since 6.0 @@ -165,7 +164,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio } /** - * @param cp Constant pool + * @param cp Constant pool * @param value to be pushed */ public PUSH(final ConstantPoolGen cp, final String value) { diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java b/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java index be1688c..cda8377 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java +++ b/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java @@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst; *

  * Stack: ..., objectref, value -> ...
  * 
- * + *

* OR * *

@@ -71,6 +71,6 @@ public class PUTFIELD extends FieldInstruction implements PopInstruction, Except
     @Override
     public Class[] getExceptions() {
         return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
-            ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+                ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
     }
 }
diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
index 800c170..9151f36 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
  * 
  * Stack: ..., value -> ...
  * 
- * + *

* OR * *

diff --git a/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
index b3cdb52..d3d8f73 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
@@ -20,7 +20,6 @@ package haidnor.jvm.bcel.generic;
  * Denotes an unparameterized instruction to produce a value on top of the stack, such as ILOAD, LDC, SIPUSH, DUP,
  * ICONST, etc.
  *
- *
  * @see ILOAD
  * @see ICONST
  * @see LDC
diff --git a/src/main/java/haidnor/jvm/bcel/generic/RET.java b/src/main/java/haidnor/jvm/bcel/generic/RET.java
index 665de71..f3de96b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/RET.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/RET.java
@@ -82,6 +82,18 @@ public class RET extends Instruction implements IndexedInstruction, TypedInstruc
         return index;
     }
 
+    /**
+     * Set index of local variable containg the return address
+     */
+    @Override
+    public final void setIndex(final int n) {
+        if (n < 0) {
+            throw new ClassGenException("Negative index value: " + n);
+        }
+        index = n;
+        setWide();
+    }
+
     /**
      * @return return address type
      */
@@ -105,18 +117,6 @@ public class RET extends Instruction implements IndexedInstruction, TypedInstruc
         }
     }
 
-    /**
-     * Set index of local variable containg the return address
-     */
-    @Override
-    public final void setIndex(final int n) {
-        if (n < 0) {
-            throw new ClassGenException("Negative index value: " + n);
-        }
-        index = n;
-        setWide();
-    }
-
     private void setWide() {
         wide = index > Const.MAX_BYTE;
         if (wide) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java b/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
index a681c7c..72d25be 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
@@ -44,8 +44,8 @@ public abstract class ReferenceType extends Type {
      * interface, then Type.OBJECT is returned. If not all of the two classes' superclasses cannot be found, "null" is
      * returned. See the JVM specification edition 2, "�4.9.2 The Bytecode Verifier".
      *
-     * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics.
      * @throws ClassNotFoundException on failure to find superclasses of this type, or the type passed as a parameter
+     * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics.
      */
     @Deprecated
     public ReferenceType firstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException {
@@ -96,9 +96,9 @@ public abstract class ReferenceType extends Type {
             final ArrayType arrType1 = (ArrayType) this;
             final ArrayType arrType2 = (ArrayType) t;
             if (arrType1.getDimensions() == arrType2.getDimensions() && arrType1.getBasicType() instanceof ObjectType
-                && arrType2.getBasicType() instanceof ObjectType) {
+                    && arrType2.getBasicType() instanceof ObjectType) {
                 return new ArrayType(((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()),
-                    arrType1.getDimensions());
+                        arrType1.getDimensions());
             }
         }
         if (this instanceof ArrayType || t instanceof ArrayType) {
@@ -110,7 +110,7 @@ public abstract class ReferenceType extends Type {
 
     private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) throws ClassNotFoundException {
         if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact()
-            || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) {
+                || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) {
             return Type.OBJECT;
             // TODO: The above line is correct comparing to the vmspec2. But one could
             // make class file verification a bit stronger here by using the notion of
@@ -147,7 +147,7 @@ public abstract class ReferenceType extends Type {
      * AASTORE definition there.
      *
      * @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be
-     *         found
+     *                                found
      */
     public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundException {
         if (!(t instanceof ReferenceType)) {
@@ -165,14 +165,14 @@ public abstract class ReferenceType extends Type {
              * If T is a class type, then this must be the same class as T, or this must be a subclass of T;
              */
             if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact()
-                && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
+                    && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
                 return true;
             }
             /*
              * If T is an interface type, this must implement interface T.
              */
             if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact()
-                && Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName())) {
+                    && Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName())) {
                 return true;
             }
         }
@@ -190,7 +190,7 @@ public abstract class ReferenceType extends Type {
              * If T is an interface type, then T must be the same interface as this or a superinterface of this (�2.13.2).
              */
             if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact()
-                && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
+                    && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
                 return true;
             }
         }
@@ -246,7 +246,7 @@ public abstract class ReferenceType extends Type {
      * doesn't throw a ClassCastException when casting a null reference to any Object, true is returned in this case.
      *
      * @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be
-     *         found
+     *                                found
      */
     public boolean isCastableTo(final Type t) throws ClassNotFoundException {
         if (this.equals(Type.NULL)) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
index c979b61..004be9d 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
@@ -39,26 +39,26 @@ public abstract class ReturnInstruction extends Instruction implements Exception
 
     @Override
     public Class[] getExceptions() {
-        return new Class[] {ExceptionConst.ILLEGAL_MONITOR_STATE};
+        return new Class[]{ExceptionConst.ILLEGAL_MONITOR_STATE};
     }
 
     public Type getType() {
         final short opcode = super.getOpcode();
         switch (opcode) {
-        case Const.IRETURN:
-            return Type.INT;
-        case Const.LRETURN:
-            return Type.LONG;
-        case Const.FRETURN:
-            return Type.FLOAT;
-        case Const.DRETURN:
-            return Type.DOUBLE;
-        case Const.ARETURN:
-            return Type.OBJECT;
-        case Const.RETURN:
-            return Type.VOID;
-        default: // Never reached
-            throw new ClassGenException("Unknown type " + opcode);
+            case Const.IRETURN:
+                return Type.INT;
+            case Const.LRETURN:
+                return Type.LONG;
+            case Const.FRETURN:
+                return Type.FLOAT;
+            case Const.DRETURN:
+                return Type.DOUBLE;
+            case Const.ARETURN:
+                return Type.OBJECT;
+            case Const.RETURN:
+                return Type.VOID;
+            default: // Never reached
+                throw new ClassGenException("Unknown type " + opcode);
         }
     }
 
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java b/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
index 8191907..16deb8b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
@@ -20,7 +20,7 @@ import haidnor.jvm.bcel.Const;
 
 /**
  * Returnaddress, the type JSR or JSR_W instructions push upon the stack.
- *
+ * 

* see vmspec2 �3.3.3 */ public class ReturnaddressType extends Type { diff --git a/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java b/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java index 11fce8d..8653986 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java +++ b/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java @@ -24,6 +24,58 @@ import java.util.Arrays; */ public final class SWITCH implements CompoundInstruction { + private final Select instruction; + + public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target) { + this(match, targets, target, 1); + } + + /** + * Template for switch() constructs. If the match array can be sorted in ascending order with gaps no larger than + * maxGap between the numbers, a TABLESWITCH instruction is generated, and a LOOKUPSWITCH otherwise. The former may be + * more efficient, but needs more space. + *

+ * Note, that the key array always will be sorted, though we leave the original arrays unaltered. + * + * @param match array of match values (case 2: ... case 7: ..., etc.) + * @param targets the instructions to be branched to for each case + * @param target the default target + * @param maxGap maximum gap that may between case branches + */ + public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) { + int[] matchClone = match.clone(); + final InstructionHandle[] targetsClone = targets.clone(); + final int matchLength = match.length; + if (matchLength < 2) { + instruction = new TABLESWITCH(match, targets, target); + } else { + sort(0, matchLength - 1, matchClone, targetsClone); + if (matchIsOrdered(matchClone, matchLength, maxGap)) { + final int maxSize = matchLength + matchLength * maxGap; + final int[] mVec = new int[maxSize]; + final InstructionHandle[] tVec = new InstructionHandle[maxSize]; + int count = 1; + mVec[0] = match[0]; + tVec[0] = targets[0]; + for (int i = 1; i < matchLength; i++) { + final int prev = match[i - 1]; + final int gap = match[i] - prev; + for (int j = 1; j < gap; j++) { + mVec[count] = prev + j; + tVec[count] = target; + count++; + } + mVec[count] = match[i]; + tVec[count] = targets[i]; + count++; + } + instruction = new TABLESWITCH(Arrays.copyOf(mVec, count), Arrays.copyOf(tVec, count), target); + } else { + instruction = new LOOKUPSWITCH(matchClone, targetsClone, target); + } + } + } + /** * @return match is sorted in ascending order with no gap bigger than maxGap? */ @@ -71,58 +123,6 @@ public final class SWITCH implements CompoundInstruction { } } - private final Select instruction; - - public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target) { - this(match, targets, target, 1); - } - - /** - * Template for switch() constructs. If the match array can be sorted in ascending order with gaps no larger than - * maxGap between the numbers, a TABLESWITCH instruction is generated, and a LOOKUPSWITCH otherwise. The former may be - * more efficient, but needs more space. - * - * Note, that the key array always will be sorted, though we leave the original arrays unaltered. - * - * @param match array of match values (case 2: ... case 7: ..., etc.) - * @param targets the instructions to be branched to for each case - * @param target the default target - * @param maxGap maximum gap that may between case branches - */ - public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) { - int[] matchClone = match.clone(); - final InstructionHandle[] targetsClone = targets.clone(); - final int matchLength = match.length; - if (matchLength < 2) { - instruction = new TABLESWITCH(match, targets, target); - } else { - sort(0, matchLength - 1, matchClone, targetsClone); - if (matchIsOrdered(matchClone, matchLength, maxGap)) { - final int maxSize = matchLength + matchLength * maxGap; - final int[] mVec = new int[maxSize]; - final InstructionHandle[] tVec = new InstructionHandle[maxSize]; - int count = 1; - mVec[0] = match[0]; - tVec[0] = targets[0]; - for (int i = 1; i < matchLength; i++) { - final int prev = match[i - 1]; - final int gap = match[i] - prev; - for (int j = 1; j < gap; j++) { - mVec[count] = prev + j; - tVec[count] = target; - count++; - } - mVec[count] = match[i]; - tVec[count] = targets[i]; - count++; - } - instruction = new TABLESWITCH(Arrays.copyOf(mVec, count), Arrays.copyOf(tVec, count), target); - } else { - instruction = new LOOKUPSWITCH(matchClone, targetsClone, target); - } - } - } - public Instruction getInstruction() { return instruction; } diff --git a/src/main/java/haidnor/jvm/bcel/generic/Select.java b/src/main/java/haidnor/jvm/bcel/generic/Select.java index 3f1808a..3db5e6f 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/Select.java +++ b/src/main/java/haidnor/jvm/bcel/generic/Select.java @@ -78,8 +78,8 @@ public abstract class Select extends BranchInstruction implements VariableLength /** * (Match, target) pairs for switch. 'Match' and 'targets' must have the same length of course. * - * @param match array of matching values - * @param targets instruction targets + * @param match array of matching values + * @param targets instruction targets * @param defaultTarget default instruction target */ Select(final short opcode, final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) { @@ -157,6 +157,14 @@ public abstract class Select extends BranchInstruction implements VariableLength return fixed_length; } + /** + * @param fixedLength the fixed_length to set + * @since 6.0 + */ + final void setFixedLength(final int fixedLength) { + this.fixed_length = fixedLength; + } + /** * @return array of match target offsets */ @@ -164,6 +172,14 @@ public abstract class Select extends BranchInstruction implements VariableLength return indices; } + /** + * @param array + * @since 6.0 + */ + final void setIndices(final int[] array) { + indices = array; + } + /** * @return index entry from indices * @since 6.0 @@ -196,7 +212,6 @@ public abstract class Select extends BranchInstruction implements VariableLength } /** - * * @return the padding * @since 6.0 */ @@ -219,6 +234,14 @@ public abstract class Select extends BranchInstruction implements VariableLength return targets; } + /** + * @param array + * @since 6.0 + */ + final void setTargets(final InstructionHandle[] array) { + targets = array; + } + /** * Read needed data (e.g. index) from file. */ @@ -233,30 +256,14 @@ public abstract class Select extends BranchInstruction implements VariableLength } /** - * @param fixedLength the fixed_length to set * @since 6.0 */ - final void setFixedLength(final int fixedLength) { - this.fixed_length = fixedLength; - } - - /** @since 6.0 */ final int setIndices(final int i, final int value) { indices[i] = value; return value; // Allow use in nested calls } /** - * - * @param array - * @since 6.0 - */ - final void setIndices(final int[] array) { - indices = array; - } - - /** - * * @param index * @param value * @since 6.0 @@ -266,7 +273,6 @@ public abstract class Select extends BranchInstruction implements VariableLength } /** - * * @param array * @since 6.0 */ @@ -291,15 +297,6 @@ public abstract class Select extends BranchInstruction implements VariableLength targets[i] = target; } - /** - * - * @param array - * @since 6.0 - */ - final void setTargets(final InstructionHandle[] array) { - targets = array; - } - /** * @return mnemonic for instruction */ @@ -323,12 +320,12 @@ public abstract class Select extends BranchInstruction implements VariableLength /** * Since this is a variable length instruction, it may shift the following instructions which then need to update their * position. - * + *

* Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable * length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte) * positions and offsets by calling this function. * - * @param offset additional offset caused by preceding (variable length) instructions + * @param offset additional offset caused by preceding (variable length) instructions * @param maxOffset the maximum offset that may be caused by these instructions * @return additional offset caused by possible change of this instruction's length */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java index 4b53711..607812b 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java +++ b/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java @@ -81,6 +81,7 @@ public class SimpleElementValueGen extends ElementValueGen { // ctors for each supported type... type could be inferred but for now lets // force it to be passed + /** * Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, assumes the one at the supplied * index is correct. @@ -102,39 +103,39 @@ public class SimpleElementValueGen extends ElementValueGen { idx = value.getIndex(); } else { switch (value.getElementValueType()) { - case STRING: - idx = cpool.addUtf8(value.getValueString()); - break; - case PRIMITIVE_INT: - idx = cpool.addInteger(value.getValueInt()); - break; - case PRIMITIVE_BYTE: - idx = cpool.addInteger(value.getValueByte()); - break; - case PRIMITIVE_CHAR: - idx = cpool.addInteger(value.getValueChar()); - break; - case PRIMITIVE_LONG: - idx = cpool.addLong(value.getValueLong()); - break; - case PRIMITIVE_FLOAT: - idx = cpool.addFloat(value.getValueFloat()); - break; - case PRIMITIVE_DOUBLE: - idx = cpool.addDouble(value.getValueDouble()); - break; - case PRIMITIVE_BOOLEAN: - if (value.getValueBoolean()) { - idx = cpool.addInteger(1); - } else { - idx = cpool.addInteger(0); - } - break; - case PRIMITIVE_SHORT: - idx = cpool.addInteger(value.getValueShort()); - break; - default: - throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType()); + case STRING: + idx = cpool.addUtf8(value.getValueString()); + break; + case PRIMITIVE_INT: + idx = cpool.addInteger(value.getValueInt()); + break; + case PRIMITIVE_BYTE: + idx = cpool.addInteger(value.getValueByte()); + break; + case PRIMITIVE_CHAR: + idx = cpool.addInteger(value.getValueChar()); + break; + case PRIMITIVE_LONG: + idx = cpool.addLong(value.getValueLong()); + break; + case PRIMITIVE_FLOAT: + idx = cpool.addFloat(value.getValueFloat()); + break; + case PRIMITIVE_DOUBLE: + idx = cpool.addDouble(value.getValueDouble()); + break; + case PRIMITIVE_BOOLEAN: + if (value.getValueBoolean()) { + idx = cpool.addInteger(1); + } else { + idx = cpool.addInteger(0); + } + break; + case PRIMITIVE_SHORT: + idx = cpool.addInteger(value.getValueShort()); + break; + default: + throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType()); } } } @@ -143,19 +144,19 @@ public class SimpleElementValueGen extends ElementValueGen { public void dump(final DataOutputStream dos) throws IOException { dos.writeByte(super.getElementValueType()); // u1 kind of value switch (super.getElementValueType()) { - case PRIMITIVE_INT: - case PRIMITIVE_BYTE: - case PRIMITIVE_CHAR: - case PRIMITIVE_FLOAT: - case PRIMITIVE_LONG: - case PRIMITIVE_BOOLEAN: - case PRIMITIVE_SHORT: - case PRIMITIVE_DOUBLE: - case STRING: - dos.writeShort(idx); - break; - default: - throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType()); + case PRIMITIVE_INT: + case PRIMITIVE_BYTE: + case PRIMITIVE_CHAR: + case PRIMITIVE_FLOAT: + case PRIMITIVE_LONG: + case PRIMITIVE_BOOLEAN: + case PRIMITIVE_SHORT: + case PRIMITIVE_DOUBLE: + case STRING: + dos.writeShort(idx); + break; + default: + throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType()); } } @@ -191,38 +192,38 @@ public class SimpleElementValueGen extends ElementValueGen { @Override public String stringifyValue() { switch (super.getElementValueType()) { - case PRIMITIVE_INT: - final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx); - return Integer.toString(c.getBytes()); - case PRIMITIVE_LONG: - final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx); - return Long.toString(j.getBytes()); - case PRIMITIVE_DOUBLE: - final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx); - return Double.toString(d.getBytes()); - case PRIMITIVE_FLOAT: - final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx); - return Float.toString(f.getBytes()); - case PRIMITIVE_SHORT: - final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx); - return Integer.toString(s.getBytes()); - case PRIMITIVE_BYTE: - final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx); - return Integer.toString(b.getBytes()); - case PRIMITIVE_CHAR: - final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx); - return Integer.toString(ch.getBytes()); - case PRIMITIVE_BOOLEAN: - final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx); - if (bo.getBytes() == 0) { - return "false"; - } - return "true"; - case STRING: - final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx); - return cu8.getBytes(); - default: - throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType()); + case PRIMITIVE_INT: + final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx); + return Integer.toString(c.getBytes()); + case PRIMITIVE_LONG: + final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx); + return Long.toString(j.getBytes()); + case PRIMITIVE_DOUBLE: + final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx); + return Double.toString(d.getBytes()); + case PRIMITIVE_FLOAT: + final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx); + return Float.toString(f.getBytes()); + case PRIMITIVE_SHORT: + final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx); + return Integer.toString(s.getBytes()); + case PRIMITIVE_BYTE: + final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx); + return Integer.toString(b.getBytes()); + case PRIMITIVE_CHAR: + final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx); + return Integer.toString(ch.getBytes()); + case PRIMITIVE_BOOLEAN: + final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx); + if (bo.getBytes() == 0) { + return "false"; + } + return "true"; + case STRING: + final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx); + return cu8.getBytes(); + default: + throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType()); } } } diff --git a/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java index 77b6bd9..2bd47a2 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java @@ -31,8 +31,8 @@ public abstract class StoreInstruction extends LocalVariableInstruction implemen /** * @param opcode Instruction opcode - * @param cTag Instruction number for compact version, ASTORE_0, e.g. - * @param n local variable index (unsigned short) + * @param cTag Instruction number for compact version, ASTORE_0, e.g. + * @param n local variable index (unsigned short) */ protected StoreInstruction(final short opcode, final short cTag, final int n) { super(opcode, cTag, n); diff --git a/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java b/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java index 583fa1c..f154117 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java +++ b/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java @@ -36,8 +36,8 @@ public class TABLESWITCH extends Select { } /** - * @param match sorted array of match values, match[0] must be low value, match[match_length - 1] high value - * @param targets where to branch for matched values + * @param match sorted array of match values, match[0] must be low value, match[match_length - 1] high value + * @param targets where to branch for matched values * @param defaultTarget default branch */ public TABLESWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) { diff --git a/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java b/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java index c2ac5fd..8a6427c 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java +++ b/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java @@ -27,16 +27,16 @@ package haidnor.jvm.bcel.generic; *

* *
- *     ...
- *     try {
- *         il.delete(start_ih, end_ih);
- *     } catch(TargetLostException e) {
- *         for (InstructionHandle target : e.getTargets()) {
- *             for (InstructionTargeter targeter : target.getTargeters()) {
- *                 targeter.updateTarget(target, new_target);
- *             }
- *         }
- *     }
+ * ...
+ * try {
+ * il.delete(start_ih, end_ih);
+ * } catch(TargetLostException e) {
+ * for (InstructionHandle target : e.getTargets()) {
+ * for (InstructionTargeter targeter : target.getTargeters()) {
+ * targeter.updateTarget(target, new_target);
+ * }
+ * }
+ * }
  * 
* * @see InstructionHandle diff --git a/src/main/java/haidnor/jvm/bcel/generic/Type.java b/src/main/java/haidnor/jvm/bcel/generic/Type.java index 8851d51..b6198e2 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/Type.java +++ b/src/main/java/haidnor/jvm/bcel/generic/Type.java @@ -61,6 +61,21 @@ public abstract class Type { }; private static final ThreadLocal CONSUMED_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0)); + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected byte type; // TODO should be final (and private) + /** + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + */ + @Deprecated + protected String signature; // signature for the type TODO should be private + + protected Type(final byte type, final String signature) { + this.type = type; + this.signature = signature; + } // int consumed_chars=0; // Remember position in string, see getArgumentTypes static int consumed(final int coded) { @@ -123,7 +138,7 @@ public abstract class Type { * Convert type to Java method signature, e.g. int[] f(java.lang.String x) becomes (Ljava/lang/String;)[I * * @param returnType what the method returns - * @param argTypes what are the argument types + * @param argTypes what are the argument types * @return method signature for given type(s). */ public static String getMethodSignature(final Type returnType, final Type[] argTypes) { @@ -294,23 +309,6 @@ public abstract class Type { tl.set(Integer.valueOf(value)); } - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected byte type; // TODO should be final (and private) - - /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter - */ - @Deprecated - protected String signature; // signature for the type TODO should be private - - protected Type(final byte type, final String signature) { - this.type = type; - this.signature = signature; - } - /** * @return whether the Types are equal */ @@ -334,18 +332,26 @@ public abstract class Type { return signature; } + /* + * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so + * it's tricky to do it in a call to the super ctor. + */ + void setSignature(final String signature) { + this.signature = signature; + } + /** * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise) */ public int getSize() { switch (type) { - case Const.T_DOUBLE: - case Const.T_LONG: - return 2; - case Const.T_VOID: - return 0; - default: - return 1; + case Const.T_DOUBLE: + case Const.T_LONG: + return 2; + case Const.T_VOID: + return 0; + default: + return 1; } } @@ -377,14 +383,6 @@ public abstract class Type { return this; } - /* - * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so - * it's tricky to do it in a call to the super ctor. - */ - void setSignature(final String signature) { - this.signature = signature; - } - /** * @return Type string, e.g. 'int[]' */ diff --git a/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java index af4feb4..adba3c9 100644 --- a/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java +++ b/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java @@ -19,7 +19,6 @@ package haidnor.jvm.bcel.generic; /** * Denotes an instruction to be a variable length instruction, such as GOTO, JSR, LOOKUPSWITCH and TABLESWITCH. * - * * @see GOTO * @see JSR * @see LOOKUPSWITCH diff --git a/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java b/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java index d96ff82..3cd0a80 100644 --- a/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java +++ b/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java @@ -57,10 +57,10 @@ abstract class AbstractClassPathRepository implements Repository { * the Repository version is returned. Otherwise, getResourceAsStream() is called on the Class object to find the * class's representation. If the representation is found, it is added to the Repository. * - * @see Class * @param clazz the runtime Class object * @return JavaClass object for given runtime class * @throws ClassNotFoundException if the class is not in the Repository, and its representation could not be found + * @see Class */ @Override public JavaClass loadClass(final Class clazz) throws ClassNotFoundException { diff --git a/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java b/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java index 7a9c2c6..7e61488 100644 --- a/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java +++ b/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java @@ -63,7 +63,7 @@ class BCELFactory extends EmptyVisitor { } else { embed += "f"; } - } else if (value instanceof Double) { + } else if (value instanceof Double) { final Double d = (Double) value; if (Double.isNaN(d)) { embed = "Double.NaN"; @@ -134,7 +134,7 @@ class BCELFactory extends EmptyVisitor { for (final CodeExceptionGen h : handlers) { final String type = h.getCatchType() == null ? "null" : BCELifier.printType(h.getCatchType()); printWriter.println(" method.addExceptionHandler(" + "ih_" + h.getStartPC().getPosition() + ", " + "ih_" + h.getEndPC().getPosition() + ", " - + "ih_" + h.getHandlerPC().getPosition() + ", " + type + ");"); + + "ih_" + h.getHandlerPC().getPosition() + ", " + type + ");"); } } @@ -149,22 +149,22 @@ class BCELFactory extends EmptyVisitor { final short opcode = ((Instruction) i).getOpcode(); int dim = 1; switch (opcode) { - case Const.NEW: - printWriter.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() + "\"));"); - break; - case Const.MULTIANEWARRAY: - dim = ((MULTIANEWARRAY) i).getDimensions(); - //$FALL-THROUGH$ - case Const.NEWARRAY: - if (type instanceof ArrayType) { - type = ((ArrayType) type).getBasicType(); - } - //$FALL-THROUGH$ - case Const.ANEWARRAY: - printWriter.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) + ", (short) " + dim + "));"); - break; - default: - throw new IllegalArgumentException("Unhandled opcode: " + opcode); + case Const.NEW: + printWriter.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() + "\"));"); + break; + case Const.MULTIANEWARRAY: + dim = ((MULTIANEWARRAY) i).getDimensions(); + //$FALL-THROUGH$ + case Const.NEWARRAY: + if (type instanceof ArrayType) { + type = ((ArrayType) type).getBasicType(); + } + //$FALL-THROUGH$ + case Const.ANEWARRAY: + printWriter.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) + ", (short) " + dim + "));"); + break; + default: + throw new IllegalArgumentException("Unhandled opcode: " + opcode); } } @@ -211,7 +211,7 @@ class BCELFactory extends EmptyVisitor { target = "null"; } printWriter.println(" BranchInstruction " + name + " = _factory.createBranchInstruction(" + CONSTANT_PREFIX - + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target + ");"); + + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target + ");"); } if (bh.hasTargeters()) { printWriter.println(" ih_" + pos + " = il.append(" + name + ");"); @@ -238,7 +238,7 @@ class BCELFactory extends EmptyVisitor { final String fieldName = i.getFieldName(constantPoolGen); final Type type = i.getFieldType(constantPoolGen); printWriter.println("il.append(_factory.createFieldAccess(\"" + className + "\", \"" + fieldName + "\", " + BCELifier.printType(type) + ", " - + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); + + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); } @Override @@ -264,7 +264,7 @@ class BCELFactory extends EmptyVisitor { final Type type = i.getReturnType(constantPoolGen); final Type[] argTypes = i.getArgumentTypes(constantPoolGen); printWriter.println("il.append(_factory.createInvoke(\"" + className + "\", \"" + methodName + "\", " + BCELifier.printType(type) + ", " - + BCELifier.printArgumentTypes(argTypes) + ", " + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); + + BCELifier.printArgumentTypes(argTypes) + ", " + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); } @Override diff --git a/src/main/java/haidnor/jvm/bcel/util/BCELifier.java b/src/main/java/haidnor/jvm/bcel/util/BCELifier.java index 6cf55b5..ab593a3 100644 --- a/src/main/java/haidnor/jvm/bcel/util/BCELifier.java +++ b/src/main/java/haidnor/jvm/bcel/util/BCELifier.java @@ -39,17 +39,25 @@ import java.util.Locale; */ public class BCELifier extends EmptyVisitor { - /** - * Enum corresponding to flag source. - */ - public enum FLAGS { - UNKNOWN, CLASS, METHOD, - } - // The base package name for imports; assumes Const is at the top level // N.B we use the class so renames will be detected by the compiler/IDE private static final String BASE_PACKAGE = Const.class.getPackage().getName(); private static final String CONSTANT_PREFIX = Const.class.getSimpleName() + "."; + private final JavaClass clazz; + private final PrintWriter printWriter; + private final ConstantPoolGen constantPoolGen; + + /** + * Constructs a new instance. + * + * @param clazz Java class to "decompile". + * @param out where to print the Java program in UTF-8. + */ + public BCELifier(final JavaClass clazz, final OutputStream out) { + this.clazz = clazz; + this.printWriter = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8), false); + this.constantPoolGen = new ConstantPoolGen(this.clazz.getConstantPool()); + } // Needs to be accessible from unit test code static JavaClass getJavaClass(final String name) throws ClassNotFoundException, IOException { @@ -94,7 +102,7 @@ public class BCELifier extends EmptyVisitor { /** * Return a string with the flag settings * - * @param flags the flags field to interpret + * @param flags the flags field to interpret * @param location the item type * @return the formatted string * @since 6.0 made public @@ -150,24 +158,6 @@ public class BCELifier extends EmptyVisitor { return printType(type.getSignature()); } - private final JavaClass clazz; - - private final PrintWriter printWriter; - - private final ConstantPoolGen constantPoolGen; - - /** - * Constructs a new instance. - * - * @param clazz Java class to "decompile". - * @param out where to print the Java program in UTF-8. - */ - public BCELifier(final JavaClass clazz, final OutputStream out) { - this.clazz = clazz; - this.printWriter = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8), false); - this.constantPoolGen = new ConstantPoolGen(this.clazz.getConstantPool()); - } - private void printCreate() { printWriter.println(" public void create(OutputStream out) throws IOException {"); final JavaField[] fields = clazz.getFields(); @@ -203,7 +193,7 @@ public class BCELifier extends EmptyVisitor { public void visitField(final JavaField field) { printWriter.println(); printWriter.println( - " field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);"); + " field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);"); final ConstantValue cv = field.getConstantValue(); if (cv != null) { printWriter.print(" field.setInitValue("); @@ -254,7 +244,7 @@ public class BCELifier extends EmptyVisitor { printWriter.println(); printWriter.println(" public " + className + "Creator() {"); printWriter.println(" _cg = new ClassGen(\"" + (packageName.isEmpty() ? className : packageName + "." + className) + "\", \"" + superName - + "\", " + "\"" + clazz.getSourceFileName() + "\", " + printFlags(clazz.getAccessFlags(), FLAGS.CLASS) + ", " + "new String[] { " + inter + " });"); + + "\", " + "\"" + clazz.getSourceFileName() + "\", " + printFlags(clazz.getAccessFlags(), FLAGS.CLASS) + ", " + "new String[] { " + inter + " });"); printWriter.println(" _cg.setMajor(" + clazz.getMajor() + ");"); printWriter.println(" _cg.setMinor(" + clazz.getMinor() + ");"); printWriter.println(); @@ -289,8 +279,8 @@ public class BCELifier extends EmptyVisitor { final MethodGen mg = new MethodGen(method, clazz.getClassName(), constantPoolGen); printWriter.println(" InstructionList il = new InstructionList();"); printWriter.println(" MethodGen method = new MethodGen(" + printFlags(method.getAccessFlags(), FLAGS.METHOD) + ", " + printType(mg.getReturnType()) - + ", " + printArgumentTypes(mg.getArgumentTypes()) + ", " + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) + " }, \"" - + method.getName() + "\", \"" + clazz.getClassName() + "\", il, _cp);"); + + ", " + printArgumentTypes(mg.getArgumentTypes()) + ", " + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) + " }, \"" + + method.getName() + "\", \"" + clazz.getClassName() + "\", il, _cp);"); final ExceptionTable exceptionTable = method.getExceptionTable(); if (exceptionTable != null) { final String[] exceptionNames = exceptionTable.getExceptionNames(); @@ -308,4 +298,11 @@ public class BCELifier extends EmptyVisitor { printWriter.println(" _cg.addMethod(method.getMethod());"); printWriter.println(" il.dispose();"); } + + /** + * Enum corresponding to flag source. + */ + public enum FLAGS { + UNKNOWN, CLASS, METHOD, + } } diff --git a/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java b/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java index f91d394..d170435 100644 --- a/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java +++ b/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java @@ -25,6 +25,21 @@ import java.io.DataInputStream; */ public final class ByteSequence extends DataInputStream { + private final ByteArrayStream byteStream; + + public ByteSequence(final byte[] bytes) { + super(new ByteArrayStream(bytes)); + byteStream = (ByteArrayStream) in; + } + + public int getIndex() { + return byteStream.getPosition(); + } + + void unreadByte() { + byteStream.unreadByte(); + } + private static final class ByteArrayStream extends ByteArrayInputStream { ByteArrayStream(final byte[] bytes) { @@ -42,19 +57,4 @@ public final class ByteSequence extends DataInputStream { } } } - - private final ByteArrayStream byteStream; - - public ByteSequence(final byte[] bytes) { - super(new ByteArrayStream(bytes)); - byteStream = (ByteArrayStream) in; - } - - public int getIndex() { - return byteStream.getPosition(); - } - - void unreadByte() { - byteStream.unreadByte(); - } } diff --git a/src/main/java/haidnor/jvm/bcel/util/ClassPath.java b/src/main/java/haidnor/jvm/bcel/util/ClassPath.java index 31b1bb9..3287891 100644 --- a/src/main/java/haidnor/jvm/bcel/util/ClassPath.java +++ b/src/main/java/haidnor/jvm/bcel/util/ClassPath.java @@ -35,6 +35,397 @@ import java.util.zip.ZipFile; */ public class ClassPath implements Closeable { + private static final FilenameFilter ARCHIVE_FILTER = (dir, name) -> { + name = name.toLowerCase(Locale.ENGLISH); + return name.endsWith(".zip") || name.endsWith(".jar"); + }; + private static final FilenameFilter MODULES_FILTER = (dir, name) -> { + name = name.toLowerCase(Locale.ENGLISH); + return name.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION); + }; + public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath(getClassPath()); + private final String classPathString; + private final ClassPath parent; + private final List paths; + + /** + * Search for classes in CLASSPATH. + * + * @deprecated Use SYSTEM_CLASS_PATH constant + */ + @Deprecated + public ClassPath() { + this(getClassPath()); + } + + @SuppressWarnings("resource") + public ClassPath(final ClassPath parent, final String classPathString) { + this.parent = parent; + this.classPathString = Objects.requireNonNull(classPathString, "classPathString"); + this.paths = new ArrayList<>(); + for (final StringTokenizer tokenizer = new StringTokenizer(classPathString, File.pathSeparator); tokenizer.hasMoreTokens(); ) { + final String path = tokenizer.nextToken(); + if (!path.isEmpty()) { + final File file = new File(path); + try { + if (file.exists()) { + if (file.isDirectory()) { + paths.add(new Dir(path)); + } else if (path.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION)) { + paths.add(new Module(new ZipFile(file))); + } else if (path.endsWith(ModularRuntimeImage.MODULES_PATH)) { + paths.add(new JrtModules(ModularRuntimeImage.MODULES_PATH)); + } else { + paths.add(new Jar(new ZipFile(file))); + } + } + } catch (final IOException e) { + if (path.endsWith(".zip") || path.endsWith(".jar")) { + System.err.println("CLASSPATH component " + file + ": " + e); + } + } + } + } + } + + /** + * Search for classes in given path. + * + * @param classPath + */ + public ClassPath(final String classPath) { + this(null, classPath); + } + + private static void addJdkModules(final String javaHome, final List list) { + String modulesPath = System.getProperty("java.modules.path"); + if (modulesPath == null || modulesPath.trim().isEmpty()) { + // Default to looking in JAVA_HOME/jmods + modulesPath = javaHome + File.separator + "jmods"; + } + final File modulesDir = new File(modulesPath); + if (modulesDir.exists()) { + final String[] modules = modulesDir.list(MODULES_FILTER); + if (modules != null) { + for (final String module : modules) { + list.add(modulesDir.getPath() + File.separatorChar + module); + } + } + } + } + + /** + * Checks for class path components in the following properties: "java.class.path", "sun.boot.class.path", + * "java.ext.dirs" + * + * @return class path as used by default by BCEL + */ + // @since 6.0 no longer final + public static String getClassPath() { + final String classPathProp = System.getProperty("java.class.path"); + final String bootClassPathProp = System.getProperty("sun.boot.class.path"); + final String extDirs = System.getProperty("java.ext.dirs"); + // System.out.println("java.version = " + System.getProperty("java.version")); + // System.out.println("java.class.path = " + classPathProp); + // System.out.println("sun.boot.class.path=" + bootClassPathProp); + // System.out.println("java.ext.dirs=" + extDirs); + final String javaHome = System.getProperty("java.home"); + final List list = new ArrayList<>(); + + // Starting in JRE 9, .class files are in the modules directory. Add them to the path. + final Path modulesPath = Paths.get(javaHome).resolve("lib/modules"); + if (Files.exists(modulesPath) && Files.isRegularFile(modulesPath)) { + list.add(modulesPath.toAbsolutePath().toString()); + } + // Starting in JDK 9, .class files are in the jmods directory. Add them to the path. + addJdkModules(javaHome, list); + + getPathComponents(classPathProp, list); + getPathComponents(bootClassPathProp, list); + final List dirs = new ArrayList<>(); + getPathComponents(extDirs, dirs); + for (final String d : dirs) { + final File extDir = new File(d); + final String[] extensions = extDir.list(ARCHIVE_FILTER); + if (extensions != null) { + for (final String extension : extensions) { + list.add(extDir.getPath() + File.separatorChar + extension); + } + } + } + + return list.stream().collect(Collectors.joining(File.pathSeparator)); + } + + private static void getPathComponents(final String path, final List list) { + if (path != null) { + final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + final String name = tokenizer.nextToken(); + final File file = new File(name); + if (file.exists()) { + list.add(name); + } + } + } + } + + @Override + public void close() throws IOException { + for (final AbstractPathEntry path : paths) { + path.close(); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ClassPath other = (ClassPath) obj; + return Objects.equals(classPathString, other.classPathString); + } + + /** + * @param name fully qualified file name, e.g. java/lang/String + * @return byte array for class + * @throws IOException if an I/O error occurs. + */ + public byte[] getBytes(final String name) throws IOException { + return getBytes(name, JavaClass.EXTENSION); + } + + /** + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suffix, e.g. .java + * @return byte array for file on class path + * @throws IOException if an I/O error occurs. + */ + public byte[] getBytes(final String name, final String suffix) throws IOException { + DataInputStream dis = null; + try (InputStream inputStream = getInputStream(name, suffix)) { + if (inputStream == null) { + throw new IOException("Couldn't find: " + name + suffix); + } + dis = new DataInputStream(inputStream); + final byte[] bytes = new byte[inputStream.available()]; + dis.readFully(bytes); + return bytes; + } finally { + if (dis != null) { + dis.close(); + } + } + } + + /** + * @param name fully qualified class name, e.g. java.lang.String + * @return input stream for class + * @throws IOException if an I/O error occurs. + */ + public ClassFile getClassFile(final String name) throws IOException { + return getClassFile(name, JavaClass.EXTENSION); + } + + /** + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suff, e.g. .java + * @return class file for the java class + * @throws IOException if an I/O error occurs. + */ + public ClassFile getClassFile(final String name, final String suffix) throws IOException { + ClassFile cf = null; + + if (parent != null) { + cf = parent.getClassFileInternal(name, suffix); + } + + if (cf == null) { + cf = getClassFileInternal(name, suffix); + } + + if (cf != null) { + return cf; + } + + throw new IOException("Couldn't find: " + name + suffix); + } + + private ClassFile getClassFileInternal(final String name, final String suffix) { + for (final AbstractPathEntry path : paths) { + final ClassFile cf = path.getClassFile(name, suffix); + if (cf != null) { + return cf; + } + } + return null; + } + + /** + * Gets an InputStream. + *

+ * The caller is responsible for closing the InputStream. + *

+ * + * @param name fully qualified class name, e.g. java.lang.String + * @return input stream for class + * @throws IOException if an I/O error occurs. + */ + public InputStream getInputStream(final String name) throws IOException { + return getInputStream(Utility.packageToPath(name), JavaClass.EXTENSION); + } + + /** + * Gets an InputStream for a class or resource on the classpath. + *

+ * The caller is responsible for closing the InputStream. + *

+ * + * @param name fully qualified file name, e.g. java/lang/String + * @param suffix file name ends with suff, e.g. .java + * @return input stream for file on class path + * @throws IOException if an I/O error occurs. + */ + public InputStream getInputStream(final String name, final String suffix) throws IOException { + try { + final java.lang.ClassLoader classLoader = getClass().getClassLoader(); + @SuppressWarnings("resource") // closed by caller + final InputStream inputStream = classLoader == null ? null : classLoader.getResourceAsStream(name + suffix); + if (inputStream != null) { + return inputStream; + } + } catch (final Exception ignored) { + // ignored + } + return getClassFile(name, suffix).getInputStream(); + } + + /** + * @param name name of file to search for, e.g. java/lang/String.java + * @return full (canonical) path for file + * @throws IOException if an I/O error occurs. + */ + public String getPath(String name) throws IOException { + final int index = name.lastIndexOf('.'); + String suffix = ""; + if (index > 0) { + suffix = name.substring(index); + name = name.substring(0, index); + } + return getPath(name, suffix); + } + + /** + * @param name name of file to search for, e.g. java/lang/String + * @param suffix file name suffix, e.g. .java + * @return full (canonical) path for file, if it exists + * @throws IOException if an I/O error occurs. + */ + public String getPath(final String name, final String suffix) throws IOException { + return getClassFile(name, suffix).getPath(); + } + + /** + * @param name fully qualified resource name, e.g. java/lang/String.class + * @return URL supplying the resource, or null if no resource with that name. + * @since 6.0 + */ + public URL getResource(final String name) { + for (final AbstractPathEntry path : paths) { + URL url; + if ((url = path.getResource(name)) != null) { + return url; + } + } + return null; + } + + /** + * @param name fully qualified resource name, e.g. java/lang/String.class + * @return InputStream supplying the resource, or null if no resource with that name. + * @since 6.0 + */ + public InputStream getResourceAsStream(final String name) { + for (final AbstractPathEntry path : paths) { + InputStream is; + if ((is = path.getResourceAsStream(name)) != null) { + return is; + } + } + return null; + } + + /** + * @param name fully qualified resource name, e.g. java/lang/String.class + * @return An Enumeration of URLs supplying the resource, or an empty Enumeration if no resource with that name. + * @since 6.0 + */ + public Enumeration getResources(final String name) { + final Vector results = new Vector<>(); + for (final AbstractPathEntry path : paths) { + URL url; + if ((url = path.getResource(name)) != null) { + results.add(url); + } + } + return results.elements(); + } + + @Override + public int hashCode() { + return classPathString.hashCode(); + } + + /** + * @return used class path string + */ + @Override + public String toString() { + if (parent != null) { + return parent + File.pathSeparator + classPathString; + } + return classPathString; + } + + /** + * Contains information about file/ZIP entry of the Java class. + */ + public interface ClassFile { + + /** + * @return base path of found class, i.e. class is contained relative to that path, which may either denote a directory, + * or zip file + */ + String getBase(); + + /** + * @return input stream for class file. + * @throws IOException if an I/O error occurs. + */ + InputStream getInputStream() throws IOException; + + /** + * @return canonical path to class file. + */ + String getPath(); + + /** + * @return size of class file. + */ + long getSize(); + + /** + * @return modification time of class file. + */ + long getTime(); + } + private abstract static class AbstractPathEntry implements Closeable { abstract ClassFile getClassFile(String name, String suffix); @@ -126,39 +517,6 @@ public class ClassPath implements Closeable { } - /** - * Contains information about file/ZIP entry of the Java class. - */ - public interface ClassFile { - - /** - * @return base path of found class, i.e. class is contained relative to that path, which may either denote a directory, - * or zip file - */ - String getBase(); - - /** - * @return input stream for class file. - * @throws IOException if an I/O error occurs. - */ - InputStream getInputStream() throws IOException; - - /** - * @return canonical path to class file. - */ - String getPath(); - - /** - * @return size of class file. - */ - long getSize(); - - /** - * @return modification time of class file. - */ - long getTime(); - } - private static class Dir extends AbstractPathEntry { private final String dir; @@ -415,367 +773,4 @@ public class ClassPath implements Closeable { } } - - private static final FilenameFilter ARCHIVE_FILTER = (dir, name) -> { - name = name.toLowerCase(Locale.ENGLISH); - return name.endsWith(".zip") || name.endsWith(".jar"); - }; - - private static final FilenameFilter MODULES_FILTER = (dir, name) -> { - name = name.toLowerCase(Locale.ENGLISH); - return name.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION); - }; - - public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath(getClassPath()); - - private static void addJdkModules(final String javaHome, final List list) { - String modulesPath = System.getProperty("java.modules.path"); - if (modulesPath == null || modulesPath.trim().isEmpty()) { - // Default to looking in JAVA_HOME/jmods - modulesPath = javaHome + File.separator + "jmods"; - } - final File modulesDir = new File(modulesPath); - if (modulesDir.exists()) { - final String[] modules = modulesDir.list(MODULES_FILTER); - if (modules != null) { - for (final String module : modules) { - list.add(modulesDir.getPath() + File.separatorChar + module); - } - } - } - } - - /** - * Checks for class path components in the following properties: "java.class.path", "sun.boot.class.path", - * "java.ext.dirs" - * - * @return class path as used by default by BCEL - */ - // @since 6.0 no longer final - public static String getClassPath() { - final String classPathProp = System.getProperty("java.class.path"); - final String bootClassPathProp = System.getProperty("sun.boot.class.path"); - final String extDirs = System.getProperty("java.ext.dirs"); - // System.out.println("java.version = " + System.getProperty("java.version")); - // System.out.println("java.class.path = " + classPathProp); - // System.out.println("sun.boot.class.path=" + bootClassPathProp); - // System.out.println("java.ext.dirs=" + extDirs); - final String javaHome = System.getProperty("java.home"); - final List list = new ArrayList<>(); - - // Starting in JRE 9, .class files are in the modules directory. Add them to the path. - final Path modulesPath = Paths.get(javaHome).resolve("lib/modules"); - if (Files.exists(modulesPath) && Files.isRegularFile(modulesPath)) { - list.add(modulesPath.toAbsolutePath().toString()); - } - // Starting in JDK 9, .class files are in the jmods directory. Add them to the path. - addJdkModules(javaHome, list); - - getPathComponents(classPathProp, list); - getPathComponents(bootClassPathProp, list); - final List dirs = new ArrayList<>(); - getPathComponents(extDirs, dirs); - for (final String d : dirs) { - final File extDir = new File(d); - final String[] extensions = extDir.list(ARCHIVE_FILTER); - if (extensions != null) { - for (final String extension : extensions) { - list.add(extDir.getPath() + File.separatorChar + extension); - } - } - } - - return list.stream().collect(Collectors.joining(File.pathSeparator)); - } - - private static void getPathComponents(final String path, final List list) { - if (path != null) { - final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - final String name = tokenizer.nextToken(); - final File file = new File(name); - if (file.exists()) { - list.add(name); - } - } - } - } - - private final String classPathString; - - private final ClassPath parent; - - private final List paths; - - /** - * Search for classes in CLASSPATH. - * - * @deprecated Use SYSTEM_CLASS_PATH constant - */ - @Deprecated - public ClassPath() { - this(getClassPath()); - } - - @SuppressWarnings("resource") - public ClassPath(final ClassPath parent, final String classPathString) { - this.parent = parent; - this.classPathString = Objects.requireNonNull(classPathString, "classPathString"); - this.paths = new ArrayList<>(); - for (final StringTokenizer tokenizer = new StringTokenizer(classPathString, File.pathSeparator); tokenizer.hasMoreTokens();) { - final String path = tokenizer.nextToken(); - if (!path.isEmpty()) { - final File file = new File(path); - try { - if (file.exists()) { - if (file.isDirectory()) { - paths.add(new Dir(path)); - } else if (path.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION)) { - paths.add(new Module(new ZipFile(file))); - } else if (path.endsWith(ModularRuntimeImage.MODULES_PATH)) { - paths.add(new JrtModules(ModularRuntimeImage.MODULES_PATH)); - } else { - paths.add(new Jar(new ZipFile(file))); - } - } - } catch (final IOException e) { - if (path.endsWith(".zip") || path.endsWith(".jar")) { - System.err.println("CLASSPATH component " + file + ": " + e); - } - } - } - } - } - - /** - * Search for classes in given path. - * - * @param classPath - */ - public ClassPath(final String classPath) { - this(null, classPath); - } - - @Override - public void close() throws IOException { - for (final AbstractPathEntry path : paths) { - path.close(); - } - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ClassPath other = (ClassPath) obj; - return Objects.equals(classPathString, other.classPathString); - } - - /** - * @param name fully qualified file name, e.g. java/lang/String - * @return byte array for class - * @throws IOException if an I/O error occurs. - */ - public byte[] getBytes(final String name) throws IOException { - return getBytes(name, JavaClass.EXTENSION); - } - - /** - * @param name fully qualified file name, e.g. java/lang/String - * @param suffix file name ends with suffix, e.g. .java - * @return byte array for file on class path - * @throws IOException if an I/O error occurs. - */ - public byte[] getBytes(final String name, final String suffix) throws IOException { - DataInputStream dis = null; - try (InputStream inputStream = getInputStream(name, suffix)) { - if (inputStream == null) { - throw new IOException("Couldn't find: " + name + suffix); - } - dis = new DataInputStream(inputStream); - final byte[] bytes = new byte[inputStream.available()]; - dis.readFully(bytes); - return bytes; - } finally { - if (dis != null) { - dis.close(); - } - } - } - - /** - * @param name fully qualified class name, e.g. java.lang.String - * @return input stream for class - * @throws IOException if an I/O error occurs. - */ - public ClassFile getClassFile(final String name) throws IOException { - return getClassFile(name, JavaClass.EXTENSION); - } - - /** - * @param name fully qualified file name, e.g. java/lang/String - * @param suffix file name ends with suff, e.g. .java - * @return class file for the java class - * @throws IOException if an I/O error occurs. - */ - public ClassFile getClassFile(final String name, final String suffix) throws IOException { - ClassFile cf = null; - - if (parent != null) { - cf = parent.getClassFileInternal(name, suffix); - } - - if (cf == null) { - cf = getClassFileInternal(name, suffix); - } - - if (cf != null) { - return cf; - } - - throw new IOException("Couldn't find: " + name + suffix); - } - - private ClassFile getClassFileInternal(final String name, final String suffix) { - for (final AbstractPathEntry path : paths) { - final ClassFile cf = path.getClassFile(name, suffix); - if (cf != null) { - return cf; - } - } - return null; - } - - /** - * Gets an InputStream. - *

- * The caller is responsible for closing the InputStream. - *

- * @param name fully qualified class name, e.g. java.lang.String - * @return input stream for class - * @throws IOException if an I/O error occurs. - */ - public InputStream getInputStream(final String name) throws IOException { - return getInputStream(Utility.packageToPath(name), JavaClass.EXTENSION); - } - - /** - * Gets an InputStream for a class or resource on the classpath. - *

- * The caller is responsible for closing the InputStream. - *

- * - * @param name fully qualified file name, e.g. java/lang/String - * @param suffix file name ends with suff, e.g. .java - * @return input stream for file on class path - * @throws IOException if an I/O error occurs. - */ - public InputStream getInputStream(final String name, final String suffix) throws IOException { - try { - final java.lang.ClassLoader classLoader = getClass().getClassLoader(); - @SuppressWarnings("resource") // closed by caller - final - InputStream inputStream = classLoader == null ? null : classLoader.getResourceAsStream(name + suffix); - if (inputStream != null) { - return inputStream; - } - } catch (final Exception ignored) { - // ignored - } - return getClassFile(name, suffix).getInputStream(); - } - - /** - * @param name name of file to search for, e.g. java/lang/String.java - * @return full (canonical) path for file - * @throws IOException if an I/O error occurs. - */ - public String getPath(String name) throws IOException { - final int index = name.lastIndexOf('.'); - String suffix = ""; - if (index > 0) { - suffix = name.substring(index); - name = name.substring(0, index); - } - return getPath(name, suffix); - } - - /** - * @param name name of file to search for, e.g. java/lang/String - * @param suffix file name suffix, e.g. .java - * @return full (canonical) path for file, if it exists - * @throws IOException if an I/O error occurs. - */ - public String getPath(final String name, final String suffix) throws IOException { - return getClassFile(name, suffix).getPath(); - } - - /** - * @param name fully qualified resource name, e.g. java/lang/String.class - * @return URL supplying the resource, or null if no resource with that name. - * @since 6.0 - */ - public URL getResource(final String name) { - for (final AbstractPathEntry path : paths) { - URL url; - if ((url = path.getResource(name)) != null) { - return url; - } - } - return null; - } - - /** - * @param name fully qualified resource name, e.g. java/lang/String.class - * @return InputStream supplying the resource, or null if no resource with that name. - * @since 6.0 - */ - public InputStream getResourceAsStream(final String name) { - for (final AbstractPathEntry path : paths) { - InputStream is; - if ((is = path.getResourceAsStream(name)) != null) { - return is; - } - } - return null; - } - - /** - * @param name fully qualified resource name, e.g. java/lang/String.class - * @return An Enumeration of URLs supplying the resource, or an empty Enumeration if no resource with that name. - * @since 6.0 - */ - public Enumeration getResources(final String name) { - final Vector results = new Vector<>(); - for (final AbstractPathEntry path : paths) { - URL url; - if ((url = path.getResource(name)) != null) { - results.add(url); - } - } - return results.elements(); - } - - @Override - public int hashCode() { - return classPathString.hashCode(); - } - - /** - * @return used class path string - */ - @Override - public String toString() { - if (parent != null) { - return parent + File.pathSeparator + classPathString; - } - return classPathString; - } } diff --git a/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java b/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java index 5040160..ec9160f 100644 --- a/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java +++ b/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java @@ -43,6 +43,16 @@ import java.lang.reflect.Modifier; */ public class JavaWrapper { + private final java.lang.ClassLoader loader; + + public JavaWrapper() { + this(getClassLoader()); + } + + public JavaWrapper(final java.lang.ClassLoader loader) { + this.loader = loader; + } + private static java.lang.ClassLoader getClassLoader() { final String s = System.getProperty("bcel.classloader"); if (StringUtils.isEmpty(s)) { @@ -72,21 +82,11 @@ public class JavaWrapper { new JavaWrapper().runMain(className, newArgv); } - private final java.lang.ClassLoader loader; - - public JavaWrapper() { - this(getClassLoader()); - } - - public JavaWrapper(final java.lang.ClassLoader loader) { - this.loader = loader; - } - /** * Runs the main method of the given class with the arguments passed in argv * * @param className the fully qualified class name - * @param argv the arguments just as you would pass them directly + * @param argv the arguments just as you would pass them directly * @throws ClassNotFoundException if {@code className} can't be found. */ public void runMain(final String className, final String[] argv) throws ClassNotFoundException { diff --git a/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java b/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java index 38dc24e..fde7d58 100644 --- a/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java +++ b/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java @@ -53,14 +53,13 @@ public class ModularRuntimeImage implements Closeable { * Constructs an instance using the JRT file system implementation from a specific Java Home. * * @param javaHome Path to a Java 9 or greater home. - * * @throws IOException an I/O error occurs accessing the file system */ public ModularRuntimeImage(final String javaHome) throws IOException { final Map emptyMap = Collections.emptyMap(); final Path jrePath = Paths.get(javaHome); final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar"); - this.classLoader = URLClassLoader.newInstance(new URL[] {jrtFsPath.toUri().toURL()}); + this.classLoader = URLClassLoader.newInstance(new URL[]{jrtFsPath.toUri().toURL()}); this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader); } diff --git a/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java b/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java index a54dfba..56aa757 100644 --- a/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java +++ b/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java @@ -36,6 +36,10 @@ public class SyntheticRepository extends MemorySensitiveClassPathRepository { private static final Map MAP = new HashMap<>(); // CLASSPATH X REPOSITORY + private SyntheticRepository(final ClassPath path) { + super(path); + } + public static SyntheticRepository getInstance() { return getInstance(ClassPath.SYSTEM_CLASS_PATH); } @@ -43,8 +47,4 @@ public class SyntheticRepository extends MemorySensitiveClassPathRepository { public static SyntheticRepository getInstance(final ClassPath classPath) { return MAP.computeIfAbsent(classPath, SyntheticRepository::new); } - - private SyntheticRepository(final ClassPath path) { - super(path); - } } diff --git a/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java b/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java new file mode 100644 index 0000000..46a7ace --- /dev/null +++ b/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java @@ -0,0 +1,108 @@ +package haidnor.jvm.classloader; + +import haidnor.jvm.bcel.classfile.ClassParser; +import haidnor.jvm.bcel.classfile.JavaClass; +import haidnor.jvm.bcel.classfile.JavaMethod; +import haidnor.jvm.rtda.Metaspace; +import lombok.SneakyThrows; + +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class JVMClassLoader { + + public final static String JAVA_HOME; + /** + * JDK java.base.jmod path + */ + public final static String javaBaseJmodPath; + + static { + JAVA_HOME = System.getenv("JAVA_HOME"); + javaBaseJmodPath = JAVA_HOME + "/jmods/java.base.jmod"; + } + + public final String name; + public JarFile jarFile = null; + + public JVMClassLoader(String name) { + this.name = name; + } + + public JVMClassLoader(JarFile jarFile, String name) { + this.name = name; + this.jarFile = jarFile; + } + + /** + * @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader + */ + @SneakyThrows + public JavaClass loadWithClassPath(String classPath) { + ClassParser classParser = null; + if (classPath.startsWith("java/")) { + classParser = new ClassParser(javaBaseJmodPath, "classes/" + classPath + ".class"); + } else if (jarFile != null) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + String className = entry.getName().substring(0, entry.getName().length() - 6); + if (className.equals(classPath)) { + InputStream inputStream = jarFile.getInputStream(entry); + classParser = new ClassParser(inputStream, null); + } + } + } + } else { + URL resource = this.getClass().getResource("/"); + String fileName = resource.getPath() + classPath + ".class"; + classParser = new ClassParser(fileName); + } + return load(classParser); + } + + @SneakyThrows + public JavaClass loadWithJar(JarFile jarFile, JarEntry entry) { + InputStream inputStream = jarFile.getInputStream(entry); + ClassParser classParser = new ClassParser(inputStream, null); + return load(classParser); + } + + public JavaClass loadWithAbsolutePath(String absolutePath) { + ClassParser classParser = new ClassParser(absolutePath); + return load(classParser); + } + + @SneakyThrows + private JavaClass load(ClassParser classParser) { + JavaClass javaClass = classParser.parse(); + javaClass.setJVMClassLoader(this); + register(javaClass); + return javaClass; + } + + @SneakyThrows + private void register(JavaClass javaClass) { + JavaClass superJavaClass = javaClass.getSuperClass(); + if (superJavaClass != null) { + register(superJavaClass); + } + Metaspace.registerJavaClass(javaClass); + + if (javaClass.getClassName().startsWith("java.")) { + return; + } + for (JavaMethod method : javaClass.getMethods()) { + if (method.toString().equals("static void ()")) { + // JavaExecutionEngine.callMethod(null, method); + break; + } + } + } + + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java new file mode 100644 index 0000000..c1d1979 --- /dev/null +++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java @@ -0,0 +1,168 @@ +package haidnor.jvm.core; + + +import haidnor.jvm.bcel.Const; +import haidnor.jvm.bcel.classfile.*; +import haidnor.jvm.instruction.Instruction; +import haidnor.jvm.instruction.InstructionFactory; +import haidnor.jvm.instruction.ReturnableInstruction; +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.runtime.JVMThread; +import haidnor.jvm.runtime.StackValue; +import haidnor.jvm.util.CodeStream; +import haidnor.jvm.util.JVMThreadHolder; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * JVM 字节码执行引擎 + */ +@Slf4j +public class JavaExecutionEngine { + + /** + * 执行 public static void main(String[] args) 方法 + */ + public static void callMainMethod(JavaClass javaClass) { + JavaMethod mainMethod = javaClass.getMainMethod(); + callMethod(null, javaClass, mainMethod); + } + + /** + * 执行普通方法 + * + * @param lastFrame 方法调用者的栈帧 + * @param javaMethod 方法元信息 + */ + public static void callMethod(Frame lastFrame, JavaClass javaClass, JavaMethod javaMethod) { + JVMThread jvmThread = JVMThreadHolder.get(); + // 调用方法时会创建新的栈帧 + Frame newFrame = new Frame(jvmThread, javaClass, javaMethod); + + // 如果线程栈内存在栈帧, 代表可能需要方法调用传参 + if (lastFrame != null) { + String signature = javaMethod.getSignature(); + String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature); + + int argumentSlotSize = argumentTypes.length; + if (!javaMethod.isStatic()) { + argumentSlotSize++; + } + + // 方法调用传参 (原理: 将顶部栈帧的操作数栈中的数据弹出, 存入新栈帧的局部变量表中) + LocalVariableTable localVariableTable = javaMethod.getLocalVariableTable(); + if (localVariableTable != null) { + for (int i = argumentSlotSize - 1; i >= 0; i--) { + LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable(); + LocalVariable localVariable = localVariableArr[i]; + int slotIndex = localVariable.getIndex(); + StackValue stackValue = lastFrame.pop(); + newFrame.slotSet(slotIndex, stackValue); + } + } + } + + // 将新栈帧压入线程栈顶部, 并执行新栈帧中的代码 + jvmThread.push(newFrame); + executeFrame(newFrame); + } + + /** + * 执行 JVM 线程栈栈帧 (haidnorJVM 中最关键的代码) + */ + @SneakyThrows + public static void executeFrame(Frame frame) { + int stackSize = frame.getJvmThread().stackSize(); + + String blank = getDebugStackInfoBlank(stackSize); + log.debug("{}┌──────────────────[{}] {} | {}", blank, stackSize, frame.getJavaClass().getClassName(), frame.getJavaMethod()); + + // 解析方法中的字节码指令 + Map instructionMap = new HashMap<>(); + CodeStream codeStream = frame.getCodeStream(); + while (codeStream.available() > 0) { + Instruction instruction = InstructionFactory.creatInstruction(codeStream); + instructionMap.put(instruction.getIndex(), instruction); + // log.debug("{}│> {}", blank, instruction); // debug 输出解析字节码指令的内容 + } + // log.debug("{}├ - - - - - - - - -", blank); + + // 执行方法中的字节码指令 + // 提示: 变量 pc 相当于程序计数器, 记录当前执行到的字节码指令的"行号" + for (int pc = 0; pc < frame.getCodeLength(); ) { + Instruction instruction = instructionMap.get(pc); + log.debug("{}│ {}", blank, instruction); + try { + // 执行字节码指令 + instruction.execute(frame); + // 若为 return 系列指令则结束当前栈帧 (RETURN,ARETURN,DRETURN,FRETURN,IRETURN) + if (instruction instanceof ReturnableInstruction) { + break; + } + // 程序计数器值增加. 指向下一次执行的字节码行号 + pc += instruction.getOffSet(); + } + // 捕获执行字节码指令抛出的异常 + catch (Exception exception) { + // 从类元信息中获取异常表 + CodeException[] exceptionTable = frame.getJavaMethod().getCode().getExceptionTable(); + + // handlerPC 是从异常表中获取的处理异常的字节码行号 (如果查询不到就会一直为 null. 代表方法无异常处理代码) + Integer handlerPC = null; + for (CodeException codeException : exceptionTable) { + if (codeException.getStartPC() <= pc && pc <= codeException.getEndPC()) { + // 异常类型 (0 代表捕获所有类型的异常) + int catchType = codeException.getCatchType(); + if (catchType == 0) { + frame.push(new StackValue(Const.T_OBJECT, exception)); + handlerPC = codeException.getHandlerPC(); + } else { + // 从常量池中查询异常表定义的异常类型 + String exceptionClassName = frame.getJavaClass().getConstantPool().constantClass_ClassName(catchType); + exceptionClassName = Utility.compactClassName(exceptionClassName, false); + + // 判断异常的泛型类型. 假如执行指令抛出的是 NullPointerException 类型, 异常表定义的是 Exception 类型, 则此异常可以被捕获 + Class exceptionClass = Class.forName(exceptionClassName); + if (exceptionClass.isAssignableFrom(exception.getClass())) { + frame.push(new StackValue(Const.T_OBJECT, exception)); + handlerPC = codeException.getHandlerPC(); + } + } + } + } + if (handlerPC != null) { + // 将程序计数器跳转到处理异常的字节码指令上 + pc = handlerPC; + } else { + // 方法无异常处理,结束栈帧. 将异常抛给调用者处理 + log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize); + throw exception; + } + } + + } + + log.debug("{}└──────────────────[{}] {} | {}", blank, stackSize, frame.getJavaClass().getClassName(), frame.getJavaMethod()); + } + + /** + * 计算绘画 jvm 线程栈 debug 日志信息的空格 + * 用于表现栈的调用关系 + * + * @param stackSize 当前 JVM 线程栈的栈帧数量 + */ + private static String getDebugStackInfoBlank(int stackSize) { + StringBuilder blank = new StringBuilder(); + blank.append(" ".repeat(stackSize - 1)); + int index = 0; + for (int i = 0; i < stackSize - 1; i++) { + blank.replace(index, index + 1, "│"); + index += 20; + } + return blank.toString(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/Instruction.java b/src/main/java/haidnor/jvm/instruction/Instruction.java new file mode 100644 index 0000000..331db8c --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/Instruction.java @@ -0,0 +1,31 @@ +package haidnor.jvm.instruction; + +import haidnor.jvm.runtime.Frame; +import haidnor.jvm.util.CodeStream; +import lombok.Getter; +import lombok.Setter; + +@Getter +public abstract class Instruction { + /** + * 指令在字节码 code 数组中的索引下标 (指令行号) + */ + private final int index; + /** + * 执行下一个指令的偏移量 + */ + @Setter + private int offSet = 1; + + public Instruction(CodeStream codeStream) { + this.index = codeStream.getIndex(); + } + + public abstract void execute(Frame frame); + + @Override + public String toString() { + return index + " " + this.getClass().getSimpleName(); + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/InstructionFactory.java b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java new file mode 100644 index 0000000..6d28943 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java @@ -0,0 +1,617 @@ +package haidnor.jvm.instruction; + +import haidnor.jvm.util.CodeStream; + +public abstract class InstructionFactory { + + public static Instruction creatInstruction(CodeStream codeStream) { + int opcode = codeStream.readJavaVmOpcode(); + switch (opcode) { +// case Const.NOP -> { +// return new NOP(codeStream); +// } +// case Const.ACONST_NULL -> { +// return new ACONST_NULL(codeStream); +// } +// case Const.ICONST_M1 -> { +// return new ICONST_M1(codeStream); +// } +// case Const.ICONST_0 -> { +// return new ICONST_0(codeStream); +// } +// case Const.ICONST_1 -> { +// return new ICONST_1(codeStream); +// } +// case Const.ICONST_2 -> { +// return new ICONST_2(codeStream); +// } +// case Const.ICONST_3 -> { +// return new ICONST_3(codeStream); +// } +// case Const.ICONST_4 -> { +// return new ICONST_4(codeStream); +// } +// case Const.ICONST_5 -> { +// return new ICONST_5(codeStream); +// } +// case Const.LCONST_0 -> { +// return new LCONST_0(codeStream); +// } +// case Const.LCONST_1 -> { +// return new LCONST_1(codeStream); +// } +// case Const.FCONST_1 -> { +// return new FCONST_1(codeStream); +// } +// case Const.FCONST_2 -> { +// return new FCONST_2(codeStream); +// } +// case Const.DCONST_0 -> { +// return new DCONST_0(codeStream); +// } +// case Const.DCONST_1 -> { +// return new DCONST_1(codeStream); +// } +// case Const.BIPUSH -> { +// return new BIPUSH(codeStream); +// } +// case Const.SIPUSH -> { +// return new SIPUSH(codeStream); +// } +// case Const.LDC -> { +// return new LDC(codeStream); +// } +// case Const.LDC_W -> { +// return new LDC_W(codeStream); +// } +// case Const.LDC2_W -> { +// return new LDC2W(codeStream); +// } +// case Const.ILOAD -> { +// return new ILOAD(codeStream); +// } +// case Const.LLOAD -> { +// return new LLOAD(codeStream); +// } +// case Const.FLOAD -> { +// return new FLOAD(codeStream); +// } +// case Const.DLOAD -> { +// return new DLOAD(codeStream); +// } +// case Const.ALOAD -> { +// return new ALOAD(codeStream); +// } +// case Const.ILOAD_0 -> { +// return new ILOAD_0(codeStream); +// } +// case Const.ILOAD_1 -> { +// return new ILOAD_1(codeStream); +// } +// case Const.ILOAD_2 -> { +// return new ILOAD_2(codeStream); +// } +// case Const.ILOAD_3 -> { +// return new ILOAD_3(codeStream); +// } +// case Const.LLOAD_0 -> { +// return new LLOAD_0(codeStream); +// } +// case Const.LLOAD_1 -> { +// return new LLOAD_1(codeStream); +// } +// case Const.LLOAD_2 -> { +// return new LLOAD_2(codeStream); +// } +// case Const.LLOAD_3 -> { +// return new LLOAD_3(codeStream); +// } +// case Const.FLOAD_0 -> { +// return new FLOAD_0(codeStream); +// } +// case Const.FLOAD_1 -> { +// return new FLOAD_1(codeStream); +// } +// case Const.FLOAD_2 -> { +// return new FLOAD_2(codeStream); +// } +// case Const.FLOAD_3 -> { +// return new FLOAD_3(codeStream); +// } +// case Const.DLOAD_0 -> { +// return new DLOAD_0(codeStream); +// } +// case Const.DLOAD_1 -> { +// return new DLOAD_1(codeStream); +// } +// case Const.DLOAD_2 -> { +// return new DLOAD_2(codeStream); +// } +// case Const.DLOAD_3 -> { +// return new DLOAD_3(codeStream); +// } +// case Const.ALOAD_0 -> { +// return new ALOAD_0(codeStream); +// } +// case Const.ALOAD_1 -> { +// return new ALOAD_1(codeStream); +// } +// case Const.ALOAD_2 -> { +// return new ALOAD_2(codeStream); +// } +// case Const.ALOAD_3 -> { +// return new ALOAD_3(codeStream); +// } +// case Const.IALOAD -> { +// return new IALOAD(codeStream); +// } +// case Const.LALOAD -> { +// return new LALOAD(codeStream); +// } +// case Const.FALOAD -> { +// return new FALOAD(codeStream); +// } +// case Const.DALOAD -> { +// return new DALOAD(codeStream); +// } +// case Const.AALOAD -> { +// return new AALOAD(codeStream); +// } +// case Const.BALOAD -> { +// return new BALOAD(codeStream); +// } +// case Const.CALOAD -> { +// return new CALOAD(codeStream); +// } +// case Const.SALOAD -> { +// return new SALOAD(codeStream); +// } +// case Const.ISTORE -> { +// return new ISTORE(codeStream); +// } +// case Const.LSTORE -> { +// return new LSTORE(codeStream); +// } +// case Const.FSTORE -> { +// return new FSTORE(codeStream); +// } +// case Const.DSTORE -> { +// return new DSTORE(codeStream); +// } +// case Const.ASTORE -> { +// return new ASTORE(codeStream); +// } +// case Const.ISTORE_0 -> { +// return new ISTORE_0(codeStream); +// } +// case Const.ISTORE_1 -> { +// return new ISTORE_1(codeStream); +// } +// case Const.ISTORE_2 -> { +// return new ISTORE_2(codeStream); +// } +// case Const.ISTORE_3 -> { +// return new ISTORE_3(codeStream); +// } +// case Const.LSTORE_0 -> { +// return new LSTORE_0(codeStream); +// } +// case Const.LSTORE_1 -> { +// return new LSTORE_1(codeStream); +// } +// case Const.LSTORE_2 -> { +// return new LSTORE_2(codeStream); +// } +// case Const.LSTORE_3 -> { +// return new LSTORE_3(codeStream); +// } +// case Const.FSTORE_0 -> { +// return new FSTORE_0(codeStream); +// } +// case Const.FSTORE_1 -> { +// return new FSTORE_1(codeStream); +// } +// case Const.FSTORE_2 -> { +// return new FSTORE_2(codeStream); +// } +// case Const.FSTORE_3 -> { +// return new FSTORE_3(codeStream); +// } +// case Const.DSTORE_0 -> { +// return new DSTORE_0(codeStream); +// } +// case Const.DSTORE_1 -> { +// return new DSTORE_1(codeStream); +// } +// case Const.DSTORE_2 -> { +// return new DSTORE_2(codeStream); +// } +// case Const.DSTORE_3 -> { +// return new DSTORE_3(codeStream); +// } +// case Const.ASTORE_0 -> { +// return new ASTORE_0(codeStream); +// } +// case Const.ASTORE_1 -> { +// return new ASTORE_1(codeStream); +// } +// case Const.ASTORE_2 -> { +// return new ASTORE_2(codeStream); +// } +// case Const.ASTORE_3 -> { +// return new ASTORE_3(codeStream); +// } +// case Const.IASTORE -> { +// return new IASTORE(codeStream); +// } +// case Const.LASTORE -> { +// return new LASTORE(codeStream); +// } +// case Const.FASTORE -> { +// return new FASTORE(codeStream); +// } +// case Const.DASTORE -> { +// return new DASTORE(codeStream); +// } +// case Const.AASTORE -> { +// return new AASTORE(codeStream); +// } +// case Const.BASTORE -> { +// return new BASTORE(codeStream); +// } +// case Const.CASTORE -> { +// return new CASTORE(codeStream); +// } +// case Const.SASTORE -> { +// return new SASTORE(codeStream); +// } +// case Const.POP -> { +// return new POP(codeStream); +// } +// case Const.POP2 -> { +// return new POP2(codeStream); +// } +// case Const.DUP -> { +// return new DUP(codeStream); +// } +// case Const.DUP_X1 -> { +// return new DUP_X1(codeStream); +// } +// case Const.DUP_X2 -> { +// return new DUP_X2(codeStream); +// } +// case Const.DUP2 -> { +// return new DUP2(codeStream); +// } +// case Const.DUP2_X1 -> { +// return new DUP2_X1(codeStream); +// } +// case Const.DUP2_X2 -> { +// return new DUP2_X2(codeStream); +// } +// case Const.SWAP -> { +// return new SWAP(codeStream); +// } +// case Const.IADD -> { +// return new IADD(codeStream); +// } +// case Const.LADD -> { +// return new LADD(codeStream); +// } +// case Const.FADD -> { +// return new FADD(codeStream); +// } +// case Const.DADD -> { +// return new DADD(codeStream); +// } +// case Const.ISUB -> { +// return new ISUB(codeStream); +// } +// case Const.LSUB -> { +// return new LSUB(codeStream); +// } +// case Const.FSUB -> { +// return new FSUB(codeStream); +// } +// case Const.DSUB -> { +// return new DSUB(codeStream); +// } +// case Const.IMUL -> { +// return new IMUL(codeStream); +// } +// case Const.LMUL -> { +// return new LMUL(codeStream); +// } +// case Const.FMUL -> { +// return new FMUL(codeStream); +// } +// case Const.DMUL -> { +// return new DMUL(codeStream); +// } +// case Const.IDIV -> { +// return new IDIV(codeStream); +// } +// case Const.LDIV -> { +// return new LDIV(codeStream); +// } +// case Const.FDIV -> { +// return new FDIV(codeStream); +// } +// case Const.DDIV -> { +// return new DDIV(codeStream); +// } +// case Const.IREM -> { +// return new IREM(codeStream); +// } +// case Const.LREM -> { +// return new LREM(codeStream); +// } +// case Const.FREM -> { +// return new FREM(codeStream); +// } +// case Const.DREM -> { +// return new DREM(codeStream); +// } +// case Const.INEG -> { +// return new INEG(codeStream); +// } +// case Const.LNEG -> { +// return new LNEG(codeStream); +// } +// case Const.FNEG -> { +// return new FNEG(codeStream); +// } +// case Const.DNEG -> { +// return new DNEG(codeStream); +// } +// case Const.ISHL -> { +// return new ISHL(codeStream); +// } +// case Const.LSHL -> { +// return new LSHL(codeStream); +// } +// case Const.ISHR -> { +// return new ISHR(codeStream); +// } +// case Const.LSHR -> { +// return new LSHR(codeStream); +// } +// case Const.IUSHR -> { +// return new IUSHR(codeStream); +// } +// case Const.LUSHR -> { +// return new LUSHR(codeStream); +// } +// case Const.IAND -> { +// return new IAND(codeStream); +// } +// case Const.LAND -> { +// return new LAND(codeStream); +// } +// case Const.IOR -> { +// return new IOR(codeStream); +// } +// case Const.LOR -> { +// return new LOR(codeStream); +// } +// case Const.IXOR -> { +// return new IXOR(codeStream); +// } +// case Const.LXOR -> { +// return new LXOR(codeStream); +// } +// case Const.IINC -> { +// return new IINC(codeStream); +// } +// case Const.I2L -> { +// return new I2L(codeStream); +// } +// case Const.I2F -> { +// return new I2F(codeStream); +// } +// case Const.I2D -> { +// return new I2D(codeStream); +// } +// case Const.L2I -> { +// return new L2I(codeStream); +// } +// case Const.L2F -> { +// return new L2F(codeStream); +// } +// case Const.L2D -> { +// return new L2D(codeStream); +// } +// case Const.F2I -> { +// return new F2I(codeStream); +// } +// case Const.F2L -> { +// return new F2L(codeStream); +// } +// case Const.F2D -> { +// return new F2D(codeStream); +// } +// case Const.D2I -> { +// return new D2I(codeStream); +// } +// case Const.D2L -> { +// return new D2L(codeStream); +// } +// case Const.D2F -> { +// return new D2F(codeStream); +// } +// case Const.I2B -> { +// return new I2B(codeStream); +// } +// case Const.I2C -> { +// return new I2C(codeStream); +// } +// case Const.I2S -> { +// return new I2S(codeStream); +// } +// case Const.LCMP -> { +// return new LCMP(codeStream); +// } +// case Const.FCMPL -> { +// return new FCMPL(codeStream); +// } +// case Const.FCMPG -> { +// return new FCMPG(codeStream); +// } +// case Const.DCMPL -> { +// return new DCMPL(codeStream); +// } +// case Const.DCMPG -> { +// return new DCMPG(codeStream); +// } +// case Const.IFEQ -> { +// return new IFEQ(codeStream); +// } +// case Const.IFNE -> { +// return new IFNE(codeStream); +// } +// case Const.IFLT -> { +// return new IFLT(codeStream); +// } +// case Const.IFGE -> { +// return new IFGE(codeStream); +// } +// case Const.IFGT -> { +// return new IFGT(codeStream); +// } +// case Const.IFLE -> { +// return new IFLE(codeStream); +// } +// case Const.IF_ICMPEQ -> { +// return new IF_ICMPEQ(codeStream); +// } +// case Const.IF_ICMPNE -> { +// return new IF_ICMPNE(codeStream); +// } +// case Const.IF_ICMPLT -> { +// return new IF_ICMPLT(codeStream); +// } +// case Const.IF_ICMPGE -> { +// return new IF_ICMPGE(codeStream); +// } +// case Const.IF_ICMPGT -> { +// return new IF_ICMPGT(codeStream); +// } +// case Const.IF_ICMPLE -> { +// return new IF_ICMPLE(codeStream); +// } +// case Const.IF_ACMPEQ -> { +// return new IF_ACMPEQ(codeStream); +// } +// case Const.IF_ACMPNE -> { +// return new IF_ACMPNE(codeStream); +// } +// case Const.GOTO -> { +// return new GOTO(codeStream); +// } +// case Const.JSR -> { +// return new JSR(codeStream); +// } +// case Const.RET -> { +// return new RET(codeStream); +// } +// case Const.TABLESWITCH -> { +// return new TABLESWITCH(codeStream); // TODO +// } +// case Const.LOOKUPSWITCH -> { +// return new LOOKUPSWITCH(codeStream); // TODO +// } +// case Const.IRETURN -> { +// return new IRETURN(codeStream); +// } +// case Const.LRETURN -> { +// return new LRETURN(codeStream); +// } +// case Const.FRETURN -> { +// return new FRETURN(codeStream); +// } +// case Const.DRETURN -> { +// return new DRETURN(codeStream); +// } +// case Const.ARETURN -> { +// return new ARETURN(codeStream); +// } +// case Const.RETURN -> { +// return new RETURN(codeStream); +// } +// case Const.GETSTATIC -> { +// return new GETSTATIC(codeStream); +// } +// case Const.PUTSTATIC -> { +// return new PUTSTATIC(codeStream); +// } +// case Const.GETFIELD -> { +// return new GETFIELD(codeStream); +// } +// case Const.PUTFIELD -> { +// return new PUTFIELD(codeStream); +// } +// case Const.INVOKEVIRTUAL -> { +// return new INVOKEVIRTUAL(codeStream); +// } +// case Const.INVOKESPECIAL -> { +// return new INVOKESPECIAL(codeStream); +// } +// case Const.INVOKESTATIC -> { +// return new INVOKESTATIC(codeStream); +// } +// case Const.INVOKEINTERFACE -> { +// return new INVOKEINTERFACE(codeStream); +// } +// case Const.INVOKEDYNAMIC -> { +// return new INVOKEDYNAMIC(codeStream); // TODO +// } +// case Const.NEW -> { +// return new NEW(codeStream); +// } +// case Const.NEWARRAY -> { +// return new NEWARRAY(codeStream); +// } +// case Const.ANEWARRAY -> { +// return new ANEWARRAY(codeStream); +// } +// case Const.ARRAYLENGTH -> { +// return new ARRAYLENGTH(codeStream); +// } +// case Const.ATHROW -> { +// return new ATHROW(codeStream); +// } +// case Const.CHECKCAST -> { +// return new CHECKCAST(codeStream); +// } +// case Const.INSTANCEOF -> { +// return new INSTANCEOF(codeStream); +// } +// case Const.MONITORENTER -> { +// return new MONITORENTER(codeStream); +// } +// case Const.MONITOREXIT -> { +// return new MONITOREXIT(codeStream); +// } +// case Const.WIDE -> { +// return new WIDE(codeStream); +// } +// case Const.MULTIANEWARRAY -> { +// return new MULTIANEWARRAY(codeStream); +// } +// case Const.IFNULL -> { +// return new IFNULL(codeStream); +// } +// case Const.IFNONNULL -> { +// return new IFNONNULL(codeStream); +// } +// case Const.GOTO_W -> { +// return new GOTO_W(codeStream); +// } +// case Const.JSR_W -> { +// return new JSR_W(codeStream); +// } + default -> throw new Error("Unknown JavaVM opcode " + opcode); + } + } + +} diff --git a/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java b/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java new file mode 100644 index 0000000..b5c91b3 --- /dev/null +++ b/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java @@ -0,0 +1,14 @@ +package haidnor.jvm.instruction; + +import haidnor.jvm.util.CodeStream; + +/** + * return 系列字节码指令的抽象类 + */ +public abstract class ReturnableInstruction extends Instruction { + + public ReturnableInstruction(CodeStream codeStream) { + super(codeStream); + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/ArrayInstance.java b/src/main/java/haidnor/jvm/rtda/ArrayInstance.java new file mode 100644 index 0000000..09ccb13 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/ArrayInstance.java @@ -0,0 +1,14 @@ +package haidnor.jvm.rtda; + +import haidnor.jvm.bcel.classfile.JavaClass; + +public abstract class ArrayInstance extends Instance { + + public final int size; + + public ArrayInstance(JavaClass javaClass, int size) { + super(javaClass); + this.size = size; + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java b/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java new file mode 100644 index 0000000..cb4a6b9 --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java @@ -0,0 +1,62 @@ +package haidnor.jvm.rtda; + +public class BasicTypeArray extends ArrayInstance { + + public int[] ints; + public long[] longs; + public float[] floats; + public double[] doubles; + + private BasicTypeArray(int size) { + super(null, size); + } + + public static BasicTypeArray charArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray boolArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray byteArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray shortArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray intArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.ints = new int[size]; + return array; + } + + public static BasicTypeArray longArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.longs = new long[size]; + return array; + } + + public static BasicTypeArray floatArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.floats = new float[size]; + return array; + } + + public static BasicTypeArray doubleArray(int size) { + final BasicTypeArray array = new BasicTypeArray(size); + array.doubles = new double[size]; + return array; + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/rtda/Instance.java b/src/main/java/haidnor/jvm/rtda/Instance.java new file mode 100644 index 0000000..588e6fe --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/Instance.java @@ -0,0 +1,50 @@ +package haidnor.jvm.rtda; + + +import haidnor.jvm.bcel.classfile.JavaClass; +import haidnor.jvm.bcel.classfile.JavaField; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Instance { + + @Getter + private final JavaClass javaClass; + + private final List javaFieldList = new ArrayList<>(); + + private Instance superInstance; + + public Instance(JavaClass javaClass) { + this.javaClass = javaClass; + } + + public void setSuperInstance(Instance superInstance) { + this.superInstance = superInstance; + } + + /** + * 获取字段 + * + * @param name 字段名称 + * @param signature 字段签名 + */ + public JavaField getField(String name, String signature) { + // this object + for (JavaField field : javaFieldList) { + if (Objects.equals(field.getName(), name) && Objects.equals(field.getSignature(), signature)) { + return field; + } + } + if (this.superInstance == null) { + return null; + } + // super object + return this.superInstance.getField(name, signature); + } + + +} diff --git a/src/main/java/haidnor/jvm/rtda/InstanceArray.java b/src/main/java/haidnor/jvm/rtda/InstanceArray.java new file mode 100644 index 0000000..7935aba --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/InstanceArray.java @@ -0,0 +1,14 @@ +package haidnor.jvm.rtda; + +import haidnor.jvm.bcel.classfile.JavaClass; + +public class InstanceArray extends ArrayInstance { + + public final Instance[] items; + + public InstanceArray(JavaClass javaClass, Instance[] items) { + super(javaClass, items.length); + this.items = items; + } + +} \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/rtda/Metaspace.java b/src/main/java/haidnor/jvm/rtda/Metaspace.java new file mode 100644 index 0000000..f3ff57b --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/Metaspace.java @@ -0,0 +1,29 @@ +package haidnor.jvm.rtda; + +import haidnor.jvm.bcel.classfile.JavaClass; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class Metaspace { + + private static final Map javaClassMap = new ConcurrentHashMap<>(); + + /** + * 名称用.符号分割 + * 例如: haidnor.jvm.test.instruction.references.NEW + */ + public static JavaClass getJavaClass(String className) { + return javaClassMap.get(className); + } + + /** + * 注册名称用.符号分割 + * 例如: haidnor.jvm.test.instruction.references.NEW + */ + public static void registerJavaClass(JavaClass javaClass) { + String className = javaClass.getClassName(); + javaClassMap.put(className, javaClass); + } + +} diff --git a/src/main/java/haidnor/jvm/rtda/package-info.java b/src/main/java/haidnor/jvm/rtda/package-info.java new file mode 100644 index 0000000..bb8b9ce --- /dev/null +++ b/src/main/java/haidnor/jvm/rtda/package-info.java @@ -0,0 +1,17 @@ +/* +JVM(Java虚拟机)的 RTDA(Run-time Data Area)是指在程序运行时分配给Java应用程序使用的内存区域,它包含了几个重要的组成部分。 + +1.程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它保存着当前线程所执行的字节码指令的地址或索引。每个线程都有自己独立的程序计数器,用于记录线程执行的位置,以便线程切换后能够恢复执行。 + +2.Java虚拟机栈(Java Virtual Machine Stacks):每个线程在创建时都会分配一个对应的Java虚拟机栈,用于存储局部变量、方法参数、动态链接信息和方法返回值等数据。每个方法在执行时会创建一个栈帧(Stack Frame),栈帧用于存储方法的局部变量和操作数栈等信息。 + +3.本地方法栈(Native Method Stack):本地方法栈与Java虚拟机栈类似,但是它为本地方法(即用其他语言编写的方法)服务。本地方法栈也会为本地方法的调用和执行提供内存空间。 + +4.Java堆(Java Heap):Java堆是Java虚拟机管理的最大的一块内存区域,用于存储对象实例和数组数据。几乎所有的对象都在Java堆上分配内存,垃圾收集器也主要针对Java堆进行垃圾回收。 + +5.方法区(Method Area):方法区是存储类的结构信息、常量池、字段和方法的字节码等数据的内存区域。它包括运行时常量池,用于存放编译期生成的各种字面量和符号引用。 + +RTDA是JVM在运行时为Java应用程序提供的数据区域,每个线程都有自己的私有数据区域(程序计数器、虚拟机栈和本地方法栈),而Java堆和方法区则是所有线程共享的。这些区域的组合提供了Java程序运行所需的内存空间。 + +*/ +package haidnor.jvm.rtda; \ No newline at end of file diff --git a/src/main/java/haidnor/jvm/runtime/Frame.java b/src/main/java/haidnor/jvm/runtime/Frame.java new file mode 100644 index 0000000..b5075c0 --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/Frame.java @@ -0,0 +1,243 @@ +package haidnor.jvm.runtime; + +import haidnor.jvm.bcel.Const; +import haidnor.jvm.bcel.classfile.Code; +import haidnor.jvm.bcel.classfile.JavaClass; +import haidnor.jvm.bcel.classfile.JavaMethod; +import haidnor.jvm.rtda.Instance; +import haidnor.jvm.util.CodeStream; +import lombok.Getter; + +import java.util.Stack; + +/** + * JVM 线程栈帧 + */ +public class Frame { + /** + * 每个栈帧中包含一个指向运行时常量池中该栈帧所属的方法的引用。包含这个引用的目的就是为了支持当前方法实现动态链接 + * 有了这个引用,执行引擎就可以找到指定的方法,加载字节码指令 + */ + @Getter + public final JavaClass javaClass; + /** + * 当前栈帧所处于的 JVM 线程 + */ + @Getter + private final JVMThread jvmThread; + /** + * 栈帧所属的方法 + *

+ * <<深入理解JAVA虚拟机>>: + * 每一个栈帧都包含一个指向运行时常量池中该栈帧所属的方法引用,持有这个引用的目的是为了支持方法调用过程中的动态链接(Dynamic Linking) + */ + @Getter + private final JavaMethod javaMethod; + /** + * 栈帧所属的方法代码对象 + */ + private final Code code; + + @Getter + private final CodeStream codeStream; + + /** + * 操作数栈 + */ + private final Stack operandStack = new Stack<>(); + + /** + * 槽位 + */ + private final Slot[] slots; + + public Frame(JVMThread thread, JavaClass javaClass, JavaMethod javaMethod) { + this.jvmThread = thread; + this.javaClass = javaClass; + this.javaMethod = javaMethod; + this.code = javaMethod.getCode(); + this.codeStream = new CodeStream(javaMethod.getCode()); + this.slots = new Slot[code.getMaxLocals()]; + } + + public int getCodeLength() { + return this.code.getCode().length; + } + + public JavaMethod getMetaMethod() { + return javaMethod; + } + + /* 操作数栈操作 --------------------------------------------------------------------------------------------------- */ + + /** + * 压入操作数栈 + */ + public void push(StackValue stackValue) { + this.operandStack.push(stackValue); + } + + /** + * 弹出操作数栈顶元素 + */ + public StackValue pop() { + return this.operandStack.pop(); + } + + /** + * 弹出操作数栈顶元素 + */ + public StackValue peek() { + return this.operandStack.peek(); + } + + /** + * 从操作数栈中弹出指定数量的元素的值 + */ + public Object[] popStacksValue(int num) { + Object[] objArr = new Object[num]; + for (int i = num - 1; i >= 0; i--) { + StackValue stackValue = operandStack.pop(); + switch (stackValue.getValueType()) { + case Const.T_CHAR, Const.T_INT, Const.T_OBJECT, Const.T_LONG, Const.T_DOUBLE, Const.T_FLOAT: + break; + case Const.T_ARRAY: + throw new Error("数组类型,未作处理"); + default: + throw new Error("无法识别的参数类型"); + } + objArr[i] = stackValue.getValue(); + } + return objArr; + } + + + public int popInt() { + StackValue stackValue = pop(); + return (int) stackValue.getValue(); + } + + public void pushInt(int value) { + push(new StackValue(Const.T_INT, value)); + } + + public long popLong() { + StackValue stackValue = pop(); + return (long) stackValue.getValue(); + } + + public void pushLong(long value) { + push(new StackValue(Const.T_LONG, value)); + } + + public float popFloat() { + StackValue stackValue = pop(); + return (float) stackValue.getValue(); + } + + public void pushFloat(float value) { + push(new StackValue(Const.T_FLOAT, value)); + } + + public double popDouble() { + StackValue stackValue = pop(); + return (double) stackValue.getValue(); + } + + public void pushDouble(double value) { + push(new StackValue(Const.T_DOUBLE, value)); + } + + public Instance popRef() { + StackValue stackValue = pop(); + return (Instance) stackValue.getValue(); + } + + public void pushRef(Object value) { + push(new StackValue(Const.T_OBJECT, value)); + } + + /** + * 获取操作数栈中元素的数量 + */ + public int operandStackSize() { + return this.operandStack.size(); + } + + /* 局部变量表操作 --------------------------------------------------------------------------------------------------- */ + + public void slotSetInt(int index, int val) { + slots[index] = new Slot(val); + } + + public int slotGetInt(int index) { + return slots[index].num; + } + + public void slotSetFloat(int index, float val) { + int tmp = Float.floatToIntBits(val); + slots[index] = new Slot(tmp); + } + + public float slotGetFloat(int index) { + int num = slots[index].num; + return Float.intBitsToFloat(num); + } + + public long slotGetLong(int index) { + int high = slots[index].num; + int low = slots[index + 1].num; + + long l1 = (high & 0x000000ffffffffL) << 32; + long l2 = low & 0x00000000ffffffffL; + return l1 | l2; + } + + public void slotSetLong(int index, long val) { + // high 32 + int high = (int) (val >> 32); + // low 32 + int low = (int) (val & 0x000000ffffffffL); + + slots[index] = new Slot(high); + slots[index + 1] = new Slot(low); + } + + public void slotSetDouble(int index, double val) { + long tmp = Double.doubleToLongBits(val); + // high 32 + int high = (int) (tmp >> 32); + // low 32 + int low = (int) (tmp & 0x000000ffffffffL); + + slots[index] = new Slot(high); + slots[index + 1] = new Slot(low); + } + + public double slotGetDouble(int index) { + long tmp = this.slotGetLong(index); + return Double.longBitsToDouble(tmp); + } + + public void slotSetRef(int index, Object ref) { + slots[index] = new Slot(ref); + } + + public Object slotGetRef(int index) { + return slots[index].ref; + } + + public void slotSet(int index, StackValue stackValue) { + switch (stackValue.getValueType()) { + case Const.T_CHAR -> throw new Error("T_CHAR,未作处理"); + case Const.T_INT -> slotSetInt(index, (int) stackValue.getValue()); + case Const.T_OBJECT -> slotSetRef(index, stackValue.getValue()); + case Const.T_LONG -> slotSetLong(index, (long) stackValue.getValue()); + case Const.T_DOUBLE -> slotSetDouble(index, (double) stackValue.getValue()); + case Const.T_FLOAT -> slotSetFloat(index, (float) stackValue.getValue()); + case Const.T_ARRAY -> throw new Error("T_ARRAY,未作处理"); + default -> throw new Error("无法识别的参数类型"); + } + } + +} diff --git a/src/main/java/haidnor/jvm/runtime/JVMThread.java b/src/main/java/haidnor/jvm/runtime/JVMThread.java new file mode 100644 index 0000000..71f355c --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/JVMThread.java @@ -0,0 +1,36 @@ +package haidnor.jvm.runtime; + +import java.util.Stack; + +/** + * JVM 线程 + *

+ * 目前这个 JVMThread 并没有真的被 start() 开启, 不继承 Thread 也可以 + */ +public class JVMThread extends Thread { + + /** + * JVM 线程栈 + */ + private final Stack stack = new Stack<>(); + + public void push(Frame frame) { + this.stack.push(frame); + } + + public Frame peek() { + return this.stack.peek(); + } + + public void pop() { + this.stack.pop(); + } + + /** + * 获取 JVM 线程栈的栈帧数量 + */ + public int stackSize() { + return this.stack.size(); + } + +} diff --git a/src/main/java/haidnor/jvm/runtime/Slot.java b/src/main/java/haidnor/jvm/runtime/Slot.java new file mode 100644 index 0000000..c0edea8 --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/Slot.java @@ -0,0 +1,21 @@ +package haidnor.jvm.runtime; + +public class Slot { + public Integer num; + public Object ref; + + public Slot(int num) { + this.num = num; + this.ref = null; + } + + public Slot(Object ref) { + this.num = null; + this.ref = ref; + } + + @Override + public String toString() { + return "Slot{" + "num=" + num + ", ref=" + ref + '}'; + } +} diff --git a/src/main/java/haidnor/jvm/runtime/StackValue.java b/src/main/java/haidnor/jvm/runtime/StackValue.java new file mode 100644 index 0000000..90adafa --- /dev/null +++ b/src/main/java/haidnor/jvm/runtime/StackValue.java @@ -0,0 +1,21 @@ +package haidnor.jvm.runtime; + +import lombok.Getter; + +@Getter +public class StackValue { + /** + * 类型 + */ + private final int valueType; + /** + * 值 + */ + private final Object value; + + public StackValue(int valueType, Object value) { + this.valueType = valueType; + this.value = value; + } + +} diff --git a/src/main/java/haidnor/jvm/util/CodeStream.java b/src/main/java/haidnor/jvm/util/CodeStream.java new file mode 100644 index 0000000..f662102 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/CodeStream.java @@ -0,0 +1,100 @@ +package haidnor.jvm.util; + + +import haidnor.jvm.bcel.classfile.Code; +import haidnor.jvm.instruction.Instruction; +import lombok.Getter; +import lombok.SneakyThrows; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +public class CodeStream { + + private final DataInputStream codeStream; + @Getter + public Code code; + /** + * 当前读取到的数组下标 + * -1 代表还没有开始读 + */ + @Getter + private int index = -1; + + public CodeStream(Code code) { + this.code = code; + this.codeStream = getDataInputStream(code.getCode()); + } + + @SneakyThrows + public int available() { + return codeStream.available(); + } + + /** + * 读取占用一个字节指定代码 + */ + @SneakyThrows + public int readJavaVmOpcode() { + this.index += 1; + return this.codeStream.readUnsignedByte(); + } + + /** + * 读取占用一个字节的操作数 + */ + @SneakyThrows + public int readByte(Instruction instruction) { + instruction.setOffSet(instruction.getOffSet() + 1); + this.index += 1; + return this.codeStream.readByte(); + } + + /** + * 读取占用一个字节的操作数 + * int 类型 + */ + @SneakyThrows + public int readUnsignedByte(Instruction instruction) { + instruction.setOffSet(instruction.getOffSet() + 1); + this.index += 1; + return this.codeStream.readUnsignedByte(); + } + + /** + * 读取占用两个字节的操作数 + */ + @SneakyThrows + public int readShort(Instruction instruction) { + instruction.setOffSet(instruction.getOffSet() + 2); + this.index += 2; + return this.codeStream.readShort(); + } + + /** + * 读取占用两个字节的操作数 + * int 类型 + */ + @SneakyThrows + public int readUnsignedShort(Instruction instruction) { + instruction.setOffSet(instruction.getOffSet() + 2); + this.index += 2; + return this.codeStream.readUnsignedShort(); + } + + /** + * 读取占用四个字节的操作数 + */ + @SneakyThrows + public int readInt(Instruction instruction) { + instruction.setOffSet(instruction.getOffSet() + 4); + this.index += 4; + return this.codeStream.readInt(); + } + + private DataInputStream getDataInputStream(byte[] bytes) { + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + return new DataInputStream(inputStream); + } + +} diff --git a/src/main/java/haidnor/jvm/util/JVMThreadHolder.java b/src/main/java/haidnor/jvm/util/JVMThreadHolder.java new file mode 100644 index 0000000..e361cbc --- /dev/null +++ b/src/main/java/haidnor/jvm/util/JVMThreadHolder.java @@ -0,0 +1,17 @@ +package haidnor.jvm.util; + +import haidnor.jvm.runtime.JVMThread; + +public abstract class JVMThreadHolder { + + private static final ThreadLocal holder = new ThreadLocal<>(); + + public static void set(JVMThread thread) { + holder.set(thread); + } + + public static JVMThread get() { + return holder.get(); + } + +} diff --git a/src/main/java/haidnor/jvm/util/SignatureUtil.java b/src/main/java/haidnor/jvm/util/SignatureUtil.java new file mode 100644 index 0000000..825e744 --- /dev/null +++ b/src/main/java/haidnor/jvm/util/SignatureUtil.java @@ -0,0 +1,34 @@ +package haidnor.jvm.util; + +import haidnor.jvm.bcel.classfile.Utility; +import lombok.SneakyThrows; + +public abstract class SignatureUtil { + + /** + * 解析方法签名返回方法参数类型数组 + */ + @SneakyThrows + public static Class[] getParameterTypeArr(String methodeSignature) { + String[] argumentTypeArr = Utility.methodSignatureArgumentTypes(methodeSignature, false); + Class[] argumentClassArr = new Class[argumentTypeArr.length]; + for (int i = 0; i < argumentTypeArr.length; i++) { + Class argumentClass; + String argumentType = argumentTypeArr[i]; + argumentClass = switch (argumentType) { + case "byte" -> byte.class; + case "short" -> short.class; + case "boolean" -> boolean.class; + case "char" -> char.class; + case "int" -> int.class; + case "long" -> long.class; + case "float" -> float.class; + case "double" -> double.class; + default -> Class.forName(argumentType); + }; + argumentClassArr[i] = argumentClass; + } + return argumentClassArr; + } + +} diff --git a/src/test/java/haidnor/jvm/Student.java b/src/test/java/haidnor/jvm/Student.java new file mode 100644 index 0000000..61aa27b --- /dev/null +++ b/src/test/java/haidnor/jvm/Student.java @@ -0,0 +1,6 @@ +package haidnor.jvm; + +public class Student extends SuperStudent{ + private static String name; + +} diff --git a/src/test/java/haidnor/jvm/SuperStudent.java b/src/test/java/haidnor/jvm/SuperStudent.java new file mode 100644 index 0000000..9ebb66e --- /dev/null +++ b/src/test/java/haidnor/jvm/SuperStudent.java @@ -0,0 +1,6 @@ +package haidnor.jvm; + +public class SuperStudent { + private static String name; + +} diff --git a/src/test/java/haidnor/jvm/test/BCELTest.java b/src/test/java/haidnor/jvm/test/BCELTest.java index 36a90c2..f775631 100644 --- a/src/test/java/haidnor/jvm/test/BCELTest.java +++ b/src/test/java/haidnor/jvm/test/BCELTest.java @@ -1,15 +1,15 @@ package haidnor.jvm.test; -import haidnor.jvm.bcel.classfile.ClassParser; import haidnor.jvm.bcel.classfile.JavaClass; +import haidnor.jvm.classloader.JVMClassLoader; -import java.io.FileInputStream; import java.io.IOException; public class BCELTest { public static void main(String[] args) throws IOException { - ClassParser classParser = new ClassParser(new FileInputStream("D:\\project_javaXL\\xuanleOa\\project-main\\target\\classes\\com\\xuanleOa\\XuanleOaApplication.class"), null); - JavaClass javaClass = classParser.parse(); - System.out.println(javaClass); + JVMClassLoader classLoader = new JVMClassLoader("JVMClassLoader"); + JavaClass javaClass = classLoader.loadWithAbsolutePath("D:\\project_haidnor\\haidnorJVM\\target\\test-classes\\haidnor\\jvm\\Student.class"); + + System.out.println(javaClass.getStaticJavaFieldMap()); } }