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,62 +51,56 @@ 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};
/** /**
* Creates a copy of the specified Exception Class array combined with any additional Exception classes. * Creates a copy of the specified Exception Class array combined with any additional Exception classes.
* *
* @param type the basic array type * @param type the basic array type
* @param extraClasses additional classes, if any * @param extraClasses additional classes, if any
* @return the merged array * @return the merged array
*/ */
public static Class<?>[] createExceptions(final EXCS type, final Class<?>... extraClasses) { public static Class<?>[] createExceptions(final EXCS type, final Class<?>... extraClasses) {
switch (type) { switch (type) {
case EXCS_CLASS_AND_INTERFACE_RESOLUTION: case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses); return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
case EXCS_ARRAY_EXCEPTION: case EXCS_ARRAY_EXCEPTION:
return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses); return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses);
case EXCS_FIELD_AND_METHOD_RESOLUTION: case EXCS_FIELD_AND_METHOD_RESOLUTION:
return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses); return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses);
case EXCS_INTERFACE_METHOD_RESOLUTION: case EXCS_INTERFACE_METHOD_RESOLUTION:
return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses); return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses);
case EXCS_STRING_RESOLUTION: case EXCS_STRING_RESOLUTION:
return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses); return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses);
default: default:
throw new AssertionError("Cannot happen; unexpected enum value: " + type); throw new AssertionError("Cannot happen; unexpected enum value: " + type);
} }
} }
@@ -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

@@ -53,7 +53,7 @@ public abstract class Repository {
/** /**
* @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend, * @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend,
* and so on. (Some people call this a transitive hull). * and so on. (Some people call this a transitive hull).
* @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found * @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found
*/ */
public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException { public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException {
@@ -62,9 +62,9 @@ public abstract class Repository {
/** /**
* @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces, * @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces,
* and so on * and so on
* @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces * @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces
* can't be found * can't be found
*/ */
public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException { public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException {
return getInterfaces(lookupClass(className)); return getInterfaces(lookupClass(className));
@@ -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);
@@ -182,7 +189,7 @@ public abstract class Repository {
/** /**
* @return class file object for given Java class by looking on the system class path; returns null if the class file * @return class file object for given Java class by looking on the system class path; returns null if the class file
* can't be found * can't be found
*/ */
public static ClassPath.ClassFile lookupClassFile(final String className) { public static ClassPath.ClassFile lookupClassFile(final String className) {
try (ClassPath path = repository.getClassPath()) { try (ClassPath path = repository.getClassPath()) {
@@ -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

@@ -33,9 +33,9 @@ public class AnnotationDefault extends Attribute {
private ElementValue defaultValue; private ElementValue defaultValue;
/** /**
* @param nameIndex Index pointing to the name <em>Code</em> * @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
@@ -44,8 +44,8 @@ public class AnnotationDefault extends Attribute {
} }
/** /**
* @param nameIndex Index pointing to the name <em>Code</em> * @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes * @param length Content length in bytes
* @param defaultValue the annotation's default value * @param defaultValue the annotation's default value
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */

View File

@@ -31,11 +31,21 @@ 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
return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
.toArray(AnnotationEntry[]::new); .toArray(AnnotationEntry[]::new);
} }
/** /**
@@ -53,25 +63,11 @@ public class AnnotationEntry implements Node {
annotationEntry.elementValuePairs = new ArrayList<>(); annotationEntry.elementValuePairs = new ArrayList<>();
for (int i = 0; i < numElementValuePairs; i++) { for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs annotationEntry.elementValuePairs
.add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool)); .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
} }
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.
@@ -45,7 +45,7 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
* @param isRuntimeVisible whether this Annotation visible at runtime * @param isRuntimeVisible whether this Annotation visible at runtime
*/ */
public Annotations(final byte annotationType, final int nameIndex, final int length, final AnnotationEntry[] annotationTable, public Annotations(final byte annotationType, final int nameIndex, final int length, final AnnotationEntry[] annotationTable,
final ConstantPool constantPool, final boolean isRuntimeVisible) { final ConstantPool constantPool, final boolean isRuntimeVisible) {
super(annotationType, nameIndex, length, constantPool); super(annotationType, nameIndex, length, constantPool);
this.annotationTable = annotationTable; this.annotationTable = annotationTable;
this.isRuntimeVisible = isRuntimeVisible; this.isRuntimeVisible = isRuntimeVisible;
@@ -63,7 +63,7 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
Annotations(final byte annotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool, Annotations(final byte annotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool,
final boolean isRuntimeVisible) throws IOException { final boolean isRuntimeVisible) throws IOException {
this(annotationType, nameIndex, length, (AnnotationEntry[]) null, constantPool, isRuntimeVisible); this(annotationType, nameIndex, length, (AnnotationEntry[]) null, constantPool, isRuntimeVisible);
final int annotationTableLength = input.readUnsignedShort(); final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength]; annotationTable = new AnnotationEntry[annotationTableLength];

View File

@@ -53,22 +53,63 @@ 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
* standard attributes such as "LineNumberTable", because those are handled internally. * standard attributes such as "LineNumberTable", because those are handled internally.
* *
* @param name the name of the attribute as stored in the class file * @param name the name of the attribute as stored in the class file
* @param unknownAttributeReader the reader object * @param unknownAttributeReader the reader object
*/ */
public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) { public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
@@ -85,13 +126,12 @@ public abstract class Attribute implements Cloneable, Node {
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It * 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 * @param dataInput Input stream
* @see JavaMethod
*
* @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 {
@@ -113,74 +153,74 @@ public abstract class Attribute implements Cloneable, Node {
// Call proper constructor, depending on 'tag' // Call proper constructor, depending on 'tag'
switch (tag) { switch (tag) {
case Const.ATTR_UNKNOWN: case Const.ATTR_UNKNOWN:
final Object r = READERS.get(name); final Object r = READERS.get(name);
if (r instanceof UnknownAttributeReader) { if (r instanceof UnknownAttributeReader) {
return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool); return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
} }
return new Unknown(nameIndex, length, dataInput, constantPool); return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CONSTANT_VALUE: case Const.ATTR_CONSTANT_VALUE:
return new ConstantValue(nameIndex, length, dataInput, constantPool); return new ConstantValue(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SOURCE_FILE: case Const.ATTR_SOURCE_FILE:
return new SourceFile(nameIndex, length, dataInput, constantPool); return new SourceFile(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CODE: case Const.ATTR_CODE:
return new Code(nameIndex, length, dataInput, constantPool); return new Code(nameIndex, length, dataInput, constantPool);
case Const.ATTR_EXCEPTIONS: case Const.ATTR_EXCEPTIONS:
return new ExceptionTable(nameIndex, length, dataInput, constantPool); return new ExceptionTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LINE_NUMBER_TABLE: case Const.ATTR_LINE_NUMBER_TABLE:
return new LineNumberTable(nameIndex, length, dataInput, constantPool); return new LineNumberTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TABLE: case Const.ATTR_LOCAL_VARIABLE_TABLE:
return new LocalVariableTable(nameIndex, length, dataInput, constantPool); return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_INNER_CLASSES: case Const.ATTR_INNER_CLASSES:
return new InnerClasses(nameIndex, length, dataInput, constantPool); return new InnerClasses(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SYNTHETIC: case Const.ATTR_SYNTHETIC:
return new Synthetic(nameIndex, length, dataInput, constantPool); return new Synthetic(nameIndex, length, dataInput, constantPool);
case Const.ATTR_DEPRECATED: case Const.ATTR_DEPRECATED:
return new Deprecated(nameIndex, length, dataInput, constantPool); return new Deprecated(nameIndex, length, dataInput, constantPool);
case Const.ATTR_PMG: case Const.ATTR_PMG:
return new PMGClass(nameIndex, length, dataInput, constantPool); return new PMGClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SIGNATURE: case Const.ATTR_SIGNATURE:
return new Signature(nameIndex, length, dataInput, constantPool); return new Signature(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP: case Const.ATTR_STACK_MAP:
// old style stack map: unneeded for JDK5 and below; // old style stack map: unneeded for JDK5 and below;
// illegal(?) for JDK6 and above. So just delete with a warning. // illegal(?) for JDK6 and above. So just delete with a warning.
println("Warning: Obsolete StackMap attribute ignored."); println("Warning: Obsolete StackMap attribute ignored.");
return new Unknown(nameIndex, length, dataInput, constantPool); return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool); return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool); return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ANNOTATION_DEFAULT: case Const.ATTR_ANNOTATION_DEFAULT:
return new AnnotationDefault(nameIndex, length, dataInput, constantPool); return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE: case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool); return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ENCLOSING_METHOD: case Const.ATTR_ENCLOSING_METHOD:
return new EnclosingMethod(nameIndex, length, dataInput, constantPool); return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP_TABLE: case Const.ATTR_STACK_MAP_TABLE:
// read new style stack map: StackMapTable. The rest of the code // read new style stack map: StackMapTable. The rest of the code
// calls this a StackMap for historical reasons. // calls this a StackMap for historical reasons.
return new StackMap(nameIndex, length, dataInput, constantPool); return new StackMap(nameIndex, length, dataInput, constantPool);
case Const.ATTR_BOOTSTRAP_METHODS: case Const.ATTR_BOOTSTRAP_METHODS:
return new BootstrapMethods(nameIndex, length, dataInput, constantPool); return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
case Const.ATTR_METHOD_PARAMETERS: case Const.ATTR_METHOD_PARAMETERS:
return new MethodParameters(nameIndex, length, dataInput, constantPool); return new MethodParameters(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE: case Const.ATTR_MODULE:
return new Module(nameIndex, length, dataInput, constantPool); return new Module(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_PACKAGES: case Const.ATTR_MODULE_PACKAGES:
return new ModulePackages(nameIndex, length, dataInput, constantPool); return new ModulePackages(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_MAIN_CLASS: case Const.ATTR_MODULE_MAIN_CLASS:
return new ModuleMainClass(nameIndex, length, dataInput, constantPool); return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_HOST: case Const.ATTR_NEST_HOST:
return new NestHost(nameIndex, length, dataInput, constantPool); return new NestHost(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_MEMBERS: case Const.ATTR_NEST_MEMBERS:
return new NestMembers(nameIndex, length, dataInput, constantPool); return new NestMembers(nameIndex, length, dataInput, constantPool);
default: default:
// Never reached // Never reached
throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
} }
} }
@@ -188,13 +228,12 @@ public abstract class Attribute implements Cloneable, Node {
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It * 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

@@ -29,15 +29,19 @@ import java.util.Arrays;
* and an array of the bootstrap arguments. * and an array of the bootstrap arguments.
* *
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
* The BootstrapMethods Attribute</a> * The BootstrapMethods Attribute</a>
* @since 6.0 * @since 6.0
*/ */
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

@@ -29,7 +29,7 @@ import java.util.stream.Stream;
* This class represents a BootstrapMethods attribute. * This class represents a BootstrapMethods attribute.
* *
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
* The BootstrapMethods Attribute</a> * The BootstrapMethods Attribute</a>
* @since 6.0 * @since 6.0
*/ */
public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> { public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
@@ -47,10 +47,10 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
} }
/** /**
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param bootstrapMethods array of bootstrap methods * @param bootstrapMethods array of bootstrap methods
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) { public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool); super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
@@ -60,9 +60,9 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
/** /**
* Construct object from Input stream. * Construct object from Input stream.
* *
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -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,13 +49,12 @@ 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.
* *
* @param inputStream Input stream * @param inputStream Input stream
* @param fileName File name * @param fileName File name
*/ */
public ClassParser(final InputStream inputStream, final String fileName) { public ClassParser(final InputStream inputStream, final String fileName) {
this.fileName = fileName; this.fileName = fileName;
@@ -82,7 +82,7 @@ public final class ClassParser {
/** /**
* Parses class from given .class file in a ZIP-archive * Parses class from given .class file in a ZIP-archive
* *
* @param zipFile zip file name * @param zipFile zip file name
* @param fileName file name * @param fileName file name
*/ */
public ClassParser(final String zipFile, final String fileName) { public ClassParser(final String zipFile, final String fileName) {
@@ -98,7 +98,7 @@ public final class ClassParser {
* not include verification of the byte code as it is performed by the java interpreter). * not include verification of the byte code as it is performed by the java interpreter).
* *
* @return Class object representing the parsed class file * @return Class object representing the parsed class file
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
public JavaClass parse() throws IOException, ClassFormatException { public JavaClass parse() throws IOException, ClassFormatException {
@@ -172,13 +172,13 @@ public final class ClassParser {
} }
// Return the information we have gathered in a new object // Return the information we have gathered in a new object
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes, return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes,
isZip ? JavaClass.ZIP : JavaClass.FILE); isZip ? JavaClass.ZIP : JavaClass.FILE);
} }
/** /**
* Reads information about the attributes of the class. * Reads information about the attributes of the class.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readAttributes() throws IOException, ClassFormatException { private void readAttributes() throws IOException, ClassFormatException {
@@ -192,7 +192,7 @@ public final class ClassParser {
/** /**
* Reads information about the class and its super class. * Reads information about the class and its super class.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readClassInfo() throws IOException, ClassFormatException { private void readClassInfo() throws IOException, ClassFormatException {
@@ -213,7 +213,7 @@ public final class ClassParser {
/** /**
* Reads constant pool entries. * Reads constant pool entries.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readConstantPool() throws IOException, ClassFormatException { private void readConstantPool() throws IOException, ClassFormatException {
@@ -223,7 +223,7 @@ public final class ClassParser {
/** /**
* Reads information about the fields of the class, i.e., its variables. * Reads information about the fields of the class, i.e., its variables.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readFields() throws IOException, ClassFormatException { private void readFields() throws IOException, ClassFormatException {
@@ -238,7 +238,7 @@ public final class ClassParser {
/** /**
* Checks whether the header of the file is ok. Of course, this has to be the first action on successive file reads. * Checks whether the header of the file is ok. Of course, this has to be the first action on successive file reads.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readID() throws IOException, ClassFormatException { private void readID() throws IOException, ClassFormatException {
@@ -250,7 +250,7 @@ public final class ClassParser {
/** /**
* Reads information about the interfaces implemented by this class. * Reads information about the interfaces implemented by this class.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readInterfaces() throws IOException, ClassFormatException { private void readInterfaces() throws IOException, ClassFormatException {
@@ -264,7 +264,7 @@ public final class ClassParser {
/** /**
* Reads information about the methods of the class. * Reads information about the methods of the class.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readMethods() throws IOException { private void readMethods() throws IOException {
@@ -278,7 +278,7 @@ public final class ClassParser {
/** /**
* Reads major and minor version of compiler which created the file. * Reads major and minor version of compiler which created the file.
* *
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
private void readVersion() throws IOException, ClassFormatException { private void readVersion() throws IOException, ClassFormatException {

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
@@ -77,9 +78,9 @@ public final class Code extends Attribute {
} }
/** /**
* @param nameIndex Index pointing to the name <em>Code</em> * @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes * @param length Content length in bytes
* @param file Input stream * @param file Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException { Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
@@ -113,17 +114,17 @@ public final class Code extends Attribute {
} }
/** /**
* @param nameIndex Index pointing to the name <em>Code</em> * @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes * @param length Content length in bytes
* @param maxStack Maximum size of stack * @param maxStack Maximum size of stack
* @param maxLocals Number of local variables * @param maxLocals Number of local variables
* @param code Actual byte code * @param code Actual byte code
* @param exceptionTable of handled exceptions * @param exceptionTable of handled exceptions
* @param attributes Attributes of code: LineNumber or LocalVariable * @param attributes Attributes of code: LineNumber or LocalVariable
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable, public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
final Attribute[] attributes, final ConstantPool constantPool) { final Attribute[] attributes, final ConstantPool constantPool) {
super(Const.ATTR_CODE, nameIndex, length, constantPool); super(Const.ATTR_CODE, nameIndex, length, constantPool);
this.maxStack = Args.requireU2(maxStack, "maxStack"); this.maxStack = Args.requireU2(maxStack, "maxStack");
this.maxLocals = Args.requireU2(maxLocals, "maxLocals"); this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
@@ -147,7 +148,7 @@ public final class Code extends Attribute {
/** /**
* @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained * @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained
* attributes * attributes
*/ */
private int calculateLength() { private int calculateLength() {
int len = 0; int len = 0;
@@ -160,9 +161,8 @@ public final class Code extends Attribute {
} }
/** /**
* @return deep copy of this attribute
*
* @param constantPool the constant pool to duplicate * @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,15 +240,23 @@ 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
*/ */
private int getInternalLength() { private int getInternalLength() {
return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */ return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */
+ code.length /* byte-code */ + code.length /* byte-code */
+ 2 /* exception-table length */ + 2 /* exception-table length */
+ 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */ + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
+ 2 /* attributes count */; + 2 /* attributes count */;
} }
/** /**
@@ -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
*/ */
@@ -328,7 +328,7 @@ public final class Code extends Attribute {
public String toString(final boolean verbose) { public String toString(final boolean verbose) {
final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber
buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n") buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n")
.append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose)); .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
if (exceptionTable.length > 0) { if (exceptionTable.length > 0) {
buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n"); buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
for (final CodeException exception : exceptionTable) { for (final CodeException exception : exceptionTable) {

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,64 +62,6 @@ public abstract class Constant implements Cloneable, Node {
return bcelComparator; return bcelComparator;
} }
/**
* Reads one constant from the given input, the type depends on a tag byte.
*
* @param dataInput Input stream
* @return Constant object
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
* @throws ClassFormatException if the next byte is not recognized
* @since 6.0 made public
*/
public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
final byte b = dataInput.readByte(); // Read tag byte
switch (b) {
case Const.CONSTANT_Class:
return new ConstantClass(dataInput);
case Const.CONSTANT_Fieldref:
return new ConstantFieldref(dataInput);
case Const.CONSTANT_Methodref:
return new ConstantMethodref(dataInput);
case Const.CONSTANT_InterfaceMethodref:
return new ConstantInterfaceMethodref(dataInput);
case Const.CONSTANT_String:
return new ConstantString(dataInput);
case Const.CONSTANT_Integer:
return new ConstantInteger(dataInput);
case Const.CONSTANT_Float:
return new ConstantFloat(dataInput);
case Const.CONSTANT_Long:
return new ConstantLong(dataInput);
case Const.CONSTANT_Double:
return new ConstantDouble(dataInput);
case Const.CONSTANT_NameAndType:
return new ConstantNameAndType(dataInput);
case Const.CONSTANT_Utf8:
return ConstantUtf8.getInstance(dataInput);
case Const.CONSTANT_MethodHandle:
return new ConstantMethodHandle(dataInput);
case Const.CONSTANT_MethodType:
return new ConstantMethodType(dataInput);
case Const.CONSTANT_Dynamic:
return new ConstantDynamic(dataInput);
case Const.CONSTANT_InvokeDynamic:
return new ConstantInvokeDynamic(dataInput);
case Const.CONSTANT_Module:
return new ConstantModule(dataInput);
case Const.CONSTANT_Package:
return new ConstantPackage(dataInput);
default:
throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
}
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/* /*
* In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via * 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. * 'instanceof'. In some places we will use the tag for switch()es anyway.
@@ -118,14 +69,63 @@ public abstract class Constant implements Cloneable, Node {
* First, we want match the specification as closely as possible. Second we need the tag as an index to select the * 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. * corresponding class name from the 'CONSTANT_NAMES' array.
*/ */
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected byte tag; // TODO should be private & final
Constant(final byte tag) { /**
this.tag = tag; * @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/**
* Reads one constant from the given input, the type depends on a tag byte.
*
* @param dataInput Input stream
* @return Constant object
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
* @throws ClassFormatException if the next byte is not recognized
* @since 6.0 made public
*/
public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
final byte b = dataInput.readByte(); // Read tag byte
switch (b) {
case Const.CONSTANT_Class:
return new ConstantClass(dataInput);
case Const.CONSTANT_Fieldref:
return new ConstantFieldref(dataInput);
case Const.CONSTANT_Methodref:
return new ConstantMethodref(dataInput);
case Const.CONSTANT_InterfaceMethodref:
return new ConstantInterfaceMethodref(dataInput);
case Const.CONSTANT_String:
return new ConstantString(dataInput);
case Const.CONSTANT_Integer:
return new ConstantInteger(dataInput);
case Const.CONSTANT_Float:
return new ConstantFloat(dataInput);
case Const.CONSTANT_Long:
return new ConstantLong(dataInput);
case Const.CONSTANT_Double:
return new ConstantDouble(dataInput);
case Const.CONSTANT_NameAndType:
return new ConstantNameAndType(dataInput);
case Const.CONSTANT_Utf8:
return ConstantUtf8.getInstance(dataInput);
case Const.CONSTANT_MethodHandle:
return new ConstantMethodHandle(dataInput);
case Const.CONSTANT_MethodType:
return new ConstantMethodType(dataInput);
case Const.CONSTANT_Dynamic:
return new ConstantDynamic(dataInput);
case Const.CONSTANT_InvokeDynamic:
return new ConstantInvokeDynamic(dataInput);
case Const.CONSTANT_Module:
return new ConstantModule(dataInput);
case Const.CONSTANT_Package:
return new ConstantPackage(dataInput);
default:
throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
}
} }
/** /**

View File

@@ -53,7 +53,7 @@ public abstract class ConstantCP extends Constant {
/** /**
* Initialize instance from file data. * Initialize instance from file data.
* *
* @param tag Constant type tag * @param tag Constant type tag
* @param file Input stream * @param file Input stream
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -62,7 +62,7 @@ public abstract class ConstantCP extends Constant {
} }
/** /**
* @param classIndex Reference to the class containing the field * @param classIndex Reference to the class containing the field
* @param nameAndTypeIndex and the field signature * @param nameAndTypeIndex and the field signature
*/ */
protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) { protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) {
@@ -107,13 +107,6 @@ public abstract class ConstantCP extends Constant {
return class_index; return 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,8 +130,8 @@ 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
public String toString() { public String toString() {

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

@@ -27,7 +27,7 @@ import java.io.IOException;
* *
* @see Constant * @see Constant
* @see <a href="https://bugs.openjdk.java.net/secure/attachment/74618/constant-dynamic.html"> Change request for JEP * @see <a href="https://bugs.openjdk.java.net/secure/attachment/74618/constant-dynamic.html"> Change request for JEP
* 309</a> * 309</a>
* @since 6.3 * @since 6.3
*/ */
public final class ConstantDynamic extends ConstantCP { public final class ConstantDynamic extends ConstantCP {
@@ -68,8 +68,8 @@ public final class ConstantDynamic extends ConstantCP {
/** /**
* @return Reference (index) to bootstrap method this constant refers to. * @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
*/ */
public int getBootstrapMethodAttrIndex() { public int getBootstrapMethodAttrIndex() {

View File

@@ -46,7 +46,7 @@ public final class ConstantFieldref extends ConstantCP {
} }
/** /**
* @param classIndex Reference to the class containing the Field * @param classIndex Reference to the class containing the Field
* @param nameAndTypeIndex and the Field signature * @param nameAndTypeIndex and the Field signature
*/ */
public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) { public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) {

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

@@ -46,7 +46,7 @@ public final class ConstantInterfaceMethodref extends ConstantCP {
} }
/** /**
* @param classIndex Reference to the class containing the method * @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature * @param nameAndTypeIndex and the method signature
*/ */
public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) { public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) {

View File

@@ -26,7 +26,7 @@ import java.io.IOException;
* *
* @see Constant * @see Constant
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.10"> The * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.10"> The
* CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification</a> * CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification</a>
* @since 6.0 * @since 6.0
*/ */
public final class ConstantInvokeDynamic extends ConstantCP { public final class ConstantInvokeDynamic extends ConstantCP {
@@ -67,8 +67,8 @@ public final class ConstantInvokeDynamic extends ConstantCP {
/** /**
* @return Reference (index) to bootstrap method this constant refers to. * @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
*/ */
public int getBootstrapMethodAttrIndex() { public int getBootstrapMethodAttrIndex() {

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

@@ -46,7 +46,7 @@ public final class ConstantMethodref extends ConstantCP {
} }
/** /**
* @param classIndex Reference to the class containing the method * @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature * @param nameAndTypeIndex and the method signature
*/ */
public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) { public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) {

View File

@@ -53,7 +53,7 @@ public final class ConstantNameAndType extends Constant {
} }
/** /**
* @param nameIndex Name of field/method * @param nameIndex Name of field/method
* @param signatureIndex and its signature * @param signatureIndex and its signature
*/ */
public ConstantNameAndType(final int nameIndex, final int signatureIndex) { public ConstantNameAndType(final int nameIndex, final int signatureIndex) {
@@ -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
*/ */

File diff suppressed because it is too large Load Diff

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.
* *
@@ -175,39 +181,7 @@ public final class ConstantUtf8 extends Constant {
System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped); System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped);
System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created); System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created);
System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE, System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE,
Cache.MAX_ENTRY_SIZE); 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++;
} }
/** /**
@@ -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 {
@@ -53,9 +54,9 @@ public final class ConstantValue extends Attribute {
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Name index in constant pool * @param nameIndex Name index in constant pool
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -64,10 +65,10 @@ public final class ConstantValue extends Attribute {
} }
/** /**
* @param nameIndex Name index in constant pool * @param nameIndex Name index in constant pool
* @param length Content length in bytes * @param length Content length in bytes
* @param constantValueIndex Index in constant pool * @param constantValueIndex Index in constant pool
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) { public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) {
super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool); super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool);
@@ -131,25 +132,25 @@ public final class ConstantValue extends Attribute {
int i; int i;
// Print constant to string depending on its type // Print constant to string depending on its type
switch (c.getTag()) { switch (c.getTag()) {
case Const.CONSTANT_Long: case Const.CONSTANT_Long:
buf = String.valueOf(((ConstantLong) c).getBytes()); buf = String.valueOf(((ConstantLong) c).getBytes());
break; break;
case Const.CONSTANT_Float: case Const.CONSTANT_Float:
buf = String.valueOf(((ConstantFloat) c).getBytes()); buf = String.valueOf(((ConstantFloat) c).getBytes());
break; break;
case Const.CONSTANT_Double: case Const.CONSTANT_Double:
buf = String.valueOf(((ConstantDouble) c).getBytes()); buf = String.valueOf(((ConstantDouble) c).getBytes());
break; break;
case Const.CONSTANT_Integer: case Const.CONSTANT_Integer:
buf = String.valueOf(((ConstantInteger) c).getBytes()); buf = String.valueOf(((ConstantInteger) c).getBytes());
break; break;
case Const.CONSTANT_String: case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex(); i = ((ConstantString) c).getStringIndex();
c = super.getConstantPool().getConstantUtf8(i); c = super.getConstantPool().getConstantUtf8(i);
buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\""; buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
break; break;
default: default:
throw new IllegalStateException("Type of ConstValue invalid: " + c); throw new IllegalStateException("Type of ConstValue invalid: " + c);
} }
return buf; return buf;
} }

View File

@@ -44,9 +44,9 @@ public final class Deprecated extends Attribute {
} }
/** /**
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param bytes Attribute contents * @param bytes Attribute contents
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -57,9 +57,9 @@ public final class Deprecated extends Attribute {
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */

View File

@@ -32,7 +32,7 @@ public class DescendingVisitor implements Visitor {
private final Stack<Object> stack = new Stack<>(); private final Stack<Object> stack = new Stack<>();
/** /**
* @param clazz Class to traverse * @param clazz Class to traverse
* @param visitor visitor object to apply to all components * @param visitor visitor object to apply to all components
*/ */
public DescendingVisitor(final JavaClass clazz, final Visitor visitor) { public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
@@ -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,72 +64,6 @@ 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';
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
return readElementValue(input, cpool, 0);
}
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @param arrayNesting level of current array nesting.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
* @since 6.7.0
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
throws IOException {
final byte tag = input.readByte();
switch (tag) {
case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR:
case PRIMITIVE_DOUBLE:
case PRIMITIVE_FLOAT:
case PRIMITIVE_INT:
case PRIMITIVE_LONG:
case PRIMITIVE_SHORT:
case PRIMITIVE_BOOLEAN:
case STRING:
return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
case ENUM_CONSTANT:
return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
case CLASS:
return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
case ANNOTATION:
// TODO isRuntimeVisible
return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
case ARRAY:
arrayNesting++;
if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
// JVM spec 4.4.1
throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
}
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
}
return new ArrayElementValue(ARRAY, evalues, cpool);
default:
throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
}
}
/** /**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/ */
@@ -145,9 +80,76 @@ public abstract class ElementValue {
this.cpool = cpool; this.cpool = cpool;
} }
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
return readElementValue(input, cpool, 0);
}
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @param arrayNesting level of current array nesting.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
* @since 6.7.0
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
throws IOException {
final byte tag = input.readByte();
switch (tag) {
case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR:
case PRIMITIVE_DOUBLE:
case PRIMITIVE_FLOAT:
case PRIMITIVE_INT:
case PRIMITIVE_LONG:
case PRIMITIVE_SHORT:
case PRIMITIVE_BOOLEAN:
case STRING:
return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
case ENUM_CONSTANT:
return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
case CLASS:
return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
case ANNOTATION:
// TODO isRuntimeVisible
return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
case ARRAY:
arrayNesting++;
if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
// JVM spec 4.4.1
throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
}
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
}
return new ArrayElementValue(ARRAY, evalues, cpool);
default:
throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
}
}
public abstract void dump(DataOutputStream dos) throws IOException; 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

@@ -1,18 +1,18 @@
/** /**
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* 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.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package haidnor.jvm.bcel.classfile; package haidnor.jvm.bcel.classfile;
@@ -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 {
@@ -59,9 +60,9 @@ public final class ExceptionTable extends Attribute {
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Index in constant pool * @param nameIndex Index in constant pool
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -75,10 +76,10 @@ public final class ExceptionTable extends Attribute {
} }
/** /**
* @param nameIndex Index in constant pool * @param nameIndex Index in constant pool
* @param length Content length in bytes * @param length Content length in bytes
* @param exceptionIndexTable Table of indices in constant pool * @param exceptionIndexTable Table of indices in constant pool
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
@@ -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;
@@ -105,14 +102,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
} }
/** /**
* @param accessFlags Access rights of method * @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature * @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes * @param attributes Collection of attributes
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
final ConstantPool constantPool) { final ConstantPool constantPool) {
super(accessFlags); super(accessFlags);
this.name_index = nameIndex; this.name_index = nameIndex;
this.signature_index = signatureIndex; this.signature_index = signatureIndex;
@@ -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

@@ -55,9 +55,9 @@ public final class InnerClass implements Cloneable, Node {
} }
/** /**
* @param innerClassIndex Class index in constant pool of inner class * @param innerClassIndex Class index in constant pool of inner class
* @param outerClassIndex Class index in constant pool of outer class * @param outerClassIndex Class index in constant pool of outer class
* @param innerNameIndex Name index in constant pool of inner class * @param innerNameIndex Name index in constant pool of inner class
* @param innerAccessFlags Access flags of inner class * @param innerAccessFlags Access flags of inner class
*/ */
public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) { public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) {
@@ -110,27 +110,6 @@ public final class InnerClass implements Cloneable, Node {
return innerAccessFlags; return 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

@@ -54,9 +54,9 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -70,8 +70,8 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
} }
/** /**
* @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes * @param length Content length in bytes
* @param innerClasses array of inner classes attributes * @param innerClasses array of inner classes attributes
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
@@ -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.
*/ */

File diff suppressed because it is too large Load Diff

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.
@@ -92,16 +84,30 @@ public final class JavaField extends FieldOrMethod {
} }
/** /**
* @param accessFlags Access rights of field * @param accessFlags Access rights of field
* @param nameIndex Points to field name in constant pool * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature * @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes * @param attributes Collection of attributes
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public JavaField(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { public JavaField(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
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;
@@ -84,7 +67,7 @@ public final class JavaMethod extends FieldOrMethod {
* Construct object from file stream. * Construct object from file stream.
* *
* @param file Input stream * @param file Input stream
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
JavaMethod(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { JavaMethod(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
@@ -92,11 +75,11 @@ public final class JavaMethod extends FieldOrMethod {
} }
/** /**
* @param accessFlags Access rights of method * @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature * @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes * @param attributes Collection of attributes
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public JavaMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { public JavaMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
@@ -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.
@@ -162,7 +159,7 @@ public final class JavaMethod extends FieldOrMethod {
/** /**
* @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception * @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
* handlers! * handlers!
*/ */
public ExceptionTable getExceptionTable() { public ExceptionTable getExceptionTable() {
for (final Attribute attribute : super.getAttributes()) { for (final Attribute attribute : super.getAttributes()) {

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;
/** /**
@@ -49,7 +53,7 @@ public final class LineNumber implements Cloneable, Node {
} }
/** /**
* @param startPc Program Counter (PC) corresponds to * @param startPc Program Counter (PC) corresponds to
* @param lineNumber line number in source file * @param lineNumber line number in source file
*/ */
public LineNumber(final int startPc, final int lineNumber) { public LineNumber(final int startPc, final 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

@@ -41,9 +41,9 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Index of name * @param nameIndex Index of name
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O Exception occurs in readUnsignedShort * @throws IOException if an I/O Exception occurs in readUnsignedShort
*/ */
@@ -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

@@ -40,9 +40,9 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
/** /**
* Construct object from input stream. * Construct object from input stream.
* *
* @param nameIndex Index in constant pool * @param nameIndex Index in constant pool
* @param length Content length in bytes * @param length Content length in bytes
* @param input Input stream * @param input Input stream
* @param constantPool Array of constants * @param constantPool Array of constants
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
@@ -56,10 +56,10 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
} }
/** /**
* @param nameIndex Index in constant pool to 'LocalVariableTable' * @param nameIndex Index in constant pool to 'LocalVariableTable'
* @param length Content length in bytes * @param length Content length in bytes
* @param localVariableTable Table of local variables * @param localVariableTable Table of local variables
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) { public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool); super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool);
@@ -116,13 +116,10 @@ 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.
*/ */
@java.lang.Deprecated @java.lang.Deprecated
public final LocalVariable getLocalVariable(final int index) { public final LocalVariable getLocalVariable(final int index) {
@@ -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

@@ -1,18 +1,18 @@
/** /**
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* 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.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package haidnor.jvm.bcel.classfile; package haidnor.jvm.bcel.classfile;

View File

@@ -27,15 +27,19 @@ import java.io.IOException;
* Entry of the parameters table. * Entry of the parameters table.
* *
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format : * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format :
* The MethodParameters Attribute</a> * The MethodParameters Attribute</a>
* @since 6.0 * @since 6.0
*/ */
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() {
@@ -45,7 +49,7 @@ public class MethodParameter implements Cloneable, Node {
* Construct object from input stream. * Construct object from input stream.
* *
* @param input Input stream * @param input Input stream
* @throws IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file * @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/ */
MethodParameter(final DataInput input) throws IOException { MethodParameter(final DataInput input) throws IOException {
@@ -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

@@ -30,7 +30,7 @@ import java.util.stream.Stream;
* This class represents a MethodParameters attribute. * This class represents a MethodParameters attribute.
* *
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format : * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format :
* The MethodParameters Attribute</a> * The MethodParameters Attribute</a>
* @since 6.0 * @since 6.0
*/ */
public class MethodParameters extends Attribute implements Iterable<MethodParameter> { public class MethodParameters extends Attribute implements Iterable<MethodParameter> {
@@ -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;
}
} }

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