This commit is contained in:
FranzHaidnor
2023-10-25 15:13:44 +08:00
parent 84c1f7f535
commit c91945c791
181 changed files with 6917 additions and 5349 deletions

View File

@@ -43,6 +43,13 @@
<version>2.0.7</version> <version>2.0.7</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
@@ -68,7 +75,7 @@
<configuration> <configuration>
<transformers> <transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>haidnor.jvm.Main</mainClass> <mainClass>haidnor.jvm.HaidnorJVM</mainClass>
</transformer> </transformer>
</transformers> </transformers>
</configuration> </configuration>

View File

@@ -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;
/**
* <a href="https://github.com/FranzHaidnor">GitHub FranzHaidnor</a>
*/
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<JarEntry> 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);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,24 +25,14 @@ import org.apache.commons.lang3.ArrayUtils;
*/ */
public final class ExceptionConst { 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 * The mother of all exceptions
*/ */
public static final Class<Throwable> THROWABLE = Throwable.class; public static final Class<Throwable> THROWABLE = Throwable.class;
/** /**
* Super class of any run-time exception * Super class of any run-time exception
*/ */
public static final Class<RuntimeException> RUNTIME_EXCEPTION = RuntimeException.class; public static final Class<RuntimeException> RUNTIME_EXCEPTION = RuntimeException.class;
/** /**
* Super class of any linking exception (aka Linkage Error) * Super class of any linking exception (aka Linkage Error)
*/ */
@@ -61,38 +51,32 @@ public final class ExceptionConst {
public static final Class<NoSuchMethodError> NO_SUCH_METHOD_ERROR = NoSuchMethodError.class; public static final Class<NoSuchMethodError> NO_SUCH_METHOD_ERROR = NoSuchMethodError.class;
public static final Class<NoClassDefFoundError> NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class; public static final Class<NoClassDefFoundError> NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class;
public static final Class<UnsatisfiedLinkError> UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class; public static final Class<UnsatisfiedLinkError> UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class;
public static final Class<VerifyError> VERIFY_ERROR = VerifyError.class; public static final Class<VerifyError> VERIFY_ERROR = VerifyError.class;
/* UnsupportedClassVersionError is new in JDK 1.2 */
// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
/** /**
* Run-Time Exceptions * Run-Time Exceptions
*/ */
public static final Class<NullPointerException> NULL_POINTER_EXCEPTION = NullPointerException.class; public static final Class<NullPointerException> NULL_POINTER_EXCEPTION = NullPointerException.class;
/* UnsupportedClassVersionError is new in JDK 1.2 */
// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
public static final Class<ArrayIndexOutOfBoundsException> ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class; public static final Class<ArrayIndexOutOfBoundsException> ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class;
public static final Class<ArithmeticException> ARITHMETIC_EXCEPTION = ArithmeticException.class; public static final Class<ArithmeticException> ARITHMETIC_EXCEPTION = ArithmeticException.class;
public static final Class<NegativeArraySizeException> NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class; public static final Class<NegativeArraySizeException> NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class;
public static final Class<ClassCastException> CLASS_CAST_EXCEPTION = ClassCastException.class; public static final Class<ClassCastException> CLASS_CAST_EXCEPTION = ClassCastException.class;
public static final Class<IllegalMonitorStateException> ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class; public static final Class<IllegalMonitorStateException> ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class;
/** /**
* Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual Machine Specification * 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, 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 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. * Empty array.
*/ */
private static final Class<?>[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below) private static final Class<?>[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below)
/** /**
* Empty array. * Empty array.
*/ */
private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class[0]; private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class[0];
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.) // 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}; private static final Class<?>[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION};
@@ -125,4 +109,12 @@ public final class ExceptionConst {
return ArrayUtils.addAll(input, extraClasses); 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,
}
} }

View File

@@ -77,6 +77,13 @@ public abstract class Repository {
return 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 * @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 * @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. * Tries to find class source using the internal repository instance.
* *
* @see Class
* @return JavaClass object for given runtime class * @return JavaClass object for given runtime class
* @throws ClassNotFoundException if the class could not be found or parsed correctly * @throws ClassNotFoundException if the class could not be found or parsed correctly
* @see Class
*/ */
public static JavaClass lookupClass(final Class<?> clazz) throws ClassNotFoundException { public static JavaClass lookupClass(final Class<?> clazz) throws ClassNotFoundException {
return repository.loadClass(clazz); return repository.loadClass(clazz);
@@ -205,11 +212,4 @@ public abstract class Repository {
public static void removeClass(final String clazz) { public static void removeClass(final String clazz) {
repository.removeClass(repository.findClass(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;
}
} }

View File

@@ -46,6 +46,15 @@ public abstract class AccessFlags {
return access_flags; 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". * @return Access flags of the object aka. "modifiers".
*/ */
@@ -53,6 +62,15 @@ public abstract class AccessFlags {
return access_flags; 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() { public final boolean isAbstract() {
return (access_flags & Const.ACC_ABSTRACT) != 0; return (access_flags & Const.ACC_ABSTRACT) != 0;
} }
@@ -181,15 +199,6 @@ public abstract class AccessFlags {
setFlag(Const.ACC_VOLATILE, flag); 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) { private void setFlag(final int flag, final boolean set) {
if ((access_flags & flag) != 0) { // Flag is set already if ((access_flags & flag) != 0) { // Flag is set already
if (!set) { if (!set) {
@@ -199,13 +208,4 @@ public abstract class AccessFlags {
access_flags |= flag; access_flags |= flag;
} }
} }
/**
* Set access flags aka "modifiers".
*
* @param accessFlags Access flags of the object.
*/
public final void setModifiers(final int accessFlags) {
setAccessFlags(accessFlags);
}
} }

View File

@@ -31,6 +31,16 @@ import java.util.stream.Stream;
public class AnnotationEntry implements Node { public class AnnotationEntry implements Node {
public static final AnnotationEntry[] EMPTY_ARRAY = {}; public static final AnnotationEntry[] EMPTY_ARRAY = {};
private final int typeIndex;
private final ConstantPool constantPool;
private final boolean isRuntimeVisible;
private List<ElementValuePair> 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) { public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain annotation data // Find attributes that contain annotation data
@@ -58,20 +68,6 @@ public class AnnotationEntry implements Node {
return annotationEntry; return annotationEntry;
} }
private final int typeIndex;
private final ConstantPool constantPool;
private final boolean isRuntimeVisible;
private List<ElementValuePair> 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. * 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. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.

View File

@@ -31,8 +31,8 @@ import java.util.stream.Stream;
*/ */
public abstract class Annotations extends Attribute implements Iterable<AnnotationEntry> { public abstract class Annotations extends Attribute implements Iterable<AnnotationEntry> {
private AnnotationEntry[] annotationTable;
private final boolean isRuntimeVisible; private final boolean isRuntimeVisible;
private AnnotationEntry[] annotationTable;
/** /**
* Constructs an instance. * Constructs an instance.

View File

@@ -53,16 +53,57 @@ import java.util.Map;
*/ */
public abstract class Attribute implements Cloneable, Node { public abstract class Attribute implements Cloneable, Node {
private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off
private static final Map<String, Object> READERS = new HashMap<>();
/** /**
* Empty array. * Empty array.
* *
* @since 6.6.0 * @since 6.6.0
*/ */
public static final Attribute[] EMPTY_ARRAY = {}; public static final Attribute[] EMPTY_ARRAY = {};
private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off
private static final Map<String, Object> 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.
*
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*
* @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 * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the
@@ -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 * 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. * 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 * @param constantPool Array of constants
* @return Attribute * @return Attribute
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @see JavaField
* @see JavaMethod
* @since 6.0 * @since 6.0
*/ */
public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException { public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
@@ -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 * 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. * is called by the Field and Method constructor methods.
* *
* @see JavaField
* @see JavaMethod
*
* @param dataInputStream Input stream * @param dataInputStream Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @return Attribute * @return Attribute
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @see JavaField
* @see JavaMethod
*/ */
public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException { public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
return readAttribute((DataInput) dataInputStream, constantPool); return readAttribute((DataInput) dataInputStream, constantPool);
@@ -209,53 +248,6 @@ public abstract class Attribute implements Cloneable, Node {
READERS.remove(name); 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.
*
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*
* @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. * 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. * 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; 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. * @return Length of attribute field in bytes.
*/ */
@@ -313,6 +313,13 @@ public abstract class Attribute implements Cloneable, Node {
return length; return length;
} }
/**
* @param length length in bytes.
*/
public final void setLength(final int length) {
this.length = length;
}
/** /**
* @return Name of attribute * @return Name of attribute
* @since 6.0 * @since 6.0
@@ -328,28 +335,6 @@ public abstract class Attribute implements Cloneable, Node {
return name_index; 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. * @param nameIndex of attribute.
*/ */
@@ -357,6 +342,13 @@ public abstract class Attribute implements Cloneable, Node {
this.name_index = nameIndex; 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. * @return attribute name.
*/ */

View File

@@ -34,10 +34,14 @@ import java.util.Arrays;
*/ */
public class BootstrapMethod implements Cloneable { 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; private int bootstrapMethodRef;
/** Array of references to the constant_pool table */ /**
* Array of references to the constant_pool table
*/
private int[] bootstrapArguments; private int[] bootstrapArguments;
/** /**
@@ -110,20 +114,6 @@ public class BootstrapMethod implements Cloneable {
return bootstrapArguments; 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 * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
*/ */
@@ -131,6 +121,13 @@ public class BootstrapMethod implements Cloneable {
this.bootstrapArguments = bootstrapArguments; 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 * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
*/ */
@@ -138,6 +135,13 @@ public class BootstrapMethod implements Cloneable {
this.bootstrapMethodRef = bootstrapMethodRef; this.bootstrapMethodRef = bootstrapMethodRef;
} }
/**
* @return count of number of boostrap arguments
*/
public int getNumBootstrapArguments() {
return bootstrapArguments.length;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -122,11 +122,6 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
return bootstrapMethods; return bootstrapMethods;
} }
@Override
public Iterator<BootstrapMethod> iterator() {
return Stream.of(bootstrapMethods).iterator();
}
/** /**
* @param bootstrapMethods the array of bootstrap methods * @param bootstrapMethods the array of bootstrap methods
*/ */
@@ -134,6 +129,11 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
this.bootstrapMethods = bootstrapMethods; this.bootstrapMethods = bootstrapMethods;
} }
@Override
public Iterator<BootstrapMethod> iterator() {
return Stream.of(bootstrapMethods).iterator();
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -26,7 +26,7 @@ import java.util.zip.ZipFile;
* Wrapper class that parses a given Java .class file. The method <a href ="#parse">parse</a> returns a * Wrapper class that parses a given Java .class file. The method <a href ="#parse">parse</a> returns a
* <a href ="JavaClass.html"> JavaClass</a> object on success. When an I/O error or an inconsistency occurs an * <a href ="JavaClass.html"> JavaClass</a> object on success. When an I/O error or an inconsistency occurs an
* appropriate exception is propagated back to the caller. * appropriate exception is propagated back to the caller.
* * <p>
* The structure and the names comply, except for a few conveniences, exactly with the * The structure and the names comply, except for a few conveniences, exactly with the
* <a href="http://docs.oracle.com/javase/specs/"> JVM specification 1.0</a>. See this paper for further details about * <a href="http://docs.oracle.com/javase/specs/"> JVM specification 1.0</a>. See this paper for further details about
* the structure of a bytecode file. * the structure of a bytecode file.
@@ -34,9 +34,10 @@ import java.util.zip.ZipFile;
public final class ClassParser { public final class ClassParser {
private static final int BUFSIZE = 8192; private static final int BUFSIZE = 8192;
private DataInputStream dataInputStream;
private final boolean fileOwned; private final boolean fileOwned;
private final String fileName; private final String fileName;
private final boolean isZip; // Loaded from zip file
private DataInputStream dataInputStream;
private String zipFile; private String zipFile;
private int classNameIndex; private int classNameIndex;
private int superclassNameIndex; private int superclassNameIndex;
@@ -48,7 +49,6 @@ public final class ClassParser {
private JavaField[] fields; // class fields, i.e., its variables private JavaField[] fields; // class fields, i.e., its variables
private JavaMethod[] methods; // methods defined in the class private JavaMethod[] methods; // methods defined in the class
private Attribute[] attributes; // attributes 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. * Parses class from the given stream.

View File

@@ -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 * This class represents a chunk of Java byte code contained in a method. It is instantiated by the
* <em>Attribute.readAttribute()</em> method. A <em>Code</em> attribute contains informations about operand stack, local * <em>Attribute.readAttribute()</em> method. A <em>Code</em> attribute contains informations about operand stack, local
* variables, byte code and the exceptions handled within this method. * variables, byte code and the exceptions handled within this method.
* * <p>
* This attribute has attributes itself, namely <em>LineNumberTable</em> which is used for debugging purposes and * This attribute has attributes itself, namely <em>LineNumberTable</em> which is used for debugging purposes and
* <em>LocalVariableTable</em> which contains information about the local variables. * <em>LocalVariableTable</em> which contains information about the local variables.
* *
@@ -52,6 +52,7 @@ import java.util.Arrays;
* attribute_info attributes[attributes_count]; * attribute_info attributes[attributes_count];
* } * }
* </pre> * </pre>
*
* @see Attribute * @see Attribute
* @see CodeException * @see CodeException
* @see LineNumberTable * @see LineNumberTable
@@ -160,9 +161,8 @@ public final class Code extends Attribute {
} }
/** /**
* @return deep copy of this attribute
*
* @param constantPool the constant pool to duplicate * @param constantPool the constant pool to duplicate
* @return deep copy of this attribute
*/ */
@Override @Override
public Attribute copy(final ConstantPool constantPool) { public Attribute copy(final ConstantPool constantPool) {
@@ -209,6 +209,14 @@ public final class Code extends Attribute {
return attributes; 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. * @return Actual byte code of the method.
*/ */
@@ -216,6 +224,14 @@ public final class Code extends Attribute {
return code; 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. * @return Table of handled exceptions.
* @see CodeException * @see CodeException
@@ -224,6 +240,14 @@ public final class Code extends Attribute {
return exceptionTable; 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 * @return the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes
*/ */
@@ -266,37 +290,6 @@ public final class Code extends Attribute {
return maxLocals; 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 * @param maxLocals maximum number of local variables
*/ */
@@ -304,6 +297,13 @@ public final class Code extends Attribute {
this.maxLocals = maxLocals; this.maxLocals = maxLocals;
} }
/**
* @return Maximum size of stack used by this method.
*/
public int getMaxStack() {
return maxStack;
}
/** /**
* @param maxStack maximum stack size * @param maxStack maximum stack size
*/ */

View File

@@ -154,27 +154,6 @@ public final class CodeException implements Cloneable, Node {
return catchType; 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 * @param catchType the type of exception that is caught
*/ */
@@ -182,6 +161,13 @@ public final class CodeException implements Cloneable, Node {
this.catchType = catchType; 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 * @param endPc end of handled block
*/ */
@@ -189,6 +175,13 @@ public final class CodeException implements Cloneable, Node {
this.endPc = endPc; 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 * @param handlerPc where the actual code is
*/ */
@@ -196,6 +189,13 @@ public final class CodeException implements Cloneable, Node {
this.handlerPc = handlerPc; 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 * @param startPc start of handled block
*/ */

View File

@@ -45,6 +45,15 @@ public abstract class Constant implements Cloneable, Node {
return THIS.toString().hashCode(); 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 * @return Comparison strategy object
@@ -53,6 +62,21 @@ public abstract class Constant implements Cloneable, Node {
return bcelComparator; return bcelComparator;
} }
/*
* 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.
*
* 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.
*/
/**
* @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. * Reads one constant from the given input, the type depends on a tag byte.
* *
@@ -104,30 +128,6 @@ public abstract class Constant implements Cloneable, Node {
} }
} }
/**
* @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.
*
* 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;
}
/** /**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * 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. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.

View File

@@ -107,13 +107,6 @@ public abstract class ConstantCP extends Constant {
return class_index; 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 * @param classIndex points to Constant_class
*/ */
@@ -121,6 +114,13 @@ public abstract class ConstantCP extends Constant {
this.class_index = classIndex; 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 * @param nameAndTypeIndex points to Constant_NameAndType
*/ */
@@ -130,7 +130,7 @@ public abstract class ConstantCP extends Constant {
/** /**
* @return String representation. * @return String representation.
* * <p>
* not final as ConstantInvokeDynamic needs to modify * not final as ConstantInvokeDynamic needs to modify
*/ */
@Override @Override

View File

@@ -88,6 +88,13 @@ public final class ConstantDouble extends Constant implements ConstantObject {
return bytes; return bytes;
} }
/**
* @param bytes the raw bytes that represent the double value
*/
public void setBytes(final double bytes) {
this.bytes = bytes;
}
/** /**
* @return Double object * @return Double object
*/ */
@@ -96,13 +103,6 @@ public final class ConstantDouble extends Constant implements ConstantObject {
return Double.valueOf(bytes); 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. * @return String representation.
*/ */

View File

@@ -68,7 +68,7 @@ public final class ConstantDynamic extends ConstantCP {
/** /**
* @return Reference (index) to bootstrap method this constant refers to. * @return Reference (index) to bootstrap method this constant refers to.
* * <p>
* 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 * @since 6.0
*/ */

View File

@@ -89,6 +89,13 @@ public final class ConstantFloat extends Constant implements ConstantObject {
return bytes; return bytes;
} }
/**
* @param bytes the raw bytes that represent this float
*/
public void setBytes(final float bytes) {
this.bytes = bytes;
}
/** /**
* @return Float object * @return Float object
*/ */
@@ -97,13 +104,6 @@ public final class ConstantFloat extends Constant implements ConstantObject {
return Float.valueOf(bytes); 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. * @return String representation.
*/ */

View File

@@ -88,6 +88,13 @@ public final class ConstantInteger extends Constant implements ConstantObject {
return bytes; return bytes;
} }
/**
* @param bytes the raw bytes that represent this integer
*/
public void setBytes(final int bytes) {
this.bytes = bytes;
}
/** /**
* @return Integer object * @return Integer object
*/ */
@@ -96,13 +103,6 @@ public final class ConstantInteger extends Constant implements ConstantObject {
return Integer.valueOf(bytes); 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. * @return String representation.
*/ */

View File

@@ -67,7 +67,7 @@ public final class ConstantInvokeDynamic extends ConstantCP {
/** /**
* @return Reference (index) to bootstrap method this constant refers to. * @return Reference (index) to bootstrap method this constant refers to.
* * <p>
* 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 * @since 6.0
*/ */

View File

@@ -88,6 +88,13 @@ public final class ConstantLong extends Constant implements ConstantObject {
return bytes; return bytes;
} }
/**
* @param bytes the raw bytes that represent this long
*/
public void setBytes(final long bytes) {
this.bytes = bytes;
}
/** /**
* @return Long object * @return Long object
*/ */
@@ -96,13 +103,6 @@ public final class ConstantLong extends Constant implements ConstantObject {
return Long.valueOf(bytes); 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. * @return String representation.
*/ */

View File

@@ -86,14 +86,14 @@ public final class ConstantMethodHandle extends Constant {
return referenceIndex; return referenceIndex;
} }
public int getReferenceKind() {
return referenceKind;
}
public void setReferenceIndex(final int referenceIndex) { public void setReferenceIndex(final int referenceIndex) {
this.referenceIndex = referenceIndex; this.referenceIndex = referenceIndex;
} }
public int getReferenceKind() {
return referenceKind;
}
public void setReferenceKind(final int referenceKind) { public void setReferenceKind(final int referenceKind) {
this.referenceKind = referenceKind; this.referenceKind = referenceKind;
} }

View File

@@ -100,6 +100,13 @@ public final class ConstantNameAndType extends Constant {
return nameIndex; return nameIndex;
} }
/**
* @param nameIndex the name index of this constant
*/
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/** /**
* @return signature * @return signature
*/ */
@@ -114,13 +121,6 @@ public final class ConstantNameAndType extends Constant {
return signatureIndex; 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 * @param signatureIndex the signature index in the constant pool of this type
*/ */

View File

@@ -35,34 +35,6 @@ import java.util.Iterator;
*/ */
public class ConstantPool implements Cloneable, Node, Iterable<Constant> { public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
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; private Constant[] constantPool;
/** /**
@@ -100,6 +72,34 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
} }
} }
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, * 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. * attributes, etc. spawns a tree of objects.
@@ -249,8 +249,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid * @throws ClassFormatException if index is invalid
* @see Constant
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index) throws ClassFormatException { public <T extends Constant> T getConstant(final int index) throws ClassFormatException {
@@ -263,8 +263,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type * @param tag Tag of expected constant, i.e., its type
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see Constant
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException {
@@ -277,8 +277,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type * @param tag Tag of expected constant, i.e., its type
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see Constant
* @since 6.6.0 * @since 6.6.0
*/ */
public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException {
@@ -296,8 +296,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param castTo The {@link Constant} subclass to cast to. * @param castTo The {@link Constant} subclass to cast to.
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid * @throws ClassFormatException if index is invalid
* @see Constant
* @since 6.6.0 * @since 6.6.0
*/ */
public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException {
@@ -326,8 +326,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return ConstantInteger value * @return ConstantInteger value
* @see ConstantInteger
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see ConstantInteger
*/ */
public ConstantInteger getConstantInteger(final int index) { public ConstantInteger getConstantInteger(final int index) {
return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class); return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
@@ -341,6 +341,13 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
return constantPool; 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 * 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. * 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<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString * @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference * @return Contents of string reference
* @throws IllegalArgumentException if tag is invalid
* @see ConstantClass * @see ConstantClass
* @see ConstantString * @see ConstantString
* @throws IllegalArgumentException if tag is invalid
*/ */
public String getConstantString(final int index, final byte tag) throws IllegalArgumentException { public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
int i; int i;
@@ -386,8 +393,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return ConstantUtf8 value * @return ConstantUtf8 value
* @see ConstantUtf8
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see ConstantUtf8
*/ */
public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException { public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class); return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
@@ -412,13 +419,6 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
constantPool[index] = constant; constantPool[index] = constant;
} }
/**
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
}
/** /**
* @return String representation. * @return String representation.
*/ */
@@ -430,4 +430,164 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
} }
return buf.toString(); 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);
}
} }

View File

@@ -57,47 +57,53 @@ import java.util.Objects;
*/ */
public final class ConstantUtf8 extends Constant { public final class ConstantUtf8 extends Constant {
private static class Cache { 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 boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS); private static final String SYS_PROP_STATISTICS = "bcel.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<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
private static final long serialVersionUID = -8506975356158971766L;
@Override
protected boolean removeEldestEntry(final Map.Entry<String, ConstantUtf8> 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;
}
}
// TODO these should perhaps be AtomicInt? // TODO these should perhaps be AtomicInt?
private static volatile int considered; private static volatile int considered;
private static volatile int created; private static volatile int created;
private static volatile int hits; private static volatile int hits;
private static volatile int skipped; 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 { static {
if (Cache.BCEL_STATISTICS) { if (Cache.BCEL_STATISTICS) {
Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats)); 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. * Clears the cache.
* *
@@ -178,38 +184,6 @@ public final class ConstantUtf8 extends Constant {
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++;
}
/** /**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * 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. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -256,4 +230,29 @@ public final class ConstantUtf8 extends Constant {
public String toString() { public String toString() {
return super.toString() + "(\"" + Utility.replace(value, "\n", "\\n") + "\")"; 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<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
private static final long serialVersionUID = -8506975356158971766L;
@Override
protected boolean removeEldestEntry(final Map.Entry<String, ConstantUtf8> 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;
}
}
} }

View File

@@ -34,6 +34,7 @@ import java.io.IOException;
* u2 constantvalue_index; * u2 constantvalue_index;
* } * }
* </pre> * </pre>
*
* @see Attribute * @see Attribute
*/ */
public final class ConstantValue extends Attribute { public final class ConstantValue extends Attribute {

View File

@@ -153,7 +153,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.3 */ /**
* @since 6.3
*/
@Override @Override
public void visitConstantDynamic(final ConstantDynamic obj) { public void visitConstantDynamic(final ConstantDynamic obj) {
stack.push(obj); stack.push(obj);
@@ -206,7 +208,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.0 */ /**
* @since 6.0
*/
@Override @Override
public void visitConstantMethodHandle(final ConstantMethodHandle obj) { public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
stack.push(obj); stack.push(obj);
@@ -221,7 +225,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.0 */ /**
* @since 6.0
*/
@Override @Override
public void visitConstantMethodType(final ConstantMethodType obj) { public void visitConstantMethodType(final ConstantMethodType obj) {
stack.push(obj); stack.push(obj);
@@ -229,7 +235,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.1 */ /**
* @since 6.1
*/
@Override @Override
public void visitConstantModule(final ConstantModule obj) { public void visitConstantModule(final ConstantModule obj) {
stack.push(obj); stack.push(obj);
@@ -244,7 +252,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.1 */ /**
* @since 6.1
*/
@Override @Override
public void visitConstantPackage(final ConstantPackage obj) { public void visitConstantPackage(final ConstantPackage obj) {
stack.push(obj); stack.push(obj);
@@ -408,7 +418,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModule(final Module obj) { public void visitModule(final Module obj) {
stack.push(obj); stack.push(obj);
@@ -420,7 +432,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleExports(final ModuleExports obj) { public void visitModuleExports(final ModuleExports obj) {
stack.push(obj); stack.push(obj);
@@ -428,7 +442,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleMainClass(final ModuleMainClass obj) { public void visitModuleMainClass(final ModuleMainClass obj) {
stack.push(obj); stack.push(obj);
@@ -436,7 +452,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleOpens(final ModuleOpens obj) { public void visitModuleOpens(final ModuleOpens obj) {
stack.push(obj); stack.push(obj);
@@ -444,7 +462,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModulePackages(final ModulePackages obj) { public void visitModulePackages(final ModulePackages obj) {
stack.push(obj); stack.push(obj);
@@ -452,7 +472,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleProvides(final ModuleProvides obj) { public void visitModuleProvides(final ModuleProvides obj) {
stack.push(obj); stack.push(obj);
@@ -460,7 +482,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleRequires(final ModuleRequires obj) { public void visitModuleRequires(final ModuleRequires obj) {
stack.push(obj); stack.push(obj);
@@ -468,7 +492,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitNestHost(final NestHost obj) { public void visitNestHost(final NestHost obj) {
stack.push(obj); stack.push(obj);
@@ -476,7 +502,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitNestMembers(final NestMembers obj) { public void visitNestMembers(final NestMembers obj) {
stack.push(obj); stack.push(obj);
@@ -494,7 +522,9 @@ public class DescendingVisitor implements Visitor {
stack.pop(); stack.pop();
} }
/** @since 6.0 */ /**
* @since 6.0
*/
@Override @Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) { public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
stack.push(obj); stack.push(obj);

View File

@@ -44,8 +44,9 @@ import java.io.IOException;
* element_value values[num_values]; * element_value values[num_values];
* } array_value; * } array_value;
* } value; * } value;
*} * }
*</pre> * </pre>
*
* @since 6.0 * @since 6.0
*/ */
public abstract class ElementValue { public abstract class ElementValue {
@@ -63,6 +64,21 @@ public abstract class ElementValue {
public static final byte PRIMITIVE_LONG = 'J'; public static final byte PRIMITIVE_LONG = 'J';
public static final byte PRIMITIVE_SHORT = 'S'; public static final byte PRIMITIVE_SHORT = 'S';
public static final byte PRIMITIVE_BOOLEAN = 'Z'; public static final byte PRIMITIVE_BOOLEAN = 'Z';
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected int type; // TODO should be final
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected ConstantPool cpool; // TODO should be final
protected ElementValue(final int type, final ConstantPool cpool) {
this.type = type;
this.cpool = cpool;
}
/** /**
* Reads an {@code element_value} as an {@code ElementValue}. * Reads an {@code element_value} as an {@code ElementValue}.
@@ -129,25 +145,11 @@ public abstract class ElementValue {
} }
} }
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected int type; // TODO should be final
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected ConstantPool cpool; // TODO should be final
protected ElementValue(final int type, final ConstantPool cpool) {
this.type = type;
this.cpool = cpool;
}
public abstract void dump(DataOutputStream dos) throws IOException; public abstract void dump(DataOutputStream dos) throws IOException;
/** @since 6.0 */ /**
* @since 6.0
*/
final ConstantPool getConstantPool() { final ConstantPool getConstantPool() {
return cpool; return cpool;
} }
@@ -156,7 +158,9 @@ public abstract class ElementValue {
return type; return type;
} }
/** @since 6.0 */ /**
* @since 6.0
*/
final int getType() { final int getType() {
return type; return type;
} }

View File

@@ -235,47 +235,65 @@ public class EmptyVisitor implements Visitor {
public void visitMethodParameters(final MethodParameters obj) { public void visitMethodParameters(final MethodParameters obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModule(final Module obj) { public void visitModule(final Module obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleExports(final ModuleExports obj) { public void visitModuleExports(final ModuleExports obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleMainClass(final ModuleMainClass obj) { public void visitModuleMainClass(final ModuleMainClass obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleOpens(final ModuleOpens obj) { public void visitModuleOpens(final ModuleOpens obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModulePackages(final ModulePackages obj) { public void visitModulePackages(final ModulePackages obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleProvides(final ModuleProvides obj) { public void visitModuleProvides(final ModuleProvides obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitModuleRequires(final ModuleRequires obj) { public void visitModuleRequires(final ModuleRequires obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitNestHost(final NestHost obj) { public void visitNestHost(final NestHost obj) {
} }
/** @since 6.4.0 */ /**
* @since 6.4.0
*/
@Override @Override
public void visitNestMembers(final NestMembers obj) { public void visitNestMembers(final NestMembers obj) {
} }

View File

@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -81,6 +81,10 @@ public class EnclosingMethod extends Attribute {
return classIndex; return classIndex;
} }
public final void setEnclosingClassIndex(final int idx) {
classIndex = idx;
}
public final ConstantNameAndType getEnclosingMethod() { public final ConstantNameAndType getEnclosingMethod() {
if (methodIndex == 0) { if (methodIndex == 0) {
return null; return null;
@@ -92,10 +96,6 @@ public class EnclosingMethod extends Attribute {
return methodIndex; return methodIndex;
} }
public final void setEnclosingClassIndex(final int idx) {
classIndex = idx;
}
public final void setEnclosingMethodIndex(final int idx) { public final void setEnclosingMethodIndex(final int idx) {
methodIndex = idx; methodIndex = idx;
} }

View File

@@ -40,6 +40,7 @@ import java.util.Arrays;
* u2 exception_index_table[number_of_exceptions]; * u2 exception_index_table[number_of_exceptions];
* } * }
* </pre> * </pre>
*
* @see Code * @see Code
*/ */
public final class ExceptionTable extends Attribute { public final class ExceptionTable extends Attribute {
@@ -132,6 +133,14 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable; 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 * @return class names of thrown exceptions
*/ */
@@ -148,14 +157,6 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable == null ? 0 : exceptionIndexTable.length; 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. * @return String representation, i.e., a list of thrown exceptions.
*/ */

View File

@@ -50,16 +50,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
*/ */
@java.lang.Deprecated @java.lang.Deprecated
protected int attributes_count; // No. of attributes 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 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@java.lang.Deprecated @java.lang.Deprecated
protected ConstantPool constant_pool; protected ConstantPool constant_pool;
// @since 6.0
private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
private String signatureAttributeString; private String signatureAttributeString;
private boolean searchedForSignatureAttribute; private boolean searchedForSignatureAttribute;
@@ -173,6 +170,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return attributes; 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. * @return Constant pool used by this object.
*/ */
@@ -180,6 +185,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return constant_pool; 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 * 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&lt;Ljava/lang/String&gt;;' Coded for * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
@@ -215,6 +227,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return name_index; 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) * @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; 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. * @param signatureIndex Index in constant pool of field signature.
*/ */

View File

@@ -110,27 +110,6 @@ public final class InnerClass implements Cloneable, Node {
return innerAccessFlags; 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 * @param innerAccessFlags access flags for this inner class
*/ */
@@ -138,6 +117,13 @@ public final class InnerClass implements Cloneable, Node {
this.innerAccessFlags = innerAccessFlags; this.innerAccessFlags = innerAccessFlags;
} }
/**
* @return class index of inner class.
*/
public int getInnerClassIndex() {
return innerClassIndex;
}
/** /**
* @param innerClassIndex index into the constant pool for this class * @param innerClassIndex index into the constant pool for this class
*/ */
@@ -145,6 +131,13 @@ public final class InnerClass implements Cloneable, Node {
this.innerClassIndex = innerClassIndex; 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 * @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; 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 * @param outerClassIndex index into the constant pool for the owning class
*/ */

View File

@@ -127,11 +127,6 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
return innerClasses; return innerClasses;
} }
@Override
public Iterator<InnerClass> iterator() {
return Stream.of(innerClasses).iterator();
}
/** /**
* @param innerClasses the array of inner classes * @param innerClasses the array of inner classes
*/ */
@@ -139,6 +134,11 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY; this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY;
} }
@Override
public Iterator<InnerClass> iterator() {
return Stream.of(innerClasses).iterator();
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -23,6 +23,9 @@ import haidnor.jvm.bcel.util.BCELComparator;
import haidnor.jvm.bcel.util.ClassQueue; import haidnor.jvm.bcel.util.ClassQueue;
import haidnor.jvm.bcel.util.Repository; import haidnor.jvm.bcel.util.Repository;
import haidnor.jvm.bcel.util.SyntheticRepository; import haidnor.jvm.bcel.util.SyntheticRepository;
import haidnor.jvm.classloader.JVMClassLoader;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import java.io.*; import java.io.*;
@@ -71,41 +74,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return THIS.getClassName().hashCode(); 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; private final String packageName;
@Getter
private final Map<String, JavaField> staticJavaFieldMap = new HashMap<>();
private String fileName;
private String sourceFileName = "<Unknown>"; private String sourceFileName = "<Unknown>";
private int classNameIndex; private int classNameIndex;
private int superclassNameIndex; private int superclassNameIndex;
@@ -119,21 +91,23 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
private JavaField[] fields; // Fields, i.e., variables of class private JavaField[] fields; // Fields, i.e., variables of class
private JavaMethod[] methods; // methods defined in the class private JavaMethod[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class private Attribute[] attributes; // attributes defined in the class
private AnnotationEntry[] annotations; // annotations defined on the class private AnnotationEntry[] annotations; // annotations defined on the class
private byte source = HEAP; // Generated in memory private byte source = HEAP; // Generated in memory
private boolean isAnonymous; private boolean isAnonymous;
private boolean isNested; private boolean isNested;
private boolean computedNestedTypeStatus; private boolean computedNestedTypeStatus;
// ---------------------------------------------- haidnorJVM >
/** /**
* In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any
* better. * better.
*/ */
private transient Repository repository = SyntheticRepository.getInstance(); private transient Repository repository = SyntheticRepository.getInstance();
@Getter
@Setter
private JVMClassLoader JVMClassLoader;
// ---------------------------------------------- haidnorJVM <
/** /**
* Constructor gets all contents as arguments. * Constructor gets all contents as arguments.
@@ -229,6 +203,45 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class); final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class);
interfaceNames[i] = Utility.compactClassName(str, false); 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();
} }
/** /**
@@ -429,6 +442,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return attributes; return attributes;
} }
/**
* @param attributes .
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
}
/** /**
* @return class in binary format * @return class in binary format
*/ */
@@ -449,6 +469,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return className; return className;
} }
/**
* @param className .
*/
public void setClassName(final String className) {
this.className = className;
}
/** /**
* @return Class name index. * @return Class name index.
*/ */
@@ -456,6 +483,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classNameIndex; return classNameIndex;
} }
/**
* @param classNameIndex .
*/
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
}
/** /**
* @return Constant pool. * @return Constant pool.
*/ */
@@ -463,6 +497,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return constantPool; 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 * @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.
@@ -471,6 +512,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return fields; return fields;
} }
/**
* @param fields .
*/
public void setFields(final JavaField[] fields) {
this.fields = fields;
}
/** /**
* @return File name of class, aka SourceFile attribute value * @return File name of class, aka SourceFile attribute value
*/ */
@@ -478,6 +526,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return fileName; 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. * @return Indices in constant pool of implemented interfaces.
*/ */
@@ -492,6 +547,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return interfaceNames; return interfaceNames;
} }
/**
* @param interfaceNames .
*/
public void setInterfaceNames(final String[] interfaceNames) {
this.interfaceNames = interfaceNames;
}
/** /**
* Get interfaces directly implemented by this JavaClass. * Get interfaces directly implemented by this JavaClass.
* *
@@ -506,6 +568,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classes; return classes;
} }
/**
* @param interfaces .
*/
public void setInterfaces(final int[] interfaces) {
this.interfaces = interfaces;
}
/** /**
* @return Major number of class file version. * @return Major number of class file version.
*/ */
@@ -513,6 +582,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return major; 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 * @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; return methods;
} }
/**
* @param methods .
*/
public void setMethods(final JavaMethod[] methods) {
this.methods = methods;
}
/** /**
* @return Minor number of class file version. * @return Minor number of class file version.
*/ */
@@ -539,6 +622,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return minor; return minor;
} }
/**
* @param minor .
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/** /**
* @return Package name. * @return Package name.
*/ */
@@ -554,6 +644,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return repository; 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 * @return returns either HEAP (generated), FILE, or ZIP
*/ */
@@ -568,6 +665,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return sourceFileName; 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. * Gets the source file path including the package path.
* *
@@ -618,6 +722,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassName; return superclassName;
} }
/**
* @param superclassName .
*/
public void setSuperclassName(final String superclassName) {
this.superclassName = superclassName;
}
/** /**
* @return Class name index. * @return Class name index.
*/ */
@@ -625,6 +736,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassNameIndex; 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. * 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; 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. * @return String representing class contents.
*/ */
@@ -859,4 +876,20 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
} }
return buf.toString(); 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;
}
} }

View File

@@ -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 * This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
* specification for details. * specification for details.
*/ */
public final class JavaField extends FieldOrMethod { public class JavaField extends FieldOrMethod {
/** /**
* Empty array constant. * Empty array constant.
@@ -36,7 +36,10 @@ public final class JavaField extends FieldOrMethod {
* @since 6.6.0 * @since 6.6.0
*/ */
public static final JavaField[] EMPTY_ARRAY = {}; public static final JavaField[] EMPTY_ARRAY = {};
/**
* Empty array.
*/
static final JavaField[] EMPTY_FIELD_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() { private static BCELComparator bcelComparator = new BCELComparator() {
@Override @Override
@@ -52,25 +55,14 @@ public final class JavaField extends FieldOrMethod {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 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() { private Object value;
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/** /**
* Construct object from file stream. * Construct object from file stream.
@@ -102,6 +94,20 @@ public final class JavaField extends FieldOrMethod {
super(accessFlags, nameIndex, signatureIndex, attributes, 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. * 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. * 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()); 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 * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* signature. * signature.

View File

@@ -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 * 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. * 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. * Empty array constant.
@@ -35,7 +35,10 @@ public final class JavaMethod extends FieldOrMethod {
* @since 6.6.0 * @since 6.6.0
*/ */
public static final JavaMethod[] EMPTY_ARRAY = {}; public static final JavaMethod[] EMPTY_ARRAY = {};
/**
* Empty array.
*/
static final JavaMethod[] EMPTY_METHOD_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() { private static BCELComparator bcelComparator = new BCELComparator() {
@Override @Override
@@ -51,26 +54,6 @@ public final class JavaMethod extends FieldOrMethod {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 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 // annotations defined on the parameters of a method
private ParameterAnnotationEntry[] parameterAnnotationEntries; private ParameterAnnotationEntry[] parameterAnnotationEntries;
@@ -112,6 +95,20 @@ public final class JavaMethod extends FieldOrMethod {
super(c); 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. * 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. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.

View File

@@ -32,10 +32,14 @@ public final class LineNumber implements Cloneable, Node {
static final LineNumber[] EMPTY_ARRAY = {}; static final LineNumber[] EMPTY_ARRAY = {};
/** Program Counter (PC) corresponds to line */ /**
* Program Counter (PC) corresponds to line
*/
private int startPc; private int startPc;
/** number in source file */ /**
* number in source file
*/
private int lineNumber; private int lineNumber;
/** /**
@@ -107,13 +111,6 @@ public final class LineNumber implements Cloneable, Node {
return lineNumber & 0xffff; return lineNumber & 0xffff;
} }
/**
* @return PC in code
*/
public int getStartPC() {
return startPc & 0xffff;
}
/** /**
* @param lineNumber the source line number * @param lineNumber the source line number
*/ */
@@ -121,6 +118,13 @@ public final class LineNumber implements Cloneable, Node {
this.lineNumber = (short) lineNumber; this.lineNumber = (short) lineNumber;
} }
/**
* @return PC in code
*/
public int getStartPC() {
return startPc & 0xffff;
}
/** /**
* @param startPc the pc for this line number * @param startPc the pc for this line number
*/ */

View File

@@ -126,6 +126,13 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
return lineNumberTable; return lineNumberTable;
} }
/**
* @param lineNumberTable the line number entries for this table
*/
public void setLineNumberTable(final LineNumber[] lineNumberTable) {
this.lineNumberTable = lineNumberTable;
}
/** /**
* Map byte code positions to source code lines. * Map byte code positions to source code lines.
* *
@@ -181,13 +188,6 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
return Stream.of(lineNumberTable).iterator(); return Stream.of(lineNumberTable).iterator();
} }
/**
* @param lineNumberTable the line number entries for this table
*/
public void setLineNumberTable(final LineNumber[] lineNumberTable) {
this.lineNumberTable = lineNumberTable;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -36,35 +36,28 @@ import java.io.IOException;
public final class LocalVariable implements Cloneable, Node { public final class LocalVariable implements Cloneable, Node {
static final LocalVariable[] EMPTY_ARRAY = {}; static final LocalVariable[] EMPTY_ARRAY = {};
/**
* Range in which the variable is valid.
*/
private int startPc;
private int length;
/**
* Index in constant pool of variable name.
*/
private int nameIndex;
/**
* Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
*/
private int signatureIndex;
/*
* Variable is index'th local variable on this method's frame.
*/
private int index;
private ConstantPool constantPool;
/** /**
* Never changes; used to match up with LocalVariableTypeTable entries. * Never changes; used to match up with LocalVariableTypeTable entries.
*/ */
private final int origIndex; private final int origIndex;
/**
* Range in which the variable is valid.
*/
private int startPc;
private int length;
/**
* Index in constant pool of variable name.
*/
private int nameIndex;
/**
* Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
*/
private int signatureIndex;
/*
* Variable is index'th local variable on this method's frame.
*/
private int index;
private ConstantPool constantPool;
/** /**
* Constructs object from file stream. * Constructs object from file stream.
@@ -164,6 +157,13 @@ public final class LocalVariable implements Cloneable, Node {
return constantPool; return constantPool;
} }
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/** /**
* @return index of register where variable is stored * @return index of register where variable is stored
*/ */
@@ -171,6 +171,13 @@ public final class LocalVariable implements Cloneable, Node {
return index; return index;
} }
/**
* @param index the index in the local variable table of this variable
*/
public void setIndex(final int index) { // TODO unused
this.index = index;
}
/** /**
* @return Variable is valid within getStartPC() .. getStartPC()+getLength() * @return Variable is valid within getStartPC() .. getStartPC()+getLength()
*/ */
@@ -178,6 +185,13 @@ public final class LocalVariable implements Cloneable, Node {
return length; return length;
} }
/**
* @param length the length of this local variable
*/
public void setLength(final int length) {
this.length = length;
}
/** /**
* @return Variable name. * @return Variable name.
*/ */
@@ -192,6 +206,13 @@ public final class LocalVariable implements Cloneable, Node {
return nameIndex; return nameIndex;
} }
/**
* @param nameIndex the index into the constant pool for the name of this variable
*/
public void setNameIndex(final int nameIndex) { // TODO unused
this.nameIndex = nameIndex;
}
/** /**
* @return index of register where variable was originally stored * @return index of register where variable was originally stored
*/ */
@@ -213,41 +234,6 @@ public final class LocalVariable implements Cloneable, Node {
return signatureIndex; return signatureIndex;
} }
/**
* @return Start of range where the variable is valid
*/
public int getStartPC() {
return startPc;
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/**
* @param index the index in the local variable table of this variable
*/
public void setIndex(final int index) { // TODO unused
this.index = index;
}
/**
* @param length the length of this local variable
*/
public void setLength(final int length) {
this.length = length;
}
/**
* @param nameIndex the index into the constant pool for the name of this variable
*/
public void setNameIndex(final int nameIndex) { // TODO unused
this.nameIndex = nameIndex;
}
/** /**
* @param signatureIndex the index into the constant pool for the signature of this variable * @param signatureIndex the index into the constant pool for the signature of this variable
*/ */
@@ -255,6 +241,13 @@ public final class LocalVariable implements Cloneable, Node {
this.signatureIndex = signatureIndex; this.signatureIndex = signatureIndex;
} }
/**
* @return Start of range where the variable is valid
*/
public int getStartPC() {
return startPc;
}
/** /**
* @param startPc Specify range where the local variable is valid. * @param startPc Specify range where the local variable is valid.
*/ */

View File

@@ -116,11 +116,8 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
} }
/** /**
*
* @param index the variable slot * @param index the variable slot
*
* @return the first LocalVariable that matches the slot or null if not found * @return the first LocalVariable that matches the slot or null if not found
*
* @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc) * @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc)
* instead. * instead.
*/ */
@@ -135,10 +132,8 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
} }
/** /**
*
* @param index the variable slot * @param index the variable slot
* @param pc the current pc that this variable is alive * @param pc the current pc that this variable is alive
*
* @return the LocalVariable that matches or null if not found * @return the LocalVariable that matches or null if not found
*/ */
public final LocalVariable getLocalVariable(final int index, final int pc) { public final LocalVariable getLocalVariable(final int index, final int pc) {
@@ -161,6 +156,10 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
return localVariableTable; return localVariableTable;
} }
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTable = localVariableTable;
}
public final int getTableLength() { public final int getTableLength() {
return localVariableTable == null ? 0 : localVariableTable.length; return localVariableTable == null ? 0 : localVariableTable.length;
} }
@@ -170,10 +169,6 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
return Stream.of(localVariableTable).iterator(); return Stream.of(localVariableTable).iterator();
} }
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTable = localVariableTable;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@@ -32,10 +32,14 @@ import java.io.IOException;
*/ */
public class MethodParameter implements Cloneable, Node { 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; private int nameIndex;
/** The access flags */ /**
* The access flags
*/
private int accessFlags; private int accessFlags;
public MethodParameter() { public MethodParameter() {
@@ -85,10 +89,18 @@ public class MethodParameter implements Cloneable, Node {
return accessFlags; return accessFlags;
} }
public void setAccessFlags(final int accessFlags) {
this.accessFlags = accessFlags;
}
public int getNameIndex() { public int getNameIndex() {
return nameIndex; return nameIndex;
} }
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/** /**
* Returns the name of the parameter. * Returns the name of the parameter.
*/ */
@@ -110,12 +122,4 @@ public class MethodParameter implements Cloneable, Node {
public boolean isSynthetic() { public boolean isSynthetic() {
return (accessFlags & Const.ACC_SYNTHETIC) != 0; return (accessFlags & Const.ACC_SYNTHETIC) != 0;
} }
public void setAccessFlags(final int accessFlags) {
this.accessFlags = accessFlags;
}
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
} }

View File

@@ -86,12 +86,12 @@ public class MethodParameters extends Attribute implements Iterable<MethodParame
return parameters; return parameters;
} }
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters;
}
@Override @Override
public Iterator<MethodParameter> iterator() { public Iterator<MethodParameter> iterator() {
return Stream.of(parameters).iterator(); return Stream.of(parameters).iterator();
} }
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters;
}
} }

View File

@@ -43,12 +43,11 @@ public final class Module extends Attribute {
private final int moduleNameIndex; private final int moduleNameIndex;
private final int moduleFlags; private final int moduleFlags;
private final int moduleVersionIndex; private final int moduleVersionIndex;
private final int usesCount;
private final int[] usesIndex;
private ModuleRequires[] requiresTable; private ModuleRequires[] requiresTable;
private ModuleExports[] exportsTable; private ModuleExports[] exportsTable;
private ModuleOpens[] opensTable; private ModuleOpens[] opensTable;
private final int usesCount;
private final int[] usesIndex;
private ModuleProvides[] providesTable; private ModuleProvides[] providesTable;
/** /**

View File

@@ -129,6 +129,13 @@ public final class ModulePackages extends Attribute {
return packageIndexTable; 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 * @return string array of package names
*/ */
@@ -138,13 +145,6 @@ public final class ModulePackages extends Attribute {
return names; 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. * @return String representation, i.e., a list of packages.
*/ */

View File

@@ -123,6 +123,13 @@ public final class NestMembers extends Attribute {
return classes; 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 * @return string array of class names
*/ */
@@ -139,13 +146,6 @@ public final class NestMembers extends Attribute {
return classes.length; 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. * @return String representation, i.e., a list of classes.
*/ */

View File

@@ -107,6 +107,13 @@ public final class PMGClass extends Attribute {
return pmgClassIndex; return pmgClassIndex;
} }
/**
* @param pmgClassIndex
*/
public void setPMGClassIndex(final int pmgClassIndex) {
this.pmgClassIndex = pmgClassIndex;
}
/** /**
* @return PMG class name. * @return PMG class name.
*/ */
@@ -121,20 +128,6 @@ public final class PMGClass extends Attribute {
return pmgIndex; 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 * @param pmgIndex
*/ */
@@ -142,6 +135,13 @@ public final class PMGClass extends Attribute {
this.pmgIndex = pmgIndex; this.pmgIndex = pmgIndex;
} }
/**
* @return PMG name.
*/
public String getPMGName() {
return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
}
/** /**
* @return String representation * @return String representation
*/ */

View File

@@ -31,19 +31,6 @@ import java.util.List;
public class ParameterAnnotationEntry implements Node { public class ParameterAnnotationEntry implements Node {
static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain parameter annotation data
final List<ParameterAnnotationEntry> 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; 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<ParameterAnnotationEntry> 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. * 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. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.

View File

@@ -29,7 +29,9 @@ import java.util.stream.Stream;
*/ */
public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> { public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> {
/** Table of parameter annotations */ /**
* Table of parameter annotations
*/
private ParameterAnnotationEntry[] parameterAnnotationTable; private ParameterAnnotationEntry[] parameterAnnotationTable;
/** /**
@@ -106,15 +108,15 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
return parameterAnnotationTable; return parameterAnnotationTable;
} }
@Override
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
/** /**
* @param parameterAnnotationTable the entries to set in this parameter annotation * @param parameterAnnotationTable the entries to set in this parameter annotation
*/ */
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) { public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = parameterAnnotationTable; this.parameterAnnotationTable = parameterAnnotationTable;
} }
@Override
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
} }

View File

@@ -33,24 +33,42 @@ import java.util.Objects;
*/ */
public final class Signature extends Attribute { 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));
} }
String getData() { /**
return new String(buf, 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)");
} }
void unread() { /**
if (pos > 0) { * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
pos--; * 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) { private static boolean identStart(final int ch) {
@@ -152,44 +170,6 @@ public final class Signature extends Attribute {
return buf.toString(); 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. * 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. * 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() { public String toString() {
return "Signature: " + getSignature(); 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--;
}
}
}
} }

View File

@@ -60,6 +60,10 @@ public class SimpleElementValue extends ElementValue {
return index; return index;
} }
public void setIndex(final int index) {
this.index = index;
}
public boolean getValueBoolean() { public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) { if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue");
@@ -128,10 +132,6 @@ public class SimpleElementValue extends ElementValue {
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes(); 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 // Whatever kind of value it is, return it as a string
@Override @Override
public String stringifyValue() { public String stringifyValue() {

View File

@@ -109,13 +109,6 @@ public final class SourceFile extends Attribute {
return sourceFileIndex; return sourceFileIndex;
} }
/**
* @return Source file name.
*/
public String getSourceFileName() {
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/** /**
* @param sourceFileIndex * @param sourceFileIndex
*/ */
@@ -123,6 +116,13 @@ public final class SourceFile extends Attribute {
this.sourceFileIndex = sourceFileIndex; this.sourceFileIndex = sourceFileIndex;
} }
/**
* @return Source file name.
*/
public String getSourceFileName() {
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/** /**
* @return String representation * @return String representation
*/ */

View File

@@ -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 * 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. * byte code offset. See CLDC specification 5.3.1.2.
* * <p>
* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4 * See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
* *
* <pre> * <pre>
@@ -41,6 +41,7 @@ import java.util.Arrays;
* full_frame; * full_frame;
* } * }
* </pre> * </pre>
*
* @see StackMap * @see StackMap
* @see StackMapType * @see StackMapType
*/ */
@@ -67,10 +68,10 @@ public final class StackMapEntry implements Node, Cloneable {
byteCodeOffset = frameType - Const.SAME_FRAME; byteCodeOffset = frameType - Const.SAME_FRAME;
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { } 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; 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) { } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
byteCodeOffset = dataInput.readUnsignedShort(); 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) { } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
byteCodeOffset = dataInput.readUnsignedShort(); byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType == Const.SAME_FRAME_EXTENDED) { } else if (frameType == Const.SAME_FRAME_EXTENDED) {
@@ -215,6 +216,29 @@ public final class StackMapEntry implements Node, Cloneable {
return byteCodeOffset; 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. * @return Constant pool used by this object.
*/ */
@@ -222,13 +246,30 @@ public final class StackMapEntry implements Node, Cloneable {
return constantPool; return constantPool;
} }
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public int getFrameType() { public int getFrameType() {
return frameType; 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 * Calculate stack map entry size
*
*/ */
int getMapEntrySize() { int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) { if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
@@ -267,18 +308,40 @@ public final class StackMapEntry implements Node, Cloneable {
return typesOfLocals.length; return typesOfLocals.length;
} }
/**
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfLocals(final int n) { // TODO unused
}
public int getNumberOfStackItems() { public int getNumberOfStackItems() {
return typesOfStackItems.length; return typesOfStackItems.length;
} }
/**
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfStackItems(final int n) { // TODO unused
}
public StackMapType[] getTypesOfLocals() { public StackMapType[] getTypesOfLocals() {
return typesOfLocals; return typesOfLocals;
} }
public void setTypesOfLocals(final StackMapType[] types) {
typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
}
public StackMapType[] getTypesOfStackItems() { public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems; return typesOfStackItems;
} }
public void setTypesOfStackItems(final StackMapType[] types) {
typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
}
private boolean invalidFrameType(final int f) { private boolean invalidFrameType(final int f) {
// @formatter:off // @formatter:off
return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
@@ -289,71 +352,6 @@ public final class StackMapEntry implements Node, Cloneable {
// @formatter:on // @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. * @return String representation.
*/ */

View File

@@ -100,6 +100,13 @@ public final class StackMapType implements Cloneable {
return constantPool; 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 * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
* otherwise * otherwise
@@ -108,10 +115,18 @@ public final class StackMapType implements Cloneable {
return index; return index;
} }
public void setIndex(final int index) {
this.index = index;
}
public byte getType() { public byte getType() {
return type; return type;
} }
public void setType(final byte type) {
this.type = checkType(type);
}
/** /**
* @return true, if type is either ITEM_Object or ITEM_NewObject * @return true, if type is either ITEM_Object or ITEM_NewObject
*/ */
@@ -132,21 +147,6 @@ public final class StackMapType implements Cloneable {
return ""; 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 * @return String representation
*/ */

View File

@@ -34,9 +34,8 @@ import java.util.Arrays;
*/ */
public final class Unknown extends Attribute { public final class Unknown extends Attribute {
private byte[] bytes;
private final String name; private final String name;
private byte[] bytes;
/** /**
* Constructs a new instance for a non-standard attribute. * Constructs a new instance for a non-standard attribute.
@@ -123,6 +122,13 @@ public final class Unknown extends Attribute {
return bytes; return bytes;
} }
/**
* @param bytes the bytes to set
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/** /**
* @return name of attribute. * @return name of attribute.
*/ */
@@ -131,13 +137,6 @@ public final class Unknown extends Attribute {
return name; return name;
} }
/**
* @param bytes the bytes to set
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -36,10 +36,8 @@ public interface UnknownAttributeReader {
* agree with what the factory expects the length to be. * 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 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. * @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 * @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) * @see Attribute#addAttributeReader(String, UnknownAttributeReader)
*/ */
Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool); Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool);

View File

@@ -35,96 +35,16 @@ import java.util.zip.GZIPOutputStream;
// @since 6.0 methods are no longer final // @since 6.0 methods are no longer final
public abstract class Utility { public abstract class Utility {
/**
* Decode characters into bytes. Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
*/
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
* <a href="Utility.html#encode(byte[], boolean)">encode()</a>
*/
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 * How many chars have been consumed during parsing in typeSignatureToString(). Read by methodSignatureToString(). Set
* by side effect, but only internally. * by side effect, but only internally.
*/ */
private static final ThreadLocal<Integer> CONSUMER_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0)); private static final ThreadLocal<Integer> 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 * 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 * 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; 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 { static {
int j = 0; int j = 0;
for (int i = 'A'; i <= 'Z'; i++) { for (int i = 'A'; i <= 'Z'; i++) {
@@ -172,7 +83,7 @@ public abstract class Utility {
/** /**
* Convert bit field of flags into string such as 'static final'. * Convert bit field of flags into string such as 'static final'.
* * <p>
* Special case: Classes compiled with new compilers and with the 'ACC_SUPER' flag would be said to be "synchronized". * 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'. * This is because SUN used the same value for the flags 'ACC_SUPER' and 'ACC_SYNCHRONIZED'.
* *
@@ -208,7 +119,6 @@ public abstract class Utility {
/** /**
* @param accessFlags the class flags * @param accessFlags the class flags
*
* @return "class" or "interface", depending on the ACC_INTERFACE flag * @return "class" or "interface", depending on the ACC_INTERFACE flag
*/ */
public static String classOrInterface(final int accessFlags) { public static String classOrInterface(final int accessFlags) {
@@ -267,7 +177,6 @@ public abstract class Utility {
* @param constantPool Array of constants * @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 * @return String representation of byte code
*
* @throws IOException if a failure from reading from the bytes argument occurs * @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 { public static String codeToString(final ByteSequence bytes, final ConstantPool constantPool, final boolean verbose) throws IOException {
@@ -630,7 +539,6 @@ public abstract class Utility {
* *
* @param s the string to convert * @param s the string to convert
* @param uncompress use gzip to uncompress the stream of bytes * @param uncompress use gzip to uncompress the stream of bytes
*
* @throws IOException if there's a gzip exception * @throws IOException if there's a gzip exception
*/ */
public static byte[] decode(final String s, final boolean uncompress) throws IOException { public static byte[] decode(final String s, final boolean uncompress) throws IOException {
@@ -671,7 +579,6 @@ public abstract class Utility {
* *
* @param bytes the byte array to convert * @param bytes the byte array to convert
* @param compress use gzip to minimize string * @param compress use gzip to minimize string
*
* @throws IOException if there's a gzip exception * @throws IOException if there's a gzip exception
*/ */
public static String encode(byte[] bytes, final boolean compress) throws IOException { public static String encode(byte[] bytes, final boolean compress) throws IOException {
@@ -724,30 +631,6 @@ public abstract class Utility {
return fillup(Integer.toString(i), length, leftJustify, fill); return fillup(Integer.toString(i), length, leftJustify, fill);
} }
/**
* WARNING:
*
* There is some nomenclature confusion through much of the BCEL code base with respect to the terms Descriptor and
* Signature. For the offical definitions see:
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3"> Descriptors in The Java
* Virtual Machine Specification</a>
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9.1"> Signatures in The Java
* Virtual Machine Specification</a>
*
* In brief, a descriptor is a string representing the type of a field or method. Signatures are similar, but more
* complex. Signatures are used to encode declarations written in the Java programming language that use types
* outside the type system of the Java Virtual Machine. They are used to describe the type of any class, interface,
* constructor, method or field whose declaration uses type variables or parameterized types.
*
* To parse a descriptor, call typeSignatureToString. To parse a signature, call signatureToString.
*
* Note that if the signature string is a single, non-generic item, the call to signatureToString reduces to a call
* to typeSignatureToString. Also note, that if you only wish to parse the first item in a longer signature string,
* 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 * 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. * "[Ljava/lang/String;" respectively.
@@ -761,7 +644,8 @@ public abstract class Utility {
boolean charFound = false; boolean charFound = false;
boolean delim = false; boolean delim = false;
int index = -1; int index = -1;
loop: for (int i = 0; i < chars.length; i++) { loop:
for (int i = 0; i < chars.length; i++) {
switch (chars[i]) { switch (chars[i]) {
case ' ': case ' ':
case '\t': case '\t':
@@ -809,13 +693,36 @@ public abstract class Utility {
/** /**
* @param ch the character to test if it's part of an identifier * @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, _) * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
*/ */
public static boolean isJavaIdentifierPart(final char ch) { public static boolean isJavaIdentifierPart(final char ch) {
return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_'; return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_';
} }
/**
* WARNING:
*
* There is some nomenclature confusion through much of the BCEL code base with respect to the terms Descriptor and
* Signature. For the offical definitions see:
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3"> Descriptors in The Java
* Virtual Machine Specification</a>
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9.1"> Signatures in The Java
* Virtual Machine Specification</a>
*
* In brief, a descriptor is a string representing the type of a field or method. Signatures are similar, but more
* complex. Signatures are used to encode declarations written in the Java programming language that use types
* outside the type system of the Java Virtual Machine. They are used to describe the type of any class, interface,
* constructor, method or field whose declaration uses type variables or parameterized types.
*
* To parse a descriptor, call typeSignatureToString. To parse a signature, call signatureToString.
*
* Note that if the signature string is a single, non-generic item, the call to signatureToString reduces to a call
* to typeSignatureToString. Also note, that if you only wish to parse the first item in a longer signature string,
* you should call typeSignatureToString directly.
*/
/** /**
* @return true, if bit 'i' in 'flag' is set * @return true, if bit 'i' in 'flag' is set
*/ */
@@ -987,7 +894,6 @@ public abstract class Utility {
* @param ret Return type of method * @param ret Return type of method
* @param argv Types of method arguments * @param argv Types of method arguments
* @return Byte code representation of method signature * @return Byte code representation of method signature
*
* @throws ClassFormatException if the signature is for Void * @throws ClassFormatException if the signature is for Void
*/ */
public static String methodTypeToSignature(final String ret, final String[] argv) throws ClassFormatException { public static String methodTypeToSignature(final String ret, final String[] argv) throws ClassFormatException {
@@ -1190,7 +1096,6 @@ public abstract class Utility {
* Convert bytes into hexadecimal string * Convert bytes into hexadecimal string
* *
* @param bytes an array of bytes to convert to hexadecimal * @param bytes an array of bytes to convert to hexadecimal
*
* @return bytes as hexadecimal string, e.g. 00 fa 12 ... * @return bytes as hexadecimal string, e.g. 00 fa 12 ...
*/ */
public static String toHexString(final byte[] bytes) { public static String toHexString(final byte[] bytes) {
@@ -1214,9 +1119,8 @@ public abstract class Utility {
* *
* @param signature in format described above * @param signature in format described above
* @return type of method signature * @return type of method signature
* @see Const
*
* @throws ClassFormatException if signature is not a method signature * @throws ClassFormatException if signature is not a method signature
* @see Const
*/ */
public static byte typeOfMethodSignature(final String signature) throws ClassFormatException { public static byte typeOfMethodSignature(final String signature) throws ClassFormatException {
int index; int index;
@@ -1236,9 +1140,8 @@ public abstract class Utility {
* *
* @param signature in format described above * @param signature in format described above
* @return type of signature * @return type of signature
* @see Const
*
* @throws ClassFormatException if signature isn't a known type * @throws ClassFormatException if signature isn't a known type
* @see Const
*/ */
public static byte typeOfSignature(final String signature) throws ClassFormatException { public static byte typeOfSignature(final String signature) throws ClassFormatException {
try { try {
@@ -1362,7 +1265,6 @@ public abstract class Utility {
} }
/** /**
*
* This method converts a type signature string into a Java type declaration such as 'String[]' and throws a * 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. * 'ClassFormatException' when the parsed type is invalid.
* *
@@ -1544,4 +1446,88 @@ public abstract class Utility {
tl.set(Integer.valueOf(value)); tl.set(Integer.valueOf(value));
} }
/**
* Decode characters into bytes. Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
*/
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
* <a href="Utility.html#encode(byte[], boolean)">encode()</a>
*/
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);
}
}
} }

View File

@@ -53,6 +53,6 @@ public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackP
*/ */
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION}; return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION};
} }
} }

View File

@@ -53,6 +53,6 @@ public class ATHROW extends Instruction implements UnconditionalBranch, Exceptio
*/ */
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.THROWABLE}; return new Class[]{ExceptionConst.THROWABLE};
} }
} }

View File

@@ -28,6 +28,38 @@ import java.util.List;
public class AnnotationEntryGen { public class AnnotationEntryGen {
static final AnnotationEntryGen[] EMPTY_ARRAY = {}; static final AnnotationEntryGen[] EMPTY_ARRAY = {};
private final ConstantPoolGen cpool;
private int typeIndex;
private List<ElementValuePairGen> 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<ElementValuePairGen> 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. * Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file.
@@ -194,42 +226,6 @@ public class AnnotationEntryGen {
return a; return a;
} }
private int typeIndex;
private List<ElementValuePairGen> 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<ElementValuePairGen> 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) { public void addElementNameValuePair(final ElementValuePairGen evp) {
if (evs == null) { if (evs == null) {
evs = new ArrayList<>(); evs = new ArrayList<>();

View File

@@ -23,6 +23,19 @@ import haidnor.jvm.bcel.Const;
*/ */
public final class BasicType extends Type { public final class BasicType extends Type {
/**
* Constructor for basic types such as int, long, 'void'
*
* @param type one of T_INT, T_BOOLEAN, ..., T_VOID
* @see Const
*/
BasicType(final byte type) {
super(type, Const.getShortTypeName(type));
if (type < Const.T_BOOLEAN || type > Const.T_VOID) {
throw new ClassGenException("Invalid type: " + type);
}
}
// @since 6.0 no longer final // @since 6.0 no longer final
public static BasicType getType(final byte type) { public static BasicType getType(final byte type) {
switch (type) { switch (type) {
@@ -49,19 +62,6 @@ public final class BasicType extends Type {
} }
} }
/**
* Constructor for basic types such as int, long, 'void'
*
* @param type one of T_INT, T_BOOLEAN, ..., T_VOID
* @see Const
*/
BasicType(final byte type) {
super(type, Const.getShortTypeName(type));
if (type < Const.T_BOOLEAN || type > Const.T_VOID) {
throw new ClassGenException("Invalid type: " + type);
}
}
/** /**
* @return true if both type objects refer to the same type * @return true if both type objects refer to the same type
*/ */

View File

@@ -26,13 +26,6 @@ package haidnor.jvm.bcel.generic;
*/ */
public final class BranchHandle extends InstructionHandle { 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 // This is also a cache in case the InstructionHandle#swapInstruction() method is used
// See BCEL-273 // See BCEL-273
private BranchInstruction bi; // An alias in fact, but saves lots of casts private BranchInstruction bi; // An alias in fact, but saves lots of casts
@@ -42,6 +35,13 @@ public final class BranchHandle extends InstructionHandle {
bi = i; 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 * Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private
* i_position field should be prevented. * i_position field should be prevented.
@@ -51,6 +51,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getPosition(); 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. * @return target of instruction.
*/ */
@@ -58,6 +65,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getTarget(); 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. * 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; 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 @Override
protected int updatePosition(final int offset, final int maxOffset) { protected int updatePosition(final int offset, final int maxOffset) {
final int x = bi.updatePosition(offset, maxOffset); final int x = bi.updatePosition(offset, maxOffset);

View File

@@ -29,30 +29,16 @@ import java.io.IOException;
*/ */
public abstract class BranchInstruction extends Instruction implements InstructionTargeter { 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 (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected int index; // Branch target relative to this instruction 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 (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected InstructionHandle target; // Target object in instruction list protected InstructionHandle target; // Target object in instruction list
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @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); 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 * @return true, if ih is target of this instruction
*/ */
@@ -116,6 +114,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return index; return index;
} }
/**
* @param index the index to set
* @since 6.0
*/
protected void setIndex(final int index) {
this.index = index;
}
/** /**
* @return the position * @return the position
* @since 6.0 * @since 6.0
@@ -124,6 +130,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return position; 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 * @return target of branch instruction
*/ */
@@ -131,6 +145,16 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return target; 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 * @return the offset to this instruction's target
*/ */
@@ -166,35 +190,9 @@ public abstract class BranchInstruction extends Instruction implements Instructi
index = bytes.readShort(); 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: * Long output format:
* * <p>
* &lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" * &lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")"
* "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt; * "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt;
* *

View File

@@ -74,6 +74,19 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
return index; 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. * @return type related with this instruction.
*/ */
@@ -99,22 +112,9 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
super.setLength(3); 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: * Long output format:
* * <p>
* &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" "&lt;"&lt; constant pool * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" "&lt;"&lt; constant pool
* index&gt;"&gt;" * index&gt;"&gt;"
* *

View File

@@ -45,42 +45,23 @@ public class ClassGen extends AccessFlags implements Cloneable {
return THIS.getClassName().hashCode(); return THIS.getClassName().hashCode();
} }
}; };
private final String fileName;
/** // ArrayLists instead of arrays to gather fields, methods, etc.
* @return Comparison strategy object private final List<JavaField> fieldList = new ArrayList<>();
*/ private final List<JavaMethod> methodList = new ArrayList<>();
public static BCELComparator getComparator() { private final List<Attribute> attributeList = new ArrayList<>();
return bcelComparator; private final List<String> interfaceList = new ArrayList<>();
} private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/* /*
* Corresponds to the fields found in a JavaClass object. * Corresponds to the fields found in a JavaClass object.
*/ */
private String className; private String className;
private String superClassName; private String superClassName;
private final String fileName;
private int classNameIndex = -1; private int classNameIndex = -1;
private int superclassNameIndex = -1; private int superclassNameIndex = -1;
private int major = Const.MAJOR_1_1; private int major = Const.MAJOR_1_1;
private int minor = Const.MINOR_1_1; private int minor = Const.MINOR_1_1;
private ConstantPoolGen cp; // Template for building up constant pool private ConstantPoolGen cp; // Template for building up constant pool
// ArrayLists instead of arrays to gather fields, methods, etc.
private final List<JavaField> fieldList = new ArrayList<>();
private final List<JavaMethod> methodList = new ArrayList<>();
private final List<Attribute> attributeList = new ArrayList<>();
private final List<String> interfaceList = new ArrayList<>();
private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
private List<ClassObserver> observers; private List<ClassObserver> observers;
/** /**
@@ -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) { public void addAnnotationEntry(final AnnotationEntryGen a) {
annotationList.add(a); annotationList.add(a);
} }
@@ -168,7 +163,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
/** /**
* Convenience method. * Convenience method.
* * <p>
* Add an empty constructor to this class that does nothing but calling super(). * Add an empty constructor to this class that does nothing but calling super().
* *
* @param accessFlags rights for constructor * @param accessFlags rights for constructor
@@ -281,14 +276,28 @@ public class ClassGen extends AccessFlags implements Cloneable {
return className; return className;
} }
public void setClassName(final String name) {
className = Utility.pathToPackage(name);
classNameIndex = cp.addClass(name);
}
public int getClassNameIndex() { public int getClassNameIndex() {
return classNameIndex; 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() { public ConstantPoolGen getConstantPool() {
return cp; return cp;
} }
public void setConstantPool(final ConstantPoolGen constantPool) {
cp = constantPool;
}
public JavaField[] getFields() { public JavaField[] getFields() {
return fieldList.toArray(JavaField.EMPTY_ARRAY); return fieldList.toArray(JavaField.EMPTY_ARRAY);
} }
@@ -338,6 +347,15 @@ public class ClassGen extends AccessFlags implements Cloneable {
return major; 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) { public JavaMethod getMethodAt(final int pos) {
return methodList.get(pos); return methodList.get(pos);
} }
@@ -346,6 +364,11 @@ public class ClassGen extends AccessFlags implements Cloneable {
return methodList.toArray(JavaMethod.EMPTY_ARRAY); 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 * @return minor version number of class file
*/ */
@@ -353,14 +376,33 @@ public class ClassGen extends AccessFlags implements Cloneable {
return minor; 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() { public String getSuperclassName() {
return superClassName; return superClassName;
} }
public void setSuperclassName(final String name) {
superClassName = Utility.pathToPackage(name);
superclassNameIndex = cp.addClass(name);
}
public int getSuperclassNameIndex() { public int getSuperclassNameIndex() {
return superclassNameIndex; 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. * 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) { public void setMethodAt(final JavaMethod method, final int pos) {
methodList.set(pos, method); 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. * Look for attributes representing annotations and unpack them.
*/ */

View File

@@ -71,14 +71,23 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return startPc == ih || endPc == ih || handlerPc == ih; 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() { public ObjectType getCatchType() {
return catchType; 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.<BR> * Get CodeException object.<BR>
* * <p>
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * 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. * has been called for the instruction list.
* *
@@ -96,25 +105,6 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return endPc; 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 * Set end of handler
* *
@@ -125,6 +115,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.endPc = endPc; this.endPc = endPc;
} }
/**
* @return start of handler
*/
public InstructionHandle getHandlerPC() {
return handlerPc;
}
/* /*
* Set handler code * Set handler code
* *
@@ -135,6 +132,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.handlerPc = handlerPc; this.handlerPc = handlerPc;
} }
/**
* @return start of handled region (inclusive)
*/
public InstructionHandle getStartPC() {
return startPc;
}
/* /*
* Set start of handler * Set start of handler
* *

View File

@@ -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 * 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 * dump time (ICONST, LDC, BIPUSH, ...). Also you can use the SWITCH instruction as a useful template for either
* LOOKUPSWITCH or TABLESWITCH. * LOOKUPSWITCH or TABLESWITCH.
* * <p>
* The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns. * The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns.
* *
* @see PUSH * @see PUSH

View File

@@ -44,35 +44,27 @@ public class ConstantPoolGen {
private static final String FIELDREF_DELIM = "&"; private static final String FIELDREF_DELIM = "&";
private static final String NAT_DELIM = "%"; // Name and Type private static final String NAT_DELIM = "%"; // Name and Type
private final Map<String, Integer> stringTable = new HashMap<>();
private final Map<String, Integer> classTable = new HashMap<>();
private final Map<String, Integer> utf8Table = new HashMap<>();
private final Map<String, Integer> natTable = new HashMap<>();
private final Map<String, Integer> cpTable = new HashMap<>();
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected int size; protected int size;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected Constant[] constants; protected Constant[] constants;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getSize() * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
*/ */
@Deprecated @Deprecated
protected int index = 1; // First entry (0) used by JVM protected int index = 1; // First entry (0) used by JVM
private final Map<String, Integer> stringTable = new HashMap<>();
private final Map<String, Integer> classTable = new HashMap<>();
private final Map<String, Integer> utf8Table = new HashMap<>();
private final Map<String, Integer> natTable = new HashMap<>();
private final Map<String, Integer> cpTable = new HashMap<>();
/** /**
* Constructs a new empty constant pool. * Constructs a new empty constant pool.
*/ */
@@ -430,6 +422,7 @@ public class ConstantPoolGen {
index += 2; // Wastes one entry according to spec index += 2; // Wastes one entry according to spec
return ret; return ret;
} }
public int addMethodref(final MethodGen method) { public int addMethodref(final MethodGen method) {
return addMethodref(method.getClassName(), method.getName(), method.getSignature()); return addMethodref(method.getClassName(), method.getName(), method.getSignature());
} }

View File

@@ -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. * Denotes a push instruction that produces a literal on the stack such as SIPUSH, BIPUSH, ICONST, etc.
* *
*
* @see ICONST * @see ICONST
* @see SIPUSH * @see SIPUSH
*/ */

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result1.word2 * ..., result.word1, result1.word2
*/ */
public class DADD extends ArithmeticInstruction { public class DADD extends ArithmeticInstruction {

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class DDIV extends ArithmeticInstruction { public class DDIV extends ArithmeticInstruction {

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class DMUL extends ArithmeticInstruction { public class DMUL extends ArithmeticInstruction {

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class DREM extends ArithmeticInstruction { public class DREM extends ArithmeticInstruction {

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class DSUB extends ArithmeticInstruction { public class DSUB extends ArithmeticInstruction {

View File

@@ -52,6 +52,21 @@ public abstract class ElementValueGen {
public static final int PRIMITIVE_SHORT = 'S'; public static final int PRIMITIVE_SHORT = 'S';
public static final int PRIMITIVE_BOOLEAN = 'Z'; public static final int PRIMITIVE_BOOLEAN = 'Z';
/**
* @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
*/
@Deprecated
protected ConstantPoolGen cpGen;
protected ElementValueGen(final int type, final ConstantPoolGen cpGen) {
this.type = type;
this.cpGen = cpGen;
}
/** /**
* Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct. * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct.
@@ -123,23 +138,6 @@ public abstract class ElementValueGen {
} }
} }
/**
* @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
*/
@Deprecated
protected ConstantPoolGen cpGen;
protected ElementValueGen(final int type, final ConstantPoolGen cpGen) {
this.type = type;
this.cpGen = cpGen;
}
public abstract void dump(DataOutputStream dos) throws IOException; public abstract void dump(DataOutputStream dos) throws IOException;
protected ConstantPoolGen getConstantPool() { protected ConstantPoolGen getConstantPool() {

View File

@@ -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 * 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 truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted.
* * <p>
* The Lava Language Specification specifies exactly which <i>RUN-TIME</i> and which <i>LINKING</i> exceptions each * The Lava Language Specification specifies exactly which <i>RUN-TIME</i> and which <i>LINKING</i> exceptions each
* instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may * 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. * be possible that an Instruction implementing this interface returns a Class[] of size 0.
* * <p>
* Please note that we speak of an "exception" here when we mean any "Throwable" object; so this term is equally used * 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. * for "Exception" and "Error" objects.
*/ */

View File

@@ -48,23 +48,7 @@ public class FieldGen extends FieldGenOrMethodGen {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 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 Object value;
private List<FieldObserver> observers; private List<FieldObserver> observers;
/** /**
@@ -104,6 +88,20 @@ public class FieldGen extends FieldGenOrMethodGen {
setConstantPool(cp); 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) { private void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute); Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute);
} }
@@ -202,31 +200,6 @@ public class FieldGen extends FieldGenOrMethodGen {
return null; 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) { public void setInitValue(final boolean b) {
checkType(Type.BOOLEAN); checkType(Type.BOOLEAN);
if (b) { 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) { private void setValue(final int index) {
final ConstantPool cp = super.getConstantPool().getConstantPool(); final ConstantPool cp = super.getConstantPool().getConstantPool();
final Constant c = cp.getConstant(index); final Constant c = cp.getConstant(index);

View File

@@ -29,29 +29,25 @@ import java.util.List;
*/ */
public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable { public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable {
private final List<Attribute> attributeList = new ArrayList<>();
// @since 6.0
private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected String name; protected String name;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected Type type; protected Type type;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected ConstantPoolGen cp; protected ConstantPoolGen cp;
private final List<Attribute> attributeList = new ArrayList<>();
// @since 6.0
private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
protected FieldGenOrMethodGen() { protected FieldGenOrMethodGen() {
} }
@@ -107,6 +103,10 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return cp; return cp;
} }
public void setConstantPool(final ConstantPoolGen cp) { // TODO could be package-protected?
this.cp = cp;
}
/** /**
* @return name of method/field. * @return name of method/field.
*/ */
@@ -115,6 +115,11 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return name; return name;
} }
@Override
public void setName(final String name) { // TODO could be package-protected?
this.name = name;
}
/** /**
* @return signature of method/field. * @return signature of method/field.
*/ */
@@ -125,6 +130,14 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return type; 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 * @since 6.0
*/ */
@@ -152,21 +165,4 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
public void removeAttributes() { public void removeAttributes() {
attributeList.clear(); 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;
}
} }

View File

@@ -46,7 +46,6 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
* generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an * 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 * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly
* distinguishes between class types and array types. * distinguishes between class types and array types.
*
*/ */
@Deprecated @Deprecated
public String getClassName(final ConstantPoolGen cpg) { public String getClassName(final ConstantPoolGen cpg) {

View File

@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
* <PRE> * <PRE>
* Stack: ..., objectref -&gt; ..., value * Stack: ..., objectref -&gt; ..., value
* </PRE> * </PRE>
* * <p>
* OR * OR
* *
* <PRE> * <PRE>

View File

@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
* <PRE> * <PRE>
* Stack: ..., -&gt; ..., value * Stack: ..., -&gt; ..., value
* </PRE> * </PRE>
* * <p>
* OR * OR
* *
* <PRE> * <PRE>

View File

@@ -56,6 +56,6 @@ public class IDIV extends ArithmeticInstruction implements ExceptionThrower {
*/ */
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
} }
} }

View File

@@ -87,6 +87,14 @@ public class IINC extends LocalVariableInstruction {
return c; return c;
} }
/**
* Sets increment factor.
*/
public final void setIncrement(final int c) {
this.c = c;
setWide();
}
/** /**
* @return int type * @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. * Sets index of local variable.
*/ */

View File

@@ -80,7 +80,7 @@ public class INVOKEDYNAMIC extends InvokeInstruction {
/** /**
* Override the parent method because our class name is held elsewhere. * Override the parent method because our class name is held elsewhere.
* * <p>
* Note: Contrary to this method's name it does not return the class name of the invoke target; rather it returns the * 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. * name of the method that will be used to invoke the Lambda method generated by this invoke dynamic instruction.
*/ */

View File

@@ -56,6 +56,6 @@ public class IREM extends ArithmeticInstruction implements ExceptionThrower {
*/ */
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
} }
} }

View File

@@ -31,6 +31,27 @@ public abstract class Instruction implements Cloneable {
static final Instruction[] EMPTY_ARRAY = {}; static final Instruction[] EMPTY_ARRAY = {};
private static InstructionComparator cmp = InstructionComparator.DEFAULT; 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. * 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; 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) * Tests if the value can fit in a byte (signed)
* *
@@ -70,6 +101,7 @@ public abstract class Instruction implements Cloneable {
* <p> * <p>
* If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned. * If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned.
* </p> * </p>
*
* @param bytes input stream bytes * @param bytes input stream bytes
* @return instruction object being read * @return instruction object being read
* @throws IOException Thrown when an I/O exception of some sort has occurred. * @throws IOException Thrown when an I/O exception of some sort has occurred.
@@ -394,39 +426,6 @@ public abstract class Instruction implements Cloneable {
return obj; 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 * 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. * methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
@@ -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 * 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. * types are). This also applies for 'Select' instructions with their multiple branch targets.
* *
* @see BranchInstruction
* @return (shallow) copy of an instruction * @return (shallow) copy of an instruction
* @see BranchInstruction
*/ */
public Instruction copy() { public Instruction copy() {
Instruction i = null; Instruction i = null;
@@ -501,6 +500,15 @@ public abstract class Instruction implements Cloneable {
return length; 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 * @return name of instruction, i.e., opcode name
*/ */
@@ -515,6 +523,13 @@ public abstract class Instruction implements Cloneable {
return opcode; 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. * Gets the hashCode of this object.
* *
@@ -548,22 +563,6 @@ public abstract class Instruction implements Cloneable {
return Const.getProduceStack(opcode); 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 * @return mnemonic for instruction in verbose format
*/ */
@@ -574,7 +573,7 @@ public abstract class Instruction implements Cloneable {
/** /**
* Long output format: * Long output format:
* * <p>
* &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")"
* *
* @param verbose long/short format switch * @param verbose long/short format switch

View File

@@ -35,7 +35,7 @@ public final class InstructionConst {
/** /**
* Predefined instruction objects. * Predefined instruction objects.
* * <p>
* NOTE these are not currently immutable, because Instruction has mutable protected fields opcode and length. * NOTE these are not currently immutable, because Instruction has mutable protected fields opcode and length.
*/ */
public static final Instruction NOP = new NOP(); public static final Instruction NOP = new NOP();
@@ -279,6 +279,9 @@ public final class InstructionConst {
INSTRUCTIONS[Const.MONITOREXIT] = MONITOREXIT; INSTRUCTIONS[Const.MONITOREXIT] = MONITOREXIT;
} }
private InstructionConst() {
} // non-instantiable
/** /**
* Gets the Instruction. * Gets the Instruction.
* *
@@ -288,7 +291,4 @@ public final class InstructionConst {
public static Instruction getInstruction(final int index) { public static Instruction getInstruction(final int index) {
return INSTRUCTIONS[index]; return INSTRUCTIONS[index];
} }
private InstructionConst() {
} // non-instantiable
} }

View File

@@ -30,28 +30,10 @@ import haidnor.jvm.bcel.Const;
*/ */
public class InstructionFactory { 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 APPEND = "append";
private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer"; 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 // 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 String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"};
private static final MethodObject[] appendMethodObjects = { 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.STRING}),
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.OBJECT}), null, null, // indices 2, 3 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(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.INT}), // No append(short)
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.LONG})}; 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() * @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"); 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) { public Instruction createAppend(final Type type) {
final byte t = type.getType(); final byte t = type.getType();
if (isString(type)) { if (isString(type)) {
@@ -720,15 +700,30 @@ public class InstructionFactory {
return cg; return cg;
} }
public ConstantPoolGen getConstantPool() {
return cp;
}
public void setClassGen(final ClassGen c) { public void setClassGen(final ClassGen c) {
cg = c; cg = c;
} }
public ConstantPoolGen getConstantPool() {
return cp;
}
public void setConstantPool(final ConstantPoolGen c) { public void setConstantPool(final ConstantPoolGen c) {
cp = 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;
}
}
} }

View File

@@ -23,7 +23,7 @@ import java.util.*;
/** /**
* Instances of this class give users a handle to the instructions contained in an InstructionList. Instruction objects * 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. * may be used more than once within a list, this is useful because it saves memory and may be much faster.
* * <p>
* Within an InstructionList an InstructionHandle object is wrapped around all instructions, i.e., it implements a cell * 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 * 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(). * traverse the list via an Enumeration returned by InstructionList.elements().
@@ -45,6 +45,21 @@ public class InstructionHandle {
* Empty array. * Empty array.
*/ */
static final InstructionTargeter[] EMPTY_INSTRUCTION_TARGETER_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<InstructionTargeter> targeters;
private Map<Object, Object> attributes;
protected InstructionHandle(final Instruction i) {
setInstruction(i);
}
/** /**
* Factory method. * Factory method.
@@ -53,24 +68,6 @@ public class InstructionHandle {
return new InstructionHandle(i); 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<InstructionTargeter> targeters;
private Map<Object, Object> attributes;
protected InstructionHandle(final Instruction i) {
setInstruction(i);
}
/** /**
* Convenience method, simply calls accept() on the contained instruction. * Convenience method, simply calls accept() on the contained instruction.
* *
@@ -152,10 +149,35 @@ public class InstructionHandle {
return instruction; 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() { public final InstructionHandle getNext() {
return next; 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 * @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.
@@ -164,10 +186,26 @@ public class InstructionHandle {
return i_position; 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() { public final InstructionHandle getPrev() {
return prev; 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 * @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 * Temporarily swap the current instruction, without disturbing anything. Meant to be used by a debugger, implementing
* breakpoints. Current instruction is returned. * breakpoints. Current instruction is returned.

View File

@@ -32,7 +32,7 @@ import java.util.*;
* <a href="InstructionHandle.html">InstructionHandles</a> objects that are returned upon append/insert operations. They * <a href="InstructionHandle.html">InstructionHandles</a> 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 * give the user (read only) access to the list structure, such that it can be traversed and manipulated in a controlled
* way. * way.
* * <p>
* A list is finally dumped to a byte code array with <a href="#getByteCode()">getByteCode</a>. * A list is finally dumped to a byte code array with <a href="#getByteCode()">getByteCode</a>.
* *
* @see Instruction * @see Instruction
@@ -41,42 +41,10 @@ import java.util.*;
*/ */
public class InstructionList implements Iterable<InstructionHandle> { public class InstructionList implements Iterable<InstructionHandle> {
/**
* 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 start;
private InstructionHandle end; private InstructionHandle end;
private int length; // number of elements in list private int length; // number of elements in list
private int[] bytePositions; // byte code offsets corresponding to instructions private int[] bytePositions; // byte code offsets corresponding to instructions
private List<InstructionListObserver> observers; private List<InstructionListObserver> observers;
/** /**
@@ -181,6 +149,36 @@ public class InstructionList implements Iterable<InstructionHandle> {
append(i); 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. * Add observer for this object.
*/ */

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class LADD extends ArithmeticInstruction { public class LADD extends ArithmeticInstruction {

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class LAND extends ArithmeticInstruction { public class LAND extends ArithmeticInstruction {

View File

@@ -24,7 +24,6 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; ..., result &lt;= -1, 0, 1&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; ..., result &lt;= -1, 0, 1&gt;
* </PRE> * </PRE>
*
*/ */
public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer { public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer {

View File

@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class LDIV extends ArithmeticInstruction implements ExceptionThrower { public class LDIV extends ArithmeticInstruction implements ExceptionThrower {
@@ -52,6 +52,6 @@ public class LDIV extends ArithmeticInstruction implements ExceptionThrower {
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
} }
} }

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class LMUL extends ArithmeticInstruction { public class LMUL extends ArithmeticInstruction {

View File

@@ -50,6 +50,6 @@ public class LREM extends ArithmeticInstruction implements ExceptionThrower {
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION}; return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
} }
} }

View File

@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
* <PRE> * <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt;
* </PRE> * </PRE>
* * <p>
* ..., result.word1, result.word2 * ..., result.word1, result.word2
*/ */
public class LSUB extends ArithmeticInstruction { public class LSUB extends ArithmeticInstruction {

View File

@@ -65,9 +65,15 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
return ih; 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. * Get LineNumber attribute.
* * <p>
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * 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. * has been called for the instruction list.
*/ */
@@ -79,12 +85,6 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
return srcLine; 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? public void setSourceLine(final int srcLine) { // TODO could be package-protected?
this.srcLine = srcLine; this.srcLine = srcLine;
} }

Some files were not shown because too many files have changed in this diff Show More