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
*/ */

View File

@@ -35,34 +35,6 @@ import java.util.Iterator;
*/ */
public class ConstantPool implements Cloneable, Node, Iterable<Constant> { public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
private static String escape(final String str) {
final int len = str.length();
final StringBuilder buf = new StringBuilder(len + 5);
final char[] ch = str.toCharArray();
for (int i = 0; i < len; i++) {
switch (ch[i]) {
case '\n':
buf.append("\\n");
break;
case '\r':
buf.append("\\r");
break;
case '\t':
buf.append("\\t");
break;
case '\b':
buf.append("\\b");
break;
case '"':
buf.append("\\\"");
break;
default:
buf.append(ch[i]);
}
}
return buf.toString();
}
private Constant[] constantPool; private Constant[] constantPool;
/** /**
@@ -100,6 +72,34 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
} }
} }
private static String escape(final String str) {
final int len = str.length();
final StringBuilder buf = new StringBuilder(len + 5);
final char[] ch = str.toCharArray();
for (int i = 0; i < len; i++) {
switch (ch[i]) {
case '\n':
buf.append("\\n");
break;
case '\r':
buf.append("\\r");
break;
case '\t':
buf.append("\\t");
break;
case '\b':
buf.append("\\b");
break;
case '"':
buf.append("\\\"");
break;
default:
buf.append(ch[i]);
}
}
return buf.toString();
}
/** /**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e., the hierarchy of methods, fields, * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e., the hierarchy of methods, fields,
* attributes, etc. spawns a tree of objects. * attributes, etc. spawns a tree of objects.
@@ -123,72 +123,72 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
int i; int i;
final byte tag = c.getTag(); final byte tag = c.getTag();
switch (tag) { switch (tag) {
case Const.CONSTANT_Class: case Const.CONSTANT_Class:
i = ((ConstantClass) c).getNameIndex(); i = ((ConstantClass) c).getNameIndex();
c = getConstantUtf8(i); c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break; break;
case Const.CONSTANT_String: case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex(); i = ((ConstantString) c).getStringIndex();
c = getConstantUtf8(i); c = getConstantUtf8(i);
str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
break; break;
case Const.CONSTANT_Utf8: case Const.CONSTANT_Utf8:
str = ((ConstantUtf8) c).getBytes(); str = ((ConstantUtf8) c).getBytes();
break; break;
case Const.CONSTANT_Double: case Const.CONSTANT_Double:
str = String.valueOf(((ConstantDouble) c).getBytes()); str = String.valueOf(((ConstantDouble) c).getBytes());
break; break;
case Const.CONSTANT_Float: case Const.CONSTANT_Float:
str = String.valueOf(((ConstantFloat) c).getBytes()); str = String.valueOf(((ConstantFloat) c).getBytes());
break; break;
case Const.CONSTANT_Long: case Const.CONSTANT_Long:
str = String.valueOf(((ConstantLong) c).getBytes()); str = String.valueOf(((ConstantLong) c).getBytes());
break; break;
case Const.CONSTANT_Integer: case Const.CONSTANT_Integer:
str = String.valueOf(((ConstantInteger) c).getBytes()); str = String.valueOf(((ConstantInteger) c).getBytes());
break; break;
case Const.CONSTANT_NameAndType: case Const.CONSTANT_NameAndType:
str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " " str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
+ constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8); + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
break; break;
case Const.CONSTANT_InterfaceMethodref: case Const.CONSTANT_InterfaceMethodref:
case Const.CONSTANT_Methodref: case Const.CONSTANT_Methodref:
case Const.CONSTANT_Fieldref: case Const.CONSTANT_Fieldref:
str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "." str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
+ constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType); + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break; break;
case Const.CONSTANT_MethodHandle: case Const.CONSTANT_MethodHandle:
// Note that the ReferenceIndex may point to a Fieldref, Methodref or // Note that the ReferenceIndex may point to a Fieldref, Methodref or
// InterfaceMethodref - so we need to peek ahead to get the actual type. // InterfaceMethodref - so we need to peek ahead to get the actual type.
final ConstantMethodHandle cmh = (ConstantMethodHandle) c; final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
str = Const.getMethodHandleName(cmh.getReferenceKind()) + " " str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
+ constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag()); + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
break; break;
case Const.CONSTANT_MethodType: case Const.CONSTANT_MethodType:
final ConstantMethodType cmt = (ConstantMethodType) c; final ConstantMethodType cmt = (ConstantMethodType) c;
str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8); str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
break; break;
case Const.CONSTANT_InvokeDynamic: case Const.CONSTANT_InvokeDynamic:
final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c; final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break; break;
case Const.CONSTANT_Dynamic: case Const.CONSTANT_Dynamic:
final ConstantDynamic cd = (ConstantDynamic) c; final ConstantDynamic cd = (ConstantDynamic) c;
str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType); str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break; break;
case Const.CONSTANT_Module: case Const.CONSTANT_Module:
i = ((ConstantModule) c).getNameIndex(); i = ((ConstantModule) c).getNameIndex();
c = getConstantUtf8(i); c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break; break;
case Const.CONSTANT_Package: case Const.CONSTANT_Package:
i = ((ConstantPackage) c).getNameIndex(); i = ((ConstantPackage) c).getNameIndex();
c = getConstantUtf8(i); c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break; break;
default: // Never reached default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + tag); throw new IllegalArgumentException("Unknown constant type " + tag);
} }
return str; return str;
} }
@@ -249,8 +249,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid * @throws ClassFormatException if index is invalid
* @see Constant
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index) throws ClassFormatException { public <T extends Constant> T getConstant(final int index) throws ClassFormatException {
@@ -263,8 +263,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type * @param tag Tag of expected constant, i.e., its type
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see Constant
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException {
@@ -277,8 +277,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type * @param tag Tag of expected constant, i.e., its type
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see Constant
* @since 6.6.0 * @since 6.6.0
*/ */
public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException {
@@ -292,12 +292,12 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
/** /**
* Gets constant from constant pool. * Gets constant from constant pool.
* *
* @param <T> A {@link Constant} subclass * @param <T> A {@link Constant} subclass
* @param index Index in constant pool * @param index Index in constant pool
* @param castTo The {@link Constant} subclass to cast to. * @param castTo The {@link Constant} subclass to cast to.
* @return Constant value * @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid * @throws ClassFormatException if index is invalid
* @see Constant
* @since 6.6.0 * @since 6.6.0
*/ */
public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException { public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException {
@@ -311,8 +311,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
// Previous check ensures this won't throw a ClassCastException // Previous check ensures this won't throw a ClassCastException
final T c = castTo.cast(constantPool[index]); final T c = castTo.cast(constantPool[index]);
if (c == null if (c == null
// the 0th element is always null // the 0th element is always null
&& index != 0) { && index != 0) {
final Constant prev = constantPool[index - 1]; final Constant prev = constantPool[index - 1];
if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) { if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) {
throw new ClassFormatException("Constant pool at index " + index + " is null."); throw new ClassFormatException("Constant pool at index " + index + " is null.");
@@ -326,8 +326,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return ConstantInteger value * @return ConstantInteger value
* @see ConstantInteger
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see ConstantInteger
*/ */
public ConstantInteger getConstantInteger(final int index) { public ConstantInteger getConstantInteger(final int index) {
return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class); return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
@@ -341,6 +341,13 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
return constantPool; return constantPool;
} }
/**
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
}
/** /**
* Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that * Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that
* points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data. * points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data.
@@ -348,9 +355,9 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param index Index in constant pool * @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString * @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference * @return Contents of string reference
* @throws IllegalArgumentException if tag is invalid
* @see ConstantClass * @see ConstantClass
* @see ConstantString * @see ConstantString
* @throws IllegalArgumentException if tag is invalid
*/ */
public String getConstantString(final int index, final byte tag) throws IllegalArgumentException { public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
int i; int i;
@@ -360,22 +367,22 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* subclassing. * subclassing.
*/ */
switch (tag) { switch (tag) {
case Const.CONSTANT_Class: case Const.CONSTANT_Class:
i = getConstant(index, ConstantClass.class).getNameIndex(); i = getConstant(index, ConstantClass.class).getNameIndex();
break; break;
case Const.CONSTANT_String: case Const.CONSTANT_String:
i = getConstant(index, ConstantString.class).getStringIndex(); i = getConstant(index, ConstantString.class).getStringIndex();
break; break;
case Const.CONSTANT_Module: case Const.CONSTANT_Module:
i = getConstant(index, ConstantModule.class).getNameIndex(); i = getConstant(index, ConstantModule.class).getNameIndex();
break; break;
case Const.CONSTANT_Package: case Const.CONSTANT_Package:
i = getConstant(index, ConstantPackage.class).getNameIndex(); i = getConstant(index, ConstantPackage.class).getNameIndex();
break; break;
case Const.CONSTANT_Utf8: case Const.CONSTANT_Utf8:
return getConstantUtf8(index).getBytes(); return getConstantUtf8(index).getBytes();
default: default:
throw new IllegalArgumentException("getConstantString called with illegal tag " + tag); throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
} }
// Finally get the string from the constant pool // Finally get the string from the constant pool
return getConstantUtf8(i).getBytes(); return getConstantUtf8(i).getBytes();
@@ -386,8 +393,8 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* *
* @param index Index in constant pool * @param index Index in constant pool
* @return ConstantUtf8 value * @return ConstantUtf8 value
* @see ConstantUtf8
* @throws ClassFormatException if constant type does not match tag * @throws ClassFormatException if constant type does not match tag
* @see ConstantUtf8
*/ */
public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException { public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class); return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
@@ -412,13 +419,6 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
constantPool[index] = constant; constantPool[index] = constant;
} }
/**
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
}
/** /**
* @return String representation. * @return String representation.
*/ */
@@ -430,4 +430,164 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
} }
return buf.toString(); return buf.toString();
} }
// ---------------------------------------------- haidnorJVM
public ConstantFieldref getConstantFieldref(int constantFieldrefIndex) {
return getConstant(constantFieldrefIndex);
}
public ConstantMethodref getConstantMethodref(int constantMethodrefIndex) {
return getConstant(constantMethodrefIndex);
}
public ConstantClass getConstantClass(int constantClassIndex) {
return getConstant(constantClassIndex);
}
public ConstantNameAndType getConstantNameAndType(int constantNameAndTypeIndex) {
return getConstant(constantNameAndTypeIndex);
}
// ConstantClass ---------------------------------------------------------------------------------------------------
/**
* 获取长类名, 例如 java/lang/String
*/
public String constantClass_ClassName(final ConstantClass constantClass) {
ConstantUtf8 constantUtf8 = getConstant(constantClass.getNameIndex());
return constantUtf8.getBytes();
}
/**
* 获取长类名, 例如 java/lang/String
*/
public String constantClass_ClassName(int constantClassIndex) {
ConstantClass constantClass = getConstant(constantClassIndex);
return constantClass_ClassName(constantClass);
}
// ConstantFieldref ------------------------------------------------------------------------------------------------
/**
* 获取字段所处于Java类的类名, 例如 java/lang/String
*/
public String constantFieldref_ClassName(final ConstantFieldref constantFieldref) {
ConstantClass constClass = getConstant(constantFieldref.getClassIndex());
return (String) constClass.getConstantValue(this);
}
/**
* 获取字段所处于Java类的类名, 例如 java/lang/String
*/
public String constantFieldref_ClassName(int constantFieldrefIndex) {
ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
return constantFieldref_ClassName(constantFieldref);
}
/**
* 获取字段名称
*/
public String getFieldName(final ConstantFieldref constantFieldref) {
ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex());
return constNameAndType.getName(this);
}
/**
* 获取字段名称
*/
public String getFieldName(int constantFieldrefIndex) {
ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
return getFieldName(constantFieldref);
}
/**
* 获取字段类型签名
*/
public String getFieldSignature(final ConstantFieldref constantFieldref) {
ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex());
return constNameAndType.getSignature(this);
}
/**
* 获取字段类型签名
*/
public String getFieldSignature(int constantFieldrefIndex) {
ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
return getFieldSignature(constantFieldref);
}
// ConstantMethodref -----------------------------------------------------------------------------------------------
/**
* 获取方法所处于Java类的类名
* 名称使用/分割,例如 haidnor/jvm/test/instruction/references/NEW
*/
public String constantMethodref_ClassName(final ConstantMethodref methodref) {
ConstantClass constClass = getConstant(methodref.getClassIndex());
return (String) constClass.getConstantValue(this);
}
/**
* 获取方法名
*/
public String constantMethodref_MethodName(final ConstantMethodref methodref) {
ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
return constNameAndType.getName(this);
}
/**
* 获取方法签名
*/
public String constantMethodref_MethodSignature(final ConstantMethodref methodref) {
ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
return constNameAndType.getSignature(this);
}
// ConstantInterfaceMethodref -----------------------------------------------------------------------------------------------
public String constantInterfaceMethodref_ClassName(final ConstantInterfaceMethodref methodref) {
ConstantClass constClass = getConstant(methodref.getClassIndex());
return (String) constClass.getConstantValue(this);
}
/**
* 获取方法名
*/
public String constantInterfaceMethodref_MethodName(final ConstantInterfaceMethodref methodref) {
ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
return constNameAndType.getName(this);
}
/**
* 获取方法签名
*/
public String constantInterfaceMethodref_MethodSignature(final ConstantInterfaceMethodref methodref) {
ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
return constNameAndType.getSignature(this);
}
// ConstantNameAndType -----------------------------------------------------------------------------------------------
/**
* ConstantNameAndType
*/
public ConstantNameAndType constantNameAndType(int constantNameAndTypeIndex) {
return getConstant(constantNameAndTypeIndex);
}
public String constantNameAndType_name(int constantNameAndTypeIndex) {
ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
return constantNameAndType.getName(this);
}
public String constantNameAndType_signature(int constantNameAndTypeIndex) {
ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
return constantNameAndType.getSignature(this);
}
} }

View File

@@ -57,47 +57,53 @@ import java.util.Objects;
*/ */
public final class ConstantUtf8 extends Constant { public final class ConstantUtf8 extends Constant {
private static class Cache { private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS); private static final String SYS_PROP_STATISTICS = "bcel.statistics";
private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue();
private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75);
private static final HashMap<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
private static final long serialVersionUID = -8506975356158971766L;
@Override
protected boolean removeEldestEntry(final Map.Entry<String, ConstantUtf8> eldest) {
return size() > MAX_ENTRIES;
}
};
// Set the size to 0 or below to skip caching entirely
private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue();
static boolean isEnabled() {
return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
}
}
// TODO these should perhaps be AtomicInt? // TODO these should perhaps be AtomicInt?
private static volatile int considered; private static volatile int considered;
private static volatile int created; private static volatile int created;
private static volatile int hits; private static volatile int hits;
private static volatile int skipped; private static volatile int skipped;
private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
private static final String SYS_PROP_STATISTICS = "bcel.statistics";
static { static {
if (Cache.BCEL_STATISTICS) { if (Cache.BCEL_STATISTICS) {
Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats)); Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats));
} }
} }
private final String value;
/**
* Initializes from another object.
*
* @param constantUtf8 the value.
*/
public ConstantUtf8(final ConstantUtf8 constantUtf8) {
this(constantUtf8.getBytes());
}
/**
* Initializes instance from file data.
*
* @param dataInput Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantUtf8(final DataInput dataInput) throws IOException {
super(Const.CONSTANT_Utf8);
value = dataInput.readUTF();
created++;
}
/**
* @param value Data
*/
public ConstantUtf8(final String value) {
super(Const.CONSTANT_Utf8);
this.value = Objects.requireNonNull(value, "value");
created++;
}
/** /**
* Clears the cache. * Clears the cache.
* *
@@ -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.
*/ */

View File

@@ -23,6 +23,9 @@ import haidnor.jvm.bcel.util.BCELComparator;
import haidnor.jvm.bcel.util.ClassQueue; import haidnor.jvm.bcel.util.ClassQueue;
import haidnor.jvm.bcel.util.Repository; import haidnor.jvm.bcel.util.Repository;
import haidnor.jvm.bcel.util.SyntheticRepository; import haidnor.jvm.bcel.util.SyntheticRepository;
import haidnor.jvm.classloader.JVMClassLoader;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import java.io.*; import java.io.*;
@@ -71,41 +74,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return THIS.getClassName().hashCode(); return THIS.getClassName().hashCode();
} }
}; };
/*
* Print debug information depending on 'JavaClass.debug'
*/
static void Debug(final String str) {
if (debug) {
System.out.println(str);
}
}
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
private static String indent(final Object obj) {
final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
final StringBuilder buf = new StringBuilder();
while (tokenizer.hasMoreTokens()) {
buf.append("\t").append(tokenizer.nextToken()).append("\n");
}
return buf.toString();
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
private String fileName;
private final String packageName; private final String packageName;
@Getter
private final Map<String, JavaField> staticJavaFieldMap = new HashMap<>();
private String fileName;
private String sourceFileName = "<Unknown>"; private String sourceFileName = "<Unknown>";
private int classNameIndex; private int classNameIndex;
private int superclassNameIndex; private int superclassNameIndex;
@@ -119,36 +91,38 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
private JavaField[] fields; // Fields, i.e., variables of class private JavaField[] fields; // Fields, i.e., variables of class
private JavaMethod[] methods; // methods defined in the class private JavaMethod[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class private Attribute[] attributes; // attributes defined in the class
private AnnotationEntry[] annotations; // annotations defined on the class private AnnotationEntry[] annotations; // annotations defined on the class
private byte source = HEAP; // Generated in memory private byte source = HEAP; // Generated in memory
private boolean isAnonymous; private boolean isAnonymous;
private boolean isNested; private boolean isNested;
private boolean computedNestedTypeStatus; private boolean computedNestedTypeStatus;
// ---------------------------------------------- haidnorJVM >
/** /**
* In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any
* better. * better.
*/ */
private transient Repository repository = SyntheticRepository.getInstance(); private transient Repository repository = SyntheticRepository.getInstance();
@Getter
@Setter
private JVMClassLoader JVMClassLoader;
// ---------------------------------------------- haidnorJVM <
/** /**
* Constructor gets all contents as arguments. * Constructor gets all contents as arguments.
* *
* @param classNameIndex Class name * @param classNameIndex Class name
* @param superclassNameIndex Superclass name * @param superclassNameIndex Superclass name
* @param fileName File name * @param fileName File name
* @param major Major compiler version * @param major Major compiler version
* @param minor Minor compiler version * @param minor Minor compiler version
* @param accessFlags Access rights defined by bit flags * @param accessFlags Access rights defined by bit flags
* @param constantPool Array of constants * @param constantPool Array of constants
* @param interfaces Implemented interfaces * @param interfaces Implemented interfaces
* @param fields Class fields * @param fields Class fields
* @param methods Class methods * @param methods Class methods
* @param attributes Class attributes * @param attributes Class attributes
*/ */
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, final int[] interfaces, final JavaField[] fields, final JavaMethod[] methods, final Attribute[] attributes) { final ConstantPool constantPool, final int[] interfaces, final JavaField[] fields, final JavaMethod[] methods, final Attribute[] attributes) {
@@ -158,19 +132,19 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
/** /**
* Constructor gets all contents as arguments. * Constructor gets all contents as arguments.
* *
* @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class. * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class.
* @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's * @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's
* superclass. * superclass.
* @param fileName File name * @param fileName File name
* @param major Major compiler version * @param major Major compiler version
* @param minor Minor compiler version * @param minor Minor compiler version
* @param accessFlags Access rights defined by bit flags * @param accessFlags Access rights defined by bit flags
* @param constantPool Array of constants * @param constantPool Array of constants
* @param interfaces Implemented interfaces * @param interfaces Implemented interfaces
* @param fields Class fields * @param fields Class fields
* @param methods Class methods * @param methods Class methods
* @param attributes Class attributes * @param attributes Class attributes
* @param source Read from file or generated in memory? * @param source Read from file or generated in memory?
*/ */
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, int[] interfaces, JavaField[] fields, JavaMethod[] methods, Attribute[] attributes, final byte source) { final ConstantPool constantPool, int[] interfaces, JavaField[] fields, JavaMethod[] methods, Attribute[] attributes, final byte source) {
@@ -229,6 +203,45 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class); final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class);
interfaceNames[i] = Utility.compactClassName(str, false); interfaceNames[i] = Utility.compactClassName(str, false);
} }
// 初始化静态字段
for (JavaField field : getFields()) {
if (field.isStatic()) {
staticJavaFieldMap.put(field.getName(), field);
}
}
}
/*
* Print debug information depending on 'JavaClass.debug'
*/
static void Debug(final String str) {
if (debug) {
System.out.println(str);
}
}
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
private static String indent(final Object obj) {
final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
final StringBuilder buf = new StringBuilder();
while (tokenizer.hasMoreTokens()) {
buf.append("\t").append(tokenizer.nextToken()).append("\n");
}
return buf.toString();
} }
/** /**
@@ -258,7 +271,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
} }
for (final Attribute attribute : this.attributes) { for (final Attribute attribute : this.attributes) {
if (attribute instanceof InnerClasses) { if (attribute instanceof InnerClasses) {
((InnerClasses) attribute).forEach(innerClass -> { ((InnerClasses) attribute).forEach(innerClass -> {
boolean innerClassAttributeRefersToMe = false; boolean innerClassAttributeRefersToMe = false;
String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class); String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class);
innerClassName = Utility.compactClassName(innerClassName, false); innerClassName = Utility.compactClassName(innerClassName, false);
@@ -429,6 +442,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return attributes; return attributes;
} }
/**
* @param attributes .
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
}
/** /**
* @return class in binary format * @return class in binary format
*/ */
@@ -449,6 +469,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return className; return className;
} }
/**
* @param className .
*/
public void setClassName(final String className) {
this.className = className;
}
/** /**
* @return Class name index. * @return Class name index.
*/ */
@@ -456,6 +483,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classNameIndex; return classNameIndex;
} }
/**
* @param classNameIndex .
*/
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
}
/** /**
* @return Constant pool. * @return Constant pool.
*/ */
@@ -463,14 +497,28 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return constantPool; return constantPool;
} }
/**
* @param constantPool .
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/** /**
* @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are * @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are
* those specific to this class, and not those of the superclass or superinterfaces. * those specific to this class, and not those of the superclass or superinterfaces.
*/ */
public JavaField[] getFields() { public JavaField[] getFields() {
return fields; return fields;
} }
/**
* @param fields .
*/
public void setFields(final JavaField[] fields) {
this.fields = fields;
}
/** /**
* @return File name of class, aka SourceFile attribute value * @return File name of class, aka SourceFile attribute value
*/ */
@@ -478,6 +526,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return fileName; return fileName;
} }
/**
* Set File name of class, aka SourceFile attribute value
*/
public void setFileName(final String fileName) {
this.fileName = fileName;
}
/** /**
* @return Indices in constant pool of implemented interfaces. * @return Indices in constant pool of implemented interfaces.
*/ */
@@ -492,6 +547,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return interfaceNames; return interfaceNames;
} }
/**
* @param interfaceNames .
*/
public void setInterfaceNames(final String[] interfaceNames) {
this.interfaceNames = interfaceNames;
}
/** /**
* Get interfaces directly implemented by this JavaClass. * Get interfaces directly implemented by this JavaClass.
* *
@@ -506,6 +568,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classes; return classes;
} }
/**
* @param interfaces .
*/
public void setInterfaces(final int[] interfaces) {
this.interfaces = interfaces;
}
/** /**
* @return Major number of class file version. * @return Major number of class file version.
*/ */
@@ -513,6 +582,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return major; return major;
} }
/**
* @param major .
*/
public void setMajor(final int major) {
this.major = major;
}
/** /**
* @return A {@link JavaMethod} corresponding to java.lang.reflect.Method if any * @return A {@link JavaMethod} corresponding to java.lang.reflect.Method if any
*/ */
@@ -532,6 +608,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return methods; return methods;
} }
/**
* @param methods .
*/
public void setMethods(final JavaMethod[] methods) {
this.methods = methods;
}
/** /**
* @return Minor number of class file version. * @return Minor number of class file version.
*/ */
@@ -539,6 +622,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return minor; return minor;
} }
/**
* @param minor .
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/** /**
* @return Package name. * @return Package name.
*/ */
@@ -554,6 +644,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return repository; return repository;
} }
/**
* Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
*/
public void setRepository(final Repository repository) { // TODO make protected?
this.repository = repository;
}
/** /**
* @return returns either HEAP (generated), FILE, or ZIP * @return returns either HEAP (generated), FILE, or ZIP
*/ */
@@ -568,6 +665,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return sourceFileName; return sourceFileName;
} }
/**
* Set absolute path to file this class was read from.
*/
public void setSourceFileName(final String sourceFileName) {
this.sourceFileName = sourceFileName;
}
/** /**
* Gets the source file path including the package path. * Gets the source file path including the package path.
* *
@@ -618,6 +722,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassName; return superclassName;
} }
/**
* @param superclassName .
*/
public void setSuperclassName(final String superclassName) {
this.superclassName = superclassName;
}
/** /**
* @return Class name index. * @return Class name index.
*/ */
@@ -625,6 +736,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassNameIndex; return superclassNameIndex;
} }
/**
* @param superclassNameIndex .
*/
public void setSuperclassNameIndex(final int superclassNameIndex) {
this.superclassNameIndex = superclassNameIndex;
}
public JavaField getStaticField(String filedName) {
return staticJavaFieldMap.get(filedName);
}
/** /**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
* *
@@ -700,111 +822,6 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return (super.getAccessFlags() & Const.ACC_SUPER) != 0; return (super.getAccessFlags() & Const.ACC_SUPER) != 0;
} }
/**
* @param attributes .
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
}
/**
* @param className .
*/
public void setClassName(final String className) {
this.className = className;
}
/**
* @param classNameIndex .
*/
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
}
/**
* @param constantPool .
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/**
* @param fields .
*/
public void setFields(final JavaField[] fields) {
this.fields = fields;
}
/**
* Set File name of class, aka SourceFile attribute value
*/
public void setFileName(final String fileName) {
this.fileName = fileName;
}
/**
* @param interfaceNames .
*/
public void setInterfaceNames(final String[] interfaceNames) {
this.interfaceNames = interfaceNames;
}
/**
* @param interfaces .
*/
public void setInterfaces(final int[] interfaces) {
this.interfaces = interfaces;
}
/**
* @param major .
*/
public void setMajor(final int major) {
this.major = major;
}
/**
* @param methods .
*/
public void setMethods(final JavaMethod[] methods) {
this.methods = methods;
}
/**
* @param minor .
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/**
* Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
*/
public void setRepository(final Repository repository) { // TODO make protected?
this.repository = repository;
}
/**
* Set absolute path to file this class was read from.
*/
public void setSourceFileName(final String sourceFileName) {
this.sourceFileName = sourceFileName;
}
/**
* @param superclassName .
*/
public void setSuperclassName(final String superclassName) {
this.superclassName = superclassName;
}
/**
* @param superclassNameIndex .
*/
public void setSuperclassNameIndex(final int superclassNameIndex) {
this.superclassNameIndex = superclassNameIndex;
}
/** /**
* @return String representing class contents. * @return String representing class contents.
*/ */
@@ -814,7 +831,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
access = access.isEmpty() ? "" : access + " "; access = access.isEmpty() ? "" : access + " ";
final StringBuilder buf = new StringBuilder(128); final StringBuilder buf = new StringBuilder(128);
buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(className).append(" extends ") buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(className).append(" extends ")
.append(Utility.compactClassName(superclassName, false)).append('\n'); .append(Utility.compactClassName(superclassName, false)).append('\n');
final int size = interfaces.length; final int size = interfaces.length;
if (size > 0) { if (size > 0) {
buf.append("implements\t\t"); buf.append("implements\t\t");
@@ -859,4 +876,20 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
} }
return buf.toString(); return buf.toString();
} }
// ---------------------------------------------- haidnorJVM
/**
* 获取 main 方法
*/
public JavaMethod getMainMethod() {
for (JavaMethod javaMethod : getMethods()) {
if (javaMethod.toString().startsWith("public static void main(String[] args)")) {
return javaMethod;
}
}
return null;
}
} }

View File

@@ -28,7 +28,7 @@ import java.util.Objects;
* This class represents the field info structure, i.e., the representation for a variable in the class. See JVM * This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
* specification for details. * specification for details.
*/ */
public final class JavaField extends FieldOrMethod { public class JavaField extends FieldOrMethod {
/** /**
* Empty array constant. * Empty array constant.
@@ -36,7 +36,10 @@ public final class JavaField extends FieldOrMethod {
* @since 6.6.0 * @since 6.6.0
*/ */
public static final JavaField[] EMPTY_ARRAY = {}; public static final JavaField[] EMPTY_ARRAY = {};
/**
* Empty array.
*/
static final JavaField[] EMPTY_FIELD_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() { private static BCELComparator bcelComparator = new BCELComparator() {
@Override @Override
@@ -52,25 +55,14 @@ public final class JavaField extends FieldOrMethod {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
} }
}; };
/** /**
* Empty array. * 值类型
*/ */
static final JavaField[] EMPTY_FIELD_ARRAY = {}; private int valueType;
/** /**
* @return Comparison strategy object *
*/ */
public static BCELComparator getComparator() { private Object value;
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/** /**
* Construct object from file stream. * Construct object from file stream.
@@ -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;
}
} }

View File

@@ -43,20 +43,19 @@ public final class Module extends Attribute {
private final int moduleNameIndex; private final int moduleNameIndex;
private final int moduleFlags; private final int moduleFlags;
private final int moduleVersionIndex; private final int moduleVersionIndex;
private final int usesCount;
private final int[] usesIndex;
private ModuleRequires[] requiresTable; private ModuleRequires[] requiresTable;
private ModuleExports[] exportsTable; private ModuleExports[] exportsTable;
private ModuleOpens[] opensTable; private ModuleOpens[] opensTable;
private final int usesCount;
private final int[] usesIndex;
private ModuleProvides[] providesTable; private ModuleProvides[] providesTable;
/** /**
* 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.
*/ */

View File

@@ -37,9 +37,9 @@ public final class ModuleMainClass 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.
*/ */
@@ -49,10 +49,10 @@ public final class ModuleMainClass 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 mainClassIndex Host class index * @param mainClassIndex Host class index
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) { public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);

View File

@@ -39,9 +39,9 @@ public final class ModulePackages 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.
*/ */
@@ -55,10 +55,10 @@ public final class ModulePackages 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 packageIndexTable Table of indices in constant pool * @param packageIndexTable Table of indices in constant pool
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) { public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool); super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
@@ -129,6 +129,13 @@ public final class ModulePackages extends Attribute {
return packageIndexTable; return packageIndexTable;
} }
/**
* @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
*/
public void setPackageIndexTable(final int[] packageIndexTable) {
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
}
/** /**
* @return string array of package names * @return string array of package names
*/ */
@@ -138,13 +145,6 @@ public final class ModulePackages extends Attribute {
return names; return names;
} }
/**
* @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
*/
public void setPackageIndexTable(final int[] packageIndexTable) {
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
}
/** /**
* @return String representation, i.e., a list of packages. * @return String representation, i.e., a list of packages.
*/ */

View File

@@ -37,9 +37,9 @@ public final class NestHost extends Attribute {
/** /**
* Constructs object from input stream. * Constructs 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.
*/ */
@@ -49,10 +49,10 @@ public final class NestHost 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 hostClassIndex Host class index * @param hostClassIndex Host class index
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public NestHost(final int nameIndex, final int length, final int hostClassIndex, final ConstantPool constantPool) { public NestHost(final int nameIndex, final int length, final int hostClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);

View File

@@ -40,9 +40,9 @@ public final class NestMembers 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.
*/ */
@@ -56,9 +56,9 @@ public final class NestMembers 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 classes Table of indices in constant pool * @param classes Table of indices in constant pool
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) { public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) {
@@ -123,6 +123,13 @@ public final class NestMembers extends Attribute {
return classes; return classes;
} }
/**
* @param classes the list of class indexes Also redefines number_of_classes according to table length.
*/
public void setClasses(final int[] classes) {
this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY;
}
/** /**
* @return string array of class names * @return string array of class names
*/ */
@@ -139,13 +146,6 @@ public final class NestMembers extends Attribute {
return classes.length; return classes.length;
} }
/**
* @param classes the list of class indexes Also redefines number_of_classes according to table length.
*/
public void setClasses(final int[] classes) {
this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY;
}
/** /**
* @return String representation, i.e., a list of classes. * @return String representation, i.e., a list of classes.
*/ */

View File

@@ -35,9 +35,9 @@ public final class PMGClass 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.
*/ */
@@ -46,11 +46,11 @@ public final class PMGClass 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 pmgIndex index in constant pool for source file name * @param pmgIndex index in constant pool for source file name
* @param pmgClassIndex Index in constant pool to CONSTANT_Utf8 * @param pmgClassIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public PMGClass(final int nameIndex, final int length, final int pmgIndex, final int pmgClassIndex, final ConstantPool constantPool) { public PMGClass(final int nameIndex, final int length, final int pmgIndex, final int pmgClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_PMG, nameIndex, length, constantPool); super(Const.ATTR_PMG, nameIndex, length, constantPool);
@@ -107,6 +107,13 @@ public final class PMGClass extends Attribute {
return pmgClassIndex; return pmgClassIndex;
} }
/**
* @param pmgClassIndex
*/
public void setPMGClassIndex(final int pmgClassIndex) {
this.pmgClassIndex = pmgClassIndex;
}
/** /**
* @return PMG class name. * @return PMG class name.
*/ */
@@ -121,20 +128,6 @@ public final class PMGClass extends Attribute {
return pmgIndex; return pmgIndex;
} }
/**
* @return PMG name.
*/
public String getPMGName() {
return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
}
/**
* @param pmgClassIndex
*/
public void setPMGClassIndex(final int pmgClassIndex) {
this.pmgClassIndex = pmgClassIndex;
}
/** /**
* @param pmgIndex * @param pmgIndex
*/ */
@@ -142,6 +135,13 @@ public final class PMGClass extends Attribute {
this.pmgIndex = pmgIndex; this.pmgIndex = pmgIndex;
} }
/**
* @return PMG name.
*/
public String getPMGName() {
return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
}
/** /**
* @return String representation * @return String representation
*/ */

View File

@@ -31,19 +31,6 @@ import java.util.List;
public class ParameterAnnotationEntry implements Node { public class ParameterAnnotationEntry implements Node {
static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain parameter annotation data
final List<ParameterAnnotationEntry> accumulatedAnnotations = new ArrayList<>(attrs.length);
for (final Attribute attribute : attrs) {
if (attribute instanceof ParameterAnnotations) {
final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries());
}
}
return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY);
}
private final AnnotationEntry[] annotationTable; private final AnnotationEntry[] annotationTable;
/** /**
@@ -61,6 +48,18 @@ public class ParameterAnnotationEntry implements Node {
} }
} }
public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain parameter annotation data
final List<ParameterAnnotationEntry> accumulatedAnnotations = new ArrayList<>(attrs.length);
for (final Attribute attribute : attrs) {
if (attribute instanceof ParameterAnnotations) {
final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries());
}
}
return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY);
}
/** /**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.

View File

@@ -29,18 +29,20 @@ import java.util.stream.Stream;
*/ */
public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> { public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> {
/** Table of parameter annotations */ /**
* Table of parameter annotations
*/
private ParameterAnnotationEntry[] parameterAnnotationTable; private ParameterAnnotationEntry[] parameterAnnotationTable;
/** /**
* @param parameterAnnotationType the subclass type of the parameter annotation * @param parameterAnnotationType the subclass type of the parameter annotation
* @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
*/ */
ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException { throws IOException {
this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool); this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool);
final int numParameters = input.readUnsignedByte(); final int numParameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[numParameters]; parameterAnnotationTable = new ParameterAnnotationEntry[numParameters];
@@ -50,14 +52,14 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
} }
/** /**
* @param parameterAnnotationType the subclass type of the parameter annotation * @param parameterAnnotationType the subclass type of the parameter annotation
* @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 parameterAnnotationTable the actual parameter annotations * @param parameterAnnotationTable the actual parameter annotations
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length,
final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) { final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
super(parameterAnnotationType, nameIndex, length, constantPool); super(parameterAnnotationType, nameIndex, length, constantPool);
this.parameterAnnotationTable = parameterAnnotationTable; this.parameterAnnotationTable = parameterAnnotationTable;
} }
@@ -106,15 +108,15 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
return parameterAnnotationTable; return parameterAnnotationTable;
} }
@Override
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
/** /**
* @param parameterAnnotationTable the entries to set in this parameter annotation * @param parameterAnnotationTable the entries to set in this parameter annotation
*/ */
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) { public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = parameterAnnotationTable; this.parameterAnnotationTable = parameterAnnotationTable;
} }
@Override
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
} }

View File

@@ -30,9 +30,9 @@ import java.io.IOException;
public class RuntimeInvisibleAnnotations extends Annotations { public class RuntimeInvisibleAnnotations extends Annotations {
/** /**
* @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
* @throws IOException Thrown when an I/O exception of some sort has occurred. * @throws IOException Thrown when an I/O exception of some sort has occurred.
*/ */

View File

@@ -29,14 +29,14 @@ import java.io.IOException;
public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations { public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations {
/** /**
* @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
* @throws IOException Thrown when an I/O exception of some sort has occurred. * @throws IOException Thrown when an I/O exception of some sort has occurred.
*/ */
public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException { throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool); super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
} }
} }

View File

@@ -30,9 +30,9 @@ import java.io.IOException;
public class RuntimeVisibleAnnotations extends Annotations { public class RuntimeVisibleAnnotations extends Annotations {
/** /**
* @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
* @throws IOException Thrown when an I/O exception of some sort has occurred. * @throws IOException Thrown when an I/O exception of some sort has occurred.
*/ */

View File

@@ -29,14 +29,14 @@ import java.io.IOException;
public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations { public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations {
/** /**
* @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
* @throws IOException Thrown when an I/O exception of some sort has occurred. * @throws IOException Thrown when an I/O exception of some sort has occurred.
*/ */
public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException { throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool); super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
} }
} }

View File

@@ -33,24 +33,42 @@ import java.util.Objects;
*/ */
public final class Signature extends Attribute { public final class Signature extends Attribute {
private int signatureIndex;
/** /**
* Extends ByteArrayInputStream to make 'unreading' chars possible. * Construct object from file stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/ */
private static final class MyByteArrayInputStream extends ByteArrayInputStream { Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
MyByteArrayInputStream(final String data) { /**
super(data.getBytes(StandardCharsets.UTF_8)); * @param nameIndex Index in constant pool to CONSTANT_Utf8
} * @param length Content length in bytes
* @param signatureIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
this.signatureIndex = signatureIndex;
// validate:
Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
}
String getData() { /**
return new String(buf, StandardCharsets.UTF_8); * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
} * physical copy.
*
void unread() { * @param c Source to copy.
if (pos > 0) { */
pos--; public Signature(final Signature c) {
} this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
} }
private static boolean identStart(final int ch) { private static boolean identStart(final int ch) {
@@ -152,44 +170,6 @@ public final class Signature extends Attribute {
return buf.toString(); return buf.toString();
} }
private int signatureIndex;
/**
* Construct object from file stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param signatureIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
this.signatureIndex = signatureIndex;
// validate:
Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Signature(final Signature c) {
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
/** /**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -250,4 +230,24 @@ public final class Signature extends Attribute {
public String toString() { public String toString() {
return "Signature: " + getSignature(); return "Signature: " + getSignature();
} }
/**
* Extends ByteArrayInputStream to make 'unreading' chars possible.
*/
private static final class MyByteArrayInputStream extends ByteArrayInputStream {
MyByteArrayInputStream(final String data) {
super(data.getBytes(StandardCharsets.UTF_8));
}
String getData() {
return new String(buf, StandardCharsets.UTF_8);
}
void unread() {
if (pos > 0) {
pos--;
}
}
}
} }

View File

@@ -37,19 +37,19 @@ public class SimpleElementValue extends ElementValue {
final int type = super.getType(); final int type = super.getType();
dos.writeByte(type); // u1 kind of value dos.writeByte(type); // u1 kind of value
switch (type) { switch (type) {
case PRIMITIVE_INT: case PRIMITIVE_INT:
case PRIMITIVE_BYTE: case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR: case PRIMITIVE_CHAR:
case PRIMITIVE_FLOAT: case PRIMITIVE_FLOAT:
case PRIMITIVE_LONG: case PRIMITIVE_LONG:
case PRIMITIVE_BOOLEAN: case PRIMITIVE_BOOLEAN:
case PRIMITIVE_SHORT: case PRIMITIVE_SHORT:
case PRIMITIVE_DOUBLE: case PRIMITIVE_DOUBLE:
case STRING: case STRING:
dos.writeShort(getIndex()); dos.writeShort(getIndex());
break; break;
default: default:
throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type); throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type);
} }
} }
@@ -60,6 +60,10 @@ public class SimpleElementValue extends ElementValue {
return index; return index;
} }
public void setIndex(final int index) {
this.index = index;
}
public boolean getValueBoolean() { public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) { if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue");
@@ -128,46 +132,42 @@ public class SimpleElementValue extends ElementValue {
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes(); return super.getConstantPool().getConstantUtf8(getIndex()).getBytes();
} }
public void setIndex(final int index) {
this.index = index;
}
// Whatever kind of value it is, return it as a string // Whatever kind of value it is, return it as a string
@Override @Override
public String stringifyValue() { public String stringifyValue() {
final ConstantPool cpool = super.getConstantPool(); final ConstantPool cpool = super.getConstantPool();
final int type = super.getType(); final int type = super.getType();
switch (type) { switch (type) {
case PRIMITIVE_INT: case PRIMITIVE_INT:
return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes()); return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes());
case PRIMITIVE_LONG: case PRIMITIVE_LONG:
final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class); final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class);
return Long.toString(j.getBytes()); return Long.toString(j.getBytes());
case PRIMITIVE_DOUBLE: case PRIMITIVE_DOUBLE:
final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class); final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class);
return Double.toString(d.getBytes()); return Double.toString(d.getBytes());
case PRIMITIVE_FLOAT: case PRIMITIVE_FLOAT:
final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class); final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class);
return Float.toString(f.getBytes()); return Float.toString(f.getBytes());
case PRIMITIVE_SHORT: case PRIMITIVE_SHORT:
final ConstantInteger s = cpool.getConstantInteger(getIndex()); final ConstantInteger s = cpool.getConstantInteger(getIndex());
return Integer.toString(s.getBytes()); return Integer.toString(s.getBytes());
case PRIMITIVE_BYTE: case PRIMITIVE_BYTE:
final ConstantInteger b = cpool.getConstantInteger(getIndex()); final ConstantInteger b = cpool.getConstantInteger(getIndex());
return Integer.toString(b.getBytes()); return Integer.toString(b.getBytes());
case PRIMITIVE_CHAR: case PRIMITIVE_CHAR:
final ConstantInteger ch = cpool.getConstantInteger(getIndex()); final ConstantInteger ch = cpool.getConstantInteger(getIndex());
return String.valueOf((char) ch.getBytes()); return String.valueOf((char) ch.getBytes());
case PRIMITIVE_BOOLEAN: case PRIMITIVE_BOOLEAN:
final ConstantInteger bo = cpool.getConstantInteger(getIndex()); final ConstantInteger bo = cpool.getConstantInteger(getIndex());
if (bo.getBytes() == 0) { if (bo.getBytes() == 0) {
return "false"; return "false";
} }
return "true"; return "true";
case STRING: case STRING:
return cpool.getConstantUtf8(getIndex()).getBytes(); return cpool.getConstantUtf8(getIndex()).getBytes();
default: default:
throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type); throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type);
} }
} }

View File

@@ -37,9 +37,9 @@ public final class SourceFile 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.
*/ */
@@ -48,13 +48,13 @@ public final class SourceFile extends Attribute {
} }
/** /**
* @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile". * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile".
* @param length Content length in bytes, the value should be 2. * @param length Content length in bytes, the value should be 2.
* @param constantPool The constant pool that this attribute is associated with. * @param constantPool The constant pool that this attribute is associated with.
* @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the * @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the
* file from which this class was compiled. It will not be interpreted as indicating the name of the directory * file from which this class was compiled. It will not be interpreted as indicating the name of the directory
* contqining the file or an absolute path; this information has to be supplied the consumer of this attribute - * contqining the file or an absolute path; this information has to be supplied the consumer of this attribute -
* in many cases, the JVM. * in many cases, the JVM.
*/ */
public SourceFile(final int nameIndex, final int length, final int sourceFileIndex, final ConstantPool constantPool) { public SourceFile(final int nameIndex, final int length, final int sourceFileIndex, final ConstantPool constantPool) {
super(Const.ATTR_SOURCE_FILE, nameIndex, Args.require(length, 2, "SourceFile length attribute"), constantPool); super(Const.ATTR_SOURCE_FILE, nameIndex, Args.require(length, 2, "SourceFile length attribute"), constantPool);
@@ -109,13 +109,6 @@ public final class SourceFile extends Attribute {
return sourceFileIndex; return sourceFileIndex;
} }
/**
* @return Source file name.
*/
public String getSourceFileName() {
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/** /**
* @param sourceFileIndex * @param sourceFileIndex
*/ */
@@ -123,6 +116,13 @@ public final class SourceFile extends Attribute {
this.sourceFileIndex = sourceFileIndex; this.sourceFileIndex = sourceFileIndex;
} }
/**
* @return Source file name.
*/
public String getSourceFileName() {
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/** /**
* @return String representation * @return String representation
*/ */

View File

@@ -50,9 +50,9 @@ public final class StackMap extends Attribute {
/** /**
* 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 dataInput Input stream * @param dataInput 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

@@ -27,7 +27,7 @@ import java.util.Arrays;
/** /**
* This class represents a stack map entry recording the types of local variables and the of stack items at a given * This class represents a stack map entry recording the types of local variables and the of stack items at a given
* byte code offset. See CLDC specification 5.3.1.2. * byte code offset. See CLDC specification 5.3.1.2.
* * <p>
* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4 * See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
* *
* <pre> * <pre>
@@ -41,6 +41,7 @@ import java.util.Arrays;
* full_frame; * full_frame;
* } * }
* </pre> * </pre>
*
* @see StackMap * @see StackMap
* @see StackMapType * @see StackMapType
*/ */
@@ -67,10 +68,10 @@ public final class StackMapEntry implements Node, Cloneable {
byteCodeOffset = frameType - Const.SAME_FRAME; byteCodeOffset = frameType - Const.SAME_FRAME;
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) }; typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)};
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
byteCodeOffset = dataInput.readUnsignedShort(); byteCodeOffset = dataInput.readUnsignedShort();
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) }; typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)};
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) { } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
byteCodeOffset = dataInput.readUnsignedShort(); byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType == Const.SAME_FRAME_EXTENDED) { } else if (frameType == Const.SAME_FRAME_EXTENDED) {
@@ -104,16 +105,16 @@ public final class StackMapEntry implements Node, Cloneable {
* DO NOT USE * DO NOT USE
* *
* @param byteCodeOffset * @param byteCodeOffset
* @param numberOfLocals NOT USED * @param numberOfLocals NOT USED
* @param typesOfLocals array of {@link StackMapType}s of locals * @param typesOfLocals array of {@link StackMapType}s of locals
* @param numberOfStackItems NOT USED * @param numberOfStackItems NOT USED
* @param typesOfStackItems array ot {@link StackMapType}s of stack items * @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool * @param constantPool the constant pool
* @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead * @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead
*/ */
@java.lang.Deprecated @java.lang.Deprecated
public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems, public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems,
final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
this.byteCodeOffset = byteCodeOffset; this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY; this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY; this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
@@ -129,14 +130,14 @@ public final class StackMapEntry implements Node, Cloneable {
/** /**
* Create an instance * Create an instance
* *
* @param tag the frameType to use * @param tag the frameType to use
* @param byteCodeOffset * @param byteCodeOffset
* @param typesOfLocals array of {@link StackMapType}s of locals * @param typesOfLocals array of {@link StackMapType}s of locals
* @param typesOfStackItems array ot {@link StackMapType}s of stack items * @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool * @param constantPool the constant pool
*/ */
public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems, public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems,
final ConstantPool constantPool) { final ConstantPool constantPool) {
this.frameType = tag; this.frameType = tag;
this.byteCodeOffset = byteCodeOffset; this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY; this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
@@ -215,6 +216,29 @@ public final class StackMapEntry implements Node, Cloneable {
return byteCodeOffset; return byteCodeOffset;
} }
public void setByteCodeOffset(final int newOffset) {
if (newOffset < 0 || newOffset > 32767) {
throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
}
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_FRAME_EXTENDED;
} else {
frameType = newOffset;
}
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
} else {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
}
} else if (invalidFrameType(frameType)) {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
byteCodeOffset = newOffset;
}
/** /**
* @return Constant pool used by this object. * @return Constant pool used by this object.
*/ */
@@ -222,13 +246,30 @@ public final class StackMapEntry implements Node, Cloneable {
return constantPool; return constantPool;
} }
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public int getFrameType() { public int getFrameType() {
return frameType; return frameType;
} }
public void setFrameType(final int ft) {
if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_FRAME;
} else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
} else if (invalidFrameType(ft)) {
throw new IllegalArgumentException("Invalid StackMap frameType");
}
frameType = ft;
}
/** /**
* Calculate stack map entry size * Calculate stack map entry size
*
*/ */
int getMapEntrySize() { int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) { if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
@@ -267,18 +308,40 @@ public final class StackMapEntry implements Node, Cloneable {
return typesOfLocals.length; return typesOfLocals.length;
} }
/**
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfLocals(final int n) { // TODO unused
}
public int getNumberOfStackItems() { public int getNumberOfStackItems() {
return typesOfStackItems.length; return typesOfStackItems.length;
} }
/**
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfStackItems(final int n) { // TODO unused
}
public StackMapType[] getTypesOfLocals() { public StackMapType[] getTypesOfLocals() {
return typesOfLocals; return typesOfLocals;
} }
public void setTypesOfLocals(final StackMapType[] types) {
typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
}
public StackMapType[] getTypesOfStackItems() { public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems; return typesOfStackItems;
} }
public void setTypesOfStackItems(final StackMapType[] types) {
typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
}
private boolean invalidFrameType(final int f) { private boolean invalidFrameType(final int f) {
// @formatter:off // @formatter:off
return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
@@ -289,71 +352,6 @@ public final class StackMapEntry implements Node, Cloneable {
// @formatter:on // @formatter:on
} }
public void setByteCodeOffset(final int newOffset) {
if (newOffset < 0 || newOffset > 32767) {
throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
}
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_FRAME_EXTENDED;
} else {
frameType = newOffset;
}
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
} else {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
}
} else if (invalidFrameType(frameType)) {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
byteCodeOffset = newOffset;
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public void setFrameType(final int ft) {
if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_FRAME;
} else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
} else if (invalidFrameType(ft)) {
throw new IllegalArgumentException("Invalid StackMap frameType");
}
frameType = ft;
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfLocals(final int n) { // TODO unused
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfStackItems(final int n) { // TODO unused
}
public void setTypesOfLocals(final StackMapType[] types) {
typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
}
public void setTypesOfStackItems(final StackMapType[] types) {
typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -38,7 +38,7 @@ public final class StackMapType implements Cloneable {
private ConstantPool constantPool; private ConstantPool constantPool;
/** /**
* @param type type tag as defined in the Constants interface * @param type type tag as defined in the Constants interface
* @param index index to constant pool, or byte code offset * @param index index to constant pool, or byte code offset
*/ */
public StackMapType(final byte type, final int index, final ConstantPool constantPool) { public StackMapType(final byte type, final int index, final ConstantPool constantPool) {
@@ -100,18 +100,33 @@ public final class StackMapType implements Cloneable {
return constantPool; return constantPool;
} }
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/** /**
* @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1 * @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
* otherwise * otherwise
*/ */
public int getIndex() { public int getIndex() {
return index; return index;
} }
public void setIndex(final int index) {
this.index = index;
}
public byte getType() { public byte getType() {
return type; return type;
} }
public void setType(final byte type) {
this.type = checkType(type);
}
/** /**
* @return true, if type is either ITEM_Object or ITEM_NewObject * @return true, if type is either ITEM_Object or ITEM_NewObject
*/ */
@@ -132,21 +147,6 @@ public final class StackMapType implements Cloneable {
return ""; return "";
} }
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public void setIndex(final int index) {
this.index = index;
}
public void setType(final byte type) {
this.type = checkType(type);
}
/** /**
* @return String representation * @return String representation
*/ */

View File

@@ -36,9 +36,9 @@ public final class Synthetic extends Attribute {
private byte[] bytes; private byte[] bytes;
/** /**
* @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic". * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic".
* @param length Content length in bytes - should be zero. * @param length Content length in bytes - should be zero.
* @param bytes Attribute contents * @param bytes Attribute contents
* @param constantPool The constant pool this attribute is associated with. * @param constantPool The constant pool this attribute is associated with.
*/ */
public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -49,9 +49,9 @@ public final class Synthetic extends Attribute {
/** /**
* Construct object from input stream. * 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

@@ -34,16 +34,15 @@ import java.util.Arrays;
*/ */
public final class Unknown extends Attribute { public final class Unknown extends Attribute {
private byte[] bytes;
private final String name; private final String name;
private byte[] bytes;
/** /**
* Constructs a new instance for a non-standard attribute. * Constructs a new instance for a non-standard attribute.
* *
* @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 bytes Attribute contents * @param bytes Attribute contents
* @param constantPool Array of constants * @param constantPool Array of constants
*/ */
public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) { public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -55,9 +54,9 @@ public final class Unknown extends Attribute {
/** /**
* Constructs a new instance from an input stream. * Constructs a new instance from an 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.
*/ */
@@ -123,6 +122,13 @@ public final class Unknown extends Attribute {
return bytes; return bytes;
} }
/**
* @param bytes the bytes to set
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/** /**
* @return name of attribute. * @return name of attribute.
*/ */
@@ -131,13 +137,6 @@ public final class Unknown extends Attribute {
return name; return name;
} }
/**
* @param bytes the bytes to set
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/** /**
* @return String representation. * @return String representation.
*/ */

View File

@@ -31,15 +31,13 @@ public interface UnknownAttributeReader {
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the * associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing. * name of the attributes it is constructing.
* *
* @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute. * @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
* @param length The length of the data contained in the attribute. This is written into the constant pool and should * @param length The length of the data contained in the attribute. This is written into the constant pool and should
* agree with what the factory expects the length to be. * agree with what the factory expects the length to be.
* @param file This is the data input that the factory needs to read its data from. * @param file This is the data input that the factory needs to read its data from.
* @param constantPool This is the constant pool associated with the Attribute that we are constructing. * @param constantPool This is the constant pool associated with the Attribute that we are constructing.
*
* @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of * @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of
* errors, a null can be returned which will cause the parsing of the class file to fail. * errors, a null can be returned which will cause the parsing of the class file to fail.
*
* @see Attribute#addAttributeReader(String, UnknownAttributeReader) * @see Attribute#addAttributeReader(String, UnknownAttributeReader)
*/ */
Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool); Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool);

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -28,11 +28,43 @@ import java.util.List;
public class AnnotationEntryGen { public class AnnotationEntryGen {
static final AnnotationEntryGen[] EMPTY_ARRAY = {}; static final AnnotationEntryGen[] EMPTY_ARRAY = {};
private final ConstantPoolGen cpool;
private int typeIndex;
private List<ElementValuePairGen> evs;
private boolean isRuntimeVisible;
/**
* Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool
* passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us
* to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name
* value pairs and the visibility.
*/
public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
this.cpool = cpool;
if (copyPoolEntries) {
typeIndex = cpool.addUtf8(a.getAnnotationType());
} else {
typeIndex = a.getAnnotationTypeIndex();
}
isRuntimeVisible = a.isRuntimeVisible();
evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
}
private AnnotationEntryGen(final ConstantPoolGen cpool) {
this.cpool = cpool;
}
public AnnotationEntryGen(final ObjectType type, final List<ElementValuePairGen> elements, final boolean vis, final ConstantPoolGen cpool) {
this.cpool = cpool;
this.typeIndex = cpool.addUtf8(type.getSignature());
evs = elements;
isRuntimeVisible = vis;
}
/** /**
* Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file. * Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file.
* *
* @param cp The constant pool gen where we can create the necessary name refs * @param cp The constant pool gen where we can create the necessary name refs
* @param annotationEntryGens An array of AnnotationGen objects * @param annotationEntryGens An array of AnnotationGen objects
*/ */
static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) { static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) {
@@ -86,11 +118,11 @@ public class AnnotationEntryGen {
final List<Attribute> newAttributes = new ArrayList<>(); final List<Attribute> newAttributes = new ArrayList<>();
if (rvaData.length > 2) { if (rvaData.length > 2) {
newAttributes newAttributes
.add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool())); .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool()));
} }
if (riaData.length > 2) { if (riaData.length > 2) {
newAttributes.add( newAttributes.add(
new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool())); new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool()));
} }
return newAttributes.toArray(Attribute.EMPTY_ARRAY); return newAttributes.toArray(Attribute.EMPTY_ARRAY);
@@ -106,7 +138,7 @@ public class AnnotationEntryGen {
* RuntimeInvisibleParameterAnnotations * RuntimeInvisibleParameterAnnotations
*/ */
static Attribute[] getParameterAnnotationAttributes(final ConstantPoolGen cp, static Attribute[] getParameterAnnotationAttributes(final ConstantPoolGen cp,
final List<AnnotationEntryGen>[] /* Array of lists, array size depends on #params */ vec) { final List<AnnotationEntryGen>[] /* Array of lists, array size depends on #params */ vec) {
final int[] visCount = new int[vec.length]; final int[] visCount = new int[vec.length];
int totalVisCount = 0; int totalVisCount = 0;
final int[] invisCount = new int[vec.length]; final int[] invisCount = new int[vec.length];
@@ -168,11 +200,11 @@ public class AnnotationEntryGen {
final List<Attribute> newAttributes = new ArrayList<>(); final List<Attribute> newAttributes = new ArrayList<>();
if (totalVisCount > 0) { if (totalVisCount > 0) {
newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)),
cp.getConstantPool())); cp.getConstantPool()));
} }
if (totalInvisCount > 0) { if (totalInvisCount > 0) {
newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)),
cp.getConstantPool())); cp.getConstantPool()));
} }
return newAttributes.toArray(Attribute.EMPTY_ARRAY); return newAttributes.toArray(Attribute.EMPTY_ARRAY);
} catch (final IOException e) { } catch (final IOException e) {
@@ -194,42 +226,6 @@ public class AnnotationEntryGen {
return a; return a;
} }
private int typeIndex;
private List<ElementValuePairGen> evs;
private final ConstantPoolGen cpool;
private boolean isRuntimeVisible;
/**
* Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool
* passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us
* to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name
* value pairs and the visibility.
*/
public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
this.cpool = cpool;
if (copyPoolEntries) {
typeIndex = cpool.addUtf8(a.getAnnotationType());
} else {
typeIndex = a.getAnnotationTypeIndex();
}
isRuntimeVisible = a.isRuntimeVisible();
evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
}
private AnnotationEntryGen(final ConstantPoolGen cpool) {
this.cpool = cpool;
}
public AnnotationEntryGen(final ObjectType type, final List<ElementValuePairGen> elements, final boolean vis, final ConstantPoolGen cpool) {
this.cpool = cpool;
this.typeIndex = cpool.addUtf8(type.getSignature());
evs = elements;
isRuntimeVisible = vis;
}
public void addElementNameValuePair(final ElementValuePairGen evp) { public void addElementNameValuePair(final ElementValuePairGen evp) {
if (evs == null) { if (evs == null) {
evs = new ArrayList<>(); evs = new ArrayList<>();

View File

@@ -43,48 +43,48 @@ public abstract class ArithmeticInstruction extends Instruction implements Typed
public Type getType(final ConstantPoolGen cp) { public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode(); final short opcode = super.getOpcode();
switch (opcode) { switch (opcode) {
case Const.DADD: case Const.DADD:
case Const.DDIV: case Const.DDIV:
case Const.DMUL: case Const.DMUL:
case Const.DNEG: case Const.DNEG:
case Const.DREM: case Const.DREM:
case Const.DSUB: case Const.DSUB:
return Type.DOUBLE; return Type.DOUBLE;
case Const.FADD: case Const.FADD:
case Const.FDIV: case Const.FDIV:
case Const.FMUL: case Const.FMUL:
case Const.FNEG: case Const.FNEG:
case Const.FREM: case Const.FREM:
case Const.FSUB: case Const.FSUB:
return Type.FLOAT; return Type.FLOAT;
case Const.IADD: case Const.IADD:
case Const.IAND: case Const.IAND:
case Const.IDIV: case Const.IDIV:
case Const.IMUL: case Const.IMUL:
case Const.INEG: case Const.INEG:
case Const.IOR: case Const.IOR:
case Const.IREM: case Const.IREM:
case Const.ISHL: case Const.ISHL:
case Const.ISHR: case Const.ISHR:
case Const.ISUB: case Const.ISUB:
case Const.IUSHR: case Const.IUSHR:
case Const.IXOR: case Const.IXOR:
return Type.INT; return Type.INT;
case Const.LADD: case Const.LADD:
case Const.LAND: case Const.LAND:
case Const.LDIV: case Const.LDIV:
case Const.LMUL: case Const.LMUL:
case Const.LNEG: case Const.LNEG:
case Const.LOR: case Const.LOR:
case Const.LREM: case Const.LREM:
case Const.LSHL: case Const.LSHL:
case Const.LSHR: case Const.LSHR:
case Const.LSUB: case Const.LSUB:
case Const.LUSHR: case Const.LUSHR:
case Const.LXOR: case Const.LXOR:
return Type.LONG; return Type.LONG;
default: // Never reached default: // Never reached
throw new ClassGenException("Unknown type " + opcode); throw new ClassGenException("Unknown type " + opcode);
} }
} }
} }

View File

@@ -49,32 +49,32 @@ public abstract class ArrayInstruction extends Instruction implements ExceptionT
public Type getType(final ConstantPoolGen cp) { public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode(); final short opcode = super.getOpcode();
switch (opcode) { switch (opcode) {
case Const.IALOAD: case Const.IALOAD:
case Const.IASTORE: case Const.IASTORE:
return Type.INT; return Type.INT;
case Const.CALOAD: case Const.CALOAD:
case Const.CASTORE: case Const.CASTORE:
return Type.CHAR; return Type.CHAR;
case Const.BALOAD: case Const.BALOAD:
case Const.BASTORE: case Const.BASTORE:
return Type.BYTE; return Type.BYTE;
case Const.SALOAD: case Const.SALOAD:
case Const.SASTORE: case Const.SASTORE:
return Type.SHORT; return Type.SHORT;
case Const.LALOAD: case Const.LALOAD:
case Const.LASTORE: case Const.LASTORE:
return Type.LONG; return Type.LONG;
case Const.DALOAD: case Const.DALOAD:
case Const.DASTORE: case Const.DASTORE:
return Type.DOUBLE; return Type.DOUBLE;
case Const.FALOAD: case Const.FALOAD:
case Const.FASTORE: case Const.FASTORE:
return Type.FLOAT; return Type.FLOAT;
case Const.AALOAD: case Const.AALOAD:
case Const.AASTORE: case Const.AASTORE:
return Type.OBJECT; return Type.OBJECT;
default: default:
throw new ClassGenException("Unknown case in switch" + opcode); throw new ClassGenException("Unknown case in switch" + opcode);
} }
} }
} }

View File

@@ -29,7 +29,7 @@ public final class ArrayType extends ReferenceType {
/** /**
* Convenience constructor for array type, e.g. int[] * Convenience constructor for array type, e.g. int[]
* *
* @param type array type, e.g. T_INT * @param type array type, e.g. T_INT
* @param dimensions array dimensions * @param dimensions array dimensions
*/ */
public ArrayType(final byte type, final int dimensions) { public ArrayType(final byte type, final int dimensions) {
@@ -39,7 +39,7 @@ public final class ArrayType extends ReferenceType {
/** /**
* Convenience constructor for reference array type, e.g. Object[] * Convenience constructor for reference array type, e.g. Object[]
* *
* @param className complete name of class (java.lang.String, e.g.) * @param className complete name of class (java.lang.String, e.g.)
* @param dimensions array dimensions * @param dimensions array dimensions
*/ */
public ArrayType(final String className, final int dimensions) { public ArrayType(final String className, final int dimensions) {
@@ -49,7 +49,7 @@ public final class ArrayType extends ReferenceType {
/** /**
* Constructor for array of given type * Constructor for array of given type
* *
* @param type type of array (may be an array itself) * @param type type of array (may be an array itself)
* @param dimensions array dimensions * @param dimensions array dimensions
*/ */
public ArrayType(final Type type, final int dimensions) { public ArrayType(final Type type, final int dimensions) {
@@ -58,17 +58,17 @@ public final class ArrayType extends ReferenceType {
throw new ClassGenException("Invalid number of dimensions: " + dimensions); throw new ClassGenException("Invalid number of dimensions: " + dimensions);
} }
switch (type.getType()) { switch (type.getType()) {
case Const.T_ARRAY: case Const.T_ARRAY:
final ArrayType array = (ArrayType) type; final ArrayType array = (ArrayType) type;
this.dimensions = dimensions + array.dimensions; this.dimensions = dimensions + array.dimensions;
basicType = array.basicType; basicType = array.basicType;
break; break;
case Const.T_VOID: case Const.T_VOID:
throw new ClassGenException("Invalid type: void[]"); throw new ClassGenException("Invalid type: void[]");
default: // Basic type or reference default: // Basic type or reference
this.dimensions = dimensions; this.dimensions = dimensions;
basicType = type; basicType = type;
break; break;
} }
final StringBuilder buf = new StringBuilder(); final StringBuilder buf = new StringBuilder();
for (int i = 0; i < this.dimensions; i++) { for (int i = 0; i < this.dimensions; i++) {

View File

@@ -23,32 +23,6 @@ import haidnor.jvm.bcel.Const;
*/ */
public final class BasicType extends Type { public final class BasicType extends Type {
// @since 6.0 no longer final
public static BasicType getType(final byte type) {
switch (type) {
case Const.T_VOID:
return VOID;
case Const.T_BOOLEAN:
return BOOLEAN;
case Const.T_BYTE:
return BYTE;
case Const.T_SHORT:
return SHORT;
case Const.T_CHAR:
return CHAR;
case Const.T_INT:
return INT;
case Const.T_LONG:
return LONG;
case Const.T_DOUBLE:
return DOUBLE;
case Const.T_FLOAT:
return FLOAT;
default:
throw new ClassGenException("Invalid type: " + type);
}
}
/** /**
* Constructor for basic types such as int, long, 'void' * Constructor for basic types such as int, long, 'void'
* *
@@ -62,6 +36,32 @@ public final class BasicType extends Type {
} }
} }
// @since 6.0 no longer final
public static BasicType getType(final byte type) {
switch (type) {
case Const.T_VOID:
return VOID;
case Const.T_BOOLEAN:
return BOOLEAN;
case Const.T_BYTE:
return BYTE;
case Const.T_SHORT:
return SHORT;
case Const.T_CHAR:
return CHAR;
case Const.T_INT:
return INT;
case Const.T_LONG:
return LONG;
case Const.T_DOUBLE:
return DOUBLE;
case Const.T_FLOAT:
return FLOAT;
default:
throw new ClassGenException("Invalid type: " + type);
}
}
/** /**
* @return true if both type objects refer to the same type * @return true if both type objects refer to the same type
*/ */

View File

@@ -26,13 +26,6 @@ package haidnor.jvm.bcel.generic;
*/ */
public final class BranchHandle extends InstructionHandle { public final class BranchHandle extends InstructionHandle {
/**
* Factory method.
*/
static BranchHandle getBranchHandle(final BranchInstruction i) {
return new BranchHandle(i);
}
// This is also a cache in case the InstructionHandle#swapInstruction() method is used // This is also a cache in case the InstructionHandle#swapInstruction() method is used
// See BCEL-273 // See BCEL-273
private BranchInstruction bi; // An alias in fact, but saves lots of casts private BranchInstruction bi; // An alias in fact, but saves lots of casts
@@ -42,6 +35,13 @@ public final class BranchHandle extends InstructionHandle {
bi = i; bi = i;
} }
/**
* Factory method.
*/
static BranchHandle getBranchHandle(final BranchInstruction i) {
return new BranchHandle(i);
}
/* /*
* Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private * Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private
* i_position field should be prevented. * i_position field should be prevented.
@@ -51,6 +51,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getPosition(); return bi.getPosition();
} }
@Override
void setPosition(final int pos) {
// Original code: i_position = bi.position = pos;
bi.setPosition(pos);
super.setPosition(pos);
}
/** /**
* @return target of instruction. * @return target of instruction.
*/ */
@@ -58,6 +65,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getTarget(); return bi.getTarget();
} }
/**
* Pass new target to instruction.
*/
public void setTarget(final InstructionHandle ih) {
bi.setTarget(ih);
}
/** /**
* Set new contents. Old instruction is disposed and may not be used anymore. * Set new contents. Old instruction is disposed and may not be used anymore.
*/ */
@@ -70,20 +84,6 @@ public final class BranchHandle extends InstructionHandle {
bi = (BranchInstruction) i; bi = (BranchInstruction) i;
} }
@Override
void setPosition(final int pos) {
// Original code: i_position = bi.position = pos;
bi.setPosition(pos);
super.setPosition(pos);
}
/**
* Pass new target to instruction.
*/
public void setTarget(final InstructionHandle ih) {
bi.setTarget(ih);
}
@Override @Override
protected int updatePosition(final int offset, final int maxOffset) { protected int updatePosition(final int offset, final int maxOffset) {
final int x = bi.updatePosition(offset, maxOffset); final int x = bi.updatePosition(offset, maxOffset);

View File

@@ -29,30 +29,16 @@ import java.io.IOException;
*/ */
public abstract class BranchInstruction extends Instruction implements InstructionTargeter { public abstract class BranchInstruction extends Instruction implements InstructionTargeter {
/**
* Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen
*/
static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) {
if (oldIh != null) {
oldIh.removeTargeter(t);
}
if (newIh != null) {
newIh.addTargeter(t);
}
}
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected int index; // Branch target relative to this instruction protected int index; // Branch target relative to this instruction
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected InstructionHandle target; // Target object in instruction list protected InstructionHandle target; // Target object in instruction list
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@@ -76,6 +62,18 @@ public abstract class BranchInstruction extends Instruction implements Instructi
setTarget(target); setTarget(target);
} }
/**
* Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen
*/
static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) {
if (oldIh != null) {
oldIh.removeTargeter(t);
}
if (newIh != null) {
newIh.addTargeter(t);
}
}
/** /**
* @return true, if ih is target of this instruction * @return true, if ih is target of this instruction
*/ */
@@ -116,6 +114,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return index; return index;
} }
/**
* @param index the index to set
* @since 6.0
*/
protected void setIndex(final int index) {
this.index = index;
}
/** /**
* @return the position * @return the position
* @since 6.0 * @since 6.0
@@ -124,6 +130,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return position; return position;
} }
/**
* @param position the position to set
* @since 6.0
*/
protected void setPosition(final int position) {
this.position = position;
}
/** /**
* @return target of branch instruction * @return target of branch instruction
*/ */
@@ -131,6 +145,16 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return target; return target;
} }
/**
* Set branch target
*
* @param target branch target
*/
public void setTarget(final InstructionHandle target) {
notifyTarget(this.target, target, this);
this.target = target;
}
/** /**
* @return the offset to this instruction's target * @return the offset to this instruction's target
*/ */
@@ -157,7 +181,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi
* Read needed data (e.g. index) from file. Conversion to a InstructionHandle is done in InstructionList(byte[]). * Read needed data (e.g. index) from file. Conversion to a InstructionHandle is done in InstructionList(byte[]).
* *
* @param bytes input stream * @param bytes input stream
* @param wide wide prefix? * @param wide wide prefix?
* @see InstructionList * @see InstructionList
*/ */
@Override @Override
@@ -166,35 +190,9 @@ public abstract class BranchInstruction extends Instruction implements Instructi
index = bytes.readShort(); index = bytes.readShort();
} }
/**
* @param index the index to set
* @since 6.0
*/
protected void setIndex(final int index) {
this.index = index;
}
/**
* @param position the position to set
* @since 6.0
*/
protected void setPosition(final int position) {
this.position = position;
}
/**
* Set branch target
*
* @param target branch target
*/
public void setTarget(final InstructionHandle target) {
notifyTarget(this.target, target, this);
this.target = target;
}
/** /**
* Long output format: * Long output format:
* * <p>
* &lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" * &lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")"
* "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt; * "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt;
* *
@@ -232,7 +230,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi
* length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte) * length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte)
* positions and offsets by calling this function. * positions and offsets by calling this function.
* *
* @param offset additional offset caused by preceding (variable length) instructions * @param offset additional offset caused by preceding (variable length) instructions
* @param maxOffset the maximum offset that may be caused by these instructions * @param maxOffset the maximum offset that may be caused by these instructions
* @return additional offset caused by possible change of this instruction's length * @return additional offset caused by possible change of this instruction's length
*/ */

View File

@@ -74,6 +74,19 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
return index; return index;
} }
/**
* Set the index to constant pool.
*
* @param index in constant pool.
*/
@Override
public void setIndex(final int index) { // TODO could be package-protected?
if (index < 0) {
throw new ClassGenException("Negative index value: " + index);
}
this.index = index;
}
/** /**
* @return type related with this instruction. * @return type related with this instruction.
*/ */
@@ -91,7 +104,7 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
* Read needed data (i.e., index) from file. * Read needed data (i.e., index) from file.
* *
* @param bytes input stream * @param bytes input stream
* @param wide wide prefix? * @param wide wide prefix?
*/ */
@Override @Override
protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
@@ -99,22 +112,9 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
super.setLength(3); super.setLength(3);
} }
/**
* Set the index to constant pool.
*
* @param index in constant pool.
*/
@Override
public void setIndex(final int index) { // TODO could be package-protected?
if (index < 0) {
throw new ClassGenException("Negative index value: " + index);
}
this.index = index;
}
/** /**
* Long output format: * Long output format:
* * <p>
* &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" "&lt;"&lt; constant pool * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" "&lt;"&lt; constant pool
* index&gt;"&gt;" * index&gt;"&gt;"
* *

View File

@@ -45,42 +45,23 @@ public class ClassGen extends AccessFlags implements Cloneable {
return THIS.getClassName().hashCode(); return THIS.getClassName().hashCode();
} }
}; };
private final String fileName;
/** // ArrayLists instead of arrays to gather fields, methods, etc.
* @return Comparison strategy object private final List<JavaField> fieldList = new ArrayList<>();
*/ private final List<JavaMethod> methodList = new ArrayList<>();
public static BCELComparator getComparator() { private final List<Attribute> attributeList = new ArrayList<>();
return bcelComparator; private final List<String> interfaceList = new ArrayList<>();
} private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/* /*
* Corresponds to the fields found in a JavaClass object. * Corresponds to the fields found in a JavaClass object.
*/ */
private String className; private String className;
private String superClassName; private String superClassName;
private final String fileName;
private int classNameIndex = -1; private int classNameIndex = -1;
private int superclassNameIndex = -1; private int superclassNameIndex = -1;
private int major = Const.MAJOR_1_1; private int major = Const.MAJOR_1_1;
private int minor = Const.MINOR_1_1; private int minor = Const.MINOR_1_1;
private ConstantPoolGen cp; // Template for building up constant pool private ConstantPoolGen cp; // Template for building up constant pool
// ArrayLists instead of arrays to gather fields, methods, etc.
private final List<JavaField> fieldList = new ArrayList<>();
private final List<JavaMethod> methodList = new ArrayList<>();
private final List<Attribute> attributeList = new ArrayList<>();
private final List<String> interfaceList = new ArrayList<>();
private final List<AnnotationEntryGen> annotationList = new ArrayList<>();
private List<ClassObserver> observers; private List<ClassObserver> observers;
/** /**
@@ -115,11 +96,11 @@ public class ClassGen extends AccessFlags implements Cloneable {
/** /**
* Convenience constructor to set up some important values initially. * Convenience constructor to set up some important values initially.
* *
* @param className fully qualified class name * @param className fully qualified class name
* @param superClassName fully qualified superclass name * @param superClassName fully qualified superclass name
* @param fileName source file name * @param fileName source file name
* @param accessFlags access qualifiers * @param accessFlags access qualifiers
* @param interfaces implemented interfaces * @param interfaces implemented interfaces
*/ */
public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces) { public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces) {
this(className, superClassName, fileName, accessFlags, interfaces, new ConstantPoolGen()); this(className, superClassName, fileName, accessFlags, interfaces, new ConstantPoolGen());
@@ -128,15 +109,15 @@ public class ClassGen extends AccessFlags implements Cloneable {
/** /**
* Convenience constructor to set up some important values initially. * Convenience constructor to set up some important values initially.
* *
* @param className fully qualified class name * @param className fully qualified class name
* @param superClassName fully qualified superclass name * @param superClassName fully qualified superclass name
* @param fileName source file name * @param fileName source file name
* @param accessFlags access qualifiers * @param accessFlags access qualifiers
* @param interfaces implemented interfaces * @param interfaces implemented interfaces
* @param cp constant pool to use * @param cp constant pool to use
*/ */
public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces, public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces,
final ConstantPoolGen cp) { final ConstantPoolGen cp) {
super(accessFlags); super(accessFlags);
this.className = className; this.className = className;
this.superClassName = superClassName; this.superClassName = superClassName;
@@ -153,6 +134,20 @@ public class ClassGen extends AccessFlags implements Cloneable {
} }
} }
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
public void addAnnotationEntry(final AnnotationEntryGen a) { public void addAnnotationEntry(final AnnotationEntryGen a) {
annotationList.add(a); annotationList.add(a);
} }
@@ -168,7 +163,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
/** /**
* Convenience method. * Convenience method.
* * <p>
* Add an empty constructor to this class that does nothing but calling super(). * Add an empty constructor to this class that does nothing but calling super().
* *
* @param accessFlags rights for constructor * @param accessFlags rights for constructor
@@ -281,14 +276,28 @@ public class ClassGen extends AccessFlags implements Cloneable {
return className; return className;
} }
public void setClassName(final String name) {
className = Utility.pathToPackage(name);
classNameIndex = cp.addClass(name);
}
public int getClassNameIndex() { public int getClassNameIndex() {
return classNameIndex; return classNameIndex;
} }
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class));
}
public ConstantPoolGen getConstantPool() { public ConstantPoolGen getConstantPool() {
return cp; return cp;
} }
public void setConstantPool(final ConstantPoolGen constantPool) {
cp = constantPool;
}
public JavaField[] getFields() { public JavaField[] getFields() {
return fieldList.toArray(JavaField.EMPTY_ARRAY); return fieldList.toArray(JavaField.EMPTY_ARRAY);
} }
@@ -328,7 +337,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
// Must be last since the above calls may still add something to it // Must be last since the above calls may still add something to it
final ConstantPool cp = this.cp.getFinalConstantPool(); final ConstantPool cp = this.cp.getFinalConstantPool();
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, super.getAccessFlags(), cp, interfaces, fields, methods, return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, super.getAccessFlags(), cp, interfaces, fields, methods,
attributes); attributes);
} }
/** /**
@@ -338,6 +347,15 @@ public class ClassGen extends AccessFlags implements Cloneable {
return major; return major;
} }
/**
* Set major version number of class file, default value is 45 (JDK 1.1)
*
* @param major major version number
*/
public void setMajor(final int major) { // TODO could be package-protected - only called by test code
this.major = major;
}
public JavaMethod getMethodAt(final int pos) { public JavaMethod getMethodAt(final int pos) {
return methodList.get(pos); return methodList.get(pos);
} }
@@ -346,6 +364,11 @@ public class ClassGen extends AccessFlags implements Cloneable {
return methodList.toArray(JavaMethod.EMPTY_ARRAY); return methodList.toArray(JavaMethod.EMPTY_ARRAY);
} }
public void setMethods(final JavaMethod[] methods) {
methodList.clear();
Collections.addAll(methodList, methods);
}
/** /**
* @return minor version number of class file * @return minor version number of class file
*/ */
@@ -353,14 +376,33 @@ public class ClassGen extends AccessFlags implements Cloneable {
return minor; return minor;
} }
/**
* Set minor version number of class file, default value is 3 (JDK 1.1)
*
* @param minor minor version number
*/
public void setMinor(final int minor) { // TODO could be package-protected - only called by test code
this.minor = minor;
}
public String getSuperclassName() { public String getSuperclassName() {
return superClassName; return superClassName;
} }
public void setSuperclassName(final String name) {
superClassName = Utility.pathToPackage(name);
superclassNameIndex = cp.addClass(name);
}
public int getSuperclassNameIndex() { public int getSuperclassNameIndex() {
return superclassNameIndex; return superclassNameIndex;
} }
public void setSuperclassNameIndex(final int superclassNameIndex) {
this.superclassNameIndex = superclassNameIndex;
superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class));
}
/** /**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
* *
@@ -446,57 +488,10 @@ public class ClassGen extends AccessFlags implements Cloneable {
} }
} }
public void setClassName(final String name) {
className = Utility.pathToPackage(name);
classNameIndex = cp.addClass(name);
}
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class));
}
public void setConstantPool(final ConstantPoolGen constantPool) {
cp = constantPool;
}
/**
* Set major version number of class file, default value is 45 (JDK 1.1)
*
* @param major major version number
*/
public void setMajor(final int major) { // TODO could be package-protected - only called by test code
this.major = major;
}
public void setMethodAt(final JavaMethod method, final int pos) { public void setMethodAt(final JavaMethod method, final int pos) {
methodList.set(pos, method); methodList.set(pos, method);
} }
public void setMethods(final JavaMethod[] methods) {
methodList.clear();
Collections.addAll(methodList, methods);
}
/**
* Set minor version number of class file, default value is 3 (JDK 1.1)
*
* @param minor minor version number
*/
public void setMinor(final int minor) { // TODO could be package-protected - only called by test code
this.minor = minor;
}
public void setSuperclassName(final String name) {
superClassName = Utility.pathToPackage(name);
superclassNameIndex = cp.addClass(name);
}
public void setSuperclassNameIndex(final int superclassNameIndex) {
this.superclassNameIndex = superclassNameIndex;
superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class));
}
/** /**
* Look for attributes representing annotations and unpack them. * Look for attributes representing annotations and unpack them.
*/ */

View File

@@ -42,8 +42,8 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
* Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling * Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
* is done. * is done.
* *
* @param startPc Start of handled region (inclusive) * @param startPc Start of handled region (inclusive)
* @param endPc End of handled region (inclusive) * @param endPc End of handled region (inclusive)
* @param handlerPc Where handling is done * @param handlerPc Where handling is done
* @param catchType which exception is handled, null for ANY * @param catchType which exception is handled, null for ANY
*/ */
@@ -71,14 +71,23 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return startPc == ih || endPc == ih || handlerPc == ih; return startPc == ih || endPc == ih || handlerPc == ih;
} }
/** Gets the type of the Exception to catch, 'null' for ANY. */ /**
* Gets the type of the Exception to catch, 'null' for ANY.
*/
public ObjectType getCatchType() { public ObjectType getCatchType() {
return catchType; return catchType;
} }
/**
* Sets the type of the Exception to catch. Set 'null' for ANY.
*/
public void setCatchType(final ObjectType catchType) {
this.catchType = catchType;
}
/** /**
* Get CodeException object.<BR> * Get CodeException object.<BR>
* * <p>
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list. * has been called for the instruction list.
* *
@@ -86,7 +95,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
*/ */
public CodeException getCodeException(final ConstantPoolGen cp) { public CodeException getCodeException(final ConstantPoolGen cp) {
return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(), return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(),
catchType == null ? 0 : cp.addClass(catchType)); catchType == null ? 0 : cp.addClass(catchType));
} }
/** /**
@@ -96,25 +105,6 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return endPc; return endPc;
} }
/**
* @return start of handler
*/
public InstructionHandle getHandlerPC() {
return handlerPc;
}
/**
* @return start of handled region (inclusive)
*/
public InstructionHandle getStartPC() {
return startPc;
}
/** Sets the type of the Exception to catch. Set 'null' for ANY. */
public void setCatchType(final ObjectType catchType) {
this.catchType = catchType;
}
/* /*
* Set end of handler * Set end of handler
* *
@@ -125,6 +115,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.endPc = endPc; this.endPc = endPc;
} }
/**
* @return start of handler
*/
public InstructionHandle getHandlerPC() {
return handlerPc;
}
/* /*
* Set handler code * Set handler code
* *
@@ -135,6 +132,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.handlerPc = handlerPc; this.handlerPc = handlerPc;
} }
/**
* @return start of handled region (inclusive)
*/
public InstructionHandle getStartPC() {
return startPc;
}
/* /*
* Set start of handler * Set start of handler
* *

View File

@@ -21,7 +21,7 @@ package haidnor.jvm.bcel.generic;
* meaning. For example, the (virtual) PUSH instruction takes an arbitrary argument and produces the appropriate code at * meaning. For example, the (virtual) PUSH instruction takes an arbitrary argument and produces the appropriate code at
* dump time (ICONST, LDC, BIPUSH, ...). Also you can use the SWITCH instruction as a useful template for either * dump time (ICONST, LDC, BIPUSH, ...). Also you can use the SWITCH instruction as a useful template for either
* LOOKUPSWITCH or TABLESWITCH. * LOOKUPSWITCH or TABLESWITCH.
* * <p>
* The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns. * The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns.
* *
* @see PUSH * @see PUSH

View File

@@ -44,35 +44,27 @@ public class ConstantPoolGen {
private static final String FIELDREF_DELIM = "&"; private static final String FIELDREF_DELIM = "&";
private static final String NAT_DELIM = "%"; // Name and Type private static final String NAT_DELIM = "%"; // Name and Type
private final Map<String, Integer> stringTable = new HashMap<>();
private final Map<String, Integer> classTable = new HashMap<>();
private final Map<String, Integer> utf8Table = new HashMap<>();
private final Map<String, Integer> natTable = new HashMap<>();
private final Map<String, Integer> cpTable = new HashMap<>();
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected int size; protected int size;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/ */
@Deprecated @Deprecated
protected Constant[] constants; protected Constant[] constants;
/** /**
* @deprecated (since 6.0) will be made private; do not access directly, use getSize() * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
*/ */
@Deprecated @Deprecated
protected int index = 1; // First entry (0) used by JVM protected int index = 1; // First entry (0) used by JVM
private final Map<String, Integer> stringTable = new HashMap<>();
private final Map<String, Integer> classTable = new HashMap<>();
private final Map<String, Integer> utf8Table = new HashMap<>();
private final Map<String, Integer> natTable = new HashMap<>();
private final Map<String, Integer> cpTable = new HashMap<>();
/** /**
* Constructs a new empty constant pool. * Constructs a new empty constant pool.
*/ */
@@ -255,63 +247,63 @@ public class ConstantPoolGen {
* Adds a constant from another ConstantPool and returns the new index. * Adds a constant from another ConstantPool and returns the new index.
* *
* @param constant The constant to add. * @param constant The constant to add.
* @param cpGen Source pool. * @param cpGen Source pool.
* @return index of entry * @return index of entry
*/ */
public int addConstant(final Constant constant, final ConstantPoolGen cpGen) { public int addConstant(final Constant constant, final ConstantPoolGen cpGen) {
final Constant[] constants = cpGen.getConstantPool().getConstantPool(); final Constant[] constants = cpGen.getConstantPool().getConstantPool();
switch (constant.getTag()) { switch (constant.getTag()) {
case Const.CONSTANT_String: { case Const.CONSTANT_String: {
final ConstantString s = (ConstantString) constant; final ConstantString s = (ConstantString) constant;
final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()]; final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
return addString(u8.getBytes()); return addString(u8.getBytes());
} }
case Const.CONSTANT_Class: { case Const.CONSTANT_Class: {
final ConstantClass s = (ConstantClass) constant; final ConstantClass s = (ConstantClass) constant;
final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()]; final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
return addClass(u8.getBytes()); return addClass(u8.getBytes());
} }
case Const.CONSTANT_NameAndType: { case Const.CONSTANT_NameAndType: {
final ConstantNameAndType n = (ConstantNameAndType) constant; final ConstantNameAndType n = (ConstantNameAndType) constant;
final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()]; final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()]; final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
return addNameAndType(u8.getBytes(), u8_2.getBytes()); return addNameAndType(u8.getBytes(), u8_2.getBytes());
} }
case Const.CONSTANT_Utf8: case Const.CONSTANT_Utf8:
return addUtf8(((ConstantUtf8) constant).getBytes()); return addUtf8(((ConstantUtf8) constant).getBytes());
case Const.CONSTANT_Double: case Const.CONSTANT_Double:
return addDouble(((ConstantDouble) constant).getBytes()); return addDouble(((ConstantDouble) constant).getBytes());
case Const.CONSTANT_Float: case Const.CONSTANT_Float:
return addFloat(((ConstantFloat) constant).getBytes()); return addFloat(((ConstantFloat) constant).getBytes());
case Const.CONSTANT_Long: case Const.CONSTANT_Long:
return addLong(((ConstantLong) constant).getBytes()); return addLong(((ConstantLong) constant).getBytes());
case Const.CONSTANT_Integer: case Const.CONSTANT_Integer:
return addInteger(((ConstantInteger) constant).getBytes()); return addInteger(((ConstantInteger) constant).getBytes());
case Const.CONSTANT_InterfaceMethodref:
case Const.CONSTANT_Methodref:
case Const.CONSTANT_Fieldref: {
final ConstantCP m = (ConstantCP) constant;
final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
final String className = Utility.pathToPackage(u8.getBytes());
u8 = (ConstantUtf8) constants[n.getNameIndex()];
final String name = u8.getBytes();
u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
final String signature = u8.getBytes();
switch (constant.getTag()) {
case Const.CONSTANT_InterfaceMethodref: case Const.CONSTANT_InterfaceMethodref:
return addInterfaceMethodref(className, name, signature);
case Const.CONSTANT_Methodref: case Const.CONSTANT_Methodref:
return addMethodref(className, name, signature); case Const.CONSTANT_Fieldref: {
case Const.CONSTANT_Fieldref: final ConstantCP m = (ConstantCP) constant;
return addFieldref(className, name, signature); final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
final String className = Utility.pathToPackage(u8.getBytes());
u8 = (ConstantUtf8) constants[n.getNameIndex()];
final String name = u8.getBytes();
u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
final String signature = u8.getBytes();
switch (constant.getTag()) {
case Const.CONSTANT_InterfaceMethodref:
return addInterfaceMethodref(className, name, signature);
case Const.CONSTANT_Methodref:
return addMethodref(className, name, signature);
case Const.CONSTANT_Fieldref:
return addFieldref(className, name, signature);
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + constant);
}
}
default: // Never reached default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + constant); throw new IllegalArgumentException("Unknown constant type " + constant);
}
}
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + constant);
} }
} }
@@ -395,9 +387,9 @@ public class ConstantPoolGen {
/** /**
* Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there. * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
* *
* @param className class name string to add * @param className class name string to add
* @param methodName method name string to add * @param methodName method name string to add
* @param signature signature string to add * @param signature signature string to add
* @return index of entry * @return index of entry
*/ */
public int addInterfaceMethodref(final String className, final String methodName, final String signature) { public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
@@ -430,6 +422,7 @@ public class ConstantPoolGen {
index += 2; // Wastes one entry according to spec index += 2; // Wastes one entry according to spec
return ret; return ret;
} }
public int addMethodref(final MethodGen method) { public int addMethodref(final MethodGen method) {
return addMethodref(method.getClassName(), method.getName(), method.getSignature()); return addMethodref(method.getClassName(), method.getName(), method.getSignature());
} }
@@ -437,9 +430,9 @@ public class ConstantPoolGen {
/** /**
* Add a new Methodref constant to the ConstantPool, if it is not already in there. * Add a new Methodref constant to the ConstantPool, if it is not already in there.
* *
* @param className class name string to add * @param className class name string to add
* @param methodName method name string to add * @param methodName method name string to add
* @param signature method signature string to add * @param signature method signature string to add
* @return index of entry * @return index of entry
*/ */
public int addMethodref(final String className, final String methodName, final String signature) { public int addMethodref(final String className, final String methodName, final String signature) {
@@ -458,7 +451,7 @@ public class ConstantPoolGen {
/** /**
* Add a new NameAndType constant to the ConstantPool if it is not already in there. * Add a new NameAndType constant to the ConstantPool if it is not already in there.
* *
* @param name Name string to add * @param name Name string to add
* @param signature signature string to add * @param signature signature string to add
* @return index of entry * @return index of entry
*/ */
@@ -654,9 +647,9 @@ public class ConstantPoolGen {
/** /**
* Look for ConstantInterfaceMethodref in ConstantPool. * Look for ConstantInterfaceMethodref in ConstantPool.
* *
* @param className Where to find method * @param className Where to find method
* @param methodName Guess what * @param methodName Guess what
* @param signature return and argument types * @param signature return and argument types
* @return index on success, -1 otherwise * @return index on success, -1 otherwise
*/ */
public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) { public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
@@ -688,9 +681,9 @@ public class ConstantPoolGen {
/** /**
* Look for ConstantMethodref in ConstantPool. * Look for ConstantMethodref in ConstantPool.
* *
* @param className Where to find method * @param className Where to find method
* @param methodName Guess what * @param methodName Guess what
* @param signature return and argument types * @param signature return and argument types
* @return index on success, -1 otherwise * @return index on success, -1 otherwise
*/ */
public int lookupMethodref(final String className, final String methodName, final String signature) { public int lookupMethodref(final String className, final String methodName, final String signature) {
@@ -700,7 +693,7 @@ public class ConstantPoolGen {
/** /**
* Look for ConstantNameAndType in ConstantPool. * Look for ConstantNameAndType in ConstantPool.
* *
* @param name of variable/method * @param name of variable/method
* @param signature of variable/method * @param signature of variable/method
* @return index on success, -1 otherwise * @return index on success, -1 otherwise
*/ */

View File

@@ -19,7 +19,6 @@ package haidnor.jvm.bcel.generic;
/** /**
* Denotes a push instruction that produces a literal on the stack such as SIPUSH, BIPUSH, ICONST, etc. * Denotes a push instruction that produces a literal on the stack such as SIPUSH, BIPUSH, ICONST, etc.
* *
*
* @see ICONST * @see ICONST
* @see SIPUSH * @see SIPUSH
*/ */

View File

@@ -43,30 +43,30 @@ public abstract class ConversionInstruction extends Instruction implements Typed
public Type getType(final ConstantPoolGen cp) { public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode(); final short opcode = super.getOpcode();
switch (opcode) { switch (opcode) {
case Const.D2I: case Const.D2I:
case Const.F2I: case Const.F2I:
case Const.L2I: case Const.L2I:
return Type.INT; return Type.INT;
case Const.D2F: case Const.D2F:
case Const.I2F: case Const.I2F:
case Const.L2F: case Const.L2F:
return Type.FLOAT; return Type.FLOAT;
case Const.D2L: case Const.D2L:
case Const.F2L: case Const.F2L:
case Const.I2L: case Const.I2L:
return Type.LONG; return Type.LONG;
case Const.F2D: case Const.F2D:
case Const.I2D: case Const.I2D:
case Const.L2D: case Const.L2D:
return Type.DOUBLE; return Type.DOUBLE;
case Const.I2B: case Const.I2B:
return Type.BYTE; return Type.BYTE;
case Const.I2C: case Const.I2C:
return Type.CHAR; return Type.CHAR;
case Const.I2S: case Const.I2S:
return Type.SHORT; return Type.SHORT;
default: // Never reached default: // Never reached
throw new ClassGenException("Unknown type " + opcode); throw new ClassGenException("Unknown type " + opcode);
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -52,83 +52,11 @@ public abstract class ElementValueGen {
public static final int PRIMITIVE_SHORT = 'S'; public static final int PRIMITIVE_SHORT = 'S';
public static final int PRIMITIVE_BOOLEAN = 'Z'; public static final int PRIMITIVE_BOOLEAN = 'Z';
/**
* Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct.
*/
public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
switch (value.getElementValueType()) {
case 'B': // byte
case 'C': // char
case 'D': // double
case 'F': // float
case 'I': // int
case 'J': // long
case 'S': // short
case 'Z': // boolean
case 's': // String
return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries);
case 'e': // Enum constant
return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries);
case '@': // Annotation
return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries);
case '[': // Array
return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries);
case 'c': // Class
return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries);
default:
throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")");
}
}
public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException {
final int type = dis.readUnsignedByte();
switch (type) {
case 'B': // byte
return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen);
case 'C': // char
return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen);
case 'D': // double
return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen);
case 'F': // float
return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen);
case 'I': // int
return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen);
case 'J': // long
return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen);
case 'S': // short
return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen);
case 'Z': // boolean
return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen);
case 's': // String
return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen);
case 'e': // Enum constant
return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen);
case 'c': // Class
return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
case '@': // Annotation
// TODO: isRuntimeVisible ??????????
// FIXME
return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false),
cpGen);
case '[': // Array
final int numArrayVals = dis.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool());
}
return new ArrayElementValueGen(ARRAY, evalues, cpGen);
default:
throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type);
}
}
/** /**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/ */
@Deprecated @Deprecated
protected int type; protected int type;
/** /**
* @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
*/ */
@@ -140,6 +68,76 @@ public abstract class ElementValueGen {
this.cpGen = cpGen; this.cpGen = cpGen;
} }
/**
* Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct.
*/
public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
switch (value.getElementValueType()) {
case 'B': // byte
case 'C': // char
case 'D': // double
case 'F': // float
case 'I': // int
case 'J': // long
case 'S': // short
case 'Z': // boolean
case 's': // String
return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries);
case 'e': // Enum constant
return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries);
case '@': // Annotation
return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries);
case '[': // Array
return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries);
case 'c': // Class
return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries);
default:
throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")");
}
}
public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException {
final int type = dis.readUnsignedByte();
switch (type) {
case 'B': // byte
return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen);
case 'C': // char
return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen);
case 'D': // double
return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen);
case 'F': // float
return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen);
case 'I': // int
return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen);
case 'J': // long
return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen);
case 'S': // short
return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen);
case 'Z': // boolean
return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen);
case 's': // String
return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen);
case 'e': // Enum constant
return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen);
case 'c': // Class
return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
case '@': // Annotation
// TODO: isRuntimeVisible ??????????
// FIXME
return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false),
cpGen);
case '[': // Array
final int numArrayVals = dis.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool());
}
return new ArrayElementValueGen(ARRAY, evalues, cpGen);
default:
throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type);
}
}
public abstract void dump(DataOutputStream dos) throws IOException; public abstract void dump(DataOutputStream dos) throws IOException;
protected ConstantPoolGen getConstantPool() { protected ConstantPoolGen getConstantPool() {

View File

@@ -36,9 +36,9 @@ public class EnumElementValueGen extends ElementValueGen {
super(ENUM_CONSTANT, cpool); super(ENUM_CONSTANT, cpool);
if (copyPoolEntries) { if (copyPoolEntries) {
typeIdx = cpool.addUtf8(value.getEnumTypeString());// was typeIdx = cpool.addUtf8(value.getEnumTypeString());// was
// addClass(value.getEnumTypeString()); // addClass(value.getEnumTypeString());
valueIdx = cpool.addUtf8(value.getEnumValueString()); // was valueIdx = cpool.addUtf8(value.getEnumValueString()); // was
// addString(value.getEnumValueString()); // addString(value.getEnumValueString());
} else { } else {
typeIdx = value.getTypeIndex(); typeIdx = value.getTypeIndex();
valueIdx = value.getValueIndex(); valueIdx = value.getValueIndex();

View File

@@ -19,11 +19,11 @@ package haidnor.jvm.bcel.generic;
/** /**
* Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite * Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite
* the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted. * the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted.
* * <p>
* The Lava Language Specification specifies exactly which <i>RUN-TIME</i> and which <i>LINKING</i> exceptions each * The Lava Language Specification specifies exactly which <i>RUN-TIME</i> and which <i>LINKING</i> exceptions each
* instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may * instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may
* be possible that an Instruction implementing this interface returns a Class[] of size 0. * be possible that an Instruction implementing this interface returns a Class[] of size 0.
* * <p>
* Please note that we speak of an "exception" here when we mean any "Throwable" object; so this term is equally used * Please note that we speak of an "exception" here when we mean any "Throwable" object; so this term is equally used
* for "Exception" and "Error" objects. * for "Exception" and "Error" objects.
*/ */

View File

@@ -48,30 +48,14 @@ public class FieldGen extends FieldGenOrMethodGen {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
} }
}; };
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
private Object value; private Object value;
private List<FieldObserver> observers; private List<FieldObserver> observers;
/** /**
* Instantiate from existing field. * Instantiate from existing field.
* *
* @param field Field object * @param field Field object
* @param cp constant pool (must contain the same entries as the field's constant pool) * @param cp constant pool (must contain the same entries as the field's constant pool)
*/ */
public FieldGen(final JavaField field, final ConstantPoolGen cp) { public FieldGen(final JavaField field, final ConstantPoolGen cp) {
this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
@@ -93,9 +77,9 @@ public class FieldGen extends FieldGenOrMethodGen {
* value associated with it as defined by setInitValue(). * value associated with it as defined by setInitValue().
* *
* @param accessFlags access qualifiers * @param accessFlags access qualifiers
* @param type field type * @param type field type
* @param name field name * @param name field name
* @param cp constant pool * @param cp constant pool
*/ */
public FieldGen(final int accessFlags, final Type type, final String name, final ConstantPoolGen cp) { public FieldGen(final int accessFlags, final Type type, final String name, final ConstantPoolGen cp) {
super(accessFlags); super(accessFlags);
@@ -104,28 +88,42 @@ public class FieldGen extends FieldGenOrMethodGen {
setConstantPool(cp); setConstantPool(cp);
} }
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
private void addAnnotationsAsAttribute(final ConstantPoolGen cp) { private void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute); Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute);
} }
private int addConstant() { private int addConstant() {
switch (super.getType().getType()) { // sic switch (super.getType().getType()) { // sic
case Const.T_INT: case Const.T_INT:
case Const.T_CHAR: case Const.T_CHAR:
case Const.T_BYTE: case Const.T_BYTE:
case Const.T_BOOLEAN: case Const.T_BOOLEAN:
case Const.T_SHORT: case Const.T_SHORT:
return super.getConstantPool().addInteger(((Integer) value).intValue()); return super.getConstantPool().addInteger(((Integer) value).intValue());
case Const.T_FLOAT: case Const.T_FLOAT:
return super.getConstantPool().addFloat(((Float) value).floatValue()); return super.getConstantPool().addFloat(((Float) value).floatValue());
case Const.T_DOUBLE: case Const.T_DOUBLE:
return super.getConstantPool().addDouble(((Double) value).doubleValue()); return super.getConstantPool().addDouble(((Double) value).doubleValue());
case Const.T_LONG: case Const.T_LONG:
return super.getConstantPool().addLong(((Long) value).longValue()); return super.getConstantPool().addLong(((Long) value).longValue());
case Const.T_REFERENCE: case Const.T_REFERENCE:
return super.getConstantPool().addString((String) value); return super.getConstantPool().addString((String) value);
default: default:
throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic
} }
} }
@@ -202,31 +200,6 @@ public class FieldGen extends FieldGenOrMethodGen {
return null; return null;
} }
@Override
public String getSignature() {
return super.getType().getSignature();
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Remove observer for this object.
*/
public void removeObserver(final FieldObserver o) {
if (observers != null) {
observers.remove(o);
}
}
public void setInitValue(final boolean b) { public void setInitValue(final boolean b) {
checkType(Type.BOOLEAN); checkType(Type.BOOLEAN);
if (b) { if (b) {
@@ -293,6 +266,31 @@ public class FieldGen extends FieldGenOrMethodGen {
} }
} }
@Override
public String getSignature() {
return super.getType().getSignature();
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Remove observer for this object.
*/
public void removeObserver(final FieldObserver o) {
if (observers != null) {
observers.remove(o);
}
}
private void setValue(final int index) { private void setValue(final int index) {
final ConstantPool cp = super.getConstantPool().getConstantPool(); final ConstantPool cp = super.getConstantPool().getConstantPool();
final Constant c = cp.getConstant(index); final Constant c = cp.getConstant(index);

View File

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

View File

@@ -43,10 +43,9 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
/** /**
* @return name of the referenced class/interface * @return name of the referenced class/interface
* @deprecated If the instruction references an array class, this method will return "java.lang.Object". For code * @deprecated If the instruction references an array class, this method will return "java.lang.Object". For code
* generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an
* array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly
* distinguishes between class types and array types. * distinguishes between class types and array types.
*
*/ */
@Deprecated @Deprecated
public String getClassName(final ConstantPoolGen cpg) { public String getClassName(final ConstantPoolGen cpg) {
@@ -63,7 +62,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
/** /**
* @return type of the referenced class/interface * @return type of the referenced class/interface
* @deprecated If the instruction references an array class, the ObjectType returned will be invalid. Use * @deprecated If the instruction references an array class, the ObjectType returned will be invalid. Use
* getReferenceType() instead. * getReferenceType() instead.
*/ */
@Deprecated @Deprecated
public ObjectType getClassType(final ConstantPoolGen cpg) { public ObjectType getClassType(final ConstantPoolGen cpg) {
@@ -100,7 +99,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
* *
* @param cpg the ConstantPoolGen used to create the instruction * @param cpg the ConstantPoolGen used to create the instruction
* @return an ObjectType (if the referenced class type is a class or interface), or an ArrayType (if the referenced * @return an ObjectType (if the referenced class type is a class or interface), or an ArrayType (if the referenced
* class type is an array class) * class type is an array class)
*/ */
public ReferenceType getReferenceType(final ConstantPoolGen cpg) { public ReferenceType getReferenceType(final ConstantPoolGen cpg) {
final ConstantPool cp = cpg.getConstantPool(); final ConstantPool cp = cpg.getConstantPool();

View File

@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
* <PRE> * <PRE>
* Stack: ..., objectref -&gt; ..., value * Stack: ..., objectref -&gt; ..., value
* </PRE> * </PRE>
* * <p>
* OR * OR
* *
* <PRE> * <PRE>
@@ -66,7 +66,7 @@ public class GETFIELD extends FieldInstruction implements ExceptionThrower, Stac
@Override @Override
public Class<?>[] getExceptions() { public Class<?>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION, return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR); ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
} }
@Override @Override

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