8301269: Update Commons BCEL to Version 6.7.0

Reviewed-by: mdoerr
Backport-of: 6a44120a16
This commit is contained in:
Goetz Lindenmaier
2023-07-25 10:57:18 +00:00
committed by Vitaly Provodin
parent 5c781b4a20
commit db41c86372
334 changed files with 22261 additions and 23773 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -20,13 +20,24 @@
package com.sun.org.apache.bcel.internal;
import jdk.xml.internal.Utils;
/**
* Exception constants.
*
* @since 6.0 (intended to replace the InstructionConstant interface)
* @LastModified: May 2021
* @LastModified: Feb 2023
*/
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
*/
@@ -64,61 +75,41 @@ public final class ExceptionConst {
* Run-Time Exceptions
*/
public static final Class<NullPointerException> NULL_POINTER_EXCEPTION = NullPointerException.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<NegativeArraySizeException> NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class;
public static final Class<ClassCastException> CLASS_CAST_EXCEPTION = ClassCastException.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
*/
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
private static final Class<?>[] EXCS_FIELD_AND_METHOD_RESOLUTION = {NO_SUCH_FIELD_ERROR, ILLEGAL_ACCESS_ERROR, NO_SUCH_METHOD_ERROR}; // Chapter 5.2
/**
* Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual
* Machine Specification
* Empty array.
*/
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
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_INTERFACE_METHOD_RESOLUTION = new Class<?>[0]; // Chapter 5.3 (as below)
private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class<?>[0];
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.)
private static final Class<?>[] EXCS_ARRAY_EXCEPTION = {
NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION
};
/**
* Enum corresponding to the various Exception Class arrays,
* used by {@link ExceptionConst#createExceptions(EXCS, Class...)}
* Empty array.
*/
public enum EXCS {
EXCS_CLASS_AND_INTERFACE_RESOLUTION,
EXCS_FIELD_AND_METHOD_RESOLUTION,
EXCS_INTERFACE_METHOD_RESOLUTION,
EXCS_STRING_RESOLUTION,
EXCS_ARRAY_EXCEPTION,
}
private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class<?>[0];
// helper method to merge exception class arrays
private static Class<?>[] mergeExceptions(final Class<?>[] input, final Class<?> ... extraClasses) {
final int extraLen = extraClasses == null ? 0 : extraClasses.length;
final Class<?>[] excs = new Class<?>[input.length + extraLen];
System.arraycopy(input, 0, excs, 0, input.length);
if (extraLen > 0) {
System.arraycopy(extraClasses, 0, excs, input.length, extraLen);
}
return excs;
}
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.)
private static final Class<?>[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION};
/**
* Creates a copy of the specified Exception Class array combined with any additional Exception classes.
*
* @param type the basic array type
* @param extraClasses additional classes, if any
* @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) {
case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
@@ -135,5 +126,8 @@ public final class ExceptionConst {
}
}
// helper method to merge exception class arrays
private static Class<?>[] mergeExceptions(final Class<?>[] input, final Class<?>... extraClasses) {
return Utils.arraysAppend(input, extraClasses);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,20 +24,54 @@ import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
/**
* The repository maintains informations about class interdependencies, e.g.,
* whether a class is a sub-class of another. Delegates actual class loading
* to SyntheticRepository with current class path by default.
* The repository maintains informations about class interdependencies, e.g., whether a class is a sub-class of another.
* Delegates actual class loading to SyntheticRepository with current class path by default.
*
* @see com.sun.org.apache.bcel.internal.util.Repository
* @see SyntheticRepository
*
* @LastModified: Jan 2020
* @LastModified: Feb 2023
*/
public abstract class Repository {
private static com.sun.org.apache.bcel.internal.util.Repository repository
= SyntheticRepository.getInstance();
private static com.sun.org.apache.bcel.internal.util.Repository repository = SyntheticRepository.getInstance();
/**
* Adds clazz to repository if there isn't an equally named class already in there.
*
* @return old entry in repository
*/
public static JavaClass addClass(final JavaClass clazz) {
final JavaClass old = repository.findClass(clazz.getClassName());
repository.storeClass(clazz);
return old;
}
/**
* Clears the repository.
*/
public static void clearCache() {
repository.clear();
}
/**
* @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).
* @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found
*/
public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException {
return clazz.getAllInterfaces();
}
/**
* @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces,
* and so on
* @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces
* can't be found
*/
public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException {
return getInterfaces(lookupClass(className));
}
/**
* @return currently used repository instance
@@ -46,205 +80,127 @@ public abstract class Repository {
return repository;
}
/**
* Sets repository instance to be used for class loading
* @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
*/
public static void setRepository( final com.sun.org.apache.bcel.internal.util.Repository rep ) {
repository = rep;
public static JavaClass[] getSuperClasses(final JavaClass clazz) throws ClassNotFoundException {
return clazz.getSuperClasses();
}
/**
* @return list of super classes of clazz in ascending order, i.e., Object is always the last element.
* @throws ClassNotFoundException if the named class or any of its superclasses can't be found
*/
public static JavaClass[] getSuperClasses(final String className) throws ClassNotFoundException {
return getSuperClasses(lookupClass(className));
}
/**
* Lookups class somewhere found on your CLASSPATH, or whereever the
* repository instance looks for it.
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final JavaClass clazz, final JavaClass inter) throws ClassNotFoundException {
return clazz.implementationOf(inter);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if inter or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final JavaClass clazz, final String inter) throws ClassNotFoundException {
return implementationOf(clazz, lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final String clazz, final JavaClass inter) throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), inter);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz, inter, or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final String clazz, final String inter) throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), lookupClass(inter));
}
/**
* Equivalent to runtime "instanceof" operator.
*
* @return class object for given fully qualified class name
* @throws ClassNotFoundException if the class could not be found or
* parsed correctly
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if any superclasses or superinterfaces of clazz can't be found
*/
public static JavaClass lookupClass( final String class_name ) throws ClassNotFoundException {
return repository.loadClass(class_name);
public static boolean instanceOf(final JavaClass clazz, final JavaClass superclass) throws ClassNotFoundException {
return clazz.instanceOf(superclass);
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if superclass can't be found
*/
public static boolean instanceOf(final JavaClass clazz, final String superclass) throws ClassNotFoundException {
return instanceOf(clazz, lookupClass(superclass));
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if clazz can't be found
*/
public static boolean instanceOf(final String clazz, final JavaClass superclass) throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), superclass);
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if either clazz or superclass can't be found
*/
public static boolean instanceOf(final String clazz, final String superclass) throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), lookupClass(superclass));
}
/**
* Tries to find class source using the internal repository instance.
*
* @see Class
* @return JavaClass object for given runtime class
* @throws ClassNotFoundException if the class could not be found or
* parsed correctly
* @throws ClassNotFoundException if the class could not be found or parsed correctly
*/
public static JavaClass lookupClass( final Class<?> clazz ) throws ClassNotFoundException {
public static JavaClass lookupClass(final Class<?> clazz) throws ClassNotFoundException {
return repository.loadClass(clazz);
}
/**
* Clear the repository.
*/
public static void clearCache() {
repository.clear();
}
/**
* Adds clazz to repository if there isn't an equally named class already in there.
* Lookups class somewhere found on your CLASSPATH, or wherever the repository instance looks for it.
*
* @return old entry in repository
* @return class object for given fully qualified class name
* @throws ClassNotFoundException if the class could not be found or parsed correctly
*/
public static JavaClass addClass( final JavaClass clazz ) {
final JavaClass old = repository.findClass(clazz.getClassName());
repository.storeClass(clazz);
return old;
public static JavaClass lookupClass(final String className) throws ClassNotFoundException {
return repository.loadClass(className);
}
/**
* Removes class with given (fully qualified) name from repository.
*/
public static void removeClass( final String clazz ) {
repository.removeClass(repository.findClass(clazz));
}
/**
* Removes given class from repository.
*/
public static void removeClass( final JavaClass clazz ) {
public static void removeClass(final JavaClass clazz) {
repository.removeClass(clazz);
}
/**
* @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
* Removes class with given (fully qualified) name from repository.
*/
public static JavaClass[] getSuperClasses( final JavaClass clazz ) throws ClassNotFoundException {
return clazz.getSuperClasses();
public static void removeClass(final String clazz) {
repository.removeClass(repository.findClass(clazz));
}
/**
* @return list of super classes of clazz in ascending order, i.e.,
* Object is always the last element.
* @throws ClassNotFoundException if the named class or any of its
* superclasses can't be found
* Sets repository instance to be used for class loading
*/
public static JavaClass[] getSuperClasses( final String class_name ) throws ClassNotFoundException {
final JavaClass jc = lookupClass(class_name);
return getSuperClasses(jc);
}
/**
* @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).
* @throws ClassNotFoundException if any of the class's
* superclasses or superinterfaces can't be found
*/
public static JavaClass[] getInterfaces( final JavaClass clazz ) throws ClassNotFoundException {
return clazz.getAllInterfaces();
}
/**
* @return all interfaces implemented by class and its super
* classes and the interfaces that extend those interfaces, and so on
* @throws ClassNotFoundException if the named class can't be found,
* or if any of its superclasses or superinterfaces can't be found
*/
public static JavaClass[] getInterfaces( final String class_name ) throws ClassNotFoundException {
return getInterfaces(lookupClass(class_name));
}
/**
* Equivalent to runtime "instanceof" operator.
* @return true, if clazz is an instance of super_class
* @throws ClassNotFoundException if any superclasses or superinterfaces
* of clazz can't be found
*/
public static boolean instanceOf( final JavaClass clazz, final JavaClass super_class )
throws ClassNotFoundException {
return clazz.instanceOf(super_class);
}
/**
* @return true, if clazz is an instance of super_class
* @throws ClassNotFoundException if either clazz or super_class
* can't be found
*/
public static boolean instanceOf( final String clazz, final String super_class )
throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), lookupClass(super_class));
}
/**
* @return true, if clazz is an instance of super_class
* @throws ClassNotFoundException if super_class can't be found
*/
public static boolean instanceOf( final JavaClass clazz, final String super_class )
throws ClassNotFoundException {
return instanceOf(clazz, lookupClass(super_class));
}
/**
* @return true, if clazz is an instance of super_class
* @throws ClassNotFoundException if clazz can't be found
*/
public static boolean instanceOf( final String clazz, final JavaClass super_class )
throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), super_class);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if any superclasses or superinterfaces
* of clazz can't be found
*/
public static boolean implementationOf( final JavaClass clazz, final JavaClass inter )
throws ClassNotFoundException {
return clazz.implementationOf(inter);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz, inter, or any superclasses
* or superinterfaces of clazz can't be found
*/
public static boolean implementationOf( final String clazz, final String inter )
throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if inter or any superclasses
* or superinterfaces of clazz can't be found
*/
public static boolean implementationOf( final JavaClass clazz, final String inter )
throws ClassNotFoundException {
return implementationOf(clazz, lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz or any superclasses or
* superinterfaces of clazz can't be found
*/
public static boolean implementationOf( final String clazz, final JavaClass inter )
throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), inter);
public static void setRepository(final com.sun.org.apache.bcel.internal.util.Repository rep) {
repository = rep;
}
}

View File

@@ -29,14 +29,17 @@ import com.sun.org.apache.bcel.internal.Const;
*/
public abstract class AccessFlags {
private int access_flags;
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int access_flags; // TODO not used externally at present
public AccessFlags() {
}
/**
* @param a
* inital access flags
* @param a initial access flags
*/
public AccessFlags(final int a) {
access_flags = a;
@@ -56,24 +59,141 @@ public abstract class AccessFlags {
return access_flags;
}
/**
* Set access flags aka "modifiers".
*
* @param access_flags
* Access flags of the object.
*/
public final void setAccessFlags(final int access_flags) {
this.access_flags = access_flags;
public final boolean isAbstract() {
return (access_flags & Const.ACC_ABSTRACT) != 0;
}
public final void isAbstract(final boolean flag) {
setFlag(Const.ACC_ABSTRACT, flag);
}
public final boolean isAnnotation() {
return (access_flags & Const.ACC_ANNOTATION) != 0;
}
public final void isAnnotation(final boolean flag) {
setFlag(Const.ACC_ANNOTATION, flag);
}
public final boolean isEnum() {
return (access_flags & Const.ACC_ENUM) != 0;
}
public final void isEnum(final boolean flag) {
setFlag(Const.ACC_ENUM, flag);
}
public final boolean isFinal() {
return (access_flags & Const.ACC_FINAL) != 0;
}
public final void isFinal(final boolean flag) {
setFlag(Const.ACC_FINAL, flag);
}
public final boolean isInterface() {
return (access_flags & Const.ACC_INTERFACE) != 0;
}
public final void isInterface(final boolean flag) {
setFlag(Const.ACC_INTERFACE, flag);
}
public final boolean isNative() {
return (access_flags & Const.ACC_NATIVE) != 0;
}
public final void isNative(final boolean flag) {
setFlag(Const.ACC_NATIVE, flag);
}
public final boolean isPrivate() {
return (access_flags & Const.ACC_PRIVATE) != 0;
}
public final void isPrivate(final boolean flag) {
setFlag(Const.ACC_PRIVATE, flag);
}
public final boolean isProtected() {
return (access_flags & Const.ACC_PROTECTED) != 0;
}
public final void isProtected(final boolean flag) {
setFlag(Const.ACC_PROTECTED, flag);
}
public final boolean isPublic() {
return (access_flags & Const.ACC_PUBLIC) != 0;
}
public final void isPublic(final boolean flag) {
setFlag(Const.ACC_PUBLIC, flag);
}
public final boolean isStatic() {
return (access_flags & Const.ACC_STATIC) != 0;
}
public final void isStatic(final boolean flag) {
setFlag(Const.ACC_STATIC, flag);
}
public final boolean isStrictfp() {
return (access_flags & Const.ACC_STRICT) != 0;
}
public final void isStrictfp(final boolean flag) {
setFlag(Const.ACC_STRICT, flag);
}
public final boolean isSynchronized() {
return (access_flags & Const.ACC_SYNCHRONIZED) != 0;
}
public final void isSynchronized(final boolean flag) {
setFlag(Const.ACC_SYNCHRONIZED, flag);
}
public final boolean isSynthetic() {
return (access_flags & Const.ACC_SYNTHETIC) != 0;
}
public final void isSynthetic(final boolean flag) {
setFlag(Const.ACC_SYNTHETIC, flag);
}
public final boolean isTransient() {
return (access_flags & Const.ACC_TRANSIENT) != 0;
}
public final void isTransient(final boolean flag) {
setFlag(Const.ACC_TRANSIENT, flag);
}
public final boolean isVarArgs() {
return (access_flags & Const.ACC_VARARGS) != 0;
}
public final void isVarArgs(final boolean flag) {
setFlag(Const.ACC_VARARGS, flag);
}
public final boolean isVolatile() {
return (access_flags & Const.ACC_VOLATILE) != 0;
}
public final void isVolatile(final boolean flag) {
setFlag(Const.ACC_VOLATILE, flag);
}
/**
* Set access flags aka "modifiers".
*
* @param access_flags
* Access flags of the object.
* @param accessFlags Access flags of the object.
*/
public final void setModifiers(final int access_flags) {
setAccessFlags(access_flags);
public final void setAccessFlags(final int accessFlags) {
this.access_flags = accessFlags;
}
private void setFlag(final int flag, final boolean set) {
@@ -81,138 +201,17 @@ public abstract class AccessFlags {
if (!set) {
access_flags ^= flag;
}
} else { // Flag not set
if (set) {
access_flags |= flag;
}
} else if (set) {
access_flags |= flag;
}
}
public final void isPublic(final boolean flag) {
setFlag(Const.ACC_PUBLIC, flag);
}
public final boolean isPublic() {
return (access_flags & Const.ACC_PUBLIC) != 0;
}
public final void isPrivate(final boolean flag) {
setFlag(Const.ACC_PRIVATE, flag);
}
public final boolean isPrivate() {
return (access_flags & Const.ACC_PRIVATE) != 0;
}
public final void isProtected(final boolean flag) {
setFlag(Const.ACC_PROTECTED, flag);
}
public final boolean isProtected() {
return (access_flags & Const.ACC_PROTECTED) != 0;
}
public final void isStatic(final boolean flag) {
setFlag(Const.ACC_STATIC, flag);
}
public final boolean isStatic() {
return (access_flags & Const.ACC_STATIC) != 0;
}
public final void isFinal(final boolean flag) {
setFlag(Const.ACC_FINAL, flag);
}
public final boolean isFinal() {
return (access_flags & Const.ACC_FINAL) != 0;
}
public final void isSynchronized(final boolean flag) {
setFlag(Const.ACC_SYNCHRONIZED, flag);
}
public final boolean isSynchronized() {
return (access_flags & Const.ACC_SYNCHRONIZED) != 0;
}
public final void isVolatile(final boolean flag) {
setFlag(Const.ACC_VOLATILE, flag);
}
public final boolean isVolatile() {
return (access_flags & Const.ACC_VOLATILE) != 0;
}
public final void isTransient(final boolean flag) {
setFlag(Const.ACC_TRANSIENT, flag);
}
public final boolean isTransient() {
return (access_flags & Const.ACC_TRANSIENT) != 0;
}
public final void isNative(final boolean flag) {
setFlag(Const.ACC_NATIVE, flag);
}
public final boolean isNative() {
return (access_flags & Const.ACC_NATIVE) != 0;
}
public final void isInterface(final boolean flag) {
setFlag(Const.ACC_INTERFACE, flag);
}
public final boolean isInterface() {
return (access_flags & Const.ACC_INTERFACE) != 0;
}
public final void isAbstract(final boolean flag) {
setFlag(Const.ACC_ABSTRACT, flag);
}
public final boolean isAbstract() {
return (access_flags & Const.ACC_ABSTRACT) != 0;
}
public final void isStrictfp(final boolean flag) {
setFlag(Const.ACC_STRICT, flag);
}
public final boolean isStrictfp() {
return (access_flags & Const.ACC_STRICT) != 0;
}
public final void isSynthetic(final boolean flag) {
setFlag(Const.ACC_SYNTHETIC, flag);
}
public final boolean isSynthetic() {
return (access_flags & Const.ACC_SYNTHETIC) != 0;
}
public final void isAnnotation(final boolean flag) {
setFlag(Const.ACC_ANNOTATION, flag);
}
public final boolean isAnnotation() {
return (access_flags & Const.ACC_ANNOTATION) != 0;
}
public final void isEnum(final boolean flag) {
setFlag(Const.ACC_ENUM, flag);
}
public final boolean isEnum() {
return (access_flags & Const.ACC_ENUM) != 0;
}
public final void isVarArgs(final boolean flag) {
setFlag(Const.ACC_VARARGS, flag);
}
public final boolean isVarArgs() {
return (access_flags & Const.ACC_VARARGS) != 0;
/**
* Set access flags aka "modifiers".
*
* @param accessFlags Access flags of the object.
*/
public final void setModifiers(final int accessFlags) {
setAccessFlags(accessFlags);
}
}

View File

@@ -28,7 +28,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents the default value of a annotation for a method info
* Represents the default value of a annotation for a method info.
*
* @since 6.0
*/
@@ -37,31 +37,30 @@ public class AnnotationDefault extends Attribute {
private ElementValue defaultValue;
/**
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
*/
AnnotationDefault(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, (ElementValue) null, constant_pool);
defaultValue = ElementValue.readElementValue(input, constant_pool);
AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (ElementValue) null, constantPool);
defaultValue = ElementValue.readElementValue(input, constantPool);
}
/**
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param defaultValue the annotation's default value
* @param constant_pool Array of constants
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param defaultValue the annotation's default value
* @param constantPool Array of constants
*/
public AnnotationDefault(final int name_index, final int length, final ElementValue defaultValue, final ConstantPool constant_pool) {
super(Const.ATTR_ANNOTATION_DEFAULT, name_index, length, constant_pool);
public AnnotationDefault(final int nameIndex, final int length, final ElementValue defaultValue, final ConstantPool constantPool) {
super(Const.ATTR_ANNOTATION_DEFAULT, nameIndex, length, constantPool);
this.defaultValue = defaultValue;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@@ -70,11 +69,15 @@ public class AnnotationDefault extends Attribute {
v.visitAnnotationDefault(this);
}
/**
* @param defaultValue the default value of this methodinfo's annotation
*/
public final void setDefaultValue(final ElementValue defaultValue) {
this.defaultValue = defaultValue;
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
defaultValue.dump(dos);
}
/**
@@ -84,14 +87,10 @@ public class AnnotationDefault extends Attribute {
return defaultValue;
}
@Override
public Attribute copy(final ConstantPool _constant_pool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
defaultValue.dump(dos);
/**
* @param defaultValue the default value of this methodinfo's annotation
*/
public final void setDefaultValue(final ElementValue defaultValue) {
this.defaultValue = defaultValue;
}
}

View File

@@ -27,43 +27,35 @@ import java.io.IOException;
/**
* @since 6.0
*/
public class AnnotationElementValue extends ElementValue
{
// For annotation element values, this is the annotation
private final AnnotationEntry annotationEntry;
public class AnnotationElementValue extends ElementValue {
// For annotation element values, this is the annotation
private final AnnotationEntry annotationEntry;
public AnnotationElementValue(final int type, final AnnotationEntry annotationEntry,
final ConstantPool cpool)
{
super(type, cpool);
if (type != ANNOTATION) {
throw new IllegalArgumentException(
"Only element values of type annotation can be built with this ctor - type specified: " + type);
}
this.annotationEntry = annotationEntry;
public AnnotationElementValue(final int type, final AnnotationEntry annotationEntry, final ConstantPool cpool) {
super(type, cpool);
if (type != ANNOTATION) {
throw new ClassFormatException("Only element values of type annotation can be built with this ctor - type specified: " + type);
}
this.annotationEntry = annotationEntry;
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
dos.writeByte(super.getType()); // u1 type of value (ANNOTATION == '@')
annotationEntry.dump(dos);
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ANNOTATION == '@')
annotationEntry.dump(dos);
}
@Override
public String stringifyValue()
{
return annotationEntry.toString();
}
public AnnotationEntry getAnnotationEntry() {
return annotationEntry;
}
@Override
public String toString()
{
return stringifyValue();
}
@Override
public String stringifyValue() {
return annotationEntry.toString();
}
public AnnotationEntry getAnnotationEntry()
{
return annotationEntry;
}
@Override
public String toString() {
return stringifyValue();
}
}

View File

@@ -25,66 +25,60 @@ import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.sun.org.apache.bcel.internal.Const;
import java.util.stream.Stream;
/**
* represents one annotation in the annotation table
* Represents one annotation in the annotation table
*
* @since 6.0
*/
public class AnnotationEntry implements Node {
private final int typeIndex;
private final ConstantPool constantPool;
private final boolean isRuntimeVisible;
public static final AnnotationEntry[] EMPTY_ARRAY = {};
private List<ElementValuePair> elementValuePairs;
public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain annotation data
return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
.toArray(AnnotationEntry[]::new);
}
/*
/**
* Factory method to create an AnnotionEntry from a DataInput
*
* @param input
* @param constantPool
* @param isRuntimeVisible
* @return the entry
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
public static AnnotationEntry read(final DataInput input, final ConstantPool constant_pool, final boolean isRuntimeVisible) throws IOException {
final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constant_pool, isRuntimeVisible);
final int num_element_value_pairs = input.readUnsignedShort();
public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException {
final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible);
final int numElementValuePairs = input.readUnsignedShort();
annotationEntry.elementValuePairs = new ArrayList<>();
for (int i = 0; i < num_element_value_pairs; i++) {
annotationEntry.elementValuePairs.add(
new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constant_pool),
constant_pool));
for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs
.add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
}
return annotationEntry;
}
public AnnotationEntry(final int type_index, final ConstantPool constant_pool, final boolean isRuntimeVisible) {
this.typeIndex = type_index;
this.constantPool = constant_pool;
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 int getTypeIndex() {
return typeIndex;
}
public ConstantPool getConstantPool() {
return constantPool;
}
public boolean isRuntimeVisible() {
return isRuntimeVisible;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely 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.
*
* @param v Visitor object
@@ -94,34 +88,8 @@ public class AnnotationEntry implements Node {
v.visitAnnotationEntry(this);
}
/**
* @return the annotation type name
*/
public String getAnnotationType() {
final ConstantUtf8 c = (ConstantUtf8) constantPool.getConstant(typeIndex, Const.CONSTANT_Utf8);
return c.getBytes();
}
/**
* @return the annotation type index
*/
public int getAnnotationTypeIndex() {
return typeIndex;
}
/**
* @return the number of element value pairs in this annotation entry
*/
public final int getNumElementValuePairs() {
return elementValuePairs.size();
}
/**
* @return the element value pairs in this annotation entry
*/
public ElementValuePair[] getElementValuePairs() {
// TODO return List
return elementValuePairs.toArray(new ElementValuePair[elementValuePairs.size()]);
public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
elementValuePairs.add(elementNameValuePair);
}
public void dump(final DataOutputStream dos) throws IOException {
@@ -133,8 +101,45 @@ public class AnnotationEntry implements Node {
}
}
public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
elementValuePairs.add(elementNameValuePair);
/**
* @return the annotation type name
*/
public String getAnnotationType() {
return constantPool.getConstantUtf8(typeIndex).getBytes();
}
/**
* @return the annotation type index
*/
public int getAnnotationTypeIndex() {
return typeIndex;
}
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @return the element value pairs in this annotation entry
*/
public ElementValuePair[] getElementValuePairs() {
// TODO return List
return elementValuePairs.toArray(ElementValuePair.EMPTY_ARRAY);
}
/**
* @return the number of element value pairs in this annotation entry
*/
public final int getNumElementValuePairs() {
return elementValuePairs.size();
}
public int getTypeIndex() {
return typeIndex;
}
public boolean isRuntimeVisible() {
return isRuntimeVisible;
}
public String toShortString() {
@@ -146,7 +151,10 @@ public class AnnotationEntry implements Node {
result.append("(");
for (final ElementValuePair element : evPairs) {
result.append(element.toShortString());
result.append(", ");
}
// remove last ", "
result.setLength(result.length() - 2);
result.append(")");
}
return result.toString();
@@ -156,16 +164,4 @@ public class AnnotationEntry implements Node {
public String toString() {
return toShortString();
}
public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain annotation data
final List<AnnotationEntry> accumulatedAnnotations = new ArrayList<>(attrs.length);
for (final Attribute attribute : attrs) {
if (attribute instanceof Annotations) {
final Annotations runtimeAnnotations = (Annotations) attribute;
Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getAnnotationEntries());
}
}
return accumulatedAnnotations.toArray(new AnnotationEntry[accumulatedAnnotations.size()]);
}
}

View File

@@ -24,40 +24,30 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* base class for annotations
*
* @since 6.0
*/
public abstract class Annotations extends Attribute {
public abstract class Annotations extends Attribute implements Iterable<AnnotationEntry> {
private AnnotationEntry[] annotationTable;
private final boolean isRuntimeVisible;
/**
* @param annotation_type the subclass type of the annotation
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
*/
Annotations(final byte annotation_type, final int name_index, final int length, final DataInput input,
final ConstantPool constant_pool, final boolean isRuntimeVisible) throws IOException {
this(annotation_type, name_index, length, (AnnotationEntry[]) null, constant_pool, isRuntimeVisible);
final int annotation_table_length = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotation_table_length];
for (int i = 0; i < annotation_table_length; i++) {
annotationTable[i] = AnnotationEntry.read(input, constant_pool, isRuntimeVisible);
}
}
/**
* @param annotationType the subclass type of the annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param annotationTable the actual annotations
* @param constantPool Array of constants
* Constructs an instance.
*
* @param annotationType the subclass type of the annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param annotationTable the actual annotations
* @param constantPool Array of constants
* @param isRuntimeVisible whether this Annotation visible at runtime
*/
public Annotations(final byte annotationType, final int nameIndex, final int length, final AnnotationEntry[] annotationTable,
final ConstantPool constantPool, final boolean isRuntimeVisible) {
@@ -67,8 +57,30 @@ public abstract class Annotations extends Attribute {
}
/**
* Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
* Constructs an instance.
*
* @param annotationType the subclass type of the annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @param isRuntimeVisible whether this Annotation visible at runtime
* @throws IOException if an I/O error occurs.
*/
Annotations(final byte annotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool,
final boolean isRuntimeVisible) throws IOException {
this(annotationType, nameIndex, length, (AnnotationEntry[]) null, constantPool, isRuntimeVisible);
final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength];
for (int i = 0; i < annotationTableLength; i++) {
annotationTable[i] = AnnotationEntry.read(input, constantPool, isRuntimeVisible);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@@ -77,21 +89,22 @@ public abstract class Annotations extends Attribute {
v.visitAnnotation(this);
}
/**
* @param annotationTable the entries to set in this annotation
*/
public final void setAnnotationTable(final AnnotationEntry[] annotationTable) {
this.annotationTable = annotationTable;
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO Auto-generated method stub
return null;
}
/**
* returns the array of annotation entries in this annotation
* Gets the array of annotation entries in this annotation
*/
public AnnotationEntry[] getAnnotationEntries() {
return annotationTable;
}
/**
* Gets the number of annotation entries in this annotation.
*
* @return the number of annotation entries in this annotation
*/
public final int getNumAnnotations() {
@@ -105,6 +118,38 @@ public abstract class Annotations extends Attribute {
return isRuntimeVisible;
}
@Override
public Iterator<AnnotationEntry> iterator() {
return Stream.of(annotationTable).iterator();
}
/**
* Sets the entries to set in this annotation.
*
* @param annotationTable the entries to set in this annotation
*/
public final void setAnnotationTable(final AnnotationEntry[] annotationTable) {
this.annotationTable = annotationTable;
}
/**
* Converts to a String representation.
*
* @return String representation
*/
@Override
public final String toString() {
final StringBuilder buf = new StringBuilder(Const.getAttributeName(getTag()));
buf.append(":\n");
for (int i = 0; i < annotationTable.length; i++) {
buf.append(" ").append(annotationTable[i]);
if (i < annotationTable.length - 1) {
buf.append('\n');
}
}
return buf.toString();
}
protected void writeAnnotations(final DataOutputStream dos) throws IOException {
if (annotationTable == null) {
return;
@@ -114,4 +159,5 @@ public abstract class Annotations extends Attribute {
element.dump(dos);
}
}
}

View File

@@ -27,40 +27,20 @@ import java.io.IOException;
/**
* @since 6.0
*/
public class ArrayElementValue extends ElementValue
{
public class ArrayElementValue extends ElementValue {
// For array types, this is the array
private final ElementValue[] elementValues;
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("{");
for (int i = 0; i < elementValues.length; i++)
{
sb.append(elementValues[i]);
if ((i + 1) < elementValues.length) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
public ArrayElementValue(final int type, final ElementValue[] datums, final ConstantPool cpool)
{
public ArrayElementValue(final int type, final ElementValue[] datums, final ConstantPool cpool) {
super(type, cpool);
if (type != ARRAY) {
throw new IllegalArgumentException(
"Only element values of type array can be built with this ctor - type specified: " + type);
throw new ClassFormatException("Only element values of type array can be built with this ctor - type specified: " + type);
}
this.elementValues = datums;
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ARRAY == '[')
dos.writeShort(elementValues.length);
for (final ElementValue evalue : elementValues) {
@@ -68,15 +48,21 @@ public class ArrayElementValue extends ElementValue
}
}
public ElementValue[] getElementValuesArray() {
return elementValues;
}
public int getElementValuesArraySize() {
return elementValues.length;
}
@Override
public String stringifyValue()
{
public String stringifyValue() {
final StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < elementValues.length; i++)
{
for (int i = 0; i < elementValues.length; i++) {
sb.append(elementValues[i].stringifyValue());
if ((i + 1) < elementValues.length) {
if (i + 1 < elementValues.length) {
sb.append(",");
}
}
@@ -84,13 +70,17 @@ public class ArrayElementValue extends ElementValue
return sb.toString();
}
public ElementValue[] getElementValuesArray()
{
return elementValues;
}
public int getElementValuesArraySize()
{
return elementValues.length;
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("{");
for (int i = 0; i < elementValues.length; i++) {
sb.append(elementValues[i]);
if (i + 1 < elementValues.length) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -27,14 +27,20 @@ import java.util.HashMap;
import java.util.Map;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* Abstract super class for <em>Attribute</em> objects. Currently the
* <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>,
* <em>Exceptiontable</em>, <em>LineNumberTable</em>,
* <em>LocalVariableTable</em>, <em>InnerClasses</em> and
* <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
* attribute stands for non-standard-attributes.
* Abstract super class for <em>Attribute</em> objects. Currently the <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>, <em>Exceptiontable</em>,
* <em>LineNumberTable</em>, <em>LocalVariableTable</em>, <em>InnerClasses</em> and <em>Synthetic</em> attributes are supported. The <em>Unknown</em> attribute
* stands for non-standard-attributes.
*
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*
* @see ConstantValue
* @see SourceFile
@@ -47,28 +53,29 @@ import com.sun.org.apache.bcel.internal.Const;
* @see Synthetic
* @see Deprecated
* @see Signature
* @LastModified: May 2021
* @LastModified: Feb 2023
*/
public abstract class Attribute implements Cloneable, Node {
private static final boolean debug = false;
private int name_index; // Points to attribute name in constant pool
private int length; // Content length of attribute field
private final byte tag; // Tag to distinguish subclasses
private ConstantPool constant_pool;
private static final Map<String, Object> readers = new HashMap<>();
private static final Map<String, Object> READERS = new HashMap<>();
/**
* 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.
* Empty array.
*
* @since 6.6.0
*/
public static final Attribute[] EMPTY_ARRAY = {};
/**
* Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the
* standard attributes such as "LineNumberTable", because those are handled internally.
*
* @param name the name of the attribute as stored in the class file
* @param r the reader object
* @param unknownAttributeReader the reader object
*/
public static void addAttributeReader(final String name, final UnknownAttributeReader r)
{
readers.put(name, r);
public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
READERS.put(name, unknownAttributeReader);
}
protected static void println(final String msg) {
@@ -78,135 +85,122 @@ public abstract class Attribute implements Cloneable, Node {
}
/**
* Class method reads one attribute from the input data stream. This method
* must not be accessible from the outside. It is called by the Field and
* Method constructor methods.
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
* @see Field
* @see Method
*
* @param file Input stream
* @param constant_pool Array of constants
* @param dataInput Input stream
* @param constantPool Array of constants
* @return Attribute
* @throws IOException
* @throws ClassFormatException
* @throws IOException if an I/O error occurs.
* @since 6.0
*/
public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool)
throws IOException, ClassFormatException
{
public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
// Get class name from constant pool via `name_index' indirection
final int name_index = file.readUnsignedShort();
final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
final String name = c.getBytes();
// Get class name from constant pool via 'name_index' indirection
final int nameIndex = dataInput.readUnsignedShort();
final String name = constantPool.getConstantUtf8(nameIndex).getBytes();
// Length of data in bytes
final int length = file.readInt();
final int length = dataInput.readInt();
// Compare strings to find known attribute
for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++)
{
if (name.equals(Const.getAttributeName(i)))
{
for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) {
if (name.equals(Const.getAttributeName(i))) {
tag = i; // found!
break;
}
}
// Call proper constructor, depending on `tag'
switch (tag)
{
case Const.ATTR_UNKNOWN:
final Object r = readers.get(name);
if (r instanceof UnknownAttributeReader)
{
return ((UnknownAttributeReader) r).createAttribute(name_index, length, file, constant_pool);
}
return new Unknown(name_index, length, file, constant_pool);
case Const.ATTR_CONSTANT_VALUE:
return new ConstantValue(name_index, length, file, constant_pool);
case Const.ATTR_SOURCE_FILE:
return new SourceFile(name_index, length, file, constant_pool);
case Const.ATTR_CODE:
return new Code(name_index, length, file, constant_pool);
case Const.ATTR_EXCEPTIONS:
return new ExceptionTable(name_index, length, file, constant_pool);
case Const.ATTR_LINE_NUMBER_TABLE:
return new LineNumberTable(name_index, length, file, constant_pool);
case Const.ATTR_LOCAL_VARIABLE_TABLE:
return new LocalVariableTable(name_index, length, file, constant_pool);
case Const.ATTR_INNER_CLASSES:
return new InnerClasses(name_index, length, file, constant_pool);
case Const.ATTR_SYNTHETIC:
return new Synthetic(name_index, length, file, constant_pool);
case Const.ATTR_DEPRECATED:
return new Deprecated(name_index, length, file, constant_pool);
case Const.ATTR_PMG:
return new PMGClass(name_index, length, file, constant_pool);
case Const.ATTR_SIGNATURE:
return new Signature(name_index, length, file, constant_pool);
case Const.ATTR_STACK_MAP:
// old style stack map: unneeded for JDK5 and below;
// illegal(?) for JDK6 and above. So just delete with a warning.
println("Warning: Obsolete StackMap attribute ignored.");
return new Unknown(name_index, length, file, constant_pool);
case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool);
case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool);
case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool);
case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool);
case Const.ATTR_ANNOTATION_DEFAULT:
return new AnnotationDefault(name_index, length, file, constant_pool);
case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
return new LocalVariableTypeTable(name_index, length, file, constant_pool);
case Const.ATTR_ENCLOSING_METHOD:
return new EnclosingMethod(name_index, length, file, constant_pool);
case Const.ATTR_STACK_MAP_TABLE:
// read new style stack map: StackMapTable. The rest of the code
// calls this a StackMap for historical reasons.
return new StackMap(name_index, length, file, constant_pool);
case Const.ATTR_BOOTSTRAP_METHODS:
return new BootstrapMethods(name_index, length, file, constant_pool);
case Const.ATTR_METHOD_PARAMETERS:
return new MethodParameters(name_index, length, file, constant_pool);
case Const.ATTR_MODULE:
return new Module(name_index, length, file, constant_pool);
case Const.ATTR_MODULE_PACKAGES:
return new ModulePackages(name_index, length, file, constant_pool);
case Const.ATTR_MODULE_MAIN_CLASS:
return new ModuleMainClass(name_index, length, file, constant_pool);
case Const.ATTR_NEST_HOST:
return new NestHost(name_index, length, file, constant_pool);
case Const.ATTR_NEST_MEMBERS:
return new NestMembers(name_index, length, file, constant_pool);
default:
// Never reached
throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
// Call proper constructor, depending on 'tag'
switch (tag) {
case Const.ATTR_UNKNOWN:
final Object r = READERS.get(name);
if (r instanceof UnknownAttributeReader) {
return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
}
return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CONSTANT_VALUE:
return new ConstantValue(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SOURCE_FILE:
return new SourceFile(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CODE:
return new Code(nameIndex, length, dataInput, constantPool);
case Const.ATTR_EXCEPTIONS:
return new ExceptionTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LINE_NUMBER_TABLE:
return new LineNumberTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TABLE:
return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_INNER_CLASSES:
return new InnerClasses(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SYNTHETIC:
return new Synthetic(nameIndex, length, dataInput, constantPool);
case Const.ATTR_DEPRECATED:
return new Deprecated(nameIndex, length, dataInput, constantPool);
case Const.ATTR_PMG:
return new PMGClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SIGNATURE:
return new Signature(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP:
// old style stack map: unneeded for JDK5 and below;
// illegal(?) for JDK6 and above. So just delete with a warning.
println("Warning: Obsolete StackMap attribute ignored.");
return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ANNOTATION_DEFAULT:
return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ENCLOSING_METHOD:
return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP_TABLE:
// read new style stack map: StackMapTable. The rest of the code
// calls this a StackMap for historical reasons.
return new StackMap(nameIndex, length, dataInput, constantPool);
case Const.ATTR_BOOTSTRAP_METHODS:
return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
case Const.ATTR_METHOD_PARAMETERS:
return new MethodParameters(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE:
return new Module(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_PACKAGES:
return new ModulePackages(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_MAIN_CLASS:
return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_HOST:
return new NestHost(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_MEMBERS:
return new NestMembers(nameIndex, length, dataInput, constantPool);
default:
// Never reached
throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
}
}
/**
* 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.
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
* @see Field
* @see Method
*
* @param file Input stream
* @param constant_pool Array of constants
* @param dataInputStream Input stream
* @param constantPool Array of constants
* @return Attribute
* @throws IOException
* @throws ClassFormatException
* @throws IOException if an I/O error occurs.
*/
public static Attribute readAttribute(final DataInputStream file, final ConstantPool constant_pool)
throws IOException, ClassFormatException
{
return readAttribute((DataInput) file, constant_pool);
public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
return readAttribute((DataInput) dataInputStream, constantPool);
}
/**
@@ -214,65 +208,95 @@ public abstract class Attribute implements Cloneable, Node {
*
* @param name the name of the attribute as stored in the class file
*/
public static void removeAttributeReader(final String name)
{
readers.remove(name);
}
protected Attribute(final byte tag, final int name_index, final int length, final ConstantPool constant_pool)
{
this.tag = tag;
this.name_index = name_index;
this.length = length;
this.constant_pool = constant_pool;
public static void removeAttributeReader(final String name) {
READERS.remove(name);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* @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.
*
* @param v
* Visitor object
* <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.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public abstract void accept(Visitor v);
/**
* Use copy() if you want to have a deep copy(), i.e., with all references
* copied correctly.
* Use copy() if you want to have a deep copy(), i.e., with all references copied correctly.
*
* @return shallow copy of this attribute
*/
@Override
public Object clone()
{
public Object clone() {
Attribute attr = null;
try
{
try {
attr = (Attribute) super.clone();
}
catch (final CloneNotSupportedException e)
{
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
}
return attr;
}
/**
* @return deep copy of this attribute
* @param constantPool constant pool to save.
* @return deep copy of this attribute.
*/
public abstract Attribute copy(ConstantPool _constant_pool);
public abstract Attribute copy(ConstantPool constantPool);
/**
* Dump attribute to file stream in binary format.
* Dumps attribute to file stream in binary format.
*
* @param file
* Output file stream
* @throws IOException
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException
{
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(name_index);
file.writeInt(length);
}
@@ -281,16 +305,14 @@ public abstract class Attribute implements Cloneable, Node {
* @return Constant pool used by this object.
* @see ConstantPool
*/
public final ConstantPool getConstantPool()
{
public final ConstantPool getConstantPool() {
return constant_pool;
}
/**
* @return Length of attribute field in bytes.
*/
public final int getLength()
{
public final int getLength() {
return length;
}
@@ -298,59 +320,51 @@ public abstract class Attribute implements Cloneable, Node {
* @return Name of attribute
* @since 6.0
*/
public String getName()
{
final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
return c.getBytes();
public String getName() {
return constant_pool.getConstantUtf8(name_index).getBytes();
}
/**
* @return Name index in constant pool of attribute name.
*/
public final int getNameIndex()
{
public final int getNameIndex() {
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()
{
public final byte getTag() {
return tag;
}
/**
* @param constant_pool Constant pool to be used for this object.
* @param constantPool Constant pool to be used for this object.
* @see ConstantPool
*/
public final void setConstantPool(final ConstantPool constant_pool)
{
this.constant_pool = constant_pool;
public final void setConstantPool(final ConstantPool constantPool) {
this.constant_pool = constantPool;
}
/**
* @param length length in bytes.
*/
public final void setLength(final int length)
{
public final void setLength(final int length) {
this.length = length;
}
/**
* @param name_index of attribute.
* @param nameIndex of attribute.
*/
public final void setNameIndex(final int name_index)
{
this.name_index = name_index;
public final void setNameIndex(final int nameIndex) {
this.name_index = nameIndex;
}
/**
* @return attribute name.
*/
@Override
public String toString()
{
public String toString() {
return Const.getAttributeName(tag);
}
}

View File

@@ -22,10 +22,9 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* Unknown (non-standard) attributes may be read via user-defined factory
* objects that can be registered with the Attribute.addAttributeReader
* method. These factory objects should implement this interface.
* Unknown (non-standard) attributes may be read via user-defined factory objects that can be registered with the
* Attribute.addAttributeReader method. These factory objects should implement this interface.
*
* @see Attribute
*
* @deprecated Use UnknownAttributeReader instead
@@ -34,30 +33,23 @@ package com.sun.org.apache.bcel.internal.classfile;
public interface AttributeReader {
/**
When this attribute reader is added via the static method
Attribute.addAttributeReader, an attribute name is associated with it.
As the class file parser parses attributes, it will call various
AttributeReaders based on the name of the attributes it is
constructing.
@param name_index An index into the constant pool, indexing a
ConstantUtf8 that represents the name of the attribute.
@param length The length of the data contained in the attribute. This
is written into the constant pool and should agree with what the
factory expects the length to be.
@param file This is the data input stream that the factory needs to read
its data from.
@param constant_pool This is the constant pool associated with the
Attribute that we are constructing.
@return The user-defined AttributeReader should take this data and use
it to construct an attribute. In the case of errors, a null can be
returned which will cause the parsing of the class file to fail.
@see Attribute#addAttributeReader( String, AttributeReader )
* When this attribute reader is added via the static method Attribute.addAttributeReader, an attribute name is
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing.
*
* @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
*
* @param length The length of the data contained in the attribute. This is written into the constant pool and should
* agree with what the factory expects the length to be.
*
* @param file This is the data input stream that the factory needs to read its data from.
*
* @param constantPool This is the constant pool associated with the Attribute that we are constructing.
*
* @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of
* errors, a null can be returned which will cause the parsing of the class file to fail.
*
* @see Attribute#addAttributeReader( String, AttributeReader )
*/
Attribute createAttribute( int name_index, int length, java.io.DataInputStream file, ConstantPool constant_pool );
Attribute createAttribute(int nameIndex, int length, java.io.DataInputStream file, ConstantPool constantPool);
}

View File

@@ -29,12 +29,11 @@ import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a bootstrap method attribute, i.e., the bootstrap
* method ref, the number of bootstrap arguments and an array of the
* bootstrap arguments.
* This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of 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 : The BootstrapMethods Attribute</a>
* @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>
* @since 6.0
*/
public class BootstrapMethod implements Cloneable {
@@ -45,9 +44,10 @@ public class BootstrapMethod implements Cloneable {
/** Array of references to the constant_pool table */
private int[] bootstrapArguments;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public BootstrapMethod(final BootstrapMethod c) {
this(c.getBootstrapMethodRef(), c.getBootstrapArguments());
@@ -57,7 +57,7 @@ public class BootstrapMethod implements Cloneable {
* Construct object from input stream.
*
* @param input Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
BootstrapMethod(final DataInput input) throws IOException {
this(input.readUnsignedShort(), input.readUnsignedShort());
@@ -68,8 +68,8 @@ public class BootstrapMethod implements Cloneable {
}
// helper method
private BootstrapMethod(final int bootstrap_method_ref, final int num_bootstrap_arguments) {
this(bootstrap_method_ref, new int[num_bootstrap_arguments]);
private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
this(bootstrapMethodRef, new int[numBootstrapArguments]);
}
/**
@@ -82,17 +82,29 @@ public class BootstrapMethod implements Cloneable {
}
/**
* @return index into constant_pool of bootstrap_method
* @return deep copy of this object
*/
public int getBootstrapMethodRef() {
return bootstrapMethodRef;
public BootstrapMethod copy() {
try {
return (BootstrapMethod) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
* Dump object to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void setBootstrapMethodRef(final int bootstrapMethodRef) {
this.bootstrapMethodRef = bootstrapMethodRef;
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(bootstrapMethodRef);
file.writeShort(bootstrapArguments.length);
for (final int bootstrapArgument : bootstrapArguments) {
file.writeShort(bootstrapArgument);
}
}
/**
@@ -102,6 +114,13 @@ public class BootstrapMethod implements Cloneable {
return bootstrapArguments;
}
/**
* @return index into constant_pool of bootstrap_method
*/
public int getBootstrapMethodRef() {
return bootstrapMethodRef;
}
/**
* @return count of number of boostrap arguments
*/
@@ -116,58 +135,36 @@ public class BootstrapMethod implements Cloneable {
this.bootstrapArguments = bootstrapArguments;
}
/**
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
*/
public void setBootstrapMethodRef(final int bootstrapMethodRef) {
this.bootstrapMethodRef = bootstrapMethodRef;
}
/**
* @return String representation.
*/
@Override
public final String toString() {
return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", "
+ Arrays.toString(bootstrapArguments) + ")";
return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
}
/**
* @return Resolved string representation
*/
public final String toString( final ConstantPool constantPool ) {
public final String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
String bootstrap_method_name;
bootstrap_method_name = constantPool.constantToString(bootstrapMethodRef,
Const.CONSTANT_MethodHandle);
buf.append(Utility.compactClassName(bootstrap_method_name, false));
final int num_bootstrap_arguments = bootstrapArguments.length;
if (num_bootstrap_arguments > 0) {
final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
buf.append(Utility.compactClassName(bootstrapMethodName, false));
final int bootstrapArgumentsLen = bootstrapArguments.length;
if (bootstrapArgumentsLen > 0) {
buf.append("\nMethod Arguments:");
for (int i = 0; i < num_bootstrap_arguments; i++) {
for (int i = 0; i < bootstrapArgumentsLen; i++) {
buf.append("\n ").append(i).append(": ");
buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
}
}
return buf.toString();
}
/**
* Dump object to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(bootstrapMethodRef);
file.writeShort(bootstrapArguments.length);
for (final int bootstrap_argument : bootstrapArguments) {
file.writeShort(bootstrap_argument);
}
}
/**
* @return deep copy of this object
*/
public BootstrapMethod copy() {
try {
return (BootstrapMethod) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
}

View File

@@ -24,73 +24,62 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* 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 : The BootstrapMethods Attribute</a>
* @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>
* @since 6.0
*/
public class BootstrapMethods extends Attribute {
public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* 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 BootstrapMethods(final BootstrapMethods c) {
this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param bootstrapMethods array of bootstrap methods
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public BootstrapMethods(final int name_index, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constant_pool) {
super(Const.ATTR_BOOTSTRAP_METHODS, name_index, length, constant_pool);
public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
this.bootstrapMethods = bootstrapMethods;
}
/**
* Construct object from Input stream.
*
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
BootstrapMethods(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, (BootstrapMethod[]) null, constant_pool);
BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
final int num_bootstrap_methods = input.readUnsignedShort();
bootstrapMethods = new BootstrapMethod[num_bootstrap_methods];
for (int i = 0; i < num_bootstrap_methods; i++) {
final int numBootstrapMethods = input.readUnsignedShort();
bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
for (int i = 0; i < numBootstrapMethods; i++) {
bootstrapMethods[i] = new BootstrapMethod(input);
}
}
/**
* @return array of bootstrap method "records"
*/
public final BootstrapMethod[] getBootstrapMethods() {
return bootstrapMethods;
}
/**
* @param bootstrapMethods the array of bootstrap methods
*/
public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
this.bootstrapMethods = bootstrapMethods;
}
/**
* @param v Visitor object
*/
@@ -103,14 +92,14 @@ public class BootstrapMethods extends Attribute {
* @return deep copy of this attribute
*/
@Override
public BootstrapMethods copy(final ConstantPool _constant_pool) {
public BootstrapMethods copy(final ConstantPool constantPool) {
final BootstrapMethods c = (BootstrapMethods) clone();
c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
for (int i = 0; i < bootstrapMethods.length; i++) {
c.bootstrapMethods[i] = bootstrapMethods[i].copy();
}
c.setConstantPool(_constant_pool);
c.setConstantPool(constantPool);
return c;
}
@@ -118,18 +107,37 @@ public class BootstrapMethods extends Attribute {
* Dump bootstrap methods attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(bootstrapMethods.length);
for (final BootstrapMethod bootstrap_method : bootstrapMethods) {
bootstrap_method.dump(file);
for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
bootstrapMethod.dump(file);
}
}
/**
* @return array of bootstrap method "records"
*/
public final BootstrapMethod[] getBootstrapMethods() {
return bootstrapMethods;
}
@Override
public Iterator<BootstrapMethod> iterator() {
return Stream.of(bootstrapMethods).iterator();
}
/**
* @param bootstrapMethods the array of bootstrap methods
*/
public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
this.bootstrapMethods = bootstrapMethods;
}
/**
* @return String representation.
*/
@@ -143,11 +151,11 @@ public class BootstrapMethods extends Attribute {
buf.append("\n");
final int start = buf.length();
buf.append(" ").append(i).append(": ");
final int indent_count = buf.length() - start;
final String[] lines = (bootstrapMethods[i].toString(super.getConstantPool())).split("\\r?\\n");
final int indentCount = buf.length() - start;
final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n");
buf.append(lines[0]);
for (int j = 1; j < lines.length; j++) {
buf.append("\n").append(" ".substring(0,indent_count)).append(lines[j]);
buf.append("\n").append(" ", 0, indentCount).append(lines[j]);
}
}
return buf.toString();

View File

@@ -24,48 +24,36 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* @since 6.0
*/
public class ClassElementValue extends ElementValue
{
public class ClassElementValue extends ElementValue {
// For primitive types and string type, this points to the value entry in
// the cpool
// For 'class' this points to the class entry in the cpool
private final int idx;
public ClassElementValue(final int type, final int idx, final ConstantPool cpool)
{
public ClassElementValue(final int type, final int idx, final ConstantPool cpool) {
super(type, cpool);
this.idx = idx;
}
public int getIndex()
{
return idx;
}
public String getClassString()
{
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(idx,
Const.CONSTANT_Utf8);
return c.getBytes();
}
@Override
public String stringifyValue()
{
final ConstantUtf8 cu8 = (ConstantUtf8) super.getConstantPool().getConstant(idx,
Const.CONSTANT_Utf8);
return cu8.getBytes();
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 kind of value
dos.writeShort(idx);
}
public String getClassString() {
return super.getConstantPool().getConstantUtf8(idx).getBytes();
}
public int getIndex() {
return idx;
}
@Override
public String stringifyValue() {
return super.getConstantPool().getConstantUtf8(idx).getBytes();
}
}

View File

@@ -22,28 +22,52 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* Thrown when the BCEL attempts to read a class file and determines
* that the file is malformed or otherwise cannot be interpreted as a
* class file.
*
* Thrown when the BCEL attempts to read a class file and determines that a class is malformed or otherwise cannot be interpreted as a class file.
*/
public class ClassFormatException extends RuntimeException {
private static final long serialVersionUID = -3569097343160139969L;
/**
* Constructs a new instance with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized by a call to
* {@link #initCause}.
*/
public ClassFormatException() {
super();
}
public ClassFormatException(final String s) {
super(s);
}
/**
* Constructs a new instance with the specified detail message. The cause is not initialized, and may subsequently be initialized by a call to
* {@link #initCause}.
*
* @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
*/
public ClassFormatException(final String message) {
super(message);
}
/**
* Constructs a new instance with the specified detail message and cause.
* <p>
* Note that the detail message associated with {@code cause} is <i>not</i> automatically incorporated in this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that
* the cause is nonexistent or unknown.)
* @since 6.0
*/
public ClassFormatException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new instance with the specified cause and a detail message of {@code (cause==null ? null : cause.toString())} (which typically contains the
* class and detail message of {@code cause}). This constructor is useful for runtime exceptions that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that the
* cause is nonexistent or unknown.)
* @since 6.7.0
*/
public ClassFormatException(final Throwable cause) {
super(cause);
}
}

View File

@@ -32,20 +32,17 @@ import java.util.zip.ZipFile;
import com.sun.org.apache.bcel.internal.Const;
/**
* 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 appropiate exception is propagated back to
* the caller.
*
* 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 the structure of a bytecode file.
* 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
* appropriate exception is propagated back to the caller.
*
* 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
* the structure of a bytecode file.
*/
public final class ClassParser {
private static final int BUFSIZE = 8192;
private DataInputStream dataInputStream;
private final boolean fileOwned;
private final String fileName;
@@ -61,8 +58,6 @@ public final class ClassParser {
private Method[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class
private final boolean isZip; // Loaded from zip file
private static final int BUFSIZE = 8192;
/**
* Parses class from the given stream.
@@ -72,9 +67,9 @@ public final class ClassParser {
*/
public ClassParser(final InputStream inputStream, final String fileName) {
this.fileName = fileName;
fileOwned = false;
this.fileOwned = false;
final String clazz = inputStream.getClass().getName(); // Not a very clean solution ...
isZip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
this.isZip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
if (inputStream instanceof DataInputStream) {
this.dataInputStream = (DataInputStream) inputStream;
} else {
@@ -82,41 +77,38 @@ public final class ClassParser {
}
}
/** Parses class from given .class file.
/**
* Parses class from given .class file.
*
* @param fileName file name
*/
public ClassParser(final String fileName) {
isZip = false;
this.isZip = false;
this.fileName = fileName;
fileOwned = true;
this.fileOwned = true;
}
/** 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 fileName file name
*/
public ClassParser(final String zipFile, final String fileName) {
isZip = true;
fileOwned = true;
this.isZip = true;
this.fileOwned = true;
this.zipFile = zipFile;
this.fileName = fileName;
}
/**
* Parses the given Java class file and return an object that represents
* the contained data, i.e., constants, methods, fields and commands.
* A <em>ClassFormatException</em> is raised, if the file is not a valid
* .class file. (This does not include verification of the byte code as it
* is performed by the java interpreter).
* Parses the given Java class file and return an object that represents the contained data, i.e., constants, methods,
* fields and commands. A <em>ClassFormatException</em> is raised, if the file is not a valid .class file. (This does
* not include verification of the byte code as it is performed by the java interpreter).
*
* @return Class object representing the parsed class file
* @throws IOException
* @throws ClassFormatException
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
public JavaClass parse() throws IOException, ClassFormatException {
ZipFile zip = null;
@@ -130,11 +122,9 @@ public final class ClassParser {
throw new IOException("File " + fileName + " not found");
}
dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
BUFSIZE));
dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), BUFSIZE));
} else {
dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(
fileName), BUFSIZE));
dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(fileName), BUFSIZE));
}
}
/****************** Read headers ********************************/
@@ -157,19 +147,19 @@ public final class ClassParser {
// Read class attributes
readAttributes();
// Check for unknown variables
//Unknown[] u = Unknown.getUnknownAttributes();
//for (int i=0; i < u.length; i++)
// System.err.println("WARNING: " + u[i]);
// Unknown[] u = Unknown.getUnknownAttributes();
// for (int i=0; i < u.length; i++)
// System.err.println("WARNING: " + u[i]);
// Everything should have been read now
// if(file.available() > 0) {
// int bytes = file.available();
// byte[] buf = new byte[bytes];
// file.read(buf);
// if(!(isZip && (buf.length == 1))) {
// System.err.println("WARNING: Trailing garbage at end of " + fileName);
// System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
// }
// }
// if(file.available() > 0) {
// int bytes = file.available();
// byte[] buf = new byte[bytes];
// file.read(buf);
// if(!(isZip && (buf.length == 1))) {
// System.err.println("WARNING: Trailing garbage at end of " + fileName);
// System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
// }
// }
} finally {
// Read everything of interest, so close the file
if (fileOwned) {
@@ -177,92 +167,88 @@ public final class ClassParser {
if (dataInputStream != null) {
dataInputStream.close();
}
} catch (final IOException ioe) {
//ignore close exceptions
} catch (final IOException ignored) {
// ignore close exceptions
}
}
try {
if (zip != null) {
zip.close();
}
} catch (final IOException ioe) {
//ignore close exceptions
} catch (final IOException ignored) {
// ignore close exceptions
}
}
// Return the information we have gathered in a new object
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor,
accessFlags, constantPool, interfaces, fields, methods, attributes, isZip
? JavaClass.ZIP
: JavaClass.FILE);
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes,
isZip ? JavaClass.ZIP : JavaClass.FILE);
}
/**
* Reads information about the attributes of the class.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readAttributes() throws IOException, ClassFormatException {
final int attributes_count = dataInputStream.readUnsignedShort();
attributes = new Attribute[attributes_count];
for (int i = 0; i < attributes_count; i++) {
final int attributesCount = dataInputStream.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(dataInputStream, constantPool);
}
}
/**
* Reads information about the class and its super class.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readClassInfo() throws IOException, ClassFormatException {
accessFlags = dataInputStream.readUnsignedShort();
/* Interfaces are implicitely abstract, the flag should be set
* according to the JVM specification.
/*
* Interfaces are implicitly abstract, the flag should be set according to the JVM specification.
*/
if ((accessFlags & Const.ACC_INTERFACE) != 0) {
accessFlags |= Const.ACC_ABSTRACT;
}
if (((accessFlags & Const.ACC_ABSTRACT) != 0)
&& ((accessFlags & Const.ACC_FINAL) != 0)) {
if ((accessFlags & Const.ACC_ABSTRACT) != 0 && (accessFlags & Const.ACC_FINAL) != 0) {
throw new ClassFormatException("Class " + fileName + " can't be both final and abstract");
}
classNameIndex = dataInputStream.readUnsignedShort();
superclassNameIndex = dataInputStream.readUnsignedShort();
}
/**
* Reads constant pool entries.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readConstantPool() throws IOException, ClassFormatException {
constantPool = new ConstantPool(dataInputStream);
}
/**
* Reads information about the fields of the class, i.e., its variables.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readFields() throws IOException, ClassFormatException {
final int fields_count = dataInputStream.readUnsignedShort();
fields = new Field[fields_count];
for (int i = 0; i < fields_count; i++) {
final int fieldsCount = dataInputStream.readUnsignedShort();
fields = new Field[fieldsCount];
for (int i = 0; i < fieldsCount; i++) {
fields[i] = new Field(dataInputStream, constantPool);
}
}
/******************** Private utility methods **********************/
/**
* Checks whether the header of the file is ok.
* Of course, this has to be the first action on successive file reads.
* @throws IOException
* @throws ClassFormatException
* 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 ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readID() throws IOException, ClassFormatException {
if (dataInputStream.readInt() != Const.JVM_CLASSFILE_MAGIC) {
@@ -270,39 +256,39 @@ public final class ClassParser {
}
}
/**
* Reads information about the interfaces implemented by this class.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readInterfaces() throws IOException, ClassFormatException {
final int interfaces_count = dataInputStream.readUnsignedShort();
interfaces = new int[interfaces_count];
for (int i = 0; i < interfaces_count; i++) {
final int interfacesCount = dataInputStream.readUnsignedShort();
interfaces = new int[interfacesCount];
for (int i = 0; i < interfacesCount; i++) {
interfaces[i] = dataInputStream.readUnsignedShort();
}
}
/**
* Reads information about the methods of the class.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readMethods() throws IOException, ClassFormatException {
final int methods_count = dataInputStream.readUnsignedShort();
methods = new Method[methods_count];
for (int i = 0; i < methods_count; i++) {
private void readMethods() throws IOException {
final int methodsCount = dataInputStream.readUnsignedShort();
methods = new Method[methodsCount];
for (int i = 0; i < methodsCount; i++) {
methods[i] = new Method(dataInputStream, constantPool);
}
}
/**
* Reads major and minor version of compiler which created the file.
* @throws IOException
* @throws ClassFormatException
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readVersion() throws IOException, ClassFormatException {
minor = dataInputStream.readUnsignedShort();

View File

@@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,126 +23,173 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* 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
* variables, byte code and the exceptions handled within this
* method.
* 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
* variables, byte code and the exceptions handled within this method.
*
* 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.
* 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.
*
* @see Attribute
* @see CodeException
* @see LineNumberTable
* <pre>
* Code_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 max_stack;
* u2 max_locals;
* u4 code_length;
* u1 code[code_length];
* u2 exception_table_length;
* {
* u2 start_pc;
* u2 end_pc;
* u2 handler_pc;
* u2 catch_type;
* } exception_table[exception_table_length];
* u2 attributes_count;
* attribute_info attributes[attributes_count];
* }
* </pre>
* @see Attribute
* @see CodeException
* @see LineNumberTable
* @see LocalVariableTable
* @LastModified: Feb 2023
*/
public final class Code extends Attribute {
private int maxStack; // Maximum size of stack used by this method // TODO this could be made final (setter is not used)
private int maxLocals; // Number of local variables // TODO this could be made final (setter is not used)
private int maxStack; // Maximum size of stack used by this method // TODO this could be made final (setter is not used)
private int maxLocals; // Number of local variables // TODO this could be made final (setter is not used)
private byte[] code; // Actual byte code
private CodeException[] exceptionTable; // Table of handled exceptions
private Attribute[] attributes; // or LocalVariable
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param code The source Code.
*/
public Code(final Code c) {
this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), c.getCode(), c
.getExceptionTable(), c.getAttributes(), c.getConstantPool());
public Code(final Code code) {
this(code.getNameIndex(), code.getLength(), code.getMaxStack(), code.getMaxLocals(), code.getCode(), code.getExceptionTable(), code.getAttributes(),
code.getConstantPool());
}
/**
* @param name_index 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 file Input stream
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool)
throws IOException {
Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
// Initialize with some default values which will be overwritten later
this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null,
(CodeException[]) null, (Attribute[]) null, constant_pool);
final int code_length = file.readInt();
code = new byte[code_length]; // Read byte code
this(nameIndex, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, constantPool);
final int codeLength = Args.requireU4(file.readInt(), 1, "Code length attribute");
code = new byte[codeLength]; // Read byte code
file.readFully(code);
/* Read exception table that contains all regions where an exception
* handler is active, i.e., a try { ... } catch() block.
/*
* Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch()
* block.
*/
final int exception_table_length = file.readUnsignedShort();
exceptionTable = new CodeException[exception_table_length];
for (int i = 0; i < exception_table_length; i++) {
final int exceptionTableLength = file.readUnsignedShort();
exceptionTable = new CodeException[exceptionTableLength];
for (int i = 0; i < exceptionTableLength; i++) {
exceptionTable[i] = new CodeException(file);
}
/* Read all attributes, currently `LineNumberTable' and
* `LocalVariableTable'
/*
* Read all attributes, currently 'LineNumberTable' and 'LocalVariableTable'
*/
final int attributes_count = file.readUnsignedShort();
attributes = new Attribute[attributes_count];
for (int i = 0; i < attributes_count; i++) {
attributes[i] = Attribute.readAttribute(file, constant_pool);
final int attributesCount = file.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(file, constantPool);
}
/* Adjust length, because of setAttributes in this(), s.b. length
* is incorrect, because it didn't take the internal attributes
* into account yet! Very subtle bug, fixed in 3.1.1.
/*
* Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal
* attributes into account yet! Very subtle bug, fixed in 3.1.1.
*/
super.setLength(length);
}
/**
* @param name_index 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 maxStack Maximum size of stack
* @param maxLocals Number of local variables
* @param code Actual byte code
* @param exceptionTable of handled exceptions
* @param attributes Attributes of code: LineNumber or LocalVariable
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public Code(final int name_index, final int length, final int maxStack, final int maxLocals, final byte[] code,
final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool) {
super(Const.ATTR_CODE, name_index, length, constant_pool);
this.maxStack = maxStack;
this.maxLocals = maxLocals;
this.code = code != null ? code : new byte[0];
this.exceptionTable = exceptionTable != null ? exceptionTable : new CodeException[0];
this.attributes = attributes != null ? attributes : new Attribute[0];
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) {
super(Const.ATTR_CODE, nameIndex, length, constantPool);
this.maxStack = Args.requireU2(maxStack, "maxStack");
this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY;
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
super.setLength(calculateLength()); // Adjust length
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitCode(this);
}
/**
* @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained
* attributes
*/
private int calculateLength() {
int len = 0;
if (attributes != null) {
for (final Attribute attribute : attributes) {
len += attribute.getLength() + 6 /* attribute header size */;
}
}
return len + getInternalLength();
}
/**
* @return deep copy of this attribute
*
* @param constantPool the constant pool to duplicate
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Code c = (Code) clone();
if (code != null) {
c.code = code.clone();
}
c.setConstantPool(constantPool);
c.exceptionTable = new CodeException[exceptionTable.length];
Arrays.setAll(c.exceptionTable, i -> exceptionTable[i].copy());
c.attributes = new Attribute[attributes.length];
Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
return c;
}
/**
* Dump code attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(maxStack);
file.writeShort(maxLocals);
@@ -159,7 +205,6 @@ public final class Code extends Attribute {
}
}
/**
* @return Collection of code attributes.
* @see Attribute
@@ -168,6 +213,31 @@ public final class Code extends Attribute {
return attributes;
}
/**
* @return Actual byte code of the method.
*/
public byte[] getCode() {
return code;
}
/**
* @return Table of handled exceptions.
* @see CodeException
*/
public CodeException[] getExceptionTable() {
return exceptionTable;
}
/**
* @return the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes
*/
private int getInternalLength() {
return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */
+ code.length /* byte-code */
+ 2 /* exception-table length */
+ 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
+ 2 /* attributes count */;
}
/**
* @return LineNumberTable of Code, if it has one
@@ -181,7 +251,6 @@ public final class Code extends Attribute {
return null;
}
/**
* @return LocalVariableTable of Code, if it has one
*/
@@ -194,24 +263,6 @@ public final class Code extends Attribute {
return null;
}
/**
* @return Actual byte code of the method.
*/
public byte[] getCode() {
return code;
}
/**
* @return Table of handled exceptions.
* @see CodeException
*/
public CodeException[] getExceptionTable() {
return exceptionTable;
}
/**
* @return Number of local variables.
*/
@@ -219,7 +270,6 @@ public final class Code extends Attribute {
return maxLocals;
}
/**
* @return Maximum size of stack used by this method.
*/
@@ -227,86 +277,62 @@ public final class Code extends Attribute {
return maxStack;
}
/**
* @return the internal length of this code attribute (minus the first 6 bytes)
* and excluding all its attributes
*/
private int getInternalLength() {
return 2 /*maxStack*/+ 2 /*maxLocals*/+ 4 /*code length*/
+ code.length /*byte-code*/
+ 2 /*exception-table length*/
+ 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
+ 2 /* attributes count */;
}
/**
* @return the full size of this code attribute, minus its first 6 bytes,
* including the size of all its contained attributes
*/
private int calculateLength() {
int len = 0;
if (attributes != null) {
for (final Attribute attribute : attributes) {
len += attribute.getLength() + 6 /*attribute header size*/;
}
}
return len + getInternalLength();
}
/**
* @param attributes the attributes to set for this Code
*/
public void setAttributes( final Attribute[] attributes ) {
this.attributes = attributes != null ? attributes : new Attribute[0];
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 : new byte[0];
public void setCode(final byte[] code) {
this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY;
super.setLength(calculateLength()); // Adjust length
}
/**
* @param exceptionTable exception table
*/
public void setExceptionTable( final CodeException[] exceptionTable ) {
this.exceptionTable = exceptionTable != null ? exceptionTable : new CodeException[0];
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
*/
public void setMaxLocals( final int maxLocals ) {
public void setMaxLocals(final int maxLocals) {
this.maxLocals = maxLocals;
}
/**
* @param maxStack maximum stack size
*/
public void setMaxStack( final int maxStack ) {
public void setMaxStack(final int maxStack) {
this.maxStack = maxStack;
}
/**
* @return String representation of code chunk.
*/
public String toString( final boolean verbose ) {
@Override
public String toString() {
return toString(true);
}
/**
* Converts this object to a String.
*
* @param verbose Provides verbose output when true.
* @return String representation of code chunk.
*/
public String toString(final boolean verbose) {
final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber
buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(
maxLocals).append(", code_length = ").append(code.length).append(")\n").append(
Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
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));
if (exceptionTable.length > 0) {
buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
for (final CodeException exception : exceptionTable) {
@@ -322,38 +348,4 @@ public final class Code extends Attribute {
}
return buf.toString();
}
/**
* @return String representation of code chunk.
*/
@Override
public String toString() {
return toString(true);
}
/**
* @return deep copy of this attribute
*
* @param _constant_pool the constant pool to duplicate
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final Code c = (Code) clone();
if (code != null) {
c.code = new byte[code.length];
System.arraycopy(code, 0, c.code, 0, code.length);
}
c.setConstantPool(_constant_pool);
c.exceptionTable = new CodeException[exceptionTable.length];
for (int i = 0; i < exceptionTable.length; i++) {
c.exceptionTable[i] = exceptionTable[i].copy();
}
c.attributes = new Attribute[attributes.length];
for (int i = 0; i < attributes.length; i++) {
c.attributes[i] = attributes[i].copy(_constant_pool);
}
return c;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -25,187 +25,104 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents an entry in the exception table of the <em>Code</em>
* attribute and is used only there. It contains a range in which a
* particular exception handler is active.
* This class represents an entry in the exception table of the <em>Code</em> attribute and is used only there. It
* contains a range in which a particular exception handler is active.
*
* @see Code
* @LastModified: May 2021
* <pre>
* Code_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 max_stack;
* u2 max_locals;
* u4 code_length;
* u1 code[code_length];
* u2 exception_table_length;
* {
* u2 start_pc;
* u2 end_pc;
* u2 handler_pc;
* u2 catch_type;
* } exception_table[exception_table_length];
* u2 attributes_count;
* attribute_info attributes[attributes_count];
* }
* </pre>
*
* @see Code
* @LastModified: Feb 2023
*/
public final class CodeException implements Cloneable, Node {
private int startPc; // Range in the code the exception handler is
private int endPc; // active. startPc is inclusive, endPc exclusive
private int handlerPc; /* Starting address of exception handler, i.e.,
* an offset from start of code.
*/
private int catchType; /* If this is zero the handler catches any
* exception, otherwise it points to the
* exception class which is to be caught.
/**
* Empty array.
*/
static final CodeException[] EMPTY_CODE_EXCEPTION_ARRAY = {};
/** Range in the code the exception handler. */
private int startPc;
/** active. startPc is inclusive, endPc exclusive. */
private int endPc;
/**
* Initialize from another object.
* Starting address of exception handler, i.e., an offset from start of code.
*/
private int handlerPc;
/*
* If this is zero the handler catches any exception, otherwise it points to the exception class which is to be caught.
*/
private int catchType;
/**
* Constructs a new instance from another instance.
*
* @param c Source for copying.
*/
public CodeException(final CodeException c) {
this(c.getStartPC(), c.getEndPC(), c.getHandlerPC(), c.getCatchType());
}
/**
* Construct object from file stream.
* Constructs a new instance from a DataInput.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
CodeException(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
.readUnsignedShort());
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param startPc Range in the code the exception handler is active,
* startPc is inclusive while
* Constructs a new instance.
*
* @param startPc Range in the code the exception handler is active, startPc is inclusive while
* @param endPc is exclusive
* @param handlerPc Starting address of exception handler, i.e.,
* an offset from start of code.
* @param catchType If zero the handler catches any
* exception, otherwise it points to the exception class which is
* to be caught.
* @param handlerPc Starting address of exception handler, i.e., an offset from start of code.
* @param catchType If zero the handler catches any exception, otherwise it points to the exception class which is to be
* caught.
*/
public CodeException(final int startPc, final int endPc, final int handlerPc, final int catchType) {
this.startPc = startPc;
this.endPc = endPc;
this.handlerPc = handlerPc;
this.catchType = catchType;
this.startPc = Args.requireU2(startPc, "startPc");
this.endPc = Args.requireU2(endPc, "endPc");
this.handlerPc = Args.requireU2(handlerPc, "handlerPc");
this.catchType = Args.requireU2(catchType, "catchType");
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitCodeException(this);
}
/**
* Dump code exception to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(startPc);
file.writeShort(endPc);
file.writeShort(handlerPc);
file.writeShort(catchType);
}
/**
* @return 0, if the handler catches any exception, otherwise it points to
* the exception class which is to be caught.
*/
public int getCatchType() {
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
*/
public void setCatchType( final int catchType ) {
this.catchType = catchType;
}
/**
* @param endPc end of handled block
*/
public void setEndPC( final int endPc ) {
this.endPc = endPc;
}
/**
* @param handlerPc where the actual code is
*/
public void setHandlerPC( final int handlerPc ) { // TODO unused
this.handlerPc = handlerPc;
}
/**
* @param startPc start of handled block
*/
public void setStartPC( final int startPc ) { // TODO unused
this.startPc = startPc;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "CodeException(startPc = " + startPc + ", endPc = " + endPc + ", handlerPc = "
+ handlerPc + ", catchType = " + catchType + ")";
}
/**
* @return String representation.
*/
public String toString( final ConstantPool cp, final boolean verbose ) {
String str;
if (catchType == 0) {
str = "<Any exception>(0)";
} else {
str = Utility.compactClassName(cp.getConstantString(catchType, Const.CONSTANT_Class), false)
+ (verbose ? "(" + catchType + ")" : "");
}
return startPc + "\t" + endPc + "\t" + handlerPc + "\t" + str;
}
public String toString( final ConstantPool cp ) {
return toString(cp, true);
}
/**
* @return deep copy of this object
*/
@@ -217,4 +134,100 @@ public final class CodeException implements Cloneable, Node {
}
return null;
}
/**
* Dumps code exception to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(startPc);
file.writeShort(endPc);
file.writeShort(handlerPc);
file.writeShort(catchType);
}
/**
* @return 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught.
*/
public int getCatchType() {
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
*/
public void setCatchType(final int catchType) {
this.catchType = catchType;
}
/**
* @param endPc end of handled block
*/
public void setEndPC(final int endPc) {
this.endPc = endPc;
}
/**
* @param handlerPc where the actual code is
*/
public void setHandlerPC(final int handlerPc) { // TODO unused
this.handlerPc = handlerPc;
}
/**
* @param startPc start of handled block
*/
public void setStartPC(final int startPc) { // TODO unused
this.startPc = startPc;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "CodeException(startPc = " + startPc + ", endPc = " + endPc + ", handlerPc = " + handlerPc + ", catchType = " + catchType + ")";
}
public String toString(final ConstantPool cp) {
return toString(cp, true);
}
/**
* @param cp constant pool source.
* @param verbose Output more if true.
* @return String representation.
*/
public String toString(final ConstantPool cp, final boolean verbose) {
String str;
if (catchType == 0) {
str = "<Any exception>(0)";
} else {
str = Utility.compactClassName(cp.getConstantString(catchType, Const.CONSTANT_Class), false) + (verbose ? "(" + catchType + ")" : "");
}
return startPc + "\t" + endPc + "\t" + handlerPc + "\t" + str;
}
}

View File

@@ -39,81 +39,24 @@ public abstract class Constant implements Cloneable, Node {
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
public boolean equals( final Object o1, final Object o2 ) {
public boolean equals(final Object o1, final Object o2) {
final Constant THIS = (Constant) o1;
final Constant THAT = (Constant) o2;
return Objects.equals(THIS.toString(), THAT.toString());
}
@Override
public int hashCode( final Object o ) {
public int hashCode(final Object o) {
final Constant THIS = (Constant) o;
return THIS.toString().hashCode();
}
};
/* In fact this tag is redundant since we can distinguish different
* `Constant' objects by their type, i.e., via `instanceof'. In some
* places we will use the tag for switch()es anyway.
*
* First, we want match the specification as closely as possible. Second we
* need the tag as an index to select the corresponding class name from the
* `CONSTANT_NAMES' array.
*/
private byte tag;
Constant(final byte tag) {
this.tag = tag;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
* @return Comparison strategy object
*/
@Override
public abstract void accept( Visitor v );
public abstract void dump( DataOutputStream file ) throws IOException;
/**
* @return Tag of constant, i.e., its type. No setTag() method to avoid
* confusion.
*/
public final byte getTag() {
return tag;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return Const.getConstantName(tag) + "[" + tag + "]";
}
/**
* @return deep copy of this constant
*/
public Constant copy() {
try {
return (Constant) super.clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
@Override
public Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
}
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
@@ -167,40 +110,96 @@ public abstract class Constant implements Cloneable, Node {
}
}
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator( final BCELComparator comparator ) {
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/**
* Returns value as defined by given BCELComparator strategy.
* By default two Constant objects are said to be equal when
* the result of toString() is equal.
/*
* 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.
*
* @see java.lang.Object#equals(java.lang.Object)
* First, we want match the specification as closely as possible. Second we need the tag as an index to select the
* corresponding class name from the 'CONSTANT_NAMES' array.
*/
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected byte tag; // TODO should be private & final
Constant(final byte tag) {
this.tag = tag;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public boolean equals( final Object obj ) {
public abstract void accept(Visitor v);
@Override
public Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
}
}
/**
* @return deep copy of this constant
*/
public Constant copy() {
try {
return (Constant) super.clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
public abstract void dump(DataOutputStream file) throws IOException;
/**
* Returns value as defined by given BCELComparator strategy. By default two Constant objects are said to be equal when
* the result of toString() is equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
}
/**
* Returns value as defined by given BCELComparator strategy.
* By default return the hashcode of the result of toString().
* @return Tag of constant, i.e., its type. No setTag() method to avoid confusion.
*/
public final byte getTag() {
return tag;
}
/**
* Returns value as defined by given BCELComparator strategy. By default return the hashcode of the result of
* toString().
*
* @see java.lang.Object#hashCode()
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* @return String representation.
*/
@Override
public String toString() {
return Const.getConstantName(tag) + "[" + tag + "]";
}
}

View File

@@ -26,8 +26,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Abstract super class for Fieldref, Methodref, InterfaceMethodref and
* InvokeDynamic constants.
* Abstract super class for Fieldref, Methodref, InterfaceMethodref and InvokeDynamic constants.
*
* @see ConstantFieldref
* @see ConstantMethodref
@@ -42,54 +41,68 @@ public abstract class ConstantCP extends Constant {
*/
// Note that this field is used to store the
// bootstrap_method_attr_index of a ConstantInvokeDynamic.
private int class_index;
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int class_index; // TODO make private (has getter & setter)
// This field has the same meaning for all subclasses.
private int name_and_type_index;
/**
* Initialize from another object.
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
public ConstantCP(final ConstantCP c) {
this(c.getTag(), c.getClassIndex(), c.getNameAndTypeIndex());
}
@java.lang.Deprecated
protected int name_and_type_index; // TODO make private (has getter & setter)
/**
* Initialize instance from file data.
*
* @param tag Constant type tag
* @param tag Constant type tag
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantCP(final byte tag, final DataInput file) throws IOException {
this(tag, file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param class_index Reference to the class containing the field
* @param name_and_type_index and the field signature
* @param classIndex Reference to the class containing the field
* @param nameAndTypeIndex and the field signature
*/
protected ConstantCP(final byte tag, final int class_index, final int name_and_type_index) {
protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) {
super(tag);
this.class_index = class_index;
this.name_and_type_index = name_and_type_index;
this.class_index = classIndex;
this.name_and_type_index = nameAndTypeIndex;
}
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantCP(final ConstantCP c) {
this(c.getTag(), c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Dump constant field reference to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump( final DataOutputStream file ) throws IOException {
public final void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(class_index);
file.writeShort(name_and_type_index);
}
/**
* @return Class this field belongs to.
*/
public String getClass(final ConstantPool cp) {
return cp.constantToString(class_index, Const.CONSTANT_Class);
}
/**
* @return Reference (index) to class this constant refers to.
@@ -98,15 +111,6 @@ public abstract class ConstantCP extends Constant {
return class_index;
}
/**
* @param class_index points to Constant_class
*/
public final void setClassIndex( final int class_index ) {
this.class_index = class_index;
}
/**
* @return Reference (index) to signature of the field.
*/
@@ -114,31 +118,27 @@ public abstract class ConstantCP extends Constant {
return name_and_type_index;
}
/**
* @param name_and_type_index points to Constant_NameAndType
* @param classIndex points to Constant_class
*/
public final void setNameAndTypeIndex( final int name_and_type_index ) {
this.name_and_type_index = name_and_type_index;
public final void setClassIndex(final int classIndex) {
this.class_index = classIndex;
}
/**
* @return Class this field belongs to.
* @param nameAndTypeIndex points to Constant_NameAndType
*/
public String getClass( final ConstantPool cp ) {
return cp.constantToString(class_index, Const.CONSTANT_Class);
public final void setNameAndTypeIndex(final int nameAndTypeIndex) {
this.name_and_type_index = nameAndTypeIndex;
}
/**
* @return String representation.
*
* not final as ConstantInvokeDynamic needs to modify
* not final as ConstantInvokeDynamic needs to modify
*/
@Override
public String toString() {
return super.toString() + "(class_index = " + class_index + ", name_and_type_index = "
+ name_and_type_index + ")";
return super.toString() + "(class_index = " + class_index + ", name_and_type_index = " + name_and_type_index + ")";
}
}

View File

@@ -28,24 +28,23 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a (external) class.
* This class is derived from the abstract {@link Constant} and represents a reference to a (external) class.
*
* @see Constant
* @see Constant
*/
public final class ConstantClass extends Constant implements ConstantObject {
private int nameIndex; // Identical to ConstantString except for the name
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantClass(final ConstantClass c) {
this(c.getNameIndex());
}
/**
* Constructs an instance from file data.
*
@@ -56,30 +55,25 @@ public final class ConstantClass extends Constant implements ConstantObject {
this(dataInput.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a
* ConstantUtf8.
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantClass(final int nameIndex) {
super(Const.CONSTANT_Class);
this.nameIndex = nameIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantClass(this);
}
/**
* Dumps constant class to file stream in binary format.
*
@@ -87,11 +81,25 @@ public final class ConstantClass extends Constant implements ConstantObject {
* @throws IOException if an I/O error occurs writing to the DataOutputStream.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of class name.
@@ -100,31 +108,13 @@ public final class ConstantClass extends Constant implements ConstantObject {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Class
*/
public void setNameIndex( final int nameIndex ) {
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/** @return String object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
final Constant c = cp.getConstant(nameIndex, Const.CONSTANT_Utf8);
return ((ConstantUtf8) c).getBytes();
}
/** @return dereferenced string
*/
public String getBytes( final ConstantPool cp ) {
return (String) getConstantValue(cp);
}
/**
* @return String representation.
*/

View File

@@ -27,8 +27,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a Double object.
* This class is derived from the abstract {@link Constant} and represents a reference to a Double object.
*
* @see Constant
* @LastModified: Jun 2019
@@ -37,6 +36,24 @@ public final class ConstantDouble extends Constant implements ConstantObject {
private double bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantDouble(final ConstantDouble c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantDouble(final DataInput file) throws IOException {
this(file.readDouble());
}
/**
* @param bytes Data
@@ -46,52 +63,29 @@ public final class ConstantDouble extends Constant implements ConstantObject {
this.bytes = bytes;
}
/**
* Initialize from another object.
*/
public ConstantDouble(final ConstantDouble c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
*/
ConstantDouble(final DataInput file) throws IOException {
this(file.readDouble());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantDouble(this);
}
/**
* Dump constant double to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeDouble(bytes);
}
/**
* @return data, i.e., 8 bytes.
*/
@@ -99,15 +93,21 @@ public final class ConstantDouble extends Constant implements ConstantObject {
return bytes;
}
/**
* @return Double object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Double.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent the double value
*/
public void setBytes( final double bytes ) {
public void setBytes(final double bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -115,12 +115,4 @@ public final class ConstantDouble extends Constant implements ConstantObject {
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
/** @return Double object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
return bytes;
}
}

View File

@@ -27,18 +27,20 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a dynamically computed constant.
* This class is derived from the abstract {@link Constant} and represents a reference to a dynamically computed
* constant.
*
* @see Constant
* @see <a href="https://bugs.openjdk.java.net/secure/attachment/74618/constant-dynamic.html">
* Change request for JEP 309</a>
* @see Constant
* @see <a href="https://bugs.openjdk.java.net/secure/attachment/74618/constant-dynamic.html"> Change request for JEP
* 309</a>
* @since 6.3
*/
public final class ConstantDynamic extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantDynamic(final ConstantDynamic c) {
this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex());
@@ -49,39 +51,37 @@ public final class ConstantDynamic extends ConstantCP {
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantDynamic(final DataInput file) throws IOException {
this(file.readShort(), file.readShort());
}
public ConstantDynamic(final int bootstrap_method_attr_index, final int name_and_type_index) {
super(Const.CONSTANT_Dynamic, bootstrap_method_attr_index, name_and_type_index);
public ConstantDynamic(final int bootstrapMethodAttrIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Dynamic, bootstrapMethodAttrIndex, nameAndTypeIndex);
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantDynamic(this);
}
/**
* @return Reference (index) to bootstrap method this constant refers to.
*
* Note that this method is a functional duplicate of getClassIndex
* for use by ConstantInvokeDynamic.
* Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
return super.getClassIndex(); // AKA bootstrap_method_attr_index
return super.getClassIndex(); // AKA bootstrap_method_attr_index
}
/**

View File

@@ -28,47 +28,44 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to a field.
*
*/
public final class ConstantFieldref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantFieldref(final ConstantFieldref c) {
super(Const.CONSTANT_Fieldref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantFieldref(final DataInput input) throws IOException {
super(Const.CONSTANT_Fieldref, input);
}
/**
* @param class_index Reference to the class containing the Field
* @param name_and_type_index and the Field signature
* @param classIndex Reference to the class containing the Field
* @param nameAndTypeIndex and the Field signature
*/
public ConstantFieldref(final int class_index, final int name_and_type_index) {
super(Const.CONSTANT_Fieldref, class_index, name_and_type_index);
public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Fieldref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of Fields,
* fields, attributes, etc. spawns a tree of objects.
* 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 Fields, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantFieldref(this);
}
}

View File

@@ -27,8 +27,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a float object.
* This class is derived from the abstract {@link Constant} and represents a reference to a float object.
*
* @see Constant
* @LastModified: Jun 2019
@@ -37,6 +36,25 @@ public final class ConstantFloat extends Constant implements ConstantObject {
private float bytes;
/**
* 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 ConstantFloat(final ConstantFloat c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantFloat(final DataInput file) throws IOException {
this(file.readFloat());
}
/**
* @param bytes Data
@@ -46,53 +64,29 @@ public final class ConstantFloat extends Constant implements ConstantObject {
this.bytes = bytes;
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
*/
public ConstantFloat(final ConstantFloat c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
*/
ConstantFloat(final DataInput file) throws IOException {
this(file.readFloat());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantFloat(this);
}
/**
* Dump constant float to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeFloat(bytes);
}
/**
* @return data, i.e., 4 bytes.
*/
@@ -100,15 +94,21 @@ public final class ConstantFloat extends Constant implements ConstantObject {
return bytes;
}
/**
* @return Float object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Float.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this float
*/
public void setBytes( final float bytes ) {
public void setBytes(final float bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -116,12 +116,4 @@ public final class ConstantFloat extends Constant implements ConstantObject {
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
/** @return Float object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
return bytes;
}
}

View File

@@ -27,8 +27,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to an int object.
* This class is derived from the abstract {@link Constant} and represents a reference to an int object.
*
* @see Constant
* @LastModified: Jun 2019
@@ -37,6 +36,24 @@ public final class ConstantInteger extends Constant implements ConstantObject {
private int bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInteger(final ConstantInteger c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantInteger(final DataInput file) throws IOException {
this(file.readInt());
}
/**
* @param bytes Data
@@ -46,52 +63,29 @@ public final class ConstantInteger extends Constant implements ConstantObject {
this.bytes = bytes;
}
/**
* Initialize from another object.
*/
public ConstantInteger(final ConstantInteger c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
*/
ConstantInteger(final DataInput file) throws IOException {
this(file.readInt());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantInteger(this);
}
/**
* Dump constant integer to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeInt(bytes);
}
/**
* @return data, i.e., 4 bytes.
*/
@@ -99,15 +93,21 @@ public final class ConstantInteger extends Constant implements ConstantObject {
return bytes;
}
/**
* @return Integer object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Integer.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this integer
*/
public void setBytes( final int bytes ) {
public void setBytes(final int bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -115,12 +115,4 @@ public final class ConstantInteger extends Constant implements ConstantObject {
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
/** @return Integer object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
return Integer.valueOf(bytes);
}
}

View File

@@ -28,47 +28,44 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to an interface method.
*
*/
public final class ConstantInterfaceMethodref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInterfaceMethodref(final ConstantInterfaceMethodref c) {
super(Const.CONSTANT_InterfaceMethodref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantInterfaceMethodref(final DataInput input) throws IOException {
super(Const.CONSTANT_InterfaceMethodref, input);
}
/**
* @param class_index Reference to the class containing the method
* @param name_and_type_index and the method signature
* @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantInterfaceMethodref(final int class_index, final int name_and_type_index) {
super(Const.CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_InterfaceMethodref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantInterfaceMethodref(this);
}
}

View File

@@ -27,61 +27,57 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a invoke dynamic.
* This class is derived from the abstract {@link Constant} and represents a reference to a invoke dynamic.
*
* @see Constant
* @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>
* @see Constant
* @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>
* @since 6.0
*/
public final class ConstantInvokeDynamic extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInvokeDynamic(final ConstantInvokeDynamic c) {
this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantInvokeDynamic(final DataInput file) throws IOException {
this(file.readShort(), file.readShort());
this(file.readUnsignedShort(), file.readUnsignedShort());
}
public ConstantInvokeDynamic(final int bootstrap_method_attr_index, final int name_and_type_index) {
super(Const.CONSTANT_InvokeDynamic, bootstrap_method_attr_index, name_and_type_index);
public ConstantInvokeDynamic(final int bootstrapMethodAttrIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_InvokeDynamic, bootstrapMethodAttrIndex, nameAndTypeIndex);
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantInvokeDynamic(this);
}
/**
* @return Reference (index) to bootstrap method this constant refers to.
*
* Note that this method is a functional duplicate of getClassIndex
* for use by ConstantInvokeDynamic.
* Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
return super.getClassIndex(); // AKA bootstrap_method_attr_index
return super.getClassIndex(); // AKA bootstrap_method_attr_index
}
/**

View File

@@ -27,8 +27,7 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a long object.
* This class is derived from the abstract {@link Constant} and represents a reference to a long object.
*
* @see Constant
* @LastModified: Jan 2020
@@ -37,6 +36,24 @@ public final class ConstantLong extends Constant implements ConstantObject {
private long bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantLong(final ConstantLong c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantLong(final DataInput file) throws IOException {
this(file.readLong());
}
/**
* @param bytes Data
@@ -46,52 +63,29 @@ public final class ConstantLong extends Constant implements ConstantObject {
this.bytes = bytes;
}
/**
* Initialize from another object.
*/
public ConstantLong(final ConstantLong c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
*/
ConstantLong(final DataInput file) throws IOException {
this(file.readLong());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantLong(this);
}
/**
* Dump constant long to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeLong(bytes);
}
/**
* @return data, i.e., 8 bytes.
*/
@@ -99,15 +93,21 @@ public final class ConstantLong extends Constant implements ConstantObject {
return bytes;
}
/**
* @return Long object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Long.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this long
*/
public void setBytes( final long bytes ) {
public void setBytes(final long bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -115,12 +115,4 @@ public final class ConstantLong extends Constant implements ConstantObject {
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
/** @return Long object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
return bytes;
}
}

View File

@@ -28,10 +28,9 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a method handle.
* This class is derived from the abstract {@link Constant} and represents a reference to a method handle.
*
* @see Constant
* @see Constant
* @since 6.0
*/
public final class ConstantMethodHandle extends Constant {
@@ -39,86 +38,76 @@ public final class ConstantMethodHandle extends Constant {
private int referenceKind;
private int referenceIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodHandle(final ConstantMethodHandle c) {
this(c.getReferenceKind(), c.getReferenceIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantMethodHandle(final DataInput file) throws IOException {
this(file.readUnsignedByte(), file.readUnsignedShort());
}
public ConstantMethodHandle(final int reference_kind, final int reference_index) {
public ConstantMethodHandle(final int referenceKind, final int referenceIndex) {
super(Const.CONSTANT_MethodHandle);
this.referenceKind = reference_kind;
this.referenceIndex = reference_index;
this.referenceKind = referenceKind;
this.referenceIndex = referenceIndex;
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantMethodHandle(this);
}
/**
* Dump method kind and index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeByte(referenceKind);
file.writeShort(referenceIndex);
}
public int getReferenceIndex() {
return referenceIndex;
}
public int getReferenceKind() {
return referenceKind;
}
public void setReferenceKind(final int reference_kind) {
this.referenceKind = reference_kind;
public void setReferenceIndex(final int referenceIndex) {
this.referenceIndex = referenceIndex;
}
public int getReferenceIndex() {
return referenceIndex;
public void setReferenceKind(final int referenceKind) {
this.referenceKind = referenceKind;
}
public void setReferenceIndex(final int reference_index) {
this.referenceIndex = reference_index;
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(referenceKind = " + referenceKind +
", referenceIndex = " + referenceIndex + ")";
return super.toString() + "(referenceKind = " + referenceKind + ", referenceIndex = " + referenceIndex + ")";
}
}

View File

@@ -28,78 +28,70 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a method type.
* This class is derived from the abstract {@link Constant} and represents a reference to a method type.
*
* @see Constant
* @see Constant
* @since 6.0
*/
public final class ConstantMethodType extends Constant {
private int descriptorIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodType(final ConstantMethodType c) {
this(c.getDescriptorIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantMethodType(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
public ConstantMethodType(final int descriptor_index) {
public ConstantMethodType(final int descriptorIndex) {
super(Const.CONSTANT_MethodType);
this.descriptorIndex = descriptor_index;
this.descriptorIndex = descriptorIndex;
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantMethodType(this);
}
/**
* Dump name and signature index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(descriptorIndex);
}
public int getDescriptorIndex() {
return descriptorIndex;
}
public void setDescriptorIndex(final int descriptor_index) {
this.descriptorIndex = descriptor_index;
public void setDescriptorIndex(final int descriptorIndex) {
this.descriptorIndex = descriptorIndex;
}
/**
* @return String representation
*/

View File

@@ -28,47 +28,44 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to a method.
*
*/
public final class ConstantMethodref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodref(final ConstantMethodref c) {
super(Const.CONSTANT_Methodref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantMethodref(final DataInput input) throws IOException {
super(Const.CONSTANT_Methodref, input);
}
/**
* @param class_index Reference to the class containing the method
* @param name_and_type_index and the method signature
* @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantMethodref(final int class_index, final int name_and_type_index) {
super(Const.CONSTANT_Methodref, class_index, name_and_type_index);
public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Methodref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantMethodref(this);
}
}

View File

@@ -28,73 +28,83 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a module.
* This class is derived from the abstract {@link Constant} and represents a reference to a module.
*
* <p>Note: Early access Java 9 support- currently subject to change</p>
* <p>
* Note: Early access Java 9 support- currently subject to change
* </p>
*
* @see Constant
* @see Constant
* @since 6.1
*/
public final class ConstantModule extends Constant implements ConstantObject {
private int nameIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantModule(final ConstantModule c) {
this(c.getNameIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantModule(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a
* ConstantUtf8.
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantModule(final int nameIndex) {
super(Const.CONSTANT_Module);
this.nameIndex = nameIndex;
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantModule(this);
}
/**
* Dump constant module to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of module name.
@@ -103,31 +113,13 @@ public final class ConstantModule extends Constant implements ConstantObject {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Module
*/
public void setNameIndex( final int nameIndex ) {
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/** @return String object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
final Constant c = cp.getConstant(nameIndex, Const.CONSTANT_Utf8);
return ((ConstantUtf8) c).getBytes();
}
/** @return dereferenced string
*/
public String getBytes( final ConstantPool cp ) {
return (String) getConstantValue(cp);
}
/**
* @return String representation.
*/

View File

@@ -28,37 +28,35 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to the name and signature
* of a field or method.
* This class is derived from the abstract {@link Constant} and represents a reference to the name and signature of a
* field or method.
*
* @see Constant
* @see Constant
*/
public final class ConstantNameAndType extends Constant {
private int nameIndex; // Name of field/method
private int signatureIndex; // and its signature.
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantNameAndType(final ConstantNameAndType c) {
this(c.getNameIndex(), c.getSignatureIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantNameAndType(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param nameIndex Name of field/method
* @param signatureIndex and its signature
@@ -69,33 +67,36 @@ public final class ConstantNameAndType extends Constant {
this.signatureIndex = signatureIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantNameAndType(this);
}
/**
* Dump name and signature index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
file.writeShort(signatureIndex);
}
/**
* @return name
*/
public String getName(final ConstantPool cp) {
return cp.constantToString(getNameIndex(), Const.CONSTANT_Utf8);
}
/**
* @return Name index in constant pool of field/method name.
@@ -104,14 +105,13 @@ public final class ConstantNameAndType extends Constant {
return nameIndex;
}
/** @return name
/**
* @return signature
*/
public String getName( final ConstantPool cp ) {
return cp.constantToString(getNameIndex(), Const.CONSTANT_Utf8);
public String getSignature(final ConstantPool cp) {
return cp.constantToString(getSignatureIndex(), Const.CONSTANT_Utf8);
}
/**
* @return Index in constant pool of field/method signature.
*/
@@ -119,36 +119,25 @@ public final class ConstantNameAndType extends Constant {
return signatureIndex;
}
/** @return signature
*/
public String getSignature( final ConstantPool cp ) {
return cp.constantToString(getSignatureIndex(), Const.CONSTANT_Utf8);
}
/**
* @param nameIndex the name index of this constant
*/
public void setNameIndex( final int nameIndex ) {
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/**
* @param signatureIndex the signature index in the constant pool of this type
*/
public void setSignatureIndex( final int signatureIndex ) {
public void setSignatureIndex(final int signatureIndex) {
this.signatureIndex = signatureIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(nameIndex = " + nameIndex + ", signatureIndex = "
+ signatureIndex + ")";
return super.toString() + "(nameIndex = " + nameIndex + ", signatureIndex = " + signatureIndex + ")";
}
}

View File

@@ -22,14 +22,14 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* This interface denotes those constants that have a "natural" value,
* such as ConstantLong, ConstantString, etc..
* This interface denotes those constants that have a "natural" value, such as ConstantLong, ConstantString, etc..
*
* @see Constant
* @see Constant
*/
public interface ConstantObject {
/** @return object representing the constant, e.g., Long for ConstantLong
/**
* @return object representing the constant, e.g., Long for ConstantLong
*/
Object getConstantValue( ConstantPool cp );
Object getConstantValue(ConstantPool cp);
}

View File

@@ -28,73 +28,83 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a package.
* This class is derived from the abstract {@link Constant} and represents a reference to a package.
*
* <p>Note: Early access Java 9 support- currently subject to change</p>
* <p>
* Note: Early access Java 9 support- currently subject to change
* </p>
*
* @see Constant
* @see Constant
* @since 6.1
*/
public final class ConstantPackage extends Constant implements ConstantObject {
private int nameIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantPackage(final ConstantPackage c) {
this(c.getNameIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantPackage(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a
* ConstantUtf8.
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantPackage(final int nameIndex) {
super(Const.CONSTANT_Package);
this.nameIndex = nameIndex;
}
/**
* 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.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantPackage(this);
}
/**
* Dump constant package to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of package name.
@@ -103,31 +113,13 @@ public final class ConstantPackage extends Constant implements ConstantObject {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Package
*/
public void setNameIndex( final int nameIndex ) {
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/** @return String object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
final Constant c = cp.getConstant(nameIndex, Const.CONSTANT_Utf8);
return ((ConstantUtf8) c).getBytes();
}
/** @return dereferenced string
*/
public String getBytes( final ConstantPool cp ) {
return (String) getConstantValue(cp);
}
/**
* @return String representation.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,23 +23,49 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
/**
* This class represents the constant pool, i.e., a table of constants, of
* a parsed classfile. It may contain null references, due to the JVM
* specification that skips an entry after an 8-byte constant (double,
* long) entry. Those interested in generating constant pools
* programatically should see <a href="../generic/ConstantPoolGen.html">
* ConstantPoolGen</a>.
* @see Constant
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen
* @LastModified: June 2022
* This class represents the constant pool, i.e., a table of constants, of a parsed classfile. It may contain null references, due to the JVM specification that
* skips an entry after an 8-byte constant (double, long) entry. Those interested in generating constant pools programmatically should see
* <a href="../generic/ConstantPoolGen.html"> ConstantPoolGen</a>.
*
* @see Constant
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen
* @LastModified: Feb 2023
*/
public class ConstantPool implements Cloneable, Node {
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;
@@ -54,320 +80,134 @@ public class ConstantPool implements Cloneable, Node {
* Reads constants from given input stream.
*
* @param input Input stream
* @throws IOException
* @throws ClassFormatException
* @throws IOException if problem in readUnsignedShort or readConstant
*/
public ConstantPool(final DataInput input) throws IOException, ClassFormatException {
public ConstantPool(final DataInput input) throws IOException {
byte tag;
final int constant_pool_count = input.readUnsignedShort();
constantPool = new Constant[constant_pool_count];
/* constantPool[0] is unused by the compiler and may be used freely
* by the implementation.
final int constantPoolCount = input.readUnsignedShort();
constantPool = new Constant[constantPoolCount];
/*
* constantPool[0] is unused by the compiler and may be used freely by the implementation.
*/
for (int i = 1; i < constant_pool_count; i++) {
for (int i = 1; i < constantPoolCount; i++) {
constantPool[i] = Constant.readConstant(input);
/* Quote from the JVM specification:
* "All eight byte constants take up two spots in the constant pool.
* If this is the n'th byte in the constant pool, then the next item
* will be numbered n+2"
/*
* Quote from the JVM specification: "All eight byte constants take up two spots in the constant pool. If this is the n'th byte in the constant
* pool, then the next item will be numbered n+2"
*
* Thus we have to increment the index counter.
*/
tag = constantPool[i].getTag();
if ((tag == Const.CONSTANT_Double) || (tag == Const.CONSTANT_Long)) {
if (tag == Const.CONSTANT_Double || tag == Const.CONSTANT_Long) {
i++;
}
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantPool(this);
}
/**
* Resolves constant to a string representation.
*
* @param c Constant to be printed
* @param c Constant to be printed
* @return String representation
* @throws IllegalArgumentException if c is unknown constant type
*/
public String constantToString( Constant c ) throws ClassFormatException {
public String constantToString(Constant c) throws IllegalArgumentException {
String str;
int i;
final byte tag = c.getTag();
switch (tag) {
case Const.CONSTANT_Class:
i = ((ConstantClass) c).getNameIndex();
c = getConstant(i, Const.CONSTANT_Utf8);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = getConstant(i, Const.CONSTANT_Utf8);
str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
break;
case Const.CONSTANT_Utf8:
str = ((ConstantUtf8) c).getBytes();
break;
case Const.CONSTANT_Double:
str = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Float:
str = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Long:
str = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Integer:
str = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_NameAndType:
str = constantToString(((ConstantNameAndType) c).getNameIndex(),
Const.CONSTANT_Utf8)
+ " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(),
Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InterfaceMethodref:
case Const.CONSTANT_Methodref:
case Const.CONSTANT_Fieldref:
str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class)
+ "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(),
Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_MethodHandle:
// Note that the ReferenceIndex may point to a Fieldref, Methodref or
// InterfaceMethodref - so we need to peek ahead to get the actual type.
final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
str = Const.getMethodHandleName(cmh.getReferenceKind())
+ " " + constantToString(cmh.getReferenceIndex(),
getConstant(cmh.getReferenceIndex()).getTag());
break;
case Const.CONSTANT_MethodType:
final ConstantMethodType cmt = (ConstantMethodType) c;
str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InvokeDynamic:
final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
str = cid.getBootstrapMethodAttrIndex()
+ ":" + constantToString(cid.getNameAndTypeIndex(),
Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_Module:
i = ((ConstantModule) c).getNameIndex();
c = getConstant(i, Const.CONSTANT_Utf8);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_Package:
i = ((ConstantPackage) c).getNameIndex();
c = getConstant(i, Const.CONSTANT_Utf8);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + tag);
case Const.CONSTANT_Class:
i = ((ConstantClass) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = getConstantUtf8(i);
str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
break;
case Const.CONSTANT_Utf8:
str = ((ConstantUtf8) c).getBytes();
break;
case Const.CONSTANT_Double:
str = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Float:
str = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Long:
str = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Integer:
str = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_NameAndType:
str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
+ constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InterfaceMethodref:
case Const.CONSTANT_Methodref:
case Const.CONSTANT_Fieldref:
str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
+ constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_MethodHandle:
// Note that the ReferenceIndex may point to a Fieldref, Methodref or
// InterfaceMethodref - so we need to peek ahead to get the actual type.
final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
+ constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
break;
case Const.CONSTANT_MethodType:
final ConstantMethodType cmt = (ConstantMethodType) c;
str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InvokeDynamic:
final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_Dynamic:
final ConstantDynamic cd = (ConstantDynamic) c;
str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_Module:
i = ((ConstantModule) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_Package:
i = ((ConstantPackage) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + tag);
}
return str;
}
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();
}
/**
* Retrieves constant at `index' from constant pool and resolve it to
* a string representation.
* Retrieves constant at 'index' from constant pool and resolve it to a string representation.
*
* @param index of constant in constant pool
* @param tag expected type
* @param index of constant in constant pool
* @param tag expected type
* @return String representation
*/
public String constantToString( final int index, final byte tag ) throws ClassFormatException {
final Constant c = getConstant(index, tag);
return constantToString(c);
public String constantToString(final int index, final byte tag) {
return constantToString(getConstant(index, tag));
}
/**
* Dump constant pool to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
*/
public void dump( final DataOutputStream file ) throws IOException {
/*
* Constants over the size of the constant pool shall not be written out.
* This is a redundant measure as the ConstantPoolGen should have already
* reported an error back in the situation.
*/
int size = constantPool.length < ConstantPoolGen.CONSTANT_POOL_SIZE ?
constantPool.length : ConstantPoolGen.CONSTANT_POOL_SIZE;
file.writeShort(size);
for (int i = 1; i < size; i++) {
if (constantPool[i] != null) {
constantPool[i].dump(file);
}
}
}
/**
* Gets constant from constant pool.
*
* @param index Index in constant pool
* @return Constant value
* @see Constant
*/
public Constant getConstant( final int index ) {
if (index >= constantPool.length || index < 0) {
throw new ClassFormatException("Invalid constant pool reference: " + index
+ ". Constant pool size is: " + constantPool.length);
}
return constantPool[index];
}
/**
* Gets constant from constant pool and check whether it has the
* expected type.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
* @see Constant
* @throws ClassFormatException
*/
public Constant getConstant( final int index, final byte tag ) throws ClassFormatException {
Constant c;
c = getConstant(index);
if (c == null) {
throw new ClassFormatException("Constant pool at index " + index + " is null.");
}
if (c.getTag() != tag) {
throw new ClassFormatException("Expected class `" + Const.getConstantName(tag)
+ "' at index " + index + " and got " + c);
}
return c;
}
/**
* @return Array of constants.
* @see Constant
*/
public Constant[] getConstantPool() {
return constantPool;
}
/**
* Gets string from constant pool and bypass the indirection of
* `ConstantClass' and `ConstantString' objects. I.e. these classes have
* an index field that points to another entry of the constant pool of
* type `ConstantUtf8' which contains the real data.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference
* @see ConstantClass
* @see ConstantString
* @throws ClassFormatException
*/
public String getConstantString( final int index, final byte tag ) throws ClassFormatException {
Constant c;
int i;
c = getConstant(index, tag);
/* This switch() is not that elegant, since the four classes have the
* same contents, they just differ in the name of the index
* field variable.
* But we want to stick to the JVM naming conventions closely though
* we could have solved these more elegantly by using the same
* variable name or by subclassing.
*/
switch (tag) {
case Const.CONSTANT_Class:
i = ((ConstantClass) c).getNameIndex();
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
break;
case Const.CONSTANT_Module:
i = ((ConstantModule) c).getNameIndex();
break;
case Const.CONSTANT_Package:
i = ((ConstantPackage) c).getNameIndex();
break;
default:
throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
}
// Finally get the string from the constant pool
c = getConstant(i, Const.CONSTANT_Utf8);
return ((ConstantUtf8) c).getBytes();
}
/**
* @return Length of constant pool.
*/
public int getLength() {
return constantPool == null ? 0 : constantPool.length;
}
/**
* @param constant Constant to set
*/
public void setConstant( final int index, final Constant constant ) {
constantPool[index] = constant;
}
/**
* @param constantPool
*/
public void setConstantPool( final Constant[] constantPool ) {
this.constantPool = constantPool;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
for (int i = 1; i < constantPool.length; i++) {
buf.append(i).append(")").append(constantPool[i]).append("\n");
}
return buf.toString();
}
/**
* @return deep copy of this constant pool
*/
@@ -386,4 +226,213 @@ public class ConstantPool implements Cloneable, Node {
}
return c;
}
/**
* Dump constant pool to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if problem in writeShort or dump
*/
public void dump(final DataOutputStream file) throws IOException {
/*
* Constants over the size of the constant pool shall not be written out.
* This is a redundant measure as the ConstantPoolGen should have already
* reported an error back in the situation.
*/
final int size = Math.min(constantPool.length, Const.MAX_CP_ENTRIES);
file.writeShort(size);
for (int i = 1; i < size; i++) {
if (constantPool[i] != null) {
constantPool[i].dump(file);
}
}
}
/**
* Gets constant from constant pool.
*
* @param index Index in constant pool
* @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid
*/
@SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index) throws ClassFormatException {
return (T) getConstant(index, Constant.class);
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag
*/
@SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException {
return (T) getConstant(index, tag, Constant.class);
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag
* @since 6.6.0
*/
public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException {
final T c = getConstant(index);
if (c.getTag() != tag) {
throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c);
}
return c;
}
/**
* Gets constant from constant pool.
*
* @param <T> A {@link Constant} subclass
* @param index Index in constant pool
* @param castTo The {@link Constant} subclass to cast to.
* @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid
* @since 6.6.0
*/
public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException {
if (index >= constantPool.length || index < 0) {
throw new ClassFormatException("Invalid constant pool reference using index: " + index + ". Constant pool size is: " + constantPool.length);
}
if (constantPool[index] != null && !castTo.isAssignableFrom(constantPool[index].getClass())) {
throw new ClassFormatException("Invalid constant pool reference at index: " + index +
". Expected " + castTo + " but was " + constantPool[index].getClass());
}
// Previous check ensures this won't throw a ClassCastException
final T c = castTo.cast(constantPool[index]);
if (c == null
// the 0th element is always null
&& index != 0) {
final Constant prev = constantPool[index - 1];
if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) {
throw new ClassFormatException("Constant pool at index " + index + " is null.");
}
}
return c;
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @return ConstantInteger value
* @see ConstantInteger
* @throws ClassFormatException if constant type does not match tag
*/
public ConstantInteger getConstantInteger(final int index) {
return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
}
/**
* @return Array of constants.
* @see Constant
*/
public Constant[] getConstantPool() {
return constantPool;
}
/**
* Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that
* points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference
* @see ConstantClass
* @see ConstantString
* @throws IllegalArgumentException if tag is invalid
*/
public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
int i;
/*
* This switch() is not that elegant, since the four classes have the same contents, they just differ in the name of the index field variable. But we
* want to stick to the JVM naming conventions closely though we could have solved these more elegantly by using the same variable name or by
* subclassing.
*/
switch (tag) {
case Const.CONSTANT_Class:
i = getConstant(index, ConstantClass.class).getNameIndex();
break;
case Const.CONSTANT_String:
i = getConstant(index, ConstantString.class).getStringIndex();
break;
case Const.CONSTANT_Module:
i = getConstant(index, ConstantModule.class).getNameIndex();
break;
case Const.CONSTANT_Package:
i = getConstant(index, ConstantPackage.class).getNameIndex();
break;
case Const.CONSTANT_Utf8:
return getConstantUtf8(index).getBytes();
default:
throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
}
// Finally get the string from the constant pool
return getConstantUtf8(i).getBytes();
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @return ConstantUtf8 value
* @see ConstantUtf8
* @throws ClassFormatException if constant type does not match tag
*/
public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
}
/**
* @return Length of constant pool.
*/
public int getLength() {
return constantPool == null ? 0 : constantPool.length;
}
@Override
public Iterator<Constant> iterator() {
return Arrays.stream(constantPool).iterator();
}
/**
* @param constant Constant to set
*/
public void setConstant(final int index, final Constant constant) {
constantPool[index] = constant;
}
/**
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
for (int i = 1; i < constantPool.length; i++) {
buf.append(i).append(")").append(constantPool[i]).append("\n");
}
return buf.toString();
}
}

View File

@@ -28,35 +28,33 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant}
* and represents a reference to a String object.
* This class is derived from the abstract {@link Constant} and represents a reference to a String object.
*
* @see Constant
* @see Constant
*/
public final class ConstantString extends Constant implements ConstantObject {
private int stringIndex; // Identical to ConstantClass except for this name
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantString(final ConstantString c) {
this(c.getStringIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantString(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param stringIndex Index of Constant_Utf8 in constant pool
*/
@@ -65,32 +63,43 @@ public final class ConstantString extends Constant implements ConstantObject {
this.stringIndex = stringIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantString(this);
}
/**
* Dump constant field reference to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(stringIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(stringIndex).getBytes();
}
/**
* @return Index in constant pool of the string (ConstantUtf8).
@@ -99,15 +108,13 @@ public final class ConstantString extends Constant implements ConstantObject {
return stringIndex;
}
/**
* @param stringIndex the index into the constant of the string value
*/
public void setStringIndex( final int stringIndex ) {
public void setStringIndex(final int stringIndex) {
this.stringIndex = stringIndex;
}
/**
* @return String representation.
*/
@@ -115,20 +122,4 @@ public final class ConstantString extends Constant implements ConstantObject {
public String toString() {
return super.toString() + "(stringIndex = " + stringIndex + ")";
}
/** @return String object
*/
@Override
public Object getConstantValue( final ConstantPool cp ) {
final Constant c = cp.getConstant(stringIndex, Const.CONSTANT_Utf8);
return ((ConstantUtf8) c).getBytes();
}
/** @return dereferenced string
*/
public String getBytes( final ConstantPool cp ) {
return (String) getConstantValue(cp);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -20,19 +20,45 @@
package com.sun.org.apache.bcel.internal.classfile;
import com.sun.org.apache.bcel.internal.Const;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
/**
* Extends the abstract {@link Constant} to represent a reference to a UTF-8 encoded string.
* <p>
* The following system properties govern caching this class performs.
* </p>
* <ul>
* <li>{@value #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is
* disabled.</li>
* <li>{@value #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0
* disables caching. Values larger than this are <em>not</em> cached.</li>
* <li>{@value #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.</li>
* </ul>
* <p>
* Here is a sample Maven invocation with caching disabled:
* </p>
*
* <pre>
* mvn test -Dbcel.statistics=true -Dbcel.maxcached.size=0 -Dbcel.maxcached=0
* </pre>
* <p>
* Here is a sample Maven invocation with caching enabled:
* </p>
*
* <pre>
* mvn test -Dbcel.statistics=true -Dbcel.maxcached.size=100000 -Dbcel.maxcached=5000000
* </pre>
*
* @see Constant
* @LastModified: Jan 2020
* @LastModified: Feb 2023
*/
public final class ConstantUtf8 extends Constant {
@@ -42,8 +68,7 @@ public final class ConstantUtf8 extends Constant {
private static final int MAX_ENTRIES = 20000;
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 HashMap<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
private static final long serialVersionUID = -8506975356158971766L;
@@ -62,6 +87,22 @@ public final class ConstantUtf8 extends Constant {
}
// TODO these should perhaps be AtomicInt?
private static volatile int considered;
private static volatile int created;
private static volatile int hits;
private static volatile int skipped;
private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
private static final String SYS_PROP_STATISTICS = "bcel.statistics";
static {
if (Cache.BCEL_STATISTICS) {
Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats));
}
}
/**
* Clears the cache.
*
@@ -71,6 +112,11 @@ public final class ConstantUtf8 extends Constant {
Cache.CACHE.clear();
}
// for access by test code
static synchronized void clearStats() {
hits = considered = skipped = created = 0;
}
/**
* Gets a new or cached instance of the given value.
* <p>
@@ -83,12 +129,14 @@ public final class ConstantUtf8 extends Constant {
*/
public static ConstantUtf8 getCachedInstance(final String value) {
if (value.length() > Cache.MAX_ENTRY_SIZE) {
skipped++;
return new ConstantUtf8(value);
}
considered++;
synchronized (ConstantUtf8.class) { // might be better with a specific lock object
ConstantUtf8 result = Cache.CACHE.get(value);
if (result != null) {
hits++;
return result;
}
result = new ConstantUtf8(value);
@@ -126,6 +174,15 @@ public final class ConstantUtf8 extends Constant {
return Cache.isEnabled() ? getCachedInstance(value) : new ConstantUtf8(value);
}
// for access by test code
static void printStats() {
final String prefix = "[Apache Commons BCEL]";
System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped);
System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created);
System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE,
Cache.MAX_ENTRY_SIZE);
}
private final String value;
/**
@@ -141,11 +198,12 @@ public final class ConstantUtf8 extends Constant {
* Initializes instance from file data.
*
* @param dataInput Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ConstantUtf8(final DataInput dataInput) throws IOException {
super(Const.CONSTANT_Utf8);
value = dataInput.readUTF();
created++;
}
/**
@@ -153,14 +211,12 @@ public final class ConstantUtf8 extends Constant {
*/
public ConstantUtf8(final String value) {
super(Const.CONSTANT_Utf8);
if (value == null) {
throw new IllegalArgumentException("Value must not be null.");
}
this.value = value;
this.value = Objects.requireNonNull(value, "value");
created++;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely 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.
*
* @param v Visitor object
@@ -174,7 +230,7 @@ public final class ConstantUtf8 extends Constant {
* Dumps String in Utf8 format to file stream.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {

View File

@@ -26,81 +26,92 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a constant
* value, i.e., a default value for initializing a class field.
* This class is instantiated by the <em>Attribute.readAttribute()</em> method.
* This class is derived from <em>Attribute</em> and represents a constant value, i.e., a default value for initializing
* a class field. This class is instantiated by the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
* <pre>
* ConstantValue_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 constantvalue_index;
* }
* </pre>
* @see Attribute
*/
public final class ConstantValue extends Attribute {
private int constantValueIndex;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* 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 ConstantValue(final ConstantValue c) {
this(c.getNameIndex(), c.getLength(), c.getConstantValueIndex(), c.getConstantPool());
}
/**
* Construct object from input stream.
* @param name_index Name index in constant pool
*
* @param nameIndex Name index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
ConstantValue(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, input.readUnsignedShort(), constant_pool);
ConstantValue(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* @param name_index Name index in constant pool
* @param nameIndex Name index in constant pool
* @param length Content length in bytes
* @param constantValueIndex Index in constant pool
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public ConstantValue(final int name_index, final int length, final int constantValueIndex,
final ConstantPool constant_pool) {
super(Const.ATTR_CONSTANT_VALUE, name_index, length, constant_pool);
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);
this.constantValueIndex = constantValueIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitConstantValue(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ConstantValue c = (ConstantValue) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dump constant value attribute to file stream on binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(constantValueIndex);
}
/**
* @return Index in constant pool of constant value.
*/
@@ -108,15 +119,13 @@ public final class ConstantValue extends Attribute {
return constantValueIndex;
}
/**
* @param constantValueIndex the index info the constant pool of this constant value
*/
public void setConstantValueIndex( final int constantValueIndex ) {
public void setConstantValueIndex(final int constantValueIndex) {
this.constantValueIndex = constantValueIndex;
}
/**
* @return String representation of constant value.
*/
@@ -127,37 +136,26 @@ public final class ConstantValue extends Attribute {
int i;
// Print constant to string depending on its type
switch (c.getTag()) {
case Const.CONSTANT_Long:
buf = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Float:
buf = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Double:
buf = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Integer:
buf = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = super.getConstantPool().getConstant(i, Const.CONSTANT_Utf8);
buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
break;
default:
throw new IllegalStateException("Type of ConstValue invalid: " + c);
case Const.CONSTANT_Long:
buf = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Float:
buf = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Double:
buf = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Integer:
buf = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = super.getConstantPool().getConstantUtf8(i);
buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
break;
default:
throw new IllegalStateException("Type of ConstValue invalid: " + c);
}
return buf;
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final ConstantValue c = (ConstantValue) clone();
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -25,52 +25,50 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and denotes that this is a
* deprecated method.
* It is instantiated from the <em>Attribute.readAttribute()</em> method.
* This class is derived from <em>Attribute</em> and denotes that this is a deprecated method. It is instantiated from
* the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
* @see Attribute
*/
public final class Deprecated extends Attribute {
private byte[] bytes;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* 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 Deprecated(final Deprecated c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param bytes Attribute contents
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public Deprecated(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
super(Const.ATTR_DEPRECATED, name_index, length, constant_pool);
public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_DEPRECATED, nameIndex, Args.require0(length, "Deprecated attribute length"), constantPool);
this.bytes = bytes;
}
/**
* Construct object from input stream.
*
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Deprecated(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (byte[]) null, constant_pool);
Deprecated(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
@@ -78,35 +76,44 @@ public final class Deprecated extends Attribute {
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitDeprecated(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Deprecated c = (Deprecated) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
@@ -114,35 +121,18 @@ public final class Deprecated extends Attribute {
return bytes;
}
/**
* @param bytes the raw bytes that represents this byte array
*/
public void setBytes( final byte[] bytes ) {
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return attribute name
*/
@Override
public String toString() {
return Const.getAttributeName(Const.ATTR_DEPRECATED);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final Deprecated c = (Deprecated) clone();
if (bytes != null) {
c.bytes = new byte[bytes.length];
System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
}
c.setConstantPool(_constant_pool);
return c;
return Const.getAttributeName(Const.ATTR_DEPRECATED) + ": true";
}
}

View File

@@ -19,7 +19,9 @@
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.util.Objects;
import java.util.Stack;
import java.util.stream.Stream;
/**
* Traverses a JavaClass with another Visitor object 'piggy-backed' that is
@@ -27,98 +29,67 @@ import java.util.Stack;
* traversal strategy, other classes can make use of it.
*
*/
public class DescendingVisitor implements Visitor
{
public class DescendingVisitor implements Visitor {
private final JavaClass clazz;
private final Visitor visitor;
private final Stack<Object> stack = new Stack<>();
/**
* @param clazz Class to traverse
* @param visitor visitor object to apply to all components
*/
public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
this.clazz = clazz;
this.visitor = visitor;
}
private <E extends Node> void accept(final E[] node) {
Stream.of(node).forEach(e -> e.accept(this));
}
/**
* @return current object
*/
public Object current() {
return stack.peek();
}
/**
* @return container of current entitity, i.e., predecessor during traversal
*/
public Object predecessor()
{
public Object predecessor() {
return predecessor(0);
}
/**
* @param level
* nesting level, i.e., 0 returns the direct predecessor
* @param level nesting level, i.e., 0 returns the direct predecessor
* @return container of current entitity, i.e., predecessor during traversal
*/
public Object predecessor(final int level)
{
public Object predecessor(final int level) {
final int size = stack.size();
if ((size < 2) || (level < 0))
{
if (size < 2 || level < 0) {
return null;
}
return stack.elementAt(size - (level + 2)); // size - 1 == current
}
/**
* @return current object
*/
public Object current()
{
return stack.peek();
}
/**
* @param clazz
* Class to traverse
* @param visitor
* visitor object to apply to all components
*/
public DescendingVisitor(final JavaClass clazz, final Visitor visitor)
{
this.clazz = clazz;
this.visitor = visitor;
}
/**
* Start traversal.
*/
public void visit()
{
public void visit() {
clazz.accept(this);
}
@Override
public void visitJavaClass(final JavaClass _clazz)
{
stack.push(_clazz);
_clazz.accept(visitor);
final Field[] fields = _clazz.getFields();
for (final Field field : fields) {
field.accept(this);
}
final Method[] methods = _clazz.getMethods();
for (final Method method : methods) {
method.accept(this);
}
final Attribute[] attributes = _clazz.getAttributes();
for (final Attribute attribute : attributes) {
attribute.accept(this);
}
_clazz.getConstantPool().accept(this);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitAnnotation(final Annotations annotation)
{
public void visitAnnotation(final Annotations annotation) {
stack.push(annotation);
annotation.accept(visitor);
final AnnotationEntry[] entries = annotation.getAnnotationEntries();
for (final AnnotationEntry entrie : entries) {
entrie.accept(this);
}
accept(annotation.getAnnotationEntries());
stack.pop();
}
@@ -126,197 +97,98 @@ public class DescendingVisitor implements Visitor
* @since 6.0
*/
@Override
public void visitAnnotationEntry(final AnnotationEntry annotationEntry)
{
public void visitAnnotationDefault(final AnnotationDefault obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationEntry(final AnnotationEntry annotationEntry) {
stack.push(annotationEntry);
annotationEntry.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitField(final Field field)
{
stack.push(field);
field.accept(visitor);
final Attribute[] attributes = field.getAttributes();
for (final Attribute attribute : attributes) {
attribute.accept(this);
}
public void visitBootstrapMethods(final BootstrapMethods bm) {
stack.push(bm);
bm.accept(visitor);
// BootstrapMethod[] bms = bm.getBootstrapMethods();
// for (int i = 0; i < bms.length; i++)
// {
// bms[i].accept(this);
// }
stack.pop();
}
@Override
public void visitConstantValue(final ConstantValue cv)
{
stack.push(cv);
cv.accept(visitor);
stack.pop();
}
@Override
public void visitMethod(final Method method)
{
stack.push(method);
method.accept(visitor);
final Attribute[] attributes = method.getAttributes();
for (final Attribute attribute : attributes) {
attribute.accept(this);
}
stack.pop();
}
@Override
public void visitExceptionTable(final ExceptionTable table)
{
stack.push(table);
table.accept(visitor);
stack.pop();
}
@Override
public void visitCode(final Code code)
{
public void visitCode(final Code code) {
stack.push(code);
code.accept(visitor);
final CodeException[] table = code.getExceptionTable();
for (final CodeException element : table) {
element.accept(this);
}
final Attribute[] attributes = code.getAttributes();
for (final Attribute attribute : attributes) {
attribute.accept(this);
}
accept(code.getExceptionTable());
accept(code.getAttributes());
stack.pop();
}
@Override
public void visitCodeException(final CodeException ce)
{
public void visitCodeException(final CodeException ce) {
stack.push(ce);
ce.accept(visitor);
stack.pop();
}
@Override
public void visitLineNumberTable(final LineNumberTable table)
{
stack.push(table);
table.accept(visitor);
final LineNumber[] numbers = table.getLineNumberTable();
for (final LineNumber number : numbers) {
number.accept(this);
}
stack.pop();
}
@Override
public void visitLineNumber(final LineNumber number)
{
stack.push(number);
number.accept(visitor);
stack.pop();
}
@Override
public void visitLocalVariableTable(final LocalVariableTable table)
{
stack.push(table);
table.accept(visitor);
final LocalVariable[] vars = table.getLocalVariableTable();
for (final LocalVariable var : vars) {
var.accept(this);
}
stack.pop();
}
@Override
public void visitStackMap(final StackMap table)
{
stack.push(table);
table.accept(visitor);
final StackMapEntry[] vars = table.getStackMap();
for (final StackMapEntry var : vars) {
var.accept(this);
}
stack.pop();
}
@Override
public void visitStackMapEntry(final StackMapEntry var)
{
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitLocalVariable(final LocalVariable var)
{
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitConstantPool(final ConstantPool cp)
{
stack.push(cp);
cp.accept(visitor);
final Constant[] constants = cp.getConstantPool();
for (int i = 1; i < constants.length; i++)
{
if (constants[i] != null)
{
constants[i].accept(this);
}
}
stack.pop();
}
@Override
public void visitConstantClass(final ConstantClass constant)
{
public void visitConstantClass(final ConstantClass constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantDouble(final ConstantDouble constant)
{
public void visitConstantDouble(final ConstantDouble constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.3 */
@Override
public void visitConstantDynamic(final ConstantDynamic obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantFieldref(final ConstantFieldref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantFieldref(final ConstantFieldref constant)
{
public void visitConstantFloat(final ConstantFloat constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantFloat(final ConstantFloat constant)
{
public void visitConstantInteger(final ConstantInteger constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantInteger(final ConstantInteger constant)
{
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantInterfaceMethodref(
final ConstantInterfaceMethodref constant)
{
public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
@@ -326,208 +198,19 @@ public class DescendingVisitor implements Visitor
* @since 6.0
*/
@Override
public void visitConstantInvokeDynamic(
final ConstantInvokeDynamic constant)
{
public void visitConstantInvokeDynamic(final ConstantInvokeDynamic constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantLong(final ConstantLong constant)
{
public void visitConstantLong(final ConstantLong constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantMethodref(final ConstantMethodref constant)
{
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantNameAndType(final ConstantNameAndType constant)
{
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantString(final ConstantString constant)
{
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantUtf8(final ConstantUtf8 constant)
{
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitInnerClasses(final InnerClasses ic)
{
stack.push(ic);
ic.accept(visitor);
final InnerClass[] ics = ic.getInnerClasses();
for (final InnerClass ic2 : ics) {
ic2.accept(this);
}
stack.pop();
}
@Override
public void visitInnerClass(final InnerClass inner)
{
stack.push(inner);
inner.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitBootstrapMethods(final BootstrapMethods bm)
{
stack.push(bm);
bm.accept(visitor);
// BootstrapMethod[] bms = bm.getBootstrapMethods();
// for (int i = 0; i < bms.length; i++)
// {
// bms[i].accept(this);
// }
stack.pop();
}
@Override
public void visitDeprecated(final Deprecated attribute)
{
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitSignature(final Signature attribute)
{
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitSourceFile(final SourceFile attribute)
{
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitSynthetic(final Synthetic attribute)
{
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitUnknown(final Unknown attribute)
{
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationDefault(final AnnotationDefault obj)
{
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj)
{
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj)
{
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj)
{
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj)
{
stack.push(obj);
obj.accept(visitor);
final MethodParameter[] table = obj.getParameters();
for (final MethodParameter element : table) {
element.accept(this);
}
stack.pop();
}
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj)
{
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitConstantMethodType(final ConstantMethodType obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
@@ -536,17 +219,16 @@ public class DescendingVisitor implements Visitor
stack.pop();
}
/** @since 6.0 */
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
stack.push(obj);
obj.accept(visitor);
public void visitConstantMethodref(final ConstantMethodref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.1 */
/** @since 6.0 */
@Override
public void visitConstantPackage(final ConstantPackage obj) {
public void visitConstantMethodType(final ConstantMethodType obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
@@ -560,41 +242,192 @@ public class DescendingVisitor implements Visitor
stack.pop();
}
/** @since 6.3 */
@Override
public void visitConstantDynamic(final ConstantDynamic obj) {
public void visitConstantNameAndType(final ConstantNameAndType constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.1 */
@Override
public void visitConstantPackage(final ConstantPackage obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantPool(final ConstantPool cp) {
stack.push(cp);
cp.accept(visitor);
Stream.of(cp.getConstantPool()).filter(Objects::nonNull).forEach(e -> e.accept(this));
stack.pop();
}
@Override
public void visitConstantString(final ConstantString constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantUtf8(final ConstantUtf8 constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantValue(final ConstantValue cv) {
stack.push(cv);
cv.accept(visitor);
stack.pop();
}
@Override
public void visitDeprecated(final Deprecated attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitExceptionTable(final ExceptionTable table) {
stack.push(table);
table.accept(visitor);
stack.pop();
}
@Override
public void visitField(final Field field) {
stack.push(field);
field.accept(visitor);
accept(field.getAttributes());
stack.pop();
}
@Override
public void visitInnerClass(final InnerClass inner) {
stack.push(inner);
inner.accept(visitor);
stack.pop();
}
@Override
public void visitInnerClasses(final InnerClasses ic) {
stack.push(ic);
ic.accept(visitor);
accept(ic.getInnerClasses());
stack.pop();
}
@Override
public void visitJavaClass(final JavaClass clazz) {
stack.push(clazz);
clazz.accept(visitor);
accept(clazz.getFields());
accept(clazz.getMethods());
accept(clazz.getAttributes());
clazz.getConstantPool().accept(this);
stack.pop();
}
@Override
public void visitLineNumber(final LineNumber number) {
stack.push(number);
number.accept(visitor);
stack.pop();
}
@Override
public void visitLineNumberTable(final LineNumberTable table) {
stack.push(table);
table.accept(visitor);
accept(table.getLineNumberTable());
stack.pop();
}
@Override
public void visitLocalVariable(final LocalVariable var) {
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitLocalVariableTable(final LocalVariableTable table) {
stack.push(table);
table.accept(visitor);
accept(table.getLocalVariableTable());
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitMethod(final Method method) {
stack.push(method);
method.accept(visitor);
accept(method.getAttributes());
stack.pop();
}
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj) {
stack.push(obj);
obj.accept(visitor);
Stream.of(obj.getParameters()).forEach(e -> e.accept(this));
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModule(final Module obj) {
stack.push(obj);
obj.accept(visitor);
final ModuleRequires[] rtable = obj.getRequiresTable();
for (final ModuleRequires element : rtable) {
element.accept(this);
}
final ModuleExports[] etable = obj.getExportsTable();
for (final ModuleExports element : etable) {
element.accept(this);
}
final ModuleOpens[] otable = obj.getOpensTable();
for (final ModuleOpens element : otable) {
element.accept(this);
}
final ModuleProvides[] ptable = obj.getProvidesTable();
for (final ModuleProvides element : ptable) {
element.accept(this);
}
accept(obj.getRequiresTable());
accept(obj.getExportsTable());
accept(obj.getOpensTable());
accept(obj.getProvidesTable());
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
public void visitModuleExports(final ModuleExports obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
@@ -602,7 +435,7 @@ public class DescendingVisitor implements Visitor
/** @since 6.4.0 */
@Override
public void visitModuleExports(final ModuleExports obj) {
public void visitModuleMainClass(final ModuleMainClass obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
@@ -616,14 +449,6 @@ public class DescendingVisitor implements Visitor
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModulePackages(final ModulePackages obj) {
@@ -634,7 +459,15 @@ public class DescendingVisitor implements Visitor
/** @since 6.4.0 */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
public void visitModuleProvides(final ModuleProvides obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
@@ -655,4 +488,65 @@ public class DescendingVisitor implements Visitor
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitSignature(final Signature attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitSourceFile(final SourceFile attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitStackMap(final StackMap table) {
stack.push(table);
table.accept(visitor);
accept(table.getStackMap());
stack.pop();
}
@Override
public void visitStackMapEntry(final StackMapEntry var) {
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitSynthetic(final Synthetic attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitUnknown(final Unknown attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
}

View File

@@ -24,103 +24,155 @@ import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
*
* <pre>
* element_value {
* u1 tag;
* union {
* u2 const_value_index;
*
* { u2 type_name_index;
* u2 const_name_index;
* } enum_const_value;
*
* u2 class_info_index;
*
* annotation annotation_value;
*
* { u2 num_values;
* element_value values[num_values];
* } array_value;
* } value;
*}
*</pre>
* @since 6.0
* @LastModified: May 2021
*/
public abstract class ElementValue
{
private final int type;
public abstract class ElementValue {
private final ConstantPool cpool;
public static final byte STRING = 's';
public static final byte ENUM_CONSTANT = 'e';
public static final byte CLASS = 'c';
public static final byte ANNOTATION = '@';
public static final byte ARRAY = '[';
public static final byte PRIMITIVE_INT = 'I';
public static final byte PRIMITIVE_BYTE = 'B';
public static final byte PRIMITIVE_CHAR = 'C';
public static final byte PRIMITIVE_DOUBLE = 'D';
public static final byte PRIMITIVE_FLOAT = 'F';
public static final byte PRIMITIVE_LONG = 'J';
public static final byte PRIMITIVE_SHORT = 'S';
public static final byte PRIMITIVE_BOOLEAN = 'Z';
@Override
public String toString()
{
return stringifyValue();
/**
* 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);
}
protected ElementValue(final int type, final ConstantPool cpool)
{
/**
* 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
*/
@java.lang.Deprecated
protected int type; // TODO should be final
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected ConstantPool cpool; // TODO should be final
protected ElementValue(final int type, final ConstantPool cpool) {
this.type = type;
this.cpool = cpool;
}
public int getElementValueType()
{
return type;
}
public abstract String stringifyValue();
public abstract void dump(DataOutputStream dos) throws IOException;
public static final byte STRING = 's';
public static final byte ENUM_CONSTANT = 'e';
public static final byte CLASS = 'c';
public static final byte ANNOTATION = '@';
public static final byte ARRAY = '[';
public static final byte PRIMITIVE_INT = 'I';
public static final byte PRIMITIVE_BYTE = 'B';
public static final byte PRIMITIVE_CHAR = 'C';
public static final byte PRIMITIVE_DOUBLE = 'D';
public static final byte PRIMITIVE_FLOAT = 'F';
public static final byte PRIMITIVE_LONG = 'J';
public static final byte PRIMITIVE_SHORT = 'S';
public static final byte PRIMITIVE_BOOLEAN = 'Z';
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException
{
final byte type = input.readByte();
switch (type)
{
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(type, 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:
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++)
{
evalues[j] = ElementValue.readElementValue(input, cpool);
}
return new ArrayElementValue(ARRAY, evalues, cpool);
default:
throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type);
}
}
/** @since 6.0 */
final ConstantPool getConstantPool() {
return cpool;
}
public int getElementValueType() {
return type;
}
/** @since 6.0 */
final int getType() {
return type;
}
public String toShortString()
{
public abstract String stringifyValue();
public String toShortString() {
return stringifyValue();
}
@Override
public String toString() {
return stringifyValue();
}
}

View File

@@ -24,56 +24,47 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* an annotation's element value pair
* An annotation's element value pair.
*
* @since 6.0
*/
public class ElementValuePair
{
public class ElementValuePair {
static final ElementValuePair[] EMPTY_ARRAY = {};
private final ElementValue elementValue;
private final ConstantPool constantPool;
private final int elementNameIndex;
public ElementValuePair(final int elementNameIndex, final ElementValue elementValue,
final ConstantPool constantPool)
{
public ElementValuePair(final int elementNameIndex, final ElementValue elementValue, final ConstantPool constantPool) {
this.elementValue = elementValue;
this.elementNameIndex = elementNameIndex;
this.constantPool = constantPool;
}
public String getNameString()
{
final ConstantUtf8 c = (ConstantUtf8) constantPool.getConstant(
elementNameIndex, Const.CONSTANT_Utf8);
return c.getBytes();
}
public final ElementValue getValue()
{
return elementValue;
}
public int getNameIndex()
{
return elementNameIndex;
}
public String toShortString()
{
final StringBuilder result = new StringBuilder();
result.append(getNameString()).append("=").append(
getValue().toShortString());
return result.toString();
}
protected void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(elementNameIndex); // u2 name of the element
elementValue.dump(dos);
}
public int getNameIndex() {
return elementNameIndex;
}
public String getNameString() {
return constantPool.getConstantUtf8(elementNameIndex).getBytes();
}
public final ElementValue getValue() {
return elementValue;
}
public String toShortString() {
final StringBuilder result = new StringBuilder();
result.append(getNameString()).append("=").append(getValue().toShortString());
return result.toString();
}
}

View File

@@ -22,304 +22,57 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* Visitor with empty method bodies, can be extended and used in conjunction
* with the DescendingVisitor class, e.g. By courtesy of David Spencer.
* Visitor with empty method bodies, can be extended and used in conjunction with the DescendingVisitor class, e.g. By
* courtesy of David Spencer.
*
* @see DescendingVisitor
*/
public class EmptyVisitor implements Visitor
{
protected EmptyVisitor()
{
public class EmptyVisitor implements Visitor {
protected EmptyVisitor() {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotation(final Annotations obj)
{
public void visitAnnotation(final Annotations obj) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj)
{
public void visitAnnotationDefault(final AnnotationDefault obj) {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationEntry(final AnnotationEntry obj)
{
public void visitAnnotationEntry(final AnnotationEntry obj) {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationDefault(final AnnotationDefault obj)
{
public void visitBootstrapMethods(final BootstrapMethods obj) {
}
@Override
public void visitCode(final Code obj)
{
public void visitCode(final Code obj) {
}
@Override
public void visitCodeException(final CodeException obj)
{
public void visitCodeException(final CodeException obj) {
}
@Override
public void visitConstantClass(final ConstantClass obj)
{
public void visitConstantClass(final ConstantClass obj) {
}
@Override
public void visitConstantDouble(final ConstantDouble obj)
{
}
@Override
public void visitConstantFieldref(final ConstantFieldref obj)
{
}
@Override
public void visitConstantFloat(final ConstantFloat obj)
{
}
@Override
public void visitConstantInteger(final ConstantInteger obj)
{
}
@Override
public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref obj)
{
}
@Override
public void visitConstantInvokeDynamic(final ConstantInvokeDynamic obj)
{
}
@Override
public void visitConstantLong(final ConstantLong obj)
{
}
@Override
public void visitConstantMethodref(final ConstantMethodref obj)
{
}
@Override
public void visitConstantNameAndType(final ConstantNameAndType obj)
{
}
@Override
public void visitConstantPool(final ConstantPool obj)
{
}
@Override
public void visitConstantString(final ConstantString obj)
{
}
@Override
public void visitConstantUtf8(final ConstantUtf8 obj)
{
}
@Override
public void visitConstantValue(final ConstantValue obj)
{
}
@Override
public void visitDeprecated(final Deprecated obj)
{
}
@Override
public void visitExceptionTable(final ExceptionTable obj)
{
}
@Override
public void visitField(final Field obj)
{
}
@Override
public void visitInnerClass(final InnerClass obj)
{
}
@Override
public void visitInnerClasses(final InnerClasses obj)
{
}
/**
* @since 6.0
*/
@Override
public void visitBootstrapMethods(final BootstrapMethods obj)
{
}
@Override
public void visitJavaClass(final JavaClass obj)
{
}
@Override
public void visitLineNumber(final LineNumber obj)
{
}
@Override
public void visitLineNumberTable(final LineNumberTable obj)
{
}
@Override
public void visitLocalVariable(final LocalVariable obj)
{
}
@Override
public void visitLocalVariableTable(final LocalVariableTable obj)
{
}
@Override
public void visitMethod(final Method obj)
{
}
@Override
public void visitSignature(final Signature obj)
{
}
@Override
public void visitSourceFile(final SourceFile obj)
{
}
@Override
public void visitSynthetic(final Synthetic obj)
{
}
@Override
public void visitUnknown(final Unknown obj)
{
}
@Override
public void visitStackMap(final StackMap obj)
{
}
@Override
public void visitStackMapEntry(final StackMapEntry obj)
{
}
/**
* @since 6.0
@Override
public void visitStackMapTable(StackMapTable obj)
{
}
*/
/**
* @since 6.0
@Override
public void visitStackMapTableEntry(StackMapTableEntry obj)
{
}
*/
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj)
{
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj)
{
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj)
{
}
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj)
{
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodType(final ConstantMethodType obj)
{
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle constantMethodHandle) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry parameterAnnotationEntry) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantPackage(final ConstantPackage constantPackage) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantModule(final ConstantModule constantModule) {
public void visitConstantDouble(final ConstantDouble obj) {
}
/**
@@ -329,14 +82,167 @@ public class EmptyVisitor implements Visitor
public void visitConstantDynamic(final ConstantDynamic obj) {
}
/** @since 6.4.0 */
@Override
public void visitModule(final Module obj) {
public void visitConstantFieldref(final ConstantFieldref obj) {
}
@Override
public void visitConstantFloat(final ConstantFloat obj) {
}
@Override
public void visitConstantInteger(final ConstantInteger obj) {
}
@Override
public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref obj) {
}
@Override
public void visitConstantInvokeDynamic(final ConstantInvokeDynamic obj) {
}
@Override
public void visitConstantLong(final ConstantLong obj) {
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle constantMethodHandle) {
}
@Override
public void visitConstantMethodref(final ConstantMethodref obj) {
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodType(final ConstantMethodType obj) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantModule(final ConstantModule constantModule) {
}
@Override
public void visitConstantNameAndType(final ConstantNameAndType obj) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantPackage(final ConstantPackage constantPackage) {
}
@Override
public void visitConstantPool(final ConstantPool obj) {
}
@Override
public void visitConstantString(final ConstantString obj) {
}
@Override
public void visitConstantUtf8(final ConstantUtf8 obj) {
}
@Override
public void visitConstantValue(final ConstantValue obj) {
}
@Override
public void visitDeprecated(final Deprecated obj) {
}
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj) {
}
@Override
public void visitExceptionTable(final ExceptionTable obj) {
}
@Override
public void visitField(final Field obj) {
}
@Override
public void visitInnerClass(final InnerClass obj) {
}
@Override
public void visitInnerClasses(final InnerClasses obj) {
}
@Override
public void visitJavaClass(final JavaClass obj) {
}
@Override
public void visitLineNumber(final LineNumber obj) {
}
@Override
public void visitLineNumberTable(final LineNumberTable obj) {
}
@Override
public void visitLocalVariable(final LocalVariable obj) {
}
@Override
public void visitLocalVariableTable(final LocalVariableTable obj) {
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
}
@Override
public void visitMethod(final Method obj) {
}
/**
* @since 6.0
* @Override public void visitStackMapTable(StackMapTable obj) { }
*/
/**
* @since 6.0
* @Override public void visitStackMapTableEntry(StackMapTableEntry obj) { }
*/
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj) {
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
public void visitModule(final Module obj) {
}
/** @since 6.4.0 */
@@ -346,12 +252,12 @@ public class EmptyVisitor implements Visitor
/** @since 6.4.0 */
@Override
public void visitModuleOpens(final ModuleOpens obj) {
public void visitModuleMainClass(final ModuleMainClass obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
public void visitModuleOpens(final ModuleOpens obj) {
}
/** @since 6.4.0 */
@@ -361,7 +267,12 @@ public class EmptyVisitor implements Visitor
/** @since 6.4.0 */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
public void visitModuleProvides(final ModuleProvides obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
}
/** @since 6.4.0 */
@@ -373,4 +284,42 @@ public class EmptyVisitor implements Visitor
@Override
public void visitNestMembers(final NestMembers obj) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry parameterAnnotationEntry) {
}
@Override
public void visitSignature(final Signature obj) {
}
@Override
public void visitSourceFile(final SourceFile obj) {
}
@Override
public void visitStackMap(final StackMap obj) {
}
@Override
public void visitStackMapEntry(final StackMapEntry obj) {
}
@Override
public void visitSynthetic(final Synthetic obj) {
}
@Override
public void visitUnknown(final Unknown obj) {
}
}

View File

@@ -26,10 +26,10 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This attribute exists for local or
* anonymous classes and ... there can be only one.
* This attribute exists for local or anonymous classes and ... there can be only one.
*
* @since 6.0
*/
@@ -41,10 +41,10 @@ public class EnclosingMethod extends Attribute {
// If the current class is not immediately enclosed by a method or
// constructor, then the value of the method_index item must be zero.
// Otherwise, the value of the method_index item must point to a
// Otherwise, the value of the method_index item must point to a
// CONSTANT_NameAndType_info structure representing the name and the
// type of a method in the class referenced by the class we point
// to in the class_index. *It is the compiler responsibility* to
// to in the class_index. *It is the compiler responsibility* to
// ensure that the method identified by this index is the closest
// lexically enclosing method that includes the local/anonymous class.
private int methodIndex;
@@ -54,27 +54,45 @@ public class EnclosingMethod extends Attribute {
this(nameIndex, len, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
}
private EnclosingMethod(final int nameIndex, final int len, final int classIdx,final int methodIdx, final ConstantPool cpool) {
super(Const.ATTR_ENCLOSING_METHOD, nameIndex, len, cpool);
classIndex = classIdx;
methodIndex = methodIdx;
private EnclosingMethod(final int nameIndex, final int len, final int classIndex, final int methodIndex, final ConstantPool cpool) {
super(Const.ATTR_ENCLOSING_METHOD, nameIndex, Args.require(len, 4, "EnclosingMethod attribute length"), cpool);
this.classIndex = Args.requireU2(classIndex, 0, cpool.getLength(), "EnclosingMethod class index");
this.methodIndex = Args.requireU2(methodIndex, "EnclosingMethod method index");
}
@Override
public void accept(final Visitor v) {
v.visitEnclosingMethod(this);
v.visitEnclosingMethod(this);
}
@Override
public Attribute copy(final ConstantPool constant_pool) {
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(classIndex);
file.writeShort(methodIndex);
}
public final ConstantClass getEnclosingClass() {
return super.getConstantPool().getConstant(classIndex, Const.CONSTANT_Class, ConstantClass.class);
}
// Accessors
public final int getEnclosingClassIndex() {
return classIndex;
}
public final ConstantNameAndType getEnclosingMethod() {
if (methodIndex == 0) {
return null;
}
return super.getConstantPool().getConstant(methodIndex, Const.CONSTANT_NameAndType, ConstantNameAndType.class);
}
public final int getEnclosingMethodIndex() {
return methodIndex;
}
@@ -86,26 +104,4 @@ public class EnclosingMethod extends Attribute {
public final void setEnclosingMethodIndex(final int idx) {
methodIndex = idx;
}
public final ConstantClass getEnclosingClass() {
final ConstantClass c =
(ConstantClass)super.getConstantPool().getConstant(classIndex,Const.CONSTANT_Class);
return c;
}
public final ConstantNameAndType getEnclosingMethod() {
if (methodIndex == 0) {
return null;
}
final ConstantNameAndType nat =
(ConstantNameAndType)super.getConstantPool().getConstant(methodIndex,Const.CONSTANT_NameAndType);
return nat;
}
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(classIndex);
file.writeShort(methodIndex);
}
}

View File

@@ -24,67 +24,49 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* @since 6.0
*/
public class EnumElementValue extends ElementValue
{
public class EnumElementValue extends ElementValue {
// For enum types, these two indices point to the type and value
private final int typeIdx;
private final int valueIdx;
public EnumElementValue(final int type, final int typeIdx, final int valueIdx,
final ConstantPool cpool)
{
public EnumElementValue(final int type, final int typeIdx, final int valueIdx, final ConstantPool cpool) {
super(type, cpool);
if (type != ENUM_CONSTANT) {
throw new IllegalArgumentException(
"Only element values of type enum can be built with this ctor - type specified: " + type);
throw new ClassFormatException("Only element values of type enum can be built with this ctor - type specified: " + type);
}
this.typeIdx = typeIdx;
this.valueIdx = valueIdx;
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ENUM_CONSTANT == 'e')
dos.writeShort(typeIdx); // u2
dos.writeShort(valueIdx); // u2
}
@Override
public String stringifyValue()
{
final ConstantUtf8 cu8 = (ConstantUtf8) super.getConstantPool().getConstant(valueIdx,
Const.CONSTANT_Utf8);
return cu8.getBytes();
public String getEnumTypeString() {
return super.getConstantPool().getConstantUtf8(typeIdx).getBytes();
}
public String getEnumTypeString()
{
final ConstantUtf8 cu8 = (ConstantUtf8) super.getConstantPool().getConstant(typeIdx,
Const.CONSTANT_Utf8);
return cu8.getBytes();// Utility.signatureToString(cu8.getBytes());
public String getEnumValueString() {
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
}
public String getEnumValueString()
{
final ConstantUtf8 cu8 = (ConstantUtf8) super.getConstantPool().getConstant(valueIdx,
Const.CONSTANT_Utf8);
return cu8.getBytes();
public int getTypeIndex() {
return typeIdx;
}
public int getValueIndex()
{
public int getValueIndex() {
return valueIdx;
}
public int getTypeIndex()
{
return typeIdx;
@Override
public String stringifyValue() {
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
}
}

View File

@@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,85 +23,104 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents the table of exceptions that are thrown by a
* method. This attribute may be used once per method. The name of
* this class is <em>ExceptionTable</em> for historical reasons; The
* Java Virtual Machine Specification, Second Edition defines this
* attribute using the name <em>Exceptions</em> (which is inconsistent
* with the other classes).
* This class represents the table of exceptions that are thrown by a method. This attribute may be used once per
* method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine
* Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with
* the other classes).
*
* @see Code
* <pre>
* Exceptions_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 number_of_exceptions;
* u2 exception_index_table[number_of_exceptions];
* }
* </pre>
* @see Code
* @LastModified: Feb 2023
*/
public final class ExceptionTable extends Attribute {
private int[] exceptionIndexTable; // constant pool
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public ExceptionTable(final ExceptionTable c) {
this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param exceptionIndexTable Table of indices in constant pool
* @param constant_pool Array of constants
*/
public ExceptionTable(final int name_index, final int length, final int[] exceptionIndexTable,
final ConstantPool constant_pool) {
super(Const.ATTR_EXCEPTIONS, name_index, length, constant_pool);
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : new int[0];
}
/**
* Construct object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int number_of_exceptions = input.readUnsignedShort();
exceptionIndexTable = new int[number_of_exceptions];
for (int i = 0; i < number_of_exceptions; i++) {
final int exceptionCount = input.readUnsignedShort();
exceptionIndexTable = new int[exceptionCount];
for (int i = 0; i < exceptionCount; i++) {
exceptionIndexTable[i] = input.readUnsignedShort();
}
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param exceptionIndexTable Table of indices in constant pool
* @param constantPool Array of constants
*/
public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY;
Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitExceptionTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ExceptionTable c = (ExceptionTable) clone();
if (exceptionIndexTable != null) {
c.exceptionIndexTable = exceptionIndexTable.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump exceptions attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(exceptionIndexTable.length);
for (final int index : exceptionIndexTable) {
@@ -110,7 +128,6 @@ public final class ExceptionTable extends Attribute {
}
}
/**
* @return Array of indices into constant pool of thrown exceptions.
*/
@@ -118,6 +135,14 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable;
}
/**
* @return class names of thrown exceptions
*/
public String[] getExceptionNames() {
final String[] names = new String[exceptionIndexTable.length];
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
return names;
}
/**
* @return Length of exception table.
@@ -126,29 +151,14 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
}
/**
* @return class names of thrown exceptions
* @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
* length.
*/
public String[] getExceptionNames() {
final String[] names = new String[exceptionIndexTable.length];
for (int i = 0; i < exceptionIndexTable.length; i++) {
names[i] = super.getConstantPool().getConstantString(exceptionIndexTable[i],
Const.CONSTANT_Class).replace('/', '.');
}
return names;
public void setExceptionIndexTable(final int[] exceptionIndexTable) {
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY;
}
/**
* @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 : new int[0];
}
/**
* @return String representation, i.e., a list of thrown exceptions.
*/
@@ -166,20 +176,4 @@ public final class ExceptionTable extends Attribute {
}
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final ExceptionTable c = (ExceptionTable) clone();
if (exceptionIndexTable != null) {
c.exceptionIndexTable = new int[exceptionIndexTable.length];
System.arraycopy(exceptionIndexTable, 0, c.exceptionIndexTable, 0,
exceptionIndexTable.length);
}
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -30,75 +30,111 @@ import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* This class represents the field info structure, i.e., the representation
* for a variable in the class. See JVM specification for details.
*
* This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
* specification for details.
*/
public final class Field extends FieldOrMethod {
/**
* Empty array constant.
*
* @since 6.6.0
*/
public static final Field[] EMPTY_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
public boolean equals( final Object o1, final Object o2 ) {
public boolean equals(final Object o1, final Object o2) {
final Field THIS = (Field) o1;
final Field THAT = (Field) o2;
return Objects.equals(THIS.getName(), THAT.getName())
&& Objects.equals(THIS.getSignature(), THAT.getSignature());
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
}
@Override
public int hashCode( final Object o ) {
public int hashCode(final Object o) {
final Field THIS = (Field) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
/**
* Empty array.
*/
static final Field[] EMPTY_FIELD_ARRAY = {};
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
/**
* Construct object from file stream.
*
* @param file Input stream
*/
Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
}
/**
* 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 Field(final Field c) {
super(c);
}
/**
* Construct object from file stream.
* @param file Input stream
*/
Field(final DataInput file, final ConstantPool constant_pool) throws IOException,
ClassFormatException {
super(file, constant_pool);
}
/**
* @param access_flags Access rights of field
* @param name_index Points to field name in constant pool
* @param signature_index Points to encoded signature
* @param accessFlags Access rights of field
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public Field(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes,
final ConstantPool constant_pool) {
super(access_flags, name_index, signature_index, attributes, constant_pool);
public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitField(this);
}
/**
* @return deep copy of this field
*/
public Field copy(final ConstantPool constantPool) {
return (Field) copy_(constantPool);
}
/**
* Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when
* their names and signatures are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
}
/**
* @return constant value associated with this field (may be null)
@@ -112,10 +148,26 @@ public final class Field extends FieldOrMethod {
return null;
}
/**
* @return type of field
*/
public Type getType() {
return Type.getReturnType(getSignature());
}
/**
* Return string representation close to declaration format,
* `public static final short MAX = 100', e.g..
* 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);
}
/**
* Return string representation close to declaration format, 'public static final short MAX = 100', e.g..
*
* @return String representation of field, including the signature.
*/
@@ -127,7 +179,7 @@ public final class Field extends FieldOrMethod {
// Get names from constant pool
access = Utility.accessToString(super.getAccessFlags());
access = access.isEmpty() ? "" : (access + " ");
access = access.isEmpty() ? "" : access + " ";
signature = Utility.signatureToString(getSignature());
name = getName();
final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber
@@ -143,61 +195,4 @@ public final class Field extends FieldOrMethod {
}
return buf.toString();
}
/**
* @return deep copy of this field
*/
public Field copy( final ConstantPool _constant_pool ) {
return (Field) copy_(_constant_pool);
}
/**
* @return type of field
*/
public Type getType() {
return Type.getReturnType(getSignature());
}
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator( final BCELComparator comparator ) {
bcelComparator = comparator;
}
/**
* Return value as defined by given BCELComparator strategy.
* By default two Field objects are said to be equal when
* their names and signatures are equal.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals( final Object obj ) {
return bcelComparator.equals(this, obj);
}
/**
* Return value as defined by given BCELComparator strategy.
* By default return the hashcode of the field's name XOR signature.
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
}

View File

@@ -23,8 +23,7 @@ import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import java.util.Arrays;
/**
* Abstract super class for fields and methods.
@@ -32,89 +31,121 @@ import com.sun.org.apache.bcel.internal.Const;
* @LastModified: Jan 2020
*/
public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
private int name_index; // Points to field name in constant pool
private int signature_index; // Points to encoded signature
private Attribute[] attributes; // Collection of attributes
private int attributes_count; // No. of attributes
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int name_index; // Points to field name in constant pool
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int signature_index; // Points to encoded signature
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected Attribute[] attributes; // Collection of attributes
/**
* @deprecated (since 6.0) will be removed (not needed)
*/
@java.lang.Deprecated
protected int attributes_count; // No. of attributes
// @since 6.0
private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
private ConstantPool constant_pool;
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected ConstantPool constant_pool;
private String signatureAttributeString = null;
private boolean searchedForSignatureAttribute = false;
private String signatureAttributeString;
private boolean searchedForSignatureAttribute;
FieldOrMethod() {
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
*/
protected FieldOrMethod(final FieldOrMethod c) {
this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(),
c.getAttributes(), c.getConstantPool());
}
/**
* Construct object from file stream.
*
* @param file Input stream
* @throws IOException
* @throws ClassFormatException
* @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
* @throws IOException if an I/O error occurs.
*/
@java.lang.Deprecated
protected FieldOrMethod(final DataInputStream file, final ConstantPool constant_pool)
throws IOException,
ClassFormatException {
this((DataInput) file, constant_pool);
protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
final int attributesCount = file.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(file, constantPool);
}
this.attributes_count = attributesCount; // init deprecated field
}
/**
* Construct object from file stream.
*
* @param file Input stream
* @throws IOException
* @throws ClassFormatException
* @throws IOException if an I/O error occurs.
* @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
*/
protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool)
throws IOException, ClassFormatException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null,
constant_pool);
final int attributes_count = file.readUnsignedShort();
attributes = new Attribute[attributes_count];
for (int i = 0; i < attributes_count; i++) {
attributes[i] = Attribute.readAttribute(file, constant_pool);
}
this.attributes_count = attributes_count; // init deprecated field
@java.lang.Deprecated
protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
this((DataInput) file, constantPool);
}
/**
* 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.
*/
protected FieldOrMethod(final FieldOrMethod c) {
this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
}
/**
* @param access_flags Access rights of method
* @param name_index Points to field name in constant pool
* @param signature_index Points to encoded signature
* @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
protected FieldOrMethod(final int access_flags, final int name_index, final int signature_index,
final Attribute[] attributes, final ConstantPool constant_pool) {
super(access_flags);
this.name_index = name_index;
this.signature_index = signature_index;
this.constant_pool = constant_pool;
protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
final ConstantPool constantPool) {
super(accessFlags);
this.name_index = nameIndex;
this.signature_index = signatureIndex;
this.constant_pool = constantPool;
setAttributes(attributes);
}
/**
* @return deep copy of this field
*/
protected FieldOrMethod copy_(final ConstantPool constantPool) {
try {
final FieldOrMethod c = (FieldOrMethod) clone();
c.constant_pool = constantPool;
c.attributes = new Attribute[attributes.length];
c.attributes_count = attributes_count; // init deprecated field
Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
return c;
} catch (final CloneNotSupportedException e) {
throw new IllegalStateException(e);
}
}
/**
* Dump object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(super.getAccessFlags());
@@ -128,115 +159,6 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
}
/**
* @return Collection of object attributes.
*/
public final Attribute[] getAttributes() {
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.
*/
public final ConstantPool getConstantPool() {
return constant_pool;
}
/**
* @param constant_pool Constant pool to be used for this object.
*/
public final void setConstantPool( final ConstantPool constant_pool ) {
this.constant_pool = constant_pool;
}
/**
* @return Index in constant pool of object's name.
*/
public final int getNameIndex() {
return name_index;
}
/**
* @param name_index Index in constant pool of object's name.
*/
public final void setNameIndex( final int name_index ) {
this.name_index = name_index;
}
/**
* @return Index in constant pool of field signature.
*/
public final int getSignatureIndex() {
return signature_index;
}
/**
* @param signature_index Index in constant pool of field signature.
*/
public final void setSignatureIndex( final int signature_index ) {
this.signature_index = signature_index;
}
/**
* @return Name of object, i.e., method name or field name
*/
public final String getName() {
ConstantUtf8 c;
c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
return c.getBytes();
}
/**
* @return String representation of object's type signature (java style)
*/
public final String getSignature() {
ConstantUtf8 c;
c = (ConstantUtf8) constant_pool.getConstant(signature_index, Const.CONSTANT_Utf8);
return c.getBytes();
}
/**
* @return deep copy of this field
*/
protected FieldOrMethod copy_( final ConstantPool _constant_pool ) {
FieldOrMethod c = null;
try {
c = (FieldOrMethod)clone();
} catch(final CloneNotSupportedException e) {
// ignored, but will cause NPE ...
}
c.constant_pool = constant_pool;
c.attributes = new Attribute[attributes.length];
c.attributes_count = attributes_count; // init deprecated field
for (int i = 0; i < attributes.length; i++) {
c.attributes[i] = attributes[i].copy(constant_pool);
}
return c;
}
/**
* @return Annotations on the field or method
* @since 6.0
@@ -250,26 +172,32 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
/**
* 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 performance -
* searches for the attribute only when requested - only searches for it
* once.
* @return Collection of object attributes.
*/
public final Attribute[] getAttributes() {
return attributes;
}
/**
* @return Constant pool used by this object.
*/
public final ConstantPool getConstantPool() {
return constant_pool;
}
/**
* 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
* performance - searches for the attribute only when requested - only searches for it once.
*
* @since 6.0
*/
public final String getGenericSignature()
{
if (!searchedForSignatureAttribute)
{
public final String getGenericSignature() {
if (!searchedForSignatureAttribute) {
boolean found = false;
for (int i = 0; !found && i < attributes.length; i++)
{
if (attributes[i] instanceof Signature)
{
signatureAttributeString = ((Signature) attributes[i])
.getSignature();
for (int i = 0; !found && i < attributes.length; i++) {
if (attributes[i] instanceof Signature) {
signatureAttributeString = ((Signature) attributes[i]).getSignature();
found = true;
}
}
@@ -277,4 +205,61 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
return signatureAttributeString;
}
/**
* @return Name of object, i.e., method name or field name
*/
public final String getName() {
return constant_pool.getConstantUtf8(name_index).getBytes();
}
/**
* @return Index in constant pool of object's name.
*/
public final int getNameIndex() {
return name_index;
}
/**
* @return String representation of object's type signature (java style)
*/
public final String getSignature() {
return constant_pool.getConstantUtf8(signature_index).getBytes();
}
/**
* @return Index in constant pool of field signature.
*/
public final int getSignatureIndex() {
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.
*/
public final void setSignatureIndex(final int signatureIndex) {
this.signature_index = signatureIndex;
}
}

View File

@@ -28,9 +28,8 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a inner class attribute, i.e., the class
* indices of the inner and outer classes, the name and the attributes
* of the inner class.
* This class represents a inner class attribute, i.e., the class indices of the inner and outer classes, the name and
* the attributes of the inner class.
*
* @see InnerClasses
*/
@@ -41,171 +40,49 @@ public final class InnerClass implements Cloneable, Node {
private int innerNameIndex;
private int innerAccessFlags;
/**
* Construct object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
InnerClass(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public InnerClass(final InnerClass c) {
this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c
.getInnerAccessFlags());
this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c.getInnerAccessFlags());
}
/**
* Construct object from file stream.
* @param file Input stream
* @throws IOException
*/
InnerClass(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
.readUnsignedShort());
}
/**
* @param innerClassIndex Class index in constant pool of inner class
* @param outerClassIndex Class index in constant pool of outer class
* @param innerNameIndex Name index in constant pool of inner class
* @param innerNameIndex Name index in constant pool of inner class
* @param innerAccessFlags Access flags of inner class
*/
public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex,
final int innerAccessFlags) {
public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) {
this.innerClassIndex = innerClassIndex;
this.outerClassIndex = outerClassIndex;
this.innerNameIndex = innerNameIndex;
this.innerAccessFlags = innerAccessFlags;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitInnerClass(this);
}
/**
* Dump inner class attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(innerClassIndex);
file.writeShort(outerClassIndex);
file.writeShort(innerNameIndex);
file.writeShort(innerAccessFlags);
}
/**
* @return access flags of inner class.
*/
public int getInnerAccessFlags() {
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
*/
public void setInnerAccessFlags( final int innerAccessFlags ) {
this.innerAccessFlags = innerAccessFlags;
}
/**
* @param innerClassIndex index into the constant pool for this class
*/
public void setInnerClassIndex( final int innerClassIndex ) {
this.innerClassIndex = innerClassIndex;
}
/**
* @param innerNameIndex index into the constant pool for this class's name
*/
public void setInnerNameIndex( final int innerNameIndex ) { // TODO unused
this.innerNameIndex = innerNameIndex;
}
/**
* @param outerClassIndex index into the constant pool for the owning class
*/
public void setOuterClassIndex( final int outerClassIndex ) { // TODO unused
this.outerClassIndex = outerClassIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", "
+ innerNameIndex + ", " + innerAccessFlags + ")";
}
/**
* @return Resolved string representation
*/
public String toString( final ConstantPool constantPool ) {
String outer_class_name;
String inner_name;
String inner_class_name = constantPool.getConstantString(innerClassIndex,
Const.CONSTANT_Class);
inner_class_name = Utility.compactClassName(inner_class_name, false);
if (outerClassIndex != 0) {
outer_class_name = constantPool.getConstantString(outerClassIndex,
Const.CONSTANT_Class);
outer_class_name = " of class " + Utility.compactClassName(outer_class_name, false);
} else {
outer_class_name = "";
}
if (innerNameIndex != 0) {
inner_name = ((ConstantUtf8) constantPool.getConstant(innerNameIndex,
Const.CONSTANT_Utf8)).getBytes();
} else {
inner_name = "(anonymous)";
}
String access = Utility.accessToString(innerAccessFlags, true);
access = access.isEmpty() ? "" : (access + " ");
return " " + access + inner_name + "=class " + inner_class_name + outer_class_name;
}
/**
* @return deep copy of this object
*/
@@ -217,4 +94,105 @@ public final class InnerClass implements Cloneable, Node {
}
return null;
}
/**
* Dump inner class attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(innerClassIndex);
file.writeShort(outerClassIndex);
file.writeShort(innerNameIndex);
file.writeShort(innerAccessFlags);
}
/**
* @return access flags of inner class.
*/
public int getInnerAccessFlags() {
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
*/
public void setInnerAccessFlags(final int innerAccessFlags) {
this.innerAccessFlags = innerAccessFlags;
}
/**
* @param innerClassIndex index into the constant pool for this class
*/
public void setInnerClassIndex(final int innerClassIndex) {
this.innerClassIndex = innerClassIndex;
}
/**
* @param innerNameIndex index into the constant pool for this class's name
*/
public void setInnerNameIndex(final int innerNameIndex) { // TODO unused
this.innerNameIndex = innerNameIndex;
}
/**
* @param outerClassIndex index into the constant pool for the owning class
*/
public void setOuterClassIndex(final int outerClassIndex) { // TODO unused
this.outerClassIndex = outerClassIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", " + innerNameIndex + ", " + innerAccessFlags + ")";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
String outerClassName;
String innerName;
String innerClassName = constantPool.getConstantString(innerClassIndex, Const.CONSTANT_Class);
innerClassName = Utility.compactClassName(innerClassName, false);
if (outerClassIndex != 0) {
outerClassName = constantPool.getConstantString(outerClassIndex, Const.CONSTANT_Class);
outerClassName = " of class " + Utility.compactClassName(outerClassName, false);
} else {
outerClassName = "";
}
if (innerNameIndex != 0) {
innerName = constantPool.getConstantUtf8(innerNameIndex).getBytes();
} else {
innerName = "(anonymous)";
}
String access = Utility.accessToString(innerAccessFlags, true);
access = access.isEmpty() ? "" : access + " ";
return " " + access + innerName + "=class " + innerClassName + outerClassName;
}
}

View File

@@ -24,93 +24,107 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and denotes that this class
* is an Inner class of another.
* to the source file of this class.
* It is instantiated from the <em>Attribute.readAttribute()</em> method.
* This class is derived from <em>Attribute</em> and denotes that this class is an Inner class of another. to the source
* file of this class. It is instantiated from the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
* @see Attribute
*/
public final class InnerClasses extends Attribute {
public final class InnerClasses extends Attribute implements Iterable<InnerClass> {
/**
* Empty array.
*/
private static final InnerClass[] EMPTY_INNER_CLASSE_ARRAY = {};
private InnerClass[] innerClasses;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* 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 InnerClasses(final InnerClasses c) {
this(c.getNameIndex(), c.getLength(), c.getInnerClasses(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param innerClasses array of inner classes attributes
* @param constant_pool Array of constants
*/
public InnerClasses(final int name_index, final int length, final InnerClass[] innerClasses,
final ConstantPool constant_pool) {
super(Const.ATTR_INNER_CLASSES, name_index, length, constant_pool);
this.innerClasses = innerClasses != null ? innerClasses : new InnerClass[0];
}
/**
* Construct object from input stream.
*
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
InnerClasses(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (InnerClass[]) null, constant_pool);
final int number_of_classes = input.readUnsignedShort();
innerClasses = new InnerClass[number_of_classes];
for (int i = 0; i < number_of_classes; i++) {
InnerClasses(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (InnerClass[]) null, constantPool);
final int classCount = input.readUnsignedShort();
innerClasses = new InnerClass[classCount];
for (int i = 0; i < classCount; i++) {
innerClasses[i] = new InnerClass(input);
}
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param innerClasses array of inner classes attributes
* @param constantPool Array of constants
*/
public InnerClasses(final int nameIndex, final int length, final InnerClass[] innerClasses, final ConstantPool constantPool) {
super(Const.ATTR_INNER_CLASSES, nameIndex, length, constantPool);
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY;
Args.requireU2(this.innerClasses.length, "innerClasses.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitInnerClasses(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO this could be recoded to use a lower level constructor after creating a copy of the inner classes
final InnerClasses c = (InnerClasses) clone();
c.innerClasses = new InnerClass[innerClasses.length];
Arrays.setAll(c.innerClasses, i -> innerClasses[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(innerClasses.length);
for (final InnerClass inner_class : innerClasses) {
inner_class.dump(file);
for (final InnerClass innerClass : innerClasses) {
innerClass.dump(file);
}
}
/**
* @return array of inner class "records"
*/
@@ -118,15 +132,18 @@ public final class InnerClasses extends Attribute {
return innerClasses;
}
@Override
public Iterator<InnerClass> iterator() {
return Stream.of(innerClasses).iterator();
}
/**
* @param innerClasses the array of inner classes
*/
public void setInnerClasses( final InnerClass[] innerClasses ) {
this.innerClasses = innerClasses != null ? innerClasses : new InnerClass[0];
public void setInnerClasses(final InnerClass[] innerClasses) {
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY;
}
/**
* @return String representation.
*/
@@ -136,25 +153,9 @@ public final class InnerClasses extends Attribute {
buf.append("InnerClasses(");
buf.append(innerClasses.length);
buf.append("):\n");
for (final InnerClass inner_class : innerClasses) {
buf.append(inner_class.toString(super.getConstantPool())).append("\n");
for (final InnerClass innerClass : innerClasses) {
buf.append(innerClass.toString(super.getConstantPool())).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
// TODO this could be recoded to use a lower level constructor after creating a copy of the inner classes
final InnerClasses c = (InnerClasses) clone();
c.innerClasses = new InnerClass[innerClasses.length];
for (int i = 0; i < innerClasses.length; i++) {
c.innerClasses[i] = innerClasses[i].copy();
}
c.setConstantPool(_constant_pool);
return c;
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -25,30 +25,23 @@ import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a (PC offset, line number) pair, i.e., a line number in
* the source that corresponds to a relative address in the byte code. This
* is used for debugging purposes.
* This class represents a (PC offset, line number) pair, i.e., a line number in the source that corresponds to a
* relative address in the byte code. This is used for debugging purposes.
*
* @see LineNumberTable
* @see LineNumberTable
*/
public final class LineNumber implements Cloneable, Node {
static final LineNumber[] EMPTY_ARRAY = {};
/** Program Counter (PC) corresponds to line */
private short startPc;
private int startPc;
/** number in source file */
private short lineNumber;
/**
* Initialize from another object.
*
* @param c the object to copy
*/
public LineNumber(final LineNumber c) {
this(c.getStartPC(), c.getLineNumber());
}
private int lineNumber;
/**
* Construct object from file stream.
@@ -60,83 +53,35 @@ public final class LineNumber implements Cloneable, Node {
this(file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param startPc Program Counter (PC) corresponds to
* @param lineNumber line number in source file
*/
public LineNumber(final int startPc, final int lineNumber) {
this.startPc = (short) startPc;
this.lineNumber = (short)lineNumber;
this.startPc = Args.requireU2(startPc, "startPc");
this.lineNumber = Args.requireU2(lineNumber, "lineNumber");
}
/**
* Initialize from another object.
*
* @param c the object to copy
*/
public LineNumber(final LineNumber c) {
this(c.getStartPC(), c.getLineNumber());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitLineNumber(this);
}
/**
* Dump line number/pc pair to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(startPc);
file.writeShort(lineNumber);
}
/**
* @return Corresponding source line
*/
public int getLineNumber() {
return 0xffff & lineNumber;
}
/**
* @return PC in code
*/
public int getStartPC() {
return 0xffff & startPc;
}
/**
* @param lineNumber the source line number
*/
public void setLineNumber( final int lineNumber ) {
this.lineNumber = (short) lineNumber;
}
/**
* @param startPc the pc for this line number
*/
public void setStartPC( final int startPc ) {
this.startPc = (short) startPc;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "LineNumber(" + startPc + ", " + lineNumber + ")";
}
/**
* @return deep copy of this object
*/
@@ -148,4 +93,51 @@ public final class LineNumber implements Cloneable, Node {
}
return null;
}
/**
* Dump line number/pc pair to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(startPc);
file.writeShort(lineNumber);
}
/**
* @return Corresponding source line
*/
public int getLineNumber() {
return lineNumber & 0xffff;
}
/**
* @return PC in code
*/
public int getStartPC() {
return startPc & 0xffff;
}
/**
* @param lineNumber the source line number
*/
public void setLineNumber(final int lineNumber) {
this.lineNumber = (short) lineNumber;
}
/**
* @param startPc the pc for this line number
*/
public void setStartPC(final int startPc) {
this.startPc = (short) startPc;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "LineNumber(" + getStartPC() + ", " + getLineNumber() + ")";
}
}

View File

@@ -19,78 +19,96 @@
*/
package com.sun.org.apache.bcel.internal.classfile;
import com.sun.org.apache.bcel.internal.Const;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.SecuritySupport;
/**
* This class represents a table of line numbers for debugging
* purposes. This attribute is used by the <em>Code</em> attribute. It
* contains pairs of PCs and line numbers.
* This class represents a table of line numbers for debugging purposes. This attribute is used by the <em>Code</em>
* attribute. It contains pairs of PCs and line numbers.
*
* @see Code
* @see Code
* @see LineNumber
* @LastModified: May 2021
*/
public final class LineNumberTable extends Attribute {
public final class LineNumberTable extends Attribute implements Iterable<LineNumber> {
private static final int MAX_LINE_LENGTH = 72;
private LineNumber[] lineNumberTable; // Table of line/numbers pairs
/**
* Construct object from input stream.
*
* @param nameIndex Index of name
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
LineNumberTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (LineNumber[]) null, constantPool);
final int lineNumberTableLength = input.readUnsignedShort();
lineNumberTable = new LineNumber[lineNumberTableLength];
for (int i = 0; i < lineNumberTableLength; i++) {
lineNumberTable[i] = new LineNumber(input);
}
}
/*
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* @param nameIndex Index of name
*
* @param length Content length in bytes
*
* @param lineNumberTable Table of line/numbers pairs
*
* @param constantPool Array of constants
*/
public LineNumberTable(final int nameIndex, final int length, final LineNumber[] lineNumberTable, final ConstantPool constantPool) {
super(Const.ATTR_LINE_NUMBER_TABLE, nameIndex, length, constantPool);
this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY;
Args.requireU2(this.lineNumberTable.length, "lineNumberTable.length");
}
/*
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*/
public LineNumberTable(final LineNumberTable c) {
this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool());
}
/*
* @param name_index Index of name
* @param length Content length in bytes
* @param lineNumberTable Table of line/numbers pairs
* @param constant_pool Array of constants
*/
public LineNumberTable(final int name_index, final int length, final LineNumber[] line_number_table,
final ConstantPool constant_pool) {
super(Const.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool);
this.lineNumberTable = line_number_table;
}
/**
* Construct object from input stream.
* @param name_index Index of name
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
LineNumberTable(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (LineNumber[]) null, constant_pool);
final int line_number_table_length = input.readUnsignedShort();
lineNumberTable = new LineNumber[line_number_table_length];
for (int i = 0; i < line_number_table_length; i++) {
lineNumberTable[i] = new LineNumber(input);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitLineNumberTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO could use the lower level constructor and thereby allow
// lineNumberTable to be made final
final LineNumberTable c = (LineNumberTable) clone();
c.lineNumberTable = new LineNumber[lineNumberTable.length];
Arrays.setAll(c.lineNumberTable, i -> lineNumberTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump line number table attribute to file stream in binary format.
*
@@ -98,7 +116,7 @@ public final class LineNumberTable extends Attribute {
* @throws IOException if an I/O Exception occurs in writeShort
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(lineNumberTable.length);
for (final LineNumber lineNumber : lineNumberTable) {
@@ -113,10 +131,65 @@ public final class LineNumberTable extends Attribute {
return lineNumberTable;
}
/**
* Map byte code positions to source code lines.
*
* @param pos byte code offset
* @return corresponding line in source code
*/
public int getSourceLine(final int pos) {
int l = 0;
int r = lineNumberTable.length - 1;
if (r < 0) {
return -1;
}
int minIndex = -1;
int min = -1;
/*
* Do a binary search since the array is ordered.
*/
do {
final int i = l + r >>> 1;
final int j = lineNumberTable[i].getStartPC();
if (j == pos) {
return lineNumberTable[i].getLineNumber();
}
if (pos < j) {
r = i - 1;
} else {
l = i + 1;
}
/*
* If exact match can't be found (which is the most common case) return the line number that corresponds to the greatest
* index less than pos.
*/
if (j < pos && j > min) {
min = j;
minIndex = i;
}
} while (l <= r);
/*
* It's possible that we did not find any valid entry for the bytecode offset we were looking for.
*/
if (minIndex < 0) {
return -1;
}
return lineNumberTable[minIndex].getLineNumber();
}
public int getTableLength() {
return lineNumberTable == null ? 0 : lineNumberTable.length;
}
@Override
public Iterator<LineNumber> iterator() {
return Stream.of(lineNumberTable).iterator();
}
/**
* @param lineNumberTable the line number entries for this table
*/
public void setLineNumberTable( final LineNumber[] lineNumberTable ) {
public void setLineNumberTable(final LineNumber[] lineNumberTable) {
this.lineNumberTable = lineNumberTable;
}
@@ -127,13 +200,12 @@ public final class LineNumberTable extends Attribute {
public String toString() {
final StringBuilder buf = new StringBuilder();
final StringBuilder line = new StringBuilder();
for (int i = 0; i < lineNumberTable.length; i++) {
line.append(lineNumberTable[i].toString());
if (i < lineNumberTable.length - 1) {
line.append(", ");
}
if ((line.length() > MAX_LINE_LENGTH) && (i < lineNumberTable.length - 1)) {
if (line.length() > MAX_LINE_LENGTH && i < lineNumberTable.length - 1) {
line.append(SecuritySupport.NEWLINE);
buf.append(line);
line.setLength(0);
@@ -142,69 +214,4 @@ public final class LineNumberTable extends Attribute {
buf.append(line);
return buf.toString();
}
/**
* Map byte code positions to source code lines.
*
* @param pos byte code offset
* @return corresponding line in source code
*/
public int getSourceLine( final int pos ) {
int l = 0;
int r = lineNumberTable.length - 1;
if (r < 0) {
return -1;
}
int min_index = -1;
int min = -1;
/* Do a binary search since the array is ordered.
*/
do {
final int i = (l + r) >>> 1;
final int j = lineNumberTable[i].getStartPC();
if (j == pos) {
return lineNumberTable[i].getLineNumber();
} else if (pos < j) {
r = i - 1;
} else {
l = i + 1;
}
/* If exact match can't be found (which is the most common case)
* return the line number that corresponds to the greatest index less
* than pos.
*/
if (j < pos && j > min) {
min = j;
min_index = i;
}
} while (l <= r);
/* It's possible that we did not find any valid entry for the bytecode
* offset we were looking for.
*/
if (min_index < 0) {
return -1;
}
return lineNumberTable[min_index].getLineNumber();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
// TODO could use the lower level constructor and thereby allow
// lineNumberTable to be made final
final LineNumberTable c = (LineNumberTable) clone();
c.lineNumberTable = new LineNumber[lineNumberTable.length];
for (int i = 0; i < lineNumberTable.length; i++) {
c.lineNumberTable[i] = lineNumberTable[i].copy();
}
c.setConstantPool(_constant_pool);
return c;
}
public int getTableLength() {
return lineNumberTable == null ? 0 : lineNumberTable.length;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,119 +24,129 @@ import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a local variable within a method. It contains its
* scope, name, signature and index on the method's frame. It is used both
* to represent an element of the LocalVariableTable as well as an element
* of the LocalVariableTypeTable. The nomenclature used here may be a bit confusing;
* while the two items have the same layout in a class file, a LocalVariableTable
* attribute contains a descriptor_index, not a signatureIndex. The
* This class represents a local variable within a method. It contains its scope, name, signature and index on the
* method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the
* LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout
* in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The
* LocalVariableTypeTable attribute does have a signatureIndex.
*
* @see com.sun.org.apache.bcel.internal.classfile.Utility for more details on the difference.
*
* @see LocalVariableTable
* @see LocalVariableTypeTable
* @LastModified: May 2021
* @see LocalVariableTable
* @see LocalVariableTypeTable
* @LastModified: Feb 2023
*/
public final class LocalVariable implements Cloneable, Node {
private int startPc; // Range in which the variable is valid
private int length;
private int nameIndex; // Index in constant pool of variable name
// Technically, a decscriptor_index for a local variable table entry
// and a signatureIndex for a local variable type table entry.
private int signatureIndex; // Index of variable signature
private int index; /* Variable is index'th local variable on
* this method's frame.
*/
private ConstantPool constantPool;
private int origIndex; // never changes; used to match up with LocalVariableTypeTable entries
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;
/**
* Initializes from another LocalVariable. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* 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. */
private final int origIndex;
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool);
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is 'index'th local variable on the method's frame
* @param constantPool Array of constants
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is 'index'th local variable on the method's frame
* @param constantPool Array of constants
* @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
final int origIndex) {
this.startPc = Args.requireU2(startPc, "startPc");
this.length = Args.requireU2(length, "length");
this.nameIndex = Args.requireU2(nameIndex, "nameIndex");
this.signatureIndex = Args.requireU2(signatureIndex, "signatureIndex");
this.index = Args.requireU2(index, "index");
this.origIndex = Args.requireU2(origIndex, "origIndex");
this.constantPool = constantPool;
}
/**
* Initializes from another LocalVariable. Note that both objects use the same references (shallow copy). Use copy() for
* a physical copy.
*
* @param localVariable Another LocalVariable.
*/
public LocalVariable(final LocalVariable localVariable) {
this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(),
localVariable.getSignatureIndex(), localVariable.getIndex(), localVariable.getConstantPool());
this.origIndex = localVariable.getOrigIndex();
this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(), localVariable.getSignatureIndex(), localVariable.getIndex(),
localVariable.getConstantPool());
}
/**
* Constructs object from file stream.
* @param file Input stream
* @throws IOException
*/
LocalVariable(final DataInput file, final ConstantPool constant_pool) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
.readUnsignedShort(), file.readUnsignedShort(), constant_pool);
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is `index'th local variable on the method's frame
* @param constantPool Array of constants
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index,
final ConstantPool constantPool) {
this.startPc = startPc;
this.length = length;
this.nameIndex = nameIndex;
this.signatureIndex = signatureIndex;
this.index = index;
this.constantPool = constantPool;
this.origIndex = index;
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is `index'th local variable on the method's frame
* @param constantPool Array of constants
* @param origIndex Variable is `index'th local variable on the method's frame prior to any changes
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index,
final ConstantPool constantPool, final int origIndex) {
this.startPc = startPc;
this.length = length;
this.nameIndex = nameIndex;
this.signatureIndex = signatureIndex;
this.index = index;
this.constantPool = constantPool;
this.origIndex = origIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitLocalVariable(this);
}
/**
* @return deep copy of this object
*/
public LocalVariable copy() {
try {
return (LocalVariable) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dumps local variable to file stream in binary format.
*
* @param dataOutputStream Output file stream
* @exception IOException if an I/O error occurs.
* @throws IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public void dump(final DataOutputStream dataOutputStream) throws IOException {
@@ -154,6 +164,12 @@ public final class LocalVariable implements Cloneable, Node {
return constantPool;
}
/**
* @return index of register where variable is stored
*/
public int getIndex() {
return index;
}
/**
* @return Variable is valid within getStartPC() .. getStartPC()+getLength()
@@ -162,17 +178,13 @@ public final class LocalVariable implements Cloneable, Node {
return length;
}
/**
* @return Variable name.
*/
public String getName() {
ConstantUtf8 c;
c = (ConstantUtf8) constantPool.getConstant(nameIndex, Const.CONSTANT_Utf8);
return c.getBytes();
return constantPool.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Index in constant pool of variable name.
*/
@@ -180,17 +192,20 @@ public final class LocalVariable implements Cloneable, Node {
return nameIndex;
}
/**
* @return index of register where variable was originally stored
*/
public int getOrigIndex() {
return origIndex;
}
/**
* @return Signature.
*/
public String getSignature() {
ConstantUtf8 c;
c = (ConstantUtf8) constantPool.getConstant(signatureIndex, Const.CONSTANT_Utf8);
return c.getBytes();
return constantPool.getConstantUtf8(signatureIndex).getBytes();
}
/**
* @return Index in constant pool of variable signature.
*/
@@ -198,23 +213,6 @@ public final class LocalVariable implements Cloneable, Node {
return signatureIndex;
}
/**
* @return index of register where variable is stored
*/
public int getIndex() {
return index;
}
/**
* @return index of register where variable was originally stored
*/
public int getOrigIndex() {
return origIndex;
}
/**
* @return Start of range where the variable is valid
*/
@@ -222,67 +220,48 @@ public final class LocalVariable implements Cloneable, Node {
return startPc;
}
/*
* Helper method shared with LocalVariableTypeTable
*/
String toStringShared( final boolean typeTable ) {
final String name = getName();
final String signature = Utility.signatureToString(getSignature(), false);
final String label = "LocalVariable" + (typeTable ? "Types" : "" );
return label + "(startPc = " + startPc + ", length = " + length + ", index = "
+ index + ":" + signature + " " + name + ")";
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool( final ConstantPool constantPool ) {
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/**
* @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
*/
public void setSignatureIndex( final int signatureIndex ) { // TODO unused
this.signatureIndex = signatureIndex;
}
/**
* @param index the index in the local variable table of this variable
*/
public void setIndex( final int index ) { // TODO unused
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
*/
public void setSignatureIndex(final int signatureIndex) { // TODO unused
this.signatureIndex = signatureIndex;
}
/**
* @param startPc Specify range where the local variable is valid.
*/
public void setStartPC( final int startPc ) { // TODO unused
public void setStartPC(final int startPc) { // TODO unused
this.startPc = startPc;
}
/**
* @return string representation.
*/
@@ -291,16 +270,13 @@ public final class LocalVariable implements Cloneable, Node {
return toStringShared(false);
}
/**
* @return deep copy of this object
/*
* Helper method shared with LocalVariableTypeTable
*/
public LocalVariable copy() {
try {
return (LocalVariable) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
String toStringShared(final boolean typeTable) {
final String name = getName();
final String signature = Utility.signatureToString(getSignature(), false);
final String label = "LocalVariable" + (typeTable ? "Types" : "");
return label + "(startPc = " + startPc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")";
}
}

View File

@@ -24,83 +24,95 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents colection of local variables in a
* method. This attribute is contained in the <em>Code</em> attribute.
* This class represents colection of local variables in a method. This attribute is contained in the <em>Code</em>
* attribute.
*
* @see Code
* @see Code
* @see LocalVariable
*/
public class LocalVariableTable extends Attribute {
public class LocalVariableTable extends Attribute implements Iterable<LocalVariable> {
private LocalVariable[] localVariableTable; // variables
/**
* Construct object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
LocalVariableTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (LocalVariable[]) null, constantPool);
final int localVariableTableLength = input.readUnsignedShort();
localVariableTable = new LocalVariable[localVariableTableLength];
for (int i = 0; i < localVariableTableLength; i++) {
localVariableTable[i] = new LocalVariable(input, constantPool);
}
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* @param nameIndex Index in constant pool to 'LocalVariableTable'
* @param length Content length in bytes
* @param localVariableTable Table of local variables
* @param constantPool Array of constants
*/
public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool);
this.localVariableTable = localVariableTable != null ? localVariableTable : LocalVariable.EMPTY_ARRAY;
Args.requireU2(this.localVariableTable.length, "localVariableTable.length");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public LocalVariableTable(final LocalVariableTable c) {
this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool());
}
/**
* @param nameIndex Index in constant pool to `LocalVariableTable'
* @param length Content length in bytes
* @param localVariableTable Table of local variables
* @param constantPool Array of constants
*/
public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable,
final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool);
this.localVariableTable = localVariableTable;
}
/**
* Construct object from input stream.
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
*/
LocalVariableTable(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (LocalVariable[]) null, constant_pool);
final int local_variable_table_length = input.readUnsignedShort();
localVariableTable = new LocalVariable[local_variable_table_length];
for (int i = 0; i < local_variable_table_length; i++) {
localVariableTable[i] = new LocalVariable(input, constant_pool);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitLocalVariableTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final LocalVariableTable c = (LocalVariableTable) clone();
c.localVariableTable = new LocalVariable[localVariableTable.length];
Arrays.setAll(c.localVariableTable, i -> localVariableTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump local variable table attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump( final DataOutputStream file ) throws IOException {
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(localVariableTable.length);
for (final LocalVariable variable : localVariableTable) {
@@ -108,26 +120,17 @@ public class LocalVariableTable extends Attribute {
}
}
/**
* @return Array of local variables of method.
*/
public final LocalVariable[] getLocalVariableTable() {
return localVariableTable;
}
/**
*
* @param index the variable slot
*
* @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) instead.
* @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc)
* instead.
*/
@java.lang.Deprecated
public final LocalVariable getLocalVariable( final int index ) {
public final LocalVariable getLocalVariable(final int index) {
for (final LocalVariable variable : localVariableTable) {
if (variable.getIndex() == index) {
return variable;
@@ -136,7 +139,6 @@ public class LocalVariableTable extends Attribute {
return null;
}
/**
*
* @param index the variable slot
@@ -144,12 +146,12 @@ public class LocalVariableTable extends Attribute {
*
* @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) {
for (final LocalVariable variable : localVariableTable) {
if (variable.getIndex() == index) {
final int start_pc = variable.getStartPC();
final int end_pc = start_pc + variable.getLength();
if ((pc >= start_pc) && (pc <= end_pc)) {
final int startPc = variable.getStartPC();
final int endPc = startPc + variable.getLength();
if (pc >= startPc && pc <= endPc) {
return variable;
}
}
@@ -157,11 +159,25 @@ public class LocalVariableTable extends Attribute {
return null;
}
public final void setLocalVariableTable( final LocalVariable[] local_variable_table ) {
this.localVariableTable = local_variable_table;
/**
* @return Array of local variables of method.
*/
public final LocalVariable[] getLocalVariableTable() {
return localVariableTable;
}
public final int getTableLength() {
return localVariableTable == null ? 0 : localVariableTable.length;
}
@Override
public Iterator<LocalVariable> iterator() {
return Stream.of(localVariableTable).iterator();
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTable = localVariableTable;
}
/**
* @return String representation.
@@ -177,24 +193,4 @@ public class LocalVariableTable extends Attribute {
}
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final LocalVariableTable c = (LocalVariableTable) clone();
c.localVariableTable = new LocalVariable[localVariableTable.length];
for (int i = 0; i < localVariableTable.length; i++) {
c.localVariableTable[i] = localVariableTable[i].copy();
}
c.setConstantPool(_constant_pool);
return c;
}
public final int getTableLength() {
return localVariableTable == null ? 0 : localVariableTable.length;
}
}

View File

@@ -23,8 +23,12 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
// The new table is used when generic types are about...
@@ -57,35 +61,49 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* @since 6.0
*/
public class LocalVariableTypeTable extends Attribute {
public class LocalVariableTypeTable extends Attribute implements Iterable<LocalVariable> {
private LocalVariable[] localVariableTypeTable; // variables
private LocalVariable[] localVariableTypeTable; // variables
LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
this(nameIdx, len, (LocalVariable[]) null, cpool);
final int localVariableTypeTableLength = input.readUnsignedShort();
localVariableTypeTable = new LocalVariable[localVariableTypeTableLength];
for (int i = 0; i < localVariableTypeTableLength; i++) {
localVariableTypeTable[i] = new LocalVariable(input, cpool);
}
}
public LocalVariableTypeTable(final int nameIndex, final int length, final LocalVariable[] localVariableTypeTable, final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE, nameIndex, length, constantPool);
this.localVariableTypeTable = localVariableTypeTable != null ? localVariableTypeTable : LocalVariable.EMPTY_ARRAY;
Args.requireU2(this.localVariableTypeTable.length, "localVariableTypeTable.length");
}
public LocalVariableTypeTable(final LocalVariableTypeTable c) {
this(c.getNameIndex(), c.getLength(), c.getLocalVariableTypeTable(), c.getConstantPool());
}
public LocalVariableTypeTable(final int name_index, final int length, final LocalVariable[] local_variable_table, final ConstantPool constant_pool) {
super(Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE, name_index, length, constant_pool);
this.localVariableTypeTable = local_variable_table;
}
LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
this(nameIdx, len, (LocalVariable[]) null, cpool);
final int local_variable_type_table_length = input.readUnsignedShort();
localVariableTypeTable = new LocalVariable[local_variable_type_table_length];
for (int i = 0; i < local_variable_type_table_length; i++) {
localVariableTypeTable[i] = new LocalVariable(input, cpool);
}
}
@Override
public void accept(final Visitor v) {
v.visitLocalVariableTypeTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final LocalVariableTypeTable c = (LocalVariableTypeTable) clone();
c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length];
Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
@@ -95,10 +113,6 @@ public class LocalVariableTypeTable extends Attribute {
}
}
public final LocalVariable[] getLocalVariableTypeTable() {
return localVariableTypeTable;
}
public final LocalVariable getLocalVariable(final int index) {
for (final LocalVariable variable : localVariableTypeTable) {
if (variable.getIndex() == index) {
@@ -109,8 +123,21 @@ public class LocalVariableTypeTable extends Attribute {
return null;
}
public final void setLocalVariableTable(final LocalVariable[] local_variable_table) {
this.localVariableTypeTable = local_variable_table;
public final LocalVariable[] getLocalVariableTypeTable() {
return localVariableTypeTable;
}
public final int getTableLength() {
return localVariableTypeTable == null ? 0 : localVariableTypeTable.length;
}
@Override
public Iterator<LocalVariable> iterator() {
return Stream.of(localVariableTypeTable).iterator();
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTypeTable = localVariableTable;
}
/**
@@ -130,24 +157,4 @@ public class LocalVariableTypeTable extends Attribute {
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constant_pool) {
final LocalVariableTypeTable c = (LocalVariableTypeTable) clone();
c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length];
for (int i = 0; i < localVariableTypeTable.length; i++) {
c.localVariableTypeTable[i] = localVariableTypeTable[i].copy();
}
c.setConstantPool(constant_pool);
return c;
}
public final int getTableLength() {
return localVariableTypeTable == null ? 0 : localVariableTypeTable.length;
}
}

View File

@@ -24,93 +24,133 @@ import java.io.DataInput;
import java.io.IOException;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* 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.
*
* This class represents the method info structure, i.e., the representation for a method in the class. See JVM
* specification for details. A method has access flags, a name, a signature and a number of attributes.
*/
public final class Method extends FieldOrMethod {
/**
* Empty array constant.
*
* @since 6.6.0
*/
public static final Method[] EMPTY_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
public boolean equals( final Object o1, final Object o2 ) {
public boolean equals(final Object o1, final Object o2) {
final Method THIS = (Method) o1;
final Method THAT = (Method) o2;
return Objects.equals(THIS.getName(), THAT.getName())
&& Objects.equals(THIS.getSignature(), THAT.getSignature());
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
}
@Override
public int hashCode( final Object o ) {
public int hashCode(final Object o) {
final Method THIS = (Method) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
/**
* Empty array.
*/
static final Method[] EMPTY_METHOD_ARRAY = {};
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
bcelComparator = comparator;
}
// annotations defined on the parameters of a method
private ParameterAnnotationEntry[] parameterAnnotationEntries;
/**
* Empty constructor, all attributes have to be defined via `setXXX'
* methods. Use at your own risk.
* Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
*/
public Method() {
}
/**
* Construct object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constantPool Array of constants
*/
public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
/**
* 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 Method(final Method c) {
super(c);
}
/**
* Construct object from file stream.
* @param file Input stream
* @throws IOException
* @throws ClassFormatException
*/
Method(final DataInput file, final ConstantPool constant_pool) throws IOException,
ClassFormatException {
super(file, constant_pool);
}
/**
* @param access_flags Access rights of method
* @param name_index Points to field name in constant pool
* @param signature_index Points to encoded signature
* @param attributes Collection of attributes
* @param constant_pool Array of constants
*/
public Method(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes,
final ConstantPool constant_pool) {
super(access_flags, name_index, signature_index, attributes, constant_pool);
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitMethod(this);
}
/**
* @return deep copy of this method
*/
public Method copy(final ConstantPool constantPool) {
return (Method) copy_(constantPool);
}
/**
* Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
* their names and signatures are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
}
/**
* @return array of method argument types
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(getSignature());
}
/**
* @return Code attribute of method, if any
@@ -124,10 +164,9 @@ public final class Method extends FieldOrMethod {
return null;
}
/**
* @return ExceptionTable attribute of method, if any, i.e., list all
* exceptions the method may throw not exception handlers!
* @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
* handlers!
*/
public ExceptionTable getExceptionTable() {
for (final Attribute attribute : super.getAttributes()) {
@@ -138,21 +177,8 @@ public final class Method extends FieldOrMethod {
return null;
}
/** @return LocalVariableTable of code attribute if any, i.e. the call is forwarded
* to the Code atribute.
*/
public LocalVariableTable getLocalVariableTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLocalVariableTable();
}
/** @return LineNumberTable of code attribute if any, i.e. the call is forwarded
* to the Code atribute.
/**
* @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
*/
public LineNumberTable getLineNumberTable() {
final Code code = getCode();
@@ -162,102 +188,15 @@ public final class Method extends FieldOrMethod {
return code.getLineNumberTable();
}
/**
* Return string representation close to declaration format,
* `public static void main(String[] args) throws IOException', e.g.
*
* @return String representation of the method.
* @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
*/
@Override
public String toString() {
final String access = Utility.accessToString(super.getAccessFlags());
// Get name and signature from constant pool
ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(super.getSignatureIndex(), Const.CONSTANT_Utf8);
String signature = c.getBytes();
c = (ConstantUtf8) super.getConstantPool().getConstant(super.getNameIndex(), Const.CONSTANT_Utf8);
final String name = c.getBytes();
signature = Utility.methodSignatureToString(signature, name, access, true,
getLocalVariableTable());
final StringBuilder buf = new StringBuilder(signature);
for (final Attribute attribute : super.getAttributes()) {
if (!((attribute instanceof Code) || (attribute instanceof ExceptionTable))) {
buf.append(" [").append(attribute).append("]");
}
public LocalVariableTable getLocalVariableTable() {
final Code code = getCode();
if (code == null) {
return null;
}
final ExceptionTable e = getExceptionTable();
if (e != null) {
final String str = e.toString();
if (!str.isEmpty()) {
buf.append("\n\t\tthrows ").append(str);
}
}
return buf.toString();
}
/**
* @return deep copy of this method
*/
public Method copy( final ConstantPool _constant_pool ) {
return (Method) copy_(_constant_pool);
}
/**
* @return return type of method
*/
public Type getReturnType() {
return Type.getReturnType(getSignature());
}
/**
* @return array of method argument types
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(getSignature());
}
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator( final BCELComparator comparator ) {
bcelComparator = comparator;
}
/**
* Return value as defined by given BCELComparator strategy.
* By default two method objects are said to be equal when
* their names and signatures are equal.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals( final Object obj ) {
return bcelComparator.equals(this, obj);
}
/**
* Return value as defined by given BCELComparator strategy.
* By default return the hashcode of the method's name XOR signature.
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
return code.getLocalVariableTable();
}
/**
@@ -270,4 +209,53 @@ public final class Method extends FieldOrMethod {
}
return parameterAnnotationEntries;
}
/**
* @return return type of method
*/
public Type getReturnType() {
return Type.getReturnType(getSignature());
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Return string representation close to declaration format, 'public static void main(String[] args) throws
* IOException', e.g.
*
* @return String representation of the method.
*/
@Override
public String toString() {
final String access = Utility.accessToString(super.getAccessFlags());
// Get name and signature from constant pool
ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
String signature = c.getBytes();
c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
final String name = c.getBytes();
signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
final StringBuilder buf = new StringBuilder(signature);
for (final Attribute attribute : super.getAttributes()) {
if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
buf.append(" [").append(attribute).append("]");
}
}
final ExceptionTable e = getExceptionTable();
if (e != null) {
final String str = e.toString();
if (!str.isEmpty()) {
buf.append("\n\t\tthrows ").append(str);
}
}
return buf.toString();
}
}

View File

@@ -30,11 +30,11 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* 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 : The MethodParameters Attribute</a>
* @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>
* @since 6.0
*/
public class MethodParameter implements Cloneable {
public class MethodParameter implements Cloneable, Node {
/** Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter */
private int nameIndex;
@@ -49,67 +49,19 @@ public class MethodParameter implements Cloneable {
* Construct object from input stream.
*
* @param input Input stream
* @throws java.io.IOException
* @throws ClassFormatException
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
MethodParameter(final DataInput input) throws IOException {
nameIndex = input.readUnsignedShort();
accessFlags = input.readUnsignedShort();
}
public int getNameIndex() {
return nameIndex;
}
public void setNameIndex(final int name_index) {
this.nameIndex = name_index;
}
/**
* Returns the name of the parameter.
*/
public String getParameterName(final ConstantPool constant_pool) {
if (nameIndex == 0) {
return null;
}
return ((ConstantUtf8) constant_pool.getConstant(nameIndex, Const.CONSTANT_Utf8)).getBytes();
}
public int getAccessFlags() {
return accessFlags;
}
public void setAccessFlags(final int access_flags) {
this.accessFlags = access_flags;
}
public boolean isFinal() {
return (accessFlags & Const.ACC_FINAL) != 0;
}
public boolean isSynthetic() {
return (accessFlags & Const.ACC_SYNTHETIC) != 0;
}
public boolean isMandated() {
return (accessFlags & Const.ACC_MANDATED) != 0;
}
@Override
public void accept(final Visitor v) {
v.visitMethodParameter(this);
}
/**
* Dump object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(nameIndex);
file.writeShort(accessFlags);
}
/**
* @return deep copy of this object
*/
@@ -121,4 +73,53 @@ public class MethodParameter implements Cloneable {
}
return null;
}
/**
* Dump object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(nameIndex);
file.writeShort(accessFlags);
}
public int getAccessFlags() {
return accessFlags;
}
public int getNameIndex() {
return nameIndex;
}
/**
* Returns the name of the parameter.
*/
public String getParameterName(final ConstantPool constantPool) {
if (nameIndex == 0) {
return null;
}
return constantPool.getConstantUtf8(nameIndex).getBytes();
}
public boolean isFinal() {
return (accessFlags & Const.ACC_FINAL) != 0;
}
public boolean isMandated() {
return (accessFlags & Const.ACC_MANDATED) != 0;
}
public boolean isSynthetic() {
return (accessFlags & Const.ACC_SYNTHETIC) != 0;
}
public void setAccessFlags(final int accessFlags) {
this.accessFlags = accessFlags;
}
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
}

View File

@@ -24,52 +24,50 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* 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 : The MethodParameters Attribute</a>
* @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>
* @since 6.0
*/
public class MethodParameters extends Attribute {
public class MethodParameters extends Attribute implements Iterable<MethodParameter> {
private MethodParameter[] parameters = new MethodParameter[0];
/**
* Empty array.
*/
private static final MethodParameter[] EMPTY_METHOD_PARAMETER_ARRAY = {};
MethodParameters(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
super(Const.ATTR_METHOD_PARAMETERS, name_index, length, constant_pool);
private MethodParameter[] parameters = EMPTY_METHOD_PARAMETER_ARRAY;
final int parameters_count = input.readUnsignedByte();
parameters = new MethodParameter[parameters_count];
for (int i = 0; i < parameters_count; i++) {
MethodParameters(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_METHOD_PARAMETERS, nameIndex, length, constantPool);
final int parameterCount = input.readUnsignedByte();
parameters = new MethodParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
parameters[i] = new MethodParameter(input);
}
}
public MethodParameter[] getParameters() {
return parameters;
}
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters;
}
@Override
public void accept(final Visitor v) {
v.visitMethodParameters(this);
}
@Override
public Attribute copy(final ConstantPool _constant_pool) {
public Attribute copy(final ConstantPool constantPool) {
final MethodParameters c = (MethodParameters) clone();
c.parameters = new MethodParameter[parameters.length];
for (int i = 0; i < parameters.length; i++) {
c.parameters[i] = parameters[i].copy();
}
c.setConstantPool(_constant_pool);
Arrays.setAll(c.parameters, i -> parameters[i].copy());
c.setConstantPool(constantPool);
return c;
}
@@ -77,14 +75,27 @@ public class MethodParameters extends Attribute {
* Dump method parameters attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeByte(parameters.length);
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeByte(parameters.length);
for (final MethodParameter parameter : parameters) {
parameter.dump(file);
}
}
public MethodParameter[] getParameters() {
return parameters;
}
@Override
public Iterator<MethodParameter> iterator() {
return Stream.of(parameters).iterator();
}
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters;
}
}

View File

@@ -24,19 +24,26 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from <em>Attribute</em> and represents the list of
* modules required, exported, opened or provided by a module.
* There may be at most one Module attribute in a ClassFile structure.
* This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or
* provided by a module. There may be at most one Module attribute in a ClassFile structure.
*
* @see Attribute
* @see Attribute
* @since 6.4.0
*/
public final class Module extends Attribute {
/**
* The module file name extension.
*
* @since 6.7.0
*/
public static final String EXTENSION = ".jmod";
private final int moduleNameIndex;
private final int moduleFlags;
private final int moduleVersionIndex;
@@ -50,34 +57,35 @@ public final class Module extends Attribute {
/**
* Construct object from input stream.
* @param name_index Index in constant pool
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Module(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
super(Const.ATTR_MODULE, name_index, length, constant_pool);
Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_MODULE, nameIndex, length, constantPool);
moduleNameIndex = input.readUnsignedShort();
moduleFlags = input.readUnsignedShort();
moduleVersionIndex = input.readUnsignedShort();
final int requires_count = input.readUnsignedShort();
requiresTable = new ModuleRequires[requires_count];
for (int i = 0; i < requires_count; i++) {
final int requiresCount = input.readUnsignedShort();
requiresTable = new ModuleRequires[requiresCount];
for (int i = 0; i < requiresCount; i++) {
requiresTable[i] = new ModuleRequires(input);
}
final int exports_count = input.readUnsignedShort();
exportsTable = new ModuleExports[exports_count];
for (int i = 0; i < exports_count; i++) {
final int exportsCount = input.readUnsignedShort();
exportsTable = new ModuleExports[exportsCount];
for (int i = 0; i < exportsCount; i++) {
exportsTable[i] = new ModuleExports(input);
}
final int opens_count = input.readUnsignedShort();
opensTable = new ModuleOpens[opens_count];
for (int i = 0; i < opens_count; i++) {
final int opensCount = input.readUnsignedShort();
opensTable = new ModuleOpens[opensCount];
for (int i = 0; i < opensCount; i++) {
opensTable[i] = new ModuleOpens(input);
}
@@ -87,72 +95,57 @@ public final class Module extends Attribute {
usesIndex[i] = input.readUnsignedShort();
}
final int provides_count = input.readUnsignedShort();
providesTable = new ModuleProvides[provides_count];
for (int i = 0; i < provides_count; i++) {
final int providesCount = input.readUnsignedShort();
providesTable = new ModuleProvides[providesCount];
for (int i = 0; i < providesCount; i++) {
providesTable[i] = new ModuleProvides(input);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModule(this);
}
// TODO add more getters and setters?
/**
* @return table of required modules
* @see ModuleRequires
* @return deep copy of this attribute
*/
public ModuleRequires[] getRequiresTable() {
return requiresTable;
@Override
public Attribute copy(final ConstantPool constantPool) {
final Module c = (Module) clone();
c.requiresTable = new ModuleRequires[requiresTable.length];
Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy());
c.exportsTable = new ModuleExports[exportsTable.length];
Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy());
c.opensTable = new ModuleOpens[opensTable.length];
Arrays.setAll(c.opensTable, i -> opensTable[i].copy());
c.providesTable = new ModuleProvides[providesTable.length];
Arrays.setAll(c.providesTable, i -> providesTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* @return table of exported interfaces
* @see ModuleExports
*/
public ModuleExports[] getExportsTable() {
return exportsTable;
}
/**
* @return table of provided interfaces
* @see ModuleOpens
*/
public ModuleOpens[] getOpensTable() {
return opensTable;
}
/**
* @return table of provided interfaces
* @see ModuleProvides
*/
public ModuleProvides[] getProvidesTable() {
return providesTable;
}
/**
* Dump Module attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(moduleNameIndex);
@@ -185,6 +178,37 @@ public final class Module extends Attribute {
}
}
/**
* @return table of exported interfaces
* @see ModuleExports
*/
public ModuleExports[] getExportsTable() {
return exportsTable;
}
/**
* @return table of provided interfaces
* @see ModuleOpens
*/
public ModuleOpens[] getOpensTable() {
return opensTable;
}
/**
* @return table of provided interfaces
* @see ModuleProvides
*/
public ModuleProvides[] getProvidesTable() {
return providesTable;
}
/**
* @return table of required modules
* @see ModuleRequires
*/
public ModuleRequires[] getRequiresTable() {
return requiresTable;
}
/**
* @return String representation, i.e., a list of packages.
@@ -194,10 +218,10 @@ public final class Module extends Attribute {
final ConstantPool cp = super.getConstantPool();
final StringBuilder buf = new StringBuilder();
buf.append("Module:\n");
buf.append(" name: ") .append(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module).replace('/', '.')).append("\n");
buf.append(" flags: ") .append(String.format("%04x", moduleFlags)).append("\n");
buf.append(" name: ").append(Utility.pathToPackage(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module))).append("\n");
buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n");
final String version = moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8);
buf.append(" version: ") .append(version).append("\n");
buf.append(" version: ").append(version).append("\n");
buf.append(" requires(").append(requiresTable.length).append("):\n");
for (final ModuleRequires module : requiresTable) {
@@ -216,8 +240,8 @@ public final class Module extends Attribute {
buf.append(" uses(").append(usesIndex.length).append("):\n");
for (final int index : usesIndex) {
final String class_name = cp.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(class_name, false)).append("\n");
final String className = cp.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
}
buf.append(" provides(").append(providesTable.length).append("):\n");
@@ -225,38 +249,6 @@ public final class Module extends Attribute {
buf.append(" ").append(module.toString(cp)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final Module c = (Module) clone();
c.requiresTable = new ModuleRequires[requiresTable.length];
for (int i = 0; i < requiresTable.length; i++) {
c.requiresTable[i] = requiresTable[i].copy();
}
c.exportsTable = new ModuleExports[exportsTable.length];
for (int i = 0; i < exportsTable.length; i++) {
c.exportsTable[i] = exportsTable[i].copy();
}
c.opensTable = new ModuleOpens[opensTable.length];
for (int i = 0; i < opensTable.length; i++) {
c.opensTable[i] = opensTable[i].copy();
}
c.providesTable = new ModuleProvides[providesTable.length];
for (int i = 0; i < providesTable.length; i++) {
c.providesTable[i] = providesTable[i].copy();
}
c.setConstantPool(_constant_pool);
return c;
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -28,19 +28,18 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the exports table of the Module attribute.
* Each entry describes a package which may open the parent module.
* This class represents an entry in the exports table of the Module attribute. Each entry describes a package which may
* open the parent module.
*
* @see Module
* @see Module
* @since 6.4.0
*/
public final class ModuleExports implements Cloneable, Node {
private final int exportsIndex; // points to CONSTANT_Package_info
private final int exportsIndex; // points to CONSTANT_Package_info
private final int exportsFlags;
private final int exportsToCount;
private final int[] exportsToIndex; // points to CONSTANT_Module_info
private final int[] exportsToIndex; // points to CONSTANT_Module_info
/**
* Construct object from file stream.
@@ -58,63 +57,19 @@ public final class ModuleExports implements Cloneable, Node {
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModuleExports(this);
}
// TODO add more getters and setters?
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(exportsIndex);
file.writeShort(exportsFlags);
file.writeShort(exportsToCount);
for (final int entry : exportsToIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "exports(" + exportsIndex + ", " + exportsFlags + ", " + exportsToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString( final ConstantPool constant_pool ) {
final StringBuilder buf = new StringBuilder();
final String package_name = constant_pool.constantToString(exportsIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(package_name, false));
buf.append(", ").append(String.format("%04x", exportsFlags));
buf.append(", to(").append(exportsToCount).append("):\n");
for (final int index : exportsToIndex) {
final String module_name = constant_pool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(module_name, false)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this object
*/
@@ -126,4 +81,43 @@ public final class ModuleExports implements Cloneable, Node {
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(exportsIndex);
file.writeShort(exportsFlags);
file.writeShort(exportsToCount);
for (final int entry : exportsToIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "exports(" + exportsIndex + ", " + exportsFlags + ", " + exportsToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = constantPool.constantToString(exportsIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(packageName, false));
buf.append(", ").append(String.format("%04x", exportsFlags));
buf.append(", to(").append(exportsToCount).append("):\n");
for (final int index : exportsToIndex) {
final String moduleName = constantPool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -26,66 +26,73 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and indicates the main class of a module.
* There may be at most one ModuleMainClass attribute in a ClassFile structure.
* This class is derived from <em>Attribute</em> and indicates the main class of a module. There may be at most one
* ModuleMainClass attribute in a ClassFile structure.
*
* @see Attribute
* @see Attribute
*/
public final class ModuleMainClass extends Attribute {
private int mainClassIndex;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
*/
public ModuleMainClass(final ModuleMainClass c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param mainClassIndex Host class index
* @param constantPool Array of constants
*/
public ModuleMainClass(final int name_index, final int length, final int mainClassIndex,
final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, name_index, length, constantPool);
this.mainClassIndex = mainClassIndex;
}
/**
* Construct object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ModuleMainClass(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, 0, constantPool);
mainClassIndex = input.readUnsignedShort();
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param mainClassIndex Host class index
* @param constantPool Array of constants
*/
public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.mainClassIndex = Args.requireU2(mainClassIndex, "mainClassIndex");
}
/**
* 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.
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public ModuleMainClass(final ModuleMainClass c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModuleMainClass(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ModuleMainClass c = (ModuleMainClass) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dump ModuleMainClass attribute to file stream in binary format.
@@ -94,12 +101,11 @@ public final class ModuleMainClass extends Attribute {
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(mainClassIndex);
}
/**
* @return index into constant pool of host class name.
*/
@@ -107,15 +113,13 @@ public final class ModuleMainClass extends Attribute {
return mainClassIndex;
}
/**
* @param mainClassIndex the host class index
*/
public void setHostClassIndex( final int mainClassIndex ) {
public void setHostClassIndex(final int mainClassIndex) {
this.mainClassIndex = mainClassIndex;
}
/**
* @return String representation
*/
@@ -123,19 +127,8 @@ public final class ModuleMainClass extends Attribute {
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("ModuleMainClass: ");
final String class_name = super.getConstantPool().getConstantString(mainClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(class_name, false));
final String className = super.getConstantPool().getConstantString(mainClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(className, false));
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final ModuleMainClass c = (ModuleMainClass) clone();
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -28,19 +28,18 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the opens table of the Module attribute.
* Each entry describes a package which the parent module opens.
* This class represents an entry in the opens table of the Module attribute. Each entry describes a package which the
* parent module opens.
*
* @see Module
* @see Module
* @since 6.4.0
*/
public final class ModuleOpens implements Cloneable, Node {
private final int opensIndex; // points to CONSTANT_Package_info
private final int opensIndex; // points to CONSTANT_Package_info
private final int opensFlags;
private final int opensToCount;
private final int[] opensToIndex; // points to CONSTANT_Module_info
private final int[] opensToIndex; // points to CONSTANT_Module_info
/**
* Construct object from file stream.
@@ -58,63 +57,19 @@ public final class ModuleOpens implements Cloneable, Node {
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModuleOpens(this);
}
// TODO add more getters and setters?
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(opensIndex);
file.writeShort(opensFlags);
file.writeShort(opensToCount);
for (final int entry : opensToIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "opens(" + opensIndex + ", " + opensFlags + ", " + opensToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString( final ConstantPool constant_pool ) {
final StringBuilder buf = new StringBuilder();
final String package_name = constant_pool.constantToString(opensIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(package_name, false));
buf.append(", ").append(String.format("%04x", opensFlags));
buf.append(", to(").append(opensToCount).append("):\n");
for (final int index : opensToIndex) {
final String module_name = constant_pool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(module_name, false)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this object
*/
@@ -126,4 +81,43 @@ public final class ModuleOpens implements Cloneable, Node {
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(opensIndex);
file.writeShort(opensFlags);
file.writeShort(opensToCount);
for (final int entry : opensToIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "opens(" + opensIndex + ", " + opensFlags + ", " + opensToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = constantPool.constantToString(opensIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(packageName, false));
buf.append(", ").append(String.format("%04x", opensFlags));
buf.append(", to(").append(opensToCount).append("):\n");
for (final int index : opensToIndex) {
final String moduleName = constantPool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,81 +23,94 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the Module attribute.
* There may be at most one ModulePackages attribute in a ClassFile structure.
* This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the
* Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure.
*
* @see Attribute
* @see Attribute
* @LastModified: Feb 2023
*/
public final class ModulePackages extends Attribute {
private int[] packageIndexTable;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* Construct object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
public ModulePackages(final ModulePackages c) {
this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
ModulePackages(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int packageCount = input.readUnsignedShort();
packageIndexTable = new int[packageCount];
for (int i = 0; i < packageCount; i++) {
packageIndexTable[i] = input.readUnsignedShort();
}
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param packageIndexTable Table of indices in constant pool
* @param constantPool Array of constants
*/
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);
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : new int[0];
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY;
Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length");
}
/**
* Construct object from input stream.
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
ModulePackages(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, (int[]) null, constant_pool);
final int number_of_packages = input.readUnsignedShort();
packageIndexTable = new int[number_of_packages];
for (int i = 0; i < number_of_packages; i++) {
packageIndexTable[i] = input.readUnsignedShort();
}
public ModulePackages(final ModulePackages c) {
this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModulePackages(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ModulePackages c = (ModulePackages) clone();
if (packageIndexTable != null) {
c.packageIndexTable = packageIndexTable.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump ModulePackages attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(packageIndexTable.length);
for (final int index : packageIndexTable) {
@@ -106,15 +118,6 @@ public final class ModulePackages extends Attribute {
}
}
/**
* @return array of indices into constant pool of package names.
*/
public int[] getPackageIndexTable() {
return packageIndexTable;
}
/**
* @return Length of package table.
*/
@@ -122,29 +125,29 @@ public final class ModulePackages extends Attribute {
return packageIndexTable == null ? 0 : packageIndexTable.length;
}
/**
* @return array of indices into constant pool of package names.
*/
public int[] getPackageIndexTable() {
return packageIndexTable;
}
/**
* @return string array of package names
*/
public String[] getPackageNames() {
final String[] names = new String[packageIndexTable.length];
for (int i = 0; i < packageIndexTable.length; i++) {
names[i] = super.getConstantPool().getConstantString(packageIndexTable[i],
Const.CONSTANT_Package).replace('/', '.');
}
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(packageIndexTable[i], Const.CONSTANT_Package)));
return names;
}
/**
* @param packageIndexTable the list of package indexes
* Also redefines number_of_packages according to table length.
* @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 : new int[0];
public void setPackageIndexTable(final int[] packageIndexTable) {
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY;
}
/**
* @return String representation, i.e., a list of packages.
*/
@@ -155,25 +158,9 @@ public final class ModulePackages extends Attribute {
buf.append(packageIndexTable.length);
buf.append("):\n");
for (final int index : packageIndexTable) {
final String package_name = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
buf.append(" ").append(Utility.compactClassName(package_name, false)).append("\n");
final String packageName = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
buf.append(" ").append(Utility.compactClassName(packageName, false)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final ModulePackages c = (ModulePackages) clone();
if (packageIndexTable != null) {
c.packageIndexTable = new int[packageIndexTable.length];
System.arraycopy(packageIndexTable, 0, c.packageIndexTable, 0,
packageIndexTable.length);
}
c.setConstantPool(_constant_pool);
return c;
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -28,18 +28,17 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the provides table of the Module attribute.
* Each entry describes a service implementation that the parent module provides.
* This class represents an entry in the provides table of the Module attribute. Each entry describes a service
* implementation that the parent module provides.
*
* @see Module
* @see Module
* @since 6.4.0
*/
public final class ModuleProvides implements Cloneable, Node {
private final int providesIndex; // points to CONSTANT_Class_info
private final int providesIndex; // points to CONSTANT_Class_info
private final int providesWithCount;
private final int[] providesWithIndex; // points to CONSTANT_Class_info
private final int[] providesWithIndex; // points to CONSTANT_Class_info
/**
* Construct object from file stream.
@@ -56,61 +55,19 @@ public final class ModuleProvides implements Cloneable, Node {
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModuleProvides(this);
}
// TODO add more getters and setters?
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(providesIndex);
file.writeShort(providesWithCount);
for (final int entry : providesWithIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "provides(" + providesIndex + ", " + providesWithCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString( final ConstantPool constant_pool ) {
final StringBuilder buf = new StringBuilder();
final String interface_name = constant_pool.constantToString(providesIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(interface_name, false));
buf.append(", with(").append(providesWithCount).append("):\n");
for (final int index : providesWithIndex) {
final String class_name = constant_pool.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(class_name, false)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this object
*/
@@ -122,4 +79,41 @@ public final class ModuleProvides implements Cloneable, Node {
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(providesIndex);
file.writeShort(providesWithCount);
for (final int entry : providesWithIndex) {
file.writeShort(entry);
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "provides(" + providesIndex + ", " + providesWithCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String interfaceName = constantPool.constantToString(providesIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(interfaceName, false));
buf.append(", with(").append(providesWithCount).append("):\n");
for (final int index : providesWithIndex) {
final String className = constantPool.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -28,18 +28,17 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the requires table of the Module attribute.
* Each entry describes a module on which the parent module depends.
* This class represents an entry in the requires table of the Module attribute. Each entry describes a module on which
* the parent module depends.
*
* @see Module
* @see Module
* @since 6.4.0
*/
public final class ModuleRequires implements Cloneable, Node {
private final int requiresIndex; // points to CONSTANT_Module_info
private final int requiresIndex; // points to CONSTANT_Module_info
private final int requiresFlags;
private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info
private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info
/**
* Construct object from file stream.
@@ -53,57 +52,19 @@ public final class ModuleRequires implements Cloneable, Node {
requiresVersionIndex = file.readUnsignedShort();
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitModuleRequires(this);
}
// TODO add more getters and setters?
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(requiresIndex);
file.writeShort(requiresFlags);
file.writeShort(requiresVersionIndex);
}
/**
* @return String representation
*/
@Override
public String toString() {
return "requires(" + requiresIndex + ", " + String.format("%04x", requiresFlags) + ", " + requiresVersionIndex + ")";
}
/**
* @return Resolved string representation
*/
public String toString( final ConstantPool constant_pool ) {
final StringBuilder buf = new StringBuilder();
final String module_name = constant_pool.constantToString(requiresIndex, Const.CONSTANT_Module);
buf.append(Utility.compactClassName(module_name, false));
buf.append(", ").append(String.format("%04x", requiresFlags));
final String version = requiresVersionIndex == 0 ? "0" : constant_pool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8);
buf.append(", ").append(version);
return buf.toString();
}
/**
* @return deep copy of this object
*/
@@ -115,4 +76,37 @@ public final class ModuleRequires implements Cloneable, Node {
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(requiresIndex);
file.writeShort(requiresFlags);
file.writeShort(requiresVersionIndex);
}
/**
* @return String representation
*/
@Override
public String toString() {
return "requires(" + requiresIndex + ", " + String.format("%04x", requiresFlags) + ", " + requiresVersionIndex + ")";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String moduleName = constantPool.constantToString(requiresIndex, Const.CONSTANT_Module);
buf.append(Utility.compactClassName(moduleName, false));
buf.append(", ").append(String.format("%04x", requiresFlags));
final String version = requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8);
buf.append(", ").append(version);
return buf.toString();
}
}

View File

@@ -26,67 +26,73 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and records the nest host of the nest
* to which the current class or interface claims to belong.
* There may be at most one NestHost attribute in a ClassFile structure.
* This class is derived from <em>Attribute</em> and records the nest host of the nest to which the current class or
* interface claims to belong. There may be at most one NestHost attribute in a ClassFile structure.
*
* @see Attribute
* @see Attribute
*/
public final class NestHost extends Attribute {
private int hostClassIndex;
/**
* Initializes from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
public NestHost(final NestHost c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
NestHost(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, 0, constantPool);
hostClassIndex = input.readUnsignedShort();
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param hostClassIndex Host class index
* @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);
this.hostClassIndex = hostClassIndex;
this.hostClassIndex = Args.requireU2(hostClassIndex, "hostClassIndex");
}
/**
* Constructs object from input stream.
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* Initializes from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
NestHost(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, 0, constant_pool);
hostClassIndex = input.readUnsignedShort();
public NestHost(final NestHost c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitNestHost(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final NestHost c = (NestHost) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dumps NestHost attribute to file stream in binary format.
@@ -95,12 +101,11 @@ public final class NestHost extends Attribute {
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(hostClassIndex);
}
/**
* @return index into constant pool of host class name.
*/
@@ -108,15 +113,13 @@ public final class NestHost extends Attribute {
return hostClassIndex;
}
/**
* @param hostClassIndex the host class index
*/
public void setHostClassIndex( final int hostClassIndex ) {
public void setHostClassIndex(final int hostClassIndex) {
this.hostClassIndex = hostClassIndex;
}
/**
* @return String representation
*/
@@ -124,19 +127,8 @@ public final class NestHost extends Attribute {
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("NestHost: ");
final String class_name = super.getConstantPool().getConstantString(hostClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(class_name, false));
final String className = super.getConstantPool().getConstantString(hostClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(className, false));
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final NestHost c = (NestHost) clone();
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -24,82 +23,95 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and records the classes and interfaces that
* are authorized to claim membership in the nest hosted by the current class or interface.
* There may be at most one NestMembers attribute in a ClassFile structure.
* This class is derived from <em>Attribute</em> and records the classes and interfaces that are authorized to claim
* membership in the nest hosted by the current class or interface. There may be at most one NestMembers attribute in a
* ClassFile structure.
*
* @see Attribute
* @see Attribute
* @LastModified: Feb 2023
*/
public final class NestMembers extends Attribute {
private int[] classes;
/**
* Construct object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
NestMembers(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int classCount = input.readUnsignedShort();
classes = new int[classCount];
for (int i = 0; i < classCount; i++) {
classes[i] = input.readUnsignedShort();
}
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param classes Table of indices in constant pool
* @param constantPool Array of constants
*/
public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY;
Args.requireU2(this.classes.length, "classes.length");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public NestMembers(final NestMembers c) {
this(c.getNameIndex(), c.getLength(), c.getClasses(), c.getConstantPool());
}
/**
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param classes Table of indices in constant pool
* @param constant_pool Array of constants
*/
public NestMembers(final int name_index, final int length, final int[] classes,
final ConstantPool constant_pool) {
super(Const.ATTR_NEST_MEMBERS, name_index, length, constant_pool);
this.classes = classes != null ? classes : new int[0];
}
/**
* Construct object from input stream.
* @param name_index Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
*/
NestMembers(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, (int[]) null, constant_pool);
final int number_of_classes = input.readUnsignedShort();
classes = new int[number_of_classes];
for (int i = 0; i < number_of_classes; i++) {
classes[i] = input.readUnsignedShort();
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitNestMembers(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final NestMembers c = (NestMembers) clone();
if (classes.length > 0) {
c.classes = classes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump NestMembers attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(classes.length);
for (final int index : classes) {
@@ -107,7 +119,6 @@ public final class NestMembers extends Attribute {
}
}
/**
* @return array of indices into constant pool of class names.
*/
@@ -115,36 +126,28 @@ public final class NestMembers extends Attribute {
return classes;
}
/**
* @return Length of classes table.
*/
public int getNumberClasses() {
return classes == null ? 0 : classes.length;
}
/**
* @return string array of class names
*/
public String[] getClassNames() {
final String[] names = new String[classes.length];
for (int i = 0; i < classes.length; i++) {
names[i] = super.getConstantPool().getConstantString(classes[i],
Const.CONSTANT_Class).replace('/', '.');
}
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(classes[i], Const.CONSTANT_Class)));
return names;
}
/**
* @param classes the list of class indexes
* Also redefines number_of_classes according to table length.
* @return Length of classes table.
*/
public void setClasses( final int[] classes ) {
this.classes = classes != null ? classes : new int[0];
public int getNumberClasses() {
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 : Const.EMPTY_INT_ARRAY;
}
/**
* @return String representation, i.e., a list of classes.
@@ -156,25 +159,9 @@ public final class NestMembers extends Attribute {
buf.append(classes.length);
buf.append("):\n");
for (final int index : classes) {
final String class_name = super.getConstantPool().getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(class_name, false)).append("\n");
final String className = super.getConstantPool().getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
}
return buf.substring(0, buf.length()-1); // remove the last newline
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final NestMembers c = (NestMembers) clone();
if (classes != null) {
c.classes = new int[classes.length];
System.arraycopy(classes, 0, c.classes, 0,
classes.length);
}
c.setConstantPool(_constant_pool);
return c;
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View File

@@ -23,9 +23,8 @@ package com.sun.org.apache.bcel.internal.classfile;
/**
* Denote class to have an accept method();
*
*/
public interface Node {
void accept( Visitor obj );
void accept(Visitor obj);
}

View File

@@ -28,83 +28,83 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from <em>Attribute</em> and represents a reference
* to a PMG attribute.
* This class is derived from <em>Attribute</em> and represents a reference to a PMG attribute.
*
* @see Attribute
* @see Attribute
*/
public final class PMGClass extends Attribute {
private int pmgClassIndex;
private int pmgIndex;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
*/
public PMGClass(final PMGClass pgmClass) {
this(pgmClass.getNameIndex(), pgmClass.getLength(), pgmClass.getPMGIndex(), pgmClass.getPMGClassIndex(),
pgmClass.getConstantPool());
}
/**
* Construct object from input stream.
* @param name_index Index in constant pool to CONSTANT_Utf8
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
PMGClass(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, input.readUnsignedShort(), input.readUnsignedShort(), constant_pool);
PMGClass(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), input.readUnsignedShort(), constantPool);
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param pmgIndex index in constant pool for source file name
* @param pmgClassIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public PMGClass(final int name_index, final int length, final int pmgIndex, final int pmgClassIndex,
final ConstantPool constantPool) {
super(Const.ATTR_PMG, name_index, length, 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);
this.pmgIndex = pmgIndex;
this.pmgClassIndex = pmgClassIndex;
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param pgmClass Source to copy.
*/
public PMGClass(final PMGClass pgmClass) {
this(pgmClass.getNameIndex(), pgmClass.getLength(), pgmClass.getPMGIndex(), pgmClass.getPMGClassIndex(), pgmClass.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
println("Visiting non-standard PMGClass object");
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(pmgIndex);
file.writeShort(pmgClassIndex);
}
/**
* @return Index in constant pool of source file name.
*/
@@ -112,15 +112,13 @@ public final class PMGClass extends Attribute {
return pmgClassIndex;
}
/**
* @param pmgClassIndex
* @return PMG class name.
*/
public void setPMGClassIndex( final int pmgClassIndex ) {
this.pmgClassIndex = pmgClassIndex;
public String getPMGClassName() {
return super.getConstantPool().getConstantUtf8(pmgClassIndex).getBytes();
}
/**
* @return Index in constant pool of source file name.
*/
@@ -128,34 +126,26 @@ public final class PMGClass extends Attribute {
return pmgIndex;
}
/**
* @param pmgIndex
*/
public void setPMGIndex( final int pmgIndex ) {
this.pmgIndex = pmgIndex;
}
/**
* @return PMG name.
*/
public String getPMGName() {
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(pmgIndex,
Const.CONSTANT_Utf8);
return c.getBytes();
return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
}
/**
* @return PMG class name.
* @param pmgClassIndex
*/
public String getPMGClassName() {
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(pmgClassIndex,
Const.CONSTANT_Utf8);
return c.getBytes();
public void setPMGClassIndex(final int pmgClassIndex) {
this.pmgClassIndex = pmgClassIndex;
}
/**
* @param pmgIndex
*/
public void setPMGIndex(final int pmgIndex) {
this.pmgIndex = pmgIndex;
}
/**
* @return String representation
@@ -164,13 +154,4 @@ public final class PMGClass extends Attribute {
public String toString() {
return "PMGClass(" + getPMGName() + ", " + getPMGClassName() + ")";
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
return (Attribute) clone();
}
}

View File

@@ -35,44 +35,48 @@ import java.util.List;
*/
public class ParameterAnnotationEntry implements Node {
private final AnnotationEntry[] annotationTable;
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;
/**
* Construct object from input stream.
*
* @param input Input stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
ParameterAnnotationEntry(final DataInput input, final ConstantPool constant_pool) throws IOException {
final int annotation_table_length = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotation_table_length];
for (int i = 0; i < annotation_table_length; i++) {
ParameterAnnotationEntry(final DataInput input, final ConstantPool constantPool) throws IOException {
final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength];
for (int i = 0; i < annotationTableLength; i++) {
// TODO isRuntimeVisible
annotationTable[i] = AnnotationEntry.read(input, constant_pool, false);
annotationTable[i] = AnnotationEntry.read(input, constantPool, false);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitParameterAnnotationEntry(this);
}
/**
* returns the array of annotation entries in this annotation
*/
public AnnotationEntry[] getAnnotationEntries() {
return annotationTable;
}
public void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(annotationTable.length);
for (final AnnotationEntry entry : annotationTable) {
@@ -80,15 +84,10 @@ 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(new ParameterAnnotationEntry[accumulatedAnnotations.size()]);
}
/**
* returns the array of annotation entries in this annotation
*/
public AnnotationEntry[] getAnnotationEntries() {
return annotationTable;
}
}

View File

@@ -24,36 +24,36 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
/**
* base class for parameter annotations
*
* @since 6.0
*/
public abstract class ParameterAnnotations extends Attribute {
public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> {
/** Table of parameter annotations */
private ParameterAnnotationEntry[] parameterAnnotationTable;
/**
* @param parameter_annotation_type the subclass type of the parameter annotation
* @param name_index Index pointing to the name <em>Code</em>
* @param parameterAnnotationType the subclass type of the parameter annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
ParameterAnnotations(final byte parameter_annotation_type, final int name_index, final int length,
final DataInput input, final ConstantPool constant_pool) throws IOException {
this(parameter_annotation_type, name_index, length, (ParameterAnnotationEntry[]) null,
constant_pool);
final int num_parameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[num_parameters];
for (int i = 0; i < num_parameters; i++) {
parameterAnnotationTable[i] = new ParameterAnnotationEntry(input, constant_pool);
ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool);
final int numParameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[numParameters];
for (int i = 0; i < numParameters; i++) {
parameterAnnotationTable[i] = new ParameterAnnotationEntry(input, constantPool);
}
}
/**
* @param parameterAnnotationType the subclass type of the parameter annotation
* @param nameIndex Index pointing to the name <em>Code</em>
@@ -62,51 +62,32 @@ public abstract class ParameterAnnotations extends Attribute {
* @param constantPool Array of constants
*/
public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length,
final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
super(parameterAnnotationType, nameIndex, length, constantPool);
this.parameterAnnotationTable = parameterAnnotationTable;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitParameterAnnotation(this);
}
/**
* @param parameterAnnotationTable the entries to set in this parameter annotation
* @return deep copy of this attribute
*/
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable ) {
this.parameterAnnotationTable = parameterAnnotationTable;
}
/**
* @return the parameter annotation entry table
*/
public final ParameterAnnotationEntry[] getParameterAnnotationTable() {
return parameterAnnotationTable;
}
/**
* returns the array of parameter annotation entries in this parameter annotation
*/
public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
return parameterAnnotationTable;
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
public void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
dos.writeByte(parameterAnnotationTable.length);
@@ -117,10 +98,28 @@ public abstract class ParameterAnnotations extends Attribute {
}
/**
* @return deep copy of this attribute
* returns the array of parameter annotation entries in this parameter annotation
*/
public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
return parameterAnnotationTable;
}
/**
* @return the parameter annotation entry table
*/
public final ParameterAnnotationEntry[] getParameterAnnotationTable() {
return parameterAnnotationTable;
}
@Override
public Attribute copy( final ConstantPool constant_pool ) {
return (Attribute) clone();
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
/**
* @param parameterAnnotationTable the entries to set in this parameter annotation
*/
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = parameterAnnotationTable;
}
}

View File

@@ -28,41 +28,33 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* represents an annotation that is represented in the class file but is not
* provided to the JVM.
* represents an annotation that is represented in the class file but is not provided to the JVM.
*
* @since 6.0
*/
public class RuntimeInvisibleAnnotations extends Annotations
{
public class RuntimeInvisibleAnnotations extends Annotations {
/**
* @param name_index
* Index pointing to the name <em>Code</em>
* @param length
* Content length in bytes
* @param input
* Input stream
* @param constant_pool
* Array of constants
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeInvisibleAnnotations(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException
{
super(Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS, name_index, length, input, constant_pool, false);
public RuntimeInvisibleAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS, nameIndex, length, input, constantPool, false);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constant_pool)
{
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException
{
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
writeAnnotations(dos);
}

View File

@@ -27,21 +27,21 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents a parameter annotation that is represented in the class file
* but is not provided to the JVM.
* Represents a parameter annotation that is represented in the class file but is not provided to the JVM.
*
* @since 6.0
*/
public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations {
/**
* @param name_index 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 input Input stream
* @param constant_pool Array of constants
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeInvisibleParameterAnnotations(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, name_index, length, input, constant_pool);
public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}

View File

@@ -28,40 +28,33 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* represents an annotation that is represented in the class file and is
* provided to the JVM.
* represents an annotation that is represented in the class file and is provided to the JVM.
*
* @since 6.0
*/
public class RuntimeVisibleAnnotations extends Annotations
{
public class RuntimeVisibleAnnotations extends Annotations {
/**
* @param name_index
* Index pointing to the name <em>Code</em>
* @param length
* Content length in bytes
* @param input
* Input stream
* @param constant_pool
* Array of constants
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeVisibleAnnotations(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException
{
super(Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, name_index, length, input, constant_pool, true);
public RuntimeVisibleAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, nameIndex, length, input, constantPool, true);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constant_pool)
{
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException
{
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
writeAnnotations(dos);
}

View File

@@ -27,21 +27,21 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents a parameter annotation that is represented in the class file
* and is provided to the JVM.
* Represents a parameter annotation that is represented in the class file and is provided to the JVM.
*
* @since 6.0
*/
public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations {
/**
* @param name_index 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 input Input stream
* @param constant_pool Array of constants
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeVisibleParameterAnnotations(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, name_index, length, input, constant_pool);
public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}

View File

@@ -25,122 +25,32 @@ import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a reference
* to a GJ attribute.
* This class is derived from <em>Attribute</em> and represents a reference to a GJ attribute.
*
* @see Attribute
* @see Attribute
*/
public final class Signature extends Attribute {
private int signatureIndex;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
*/
public Signature(final Signature c) {
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
/**
* Construct object from file stream.
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
*/
Signature(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, input.readUnsignedShort(), constant_pool);
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param signatureIndex Index in constant pool to CONSTANT_Utf8
* @param constant_pool Array of constants
*/
public Signature(final int name_index, final int length, final int signatureIndex, final ConstantPool constant_pool) {
super(Const.ATTR_SIGNATURE, name_index, length, constant_pool);
this.signatureIndex = signatureIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
//System.err.println("Visiting non-standard Signature object");
v.visitSignature(this);
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
super.dump(file);
file.writeShort(signatureIndex);
}
/**
* @return Index in constant pool of source file name.
*/
public int getSignatureIndex() {
return signatureIndex;
}
/**
* @param signatureIndex the index info the constant pool of this signature
*/
public void setSignatureIndex( final int signatureIndex ) {
this.signatureIndex = signatureIndex;
}
/**
* @return GJ signature.
*/
public String getSignature() {
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(signatureIndex,
Const.CONSTANT_Utf8);
return c.getBytes();
}
/**
* Extends ByteArrayInputStream to make 'unreading' chars possible.
*/
private static final class MyByteArrayInputStream extends ByteArrayInputStream {
MyByteArrayInputStream(final String data) {
super(data.getBytes());
super(data.getBytes(StandardCharsets.UTF_8));
}
String getData() {
return new String(buf);
return new String(buf, StandardCharsets.UTF_8);
}
void unread() {
if (pos > 0) {
pos--;
@@ -148,19 +58,59 @@ public final class Signature extends Attribute {
}
}
private static boolean identStart( final int ch ) {
private static boolean identStart(final int ch) {
return ch == 'T' || ch == 'L';
}
// @since 6.0 is no longer final
public static boolean isActualParameterList(final String s) {
return s.startsWith("L") && s.endsWith(">;");
}
private static void matchIdent( final MyByteArrayInputStream in, final StringBuilder buf ) {
// @since 6.0 is no longer final
public static boolean isFormalParameterList(final String s) {
return s.startsWith("<") && s.indexOf(':') > 0;
}
private static void matchGJIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
int ch;
matchIdent(in, buf);
ch = in.read();
if (ch == '<' || ch == '(') { // Parameterized or method
// System.out.println("Enter <");
buf.append((char) ch);
matchGJIdent(in, buf);
while ((ch = in.read()) != '>' && ch != ')') { // List of parameters
if (ch == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " reaching EOF");
}
// System.out.println("Still no >");
buf.append(", ");
in.unread();
matchGJIdent(in, buf); // Recursive call
}
// System.out.println("Exit >");
buf.append((char) ch);
} else {
in.unread();
}
ch = in.read();
if (identStart(ch)) {
in.unread();
matchGJIdent(in, buf);
} else if (ch == ')') {
in.unread();
} else if (ch != ';') {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " read " + (char) ch);
}
}
private static void matchIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
int ch;
if ((ch = in.read()) == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData()
+ " no ident, reaching EOF");
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF");
}
//System.out.println("return from ident:" + (char)ch);
// System.out.println("return from ident:" + (char)ch);
if (!identStart(ch)) {
final StringBuilder buf2 = new StringBuilder();
int count = 1;
@@ -170,11 +120,15 @@ public final class Signature extends Attribute {
ch = in.read();
}
if (ch == ':') { // Ok, formal parameter
in.skip("Ljava/lang/Object".length());
final int skipExpected = "Ljava/lang/Object".length();
final long skipActual = in.skip(skipExpected);
if (skipActual != skipExpected) {
throw new IllegalStateException(String.format("Unexpected skip: expected=%,d, actual=%,d", skipExpected, skipActual));
}
buf.append(buf2);
ch = in.read();
in.unread();
//System.out.println("so far:" + buf2 + ":next:" +(char)ch);
// System.out.println("so far:" + buf2 + ":next:" +(char)ch);
} else {
for (int i = 0; i < count; i++) {
in.unread();
@@ -187,87 +141,118 @@ public final class Signature extends Attribute {
do {
buf2.append((char) ch);
ch = in.read();
//System.out.println("within ident:"+ (char)ch);
} while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/')));
buf.append(buf2.toString().replace('/', '.'));
//System.out.println("regular return ident:"+ (char)ch + ":" + buf2);
// System.out.println("within ident:"+ (char)ch);
} while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/'));
buf.append(Utility.pathToPackage(buf2.toString()));
// System.out.println("regular return ident:"+ (char)ch + ":" + buf2);
if (ch != -1) {
in.unread();
}
}
private static void matchGJIdent( final MyByteArrayInputStream in, final StringBuilder buf ) {
int ch;
matchIdent(in, buf);
ch = in.read();
if ((ch == '<') || ch == '(') { // Parameterized or method
//System.out.println("Enter <");
buf.append((char) ch);
matchGJIdent(in, buf);
while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters
if (ch == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData()
+ " reaching EOF");
}
//System.out.println("Still no >");
buf.append(", ");
in.unread();
matchGJIdent(in, buf); // Recursive call
}
//System.out.println("Exit >");
buf.append((char) ch);
} else {
in.unread();
}
ch = in.read();
if (identStart(ch)) {
in.unread();
matchGJIdent(in, buf);
} else if (ch == ')') {
in.unread();
return;
} else if (ch != ';') {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " read " + (char) ch);
}
}
public static String translate( final String s ) {
//System.out.println("Sig:" + s);
public static String translate(final String s) {
// System.out.println("Sig:" + s);
final StringBuilder buf = new StringBuilder();
matchGJIdent(new MyByteArrayInputStream(s), buf);
return buf.toString();
}
private int signatureIndex;
// @since 6.0 is no longer final
public static boolean isFormalParameterList( final String s ) {
return s.startsWith("<") && (s.indexOf(':') > 0);
/**
* 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);
}
// @since 6.0 is no longer final
public static boolean isActualParameterList( final String s ) {
return s.startsWith("L") && s.endsWith(">;");
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param signatureIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
this.signatureIndex = signatureIndex;
// validate:
Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Signature(final Signature c) {
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
// System.err.println("Visiting non-standard Signature object");
v.visitSignature(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(signatureIndex);
}
/**
* @return GJ signature.
*/
public String getSignature() {
return super.getConstantPool().getConstantUtf8(signatureIndex).getBytes();
}
/**
* @return Index in constant pool of source file name.
*/
public int getSignatureIndex() {
return signatureIndex;
}
/**
* @param signatureIndex the index info the constant pool of this signature
*/
public void setSignatureIndex(final int signatureIndex) {
this.signatureIndex = signatureIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
final String s = getSignature();
return "Signature: " + s;
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
return (Attribute) clone();
return "Signature: " + getSignature();
}
}

View File

@@ -29,188 +29,19 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* @since 6.0
*/
public class SimpleElementValue extends ElementValue
{
public class SimpleElementValue extends ElementValue {
private int index;
public SimpleElementValue(final int type, final int index, final ConstantPool cpool)
{
public SimpleElementValue(final int type, final int index, final ConstantPool cpool) {
super(type, cpool);
this.index = index;
}
/**
* @return Value entry index in the cpool
*/
public int getIndex()
{
return index;
}
public void setIndex(final int index)
{
this.index = index;
}
public String getValueString()
{
if (super.getType() != STRING) {
throw new IllegalStateException(
"Dont call getValueString() on a non STRING ElementValue");
}
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(getIndex(),
Const.CONSTANT_Utf8);
return c.getBytes();
}
public int getValueInt()
{
if (super.getType() != PRIMITIVE_INT) {
throw new IllegalStateException(
"Dont call getValueString() on a non STRING ElementValue");
}
final ConstantInteger c = (ConstantInteger) super.getConstantPool().getConstant(getIndex(),
Const.CONSTANT_Integer);
return c.getBytes();
}
public byte getValueByte()
{
if (super.getType() != PRIMITIVE_BYTE) {
throw new IllegalStateException(
"Dont call getValueByte() on a non BYTE ElementValue");
}
final ConstantInteger c = (ConstantInteger) super.getConstantPool().getConstant(getIndex(),
Const.CONSTANT_Integer);
return (byte) c.getBytes();
}
public char getValueChar()
{
if (super.getType() != PRIMITIVE_CHAR) {
throw new IllegalStateException(
"Dont call getValueChar() on a non CHAR ElementValue");
}
final ConstantInteger c = (ConstantInteger) super.getConstantPool().getConstant(getIndex(),
Const.CONSTANT_Integer);
return (char) c.getBytes();
}
public long getValueLong()
{
if (super.getType() != PRIMITIVE_LONG) {
throw new IllegalStateException(
"Dont call getValueLong() on a non LONG ElementValue");
}
final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex());
return j.getBytes();
}
public float getValueFloat()
{
if (super.getType() != PRIMITIVE_FLOAT) {
throw new IllegalStateException(
"Dont call getValueFloat() on a non FLOAT ElementValue");
}
final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex());
return f.getBytes();
}
public double getValueDouble()
{
if (super.getType() != PRIMITIVE_DOUBLE) {
throw new IllegalStateException(
"Dont call getValueDouble() on a non DOUBLE ElementValue");
}
final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex());
return d.getBytes();
}
public boolean getValueBoolean()
{
if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException(
"Dont call getValueBoolean() on a non BOOLEAN ElementValue");
}
final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return bo.getBytes() != 0;
}
public short getValueShort()
{
if (super.getType() != PRIMITIVE_SHORT) {
throw new IllegalStateException(
"Dont call getValueShort() on a non SHORT ElementValue");
}
final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return (short) s.getBytes();
}
@Override
public String toString()
{
return stringifyValue();
}
// Whatever kind of value it is, return it as a string
@Override
public String stringifyValue()
{
final ConstantPool cpool = super.getConstantPool();
final int _type = super.getType();
switch (_type)
{
case PRIMITIVE_INT:
final ConstantInteger c = (ConstantInteger) cpool.getConstant(getIndex(),
Const.CONSTANT_Integer);
return Integer.toString(c.getBytes());
case PRIMITIVE_LONG:
final ConstantLong j = (ConstantLong) cpool.getConstant(getIndex(),
Const.CONSTANT_Long);
return Long.toString(j.getBytes());
case PRIMITIVE_DOUBLE:
final ConstantDouble d = (ConstantDouble) cpool.getConstant(getIndex(),
Const.CONSTANT_Double);
return Double.toString(d.getBytes());
case PRIMITIVE_FLOAT:
final ConstantFloat f = (ConstantFloat) cpool.getConstant(getIndex(),
Const.CONSTANT_Float);
return Float.toString(f.getBytes());
case PRIMITIVE_SHORT:
final ConstantInteger s = (ConstantInteger) cpool.getConstant(getIndex(),
Const.CONSTANT_Integer);
return Integer.toString(s.getBytes());
case PRIMITIVE_BYTE:
final ConstantInteger b = (ConstantInteger) cpool.getConstant(getIndex(),
Const.CONSTANT_Integer);
return Integer.toString(b.getBytes());
case PRIMITIVE_CHAR:
final ConstantInteger ch = (ConstantInteger) cpool.getConstant(
getIndex(), Const.CONSTANT_Integer);
return String.valueOf((char)ch.getBytes());
case PRIMITIVE_BOOLEAN:
final ConstantInteger bo = (ConstantInteger) cpool.getConstant(
getIndex(), Const.CONSTANT_Integer);
if (bo.getBytes() == 0) {
return "false";
}
return "true";
case STRING:
final ConstantUtf8 cu8 = (ConstantUtf8) cpool.getConstant(getIndex(),
Const.CONSTANT_Utf8);
return cu8.getBytes();
default:
throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + _type);
}
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
final int _type = super.getType();
dos.writeByte(_type); // u1 kind of value
switch (_type)
{
public void dump(final DataOutputStream dos) throws IOException {
final int type = super.getType();
dos.writeByte(type); // u1 kind of value
switch (type) {
case PRIMITIVE_INT:
case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR:
@@ -223,7 +54,130 @@ public class SimpleElementValue extends ElementValue
dos.writeShort(getIndex());
break;
default:
throw new IllegalStateException("SimpleElementValue doesnt know how to write out type " + _type);
throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type);
}
}
/**
* @return Value entry index in the cpool
*/
public int getIndex() {
return index;
}
public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue");
}
final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return bo.getBytes() != 0;
}
public byte getValueByte() {
if (super.getType() != PRIMITIVE_BYTE) {
throw new IllegalStateException("Dont call getValueByte() on a non BYTE ElementValue");
}
return (byte) super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public char getValueChar() {
if (super.getType() != PRIMITIVE_CHAR) {
throw new IllegalStateException("Dont call getValueChar() on a non CHAR ElementValue");
}
return (char) super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public double getValueDouble() {
if (super.getType() != PRIMITIVE_DOUBLE) {
throw new IllegalStateException("Dont call getValueDouble() on a non DOUBLE ElementValue");
}
final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex());
return d.getBytes();
}
public float getValueFloat() {
if (super.getType() != PRIMITIVE_FLOAT) {
throw new IllegalStateException("Dont call getValueFloat() on a non FLOAT ElementValue");
}
final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex());
return f.getBytes();
}
public int getValueInt() {
if (super.getType() != PRIMITIVE_INT) {
throw new IllegalStateException("Dont call getValueInt() on a non INT ElementValue");
}
return super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public long getValueLong() {
if (super.getType() != PRIMITIVE_LONG) {
throw new IllegalStateException("Dont call getValueLong() on a non LONG ElementValue");
}
final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex());
return j.getBytes();
}
public short getValueShort() {
if (super.getType() != PRIMITIVE_SHORT) {
throw new IllegalStateException("Dont call getValueShort() on a non SHORT ElementValue");
}
final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return (short) s.getBytes();
}
public String getValueString() {
if (super.getType() != STRING) {
throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue");
}
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes();
}
public void setIndex(final int index) {
this.index = index;
}
// Whatever kind of value it is, return it as a string
@Override
public String stringifyValue() {
final ConstantPool cpool = super.getConstantPool();
final int type = super.getType();
switch (type) {
case PRIMITIVE_INT:
return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes());
case PRIMITIVE_LONG:
final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class);
return Long.toString(j.getBytes());
case PRIMITIVE_DOUBLE:
final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class);
return Double.toString(d.getBytes());
case PRIMITIVE_FLOAT:
final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class);
return Float.toString(f.getBytes());
case PRIMITIVE_SHORT:
final ConstantInteger s = cpool.getConstantInteger(getIndex());
return Integer.toString(s.getBytes());
case PRIMITIVE_BYTE:
final ConstantInteger b = cpool.getConstantInteger(getIndex());
return Integer.toString(b.getBytes());
case PRIMITIVE_CHAR:
final ConstantInteger ch = cpool.getConstantInteger(getIndex());
return String.valueOf((char) ch.getBytes());
case PRIMITIVE_BOOLEAN:
final ConstantInteger bo = cpool.getConstantInteger(getIndex());
if (bo.getBytes() == 0) {
return "false";
}
return "true";
case STRING:
return cpool.getConstantUtf8(getIndex()).getBytes();
default:
throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type);
}
}
@Override
public String toString() {
return stringifyValue();
}
}

View File

@@ -26,88 +26,87 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a reference
* to the source file of this class. At most one SourceFile attribute
* should appear per classfile. The intention of this class is that it is
* instantiated from the <em>Attribute.readAttribute()</em> method.
* This class is derived from <em>Attribute</em> and represents a reference to the source file of this class. At most
* one SourceFile attribute should appear per classfile. The intention of this class is that it is instantiated from the
* <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
* @see Attribute
*/
public final class SourceFile extends Attribute {
private int sourceFileIndex;
/**
* Construct object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
SourceFile(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
* @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile".
* @param length Content length in bytes, the value should be 2.
* @param constantPool The constant pool that this attribute is associated with.
* @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the
* file from which this class was compiled. It will not be interpreted as indicating the name of the directory
* contqining the file or an absolute path; this information has to be supplied the consumer of this attribute -
* in many cases, the JVM.
*/
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);
this.sourceFileIndex = Args.requireU2(sourceFileIndex, 0, constantPool.getLength(), "SourceFile source file index");
}
/**
* 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 SourceFile(final SourceFile c) {
this(c.getNameIndex(), c.getLength(), c.getSourceFileIndex(), c.getConstantPool());
}
/**
* Construct object from input stream.
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
*/
SourceFile(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, input.readUnsignedShort(), constant_pool);
}
/**
* @param name_index Index in constant pool to CONSTANT_Utf8, which
* should represent the string "SourceFile".
* @param length Content length in bytes, the value should be 2.
* @param constantPool The constant pool that this attribute is
* associated with.
* @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This
* string will be interpreted as the name of the file from which this
* class was compiled. It will not be interpreted as indicating the name
* of the directory contqining the file or an absolute path; this
* information has to be supplied the consumer of this attribute - in
* many cases, the JVM.
*/
public SourceFile(final int name_index, final int length, final int sourceFileIndex, final ConstantPool constantPool) {
super(Const.ATTR_SOURCE_FILE, name_index, length, constantPool);
this.sourceFileIndex = sourceFileIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitSourceFile(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(sourceFileIndex);
}
/**
* @return Index in constant pool of source file name.
*/
@@ -115,24 +114,19 @@ public final class SourceFile extends Attribute {
return sourceFileIndex;
}
/**
* @param sourceFileIndex
*/
public void setSourceFileIndex( final int sourceFileIndex ) {
this.sourceFileIndex = sourceFileIndex;
}
/**
* @return Source file name.
*/
public String getSourceFileName() {
final ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(sourceFileIndex,
Const.CONSTANT_Utf8);
return c.getBytes();
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/**
* @param sourceFileIndex
*/
public void setSourceFileIndex(final int sourceFileIndex) {
this.sourceFileIndex = sourceFileIndex;
}
/**
* @return String representation
@@ -141,13 +135,4 @@ public final class SourceFile extends Attribute {
public String toString() {
return "SourceFile: " + getSourceFileName();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
return (Attribute) clone();
}
}

View File

@@ -23,142 +23,144 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a stack map attribute used for
* preverification of Java classes for the <a
* href="https://www.oracle.com/java/technologies/javameoverview.html">Java Platform, Micro Edition</a>
* (Java ME). This attribute is used by the <a
* href="https://www.oracle.com/technetwork/java/embedded/javame/java-mobile/kvmwp-150240.pdf">KVM</a>
* and contained within the Code attribute of a method. See CLDC specification
* 5.3.1.2
* This class represents a stack map attribute used for preverification of Java classes for the
* <a href="http://java.sun.com/j2me/"> Java 2 Micro Edition</a> (J2ME). This attribute is used by the
* <a href="http://java.sun.com/products/cldc/">KVM</a> and contained within the Code attribute of a method. See CLDC
* specification 5.3.1.2
*
* @see Code
* @see StackMapEntry
* @see StackMapType
* <pre>
* StackMapTable_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 number_of_entries;
* stack_map_frame entries[number_of_entries];
* }
* </pre>
*
* @see Code
* @see StackMapEntry
* @see StackMapType
* @LastModified: Oct 2020
*/
public final class StackMap extends Attribute {
private StackMapEntry[] map; // Table of stack map entries
/*
* @param name_index Index of name
* @param length Content length in bytes
* @param map Table of stack map entries
* @param constant_pool Array of constants
*/
public StackMap(final int name_index, final int length, final StackMapEntry[] map, final ConstantPool constant_pool) {
super(Const.ATTR_STACK_MAP, name_index, length, constant_pool);
this.map = map;
}
private StackMapEntry[] table; // Table of stack map entries
/**
* Construct object from input stream.
*
* @param name_index Index of name
* @param nameIndex Index of name
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param dataInput Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
StackMap(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool) throws IOException {
this(name_index, length, (StackMapEntry[]) null, constant_pool);
final int map_length = input.readUnsignedShort();
map = new StackMapEntry[map_length];
for (int i = 0; i < map_length; i++) {
map[i] = new StackMapEntry(input, constant_pool);
StackMap(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (StackMapEntry[]) null, constantPool);
final int mapLength = dataInput.readUnsignedShort();
table = new StackMapEntry[mapLength];
for (int i = 0; i < mapLength; i++) {
table[i] = new StackMapEntry(dataInput, constantPool);
}
}
/*
* @param nameIndex Index of name
*
* @param length Content length in bytes
*
* @param map Table of stack map entries
*
* @param constantPool Array of constants
*/
public StackMap(final int nameIndex, final int length, final StackMapEntry[] table, final ConstantPool constantPool) {
super(Const.ATTR_STACK_MAP, nameIndex, length, constantPool);
this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
Args.requireU2(this.table.length, "table.length");
}
/**
* 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.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackMap(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final StackMap c = (StackMap) clone();
c.table = new StackMapEntry[table.length];
Arrays.setAll(c.table, i -> table[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump stack map table attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(map.length);
for (final StackMapEntry entry : map) {
file.writeShort(table.length);
for (final StackMapEntry entry : table) {
entry.dump(file);
}
}
public int getMapLength() {
return table.length;
}
/**
* @return Array of stack map entries
*/
public StackMapEntry[] getStackMap() {
return map;
return table;
}
/**
* @param map Array of stack map entries
* @param table Array of stack map entries
*/
public void setStackMap( final StackMapEntry[] map ) {
this.map = map;
public void setStackMap(final StackMapEntry[] table) {
this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
int len = 2; // Length of 'number_of_entries' field prior to the array of stack maps
for (final StackMapEntry element : map) {
for (final StackMapEntry element : this.table) {
len += element.getMapEntrySize();
}
setLength(len);
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder("StackMap(");
for (int i = 0; i < map.length; i++) {
buf.append(map[i]);
if (i < map.length - 1) {
int runningOffset = -1; // no +1 on first entry
for (int i = 0; i < table.length; i++) {
runningOffset = table[i].getByteCodeOffset() + runningOffset + 1;
buf.append(String.format("%n@%03d %s", runningOffset, table[i]));
if (i < table.length - 1) {
buf.append(", ");
}
}
buf.append(')');
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final StackMap c = (StackMap) clone();
c.map = new StackMapEntry[map.length];
for (int i = 0; i < map.length; i++) {
c.map[i] = map[i].copy();
}
c.setConstantPool(_constant_pool);
return c;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
v.visitStackMap(this);
}
public int getMapLength() {
return map == null ? 0 : map.length;
}
}

View File

@@ -24,18 +24,33 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a stack map entry recording the types of
* local variables and the the of stack items at a given byte code offset.
* See CLDC specification 5.3.1.2
* This class represents a stack map entry recording the types of local variables and the of stack items at a given
* byte code offset. See CLDC specification 5.3.1.2.
*
* @see StackMap
* @see StackMapType
* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
*
* <pre>
* union stack_map_frame {
* same_frame;
* same_locals_1_stack_item_frame;
* same_locals_1_stack_item_frame_extended;
* chop_frame;
* same_frame_extended;
* append_frame;
* full_frame;
* }
* </pre>
* @see StackMap
* @see StackMapType
*/
public final class StackMapEntry implements Node, Cloneable
{
public final class StackMapEntry implements Node, Cloneable {
static final StackMapEntry[] EMPTY_ARRAY = {};
private int frameType;
private int byteCodeOffset;
@@ -43,53 +58,49 @@ public final class StackMapEntry implements Node, Cloneable
private StackMapType[] typesOfStackItems;
private ConstantPool constantPool;
/**
* Construct object from input stream.
*
* @param input Input stream
* @throws IOException
* @param dataInput Input stream
* @throws IOException if an I/O error occurs.
*/
StackMapEntry(final DataInput input, final ConstantPool constantPool) throws IOException {
this(input.readByte() & 0xFF, -1, null, null, constantPool);
StackMapEntry(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
this(dataInput.readByte() & 0xFF, -1, null, null, constantPool);
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
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;
typesOfStackItems = new StackMapType[1];
typesOfStackItems[0] = new StackMapType(input, constantPool);
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
byteCodeOffset = input.readShort();
typesOfStackItems = new StackMapType[1];
typesOfStackItems[0] = new StackMapType(input, constantPool);
byteCodeOffset = dataInput.readUnsignedShort();
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
byteCodeOffset = input.readShort();
byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
byteCodeOffset = input.readShort();
byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
byteCodeOffset = input.readShort();
final int number_of_locals = frameType - 251;
typesOfLocals = new StackMapType[number_of_locals];
for (int i = 0; i < number_of_locals; i++) {
typesOfLocals[i] = new StackMapType(input, constantPool);
byteCodeOffset = dataInput.readUnsignedShort();
final int numberOfLocals = frameType - 251;
typesOfLocals = new StackMapType[numberOfLocals];
for (int i = 0; i < numberOfLocals; i++) {
typesOfLocals[i] = new StackMapType(dataInput, constantPool);
}
} else if (frameType == Const.FULL_FRAME) {
byteCodeOffset = input.readShort();
final int number_of_locals = input.readShort();
typesOfLocals = new StackMapType[number_of_locals];
for (int i = 0; i < number_of_locals; i++) {
typesOfLocals[i] = new StackMapType(input, constantPool);
byteCodeOffset = dataInput.readUnsignedShort();
final int numberOfLocals = dataInput.readUnsignedShort();
typesOfLocals = new StackMapType[numberOfLocals];
for (int i = 0; i < numberOfLocals; i++) {
typesOfLocals[i] = new StackMapType(dataInput, constantPool);
}
final int number_of_stack_items = input.readShort();
typesOfStackItems = new StackMapType[number_of_stack_items];
for (int i = 0; i < number_of_stack_items; i++) {
typesOfStackItems[i] = new StackMapType(input, constantPool);
final int numberOfStackItems = dataInput.readUnsignedShort();
typesOfStackItems = new StackMapType[numberOfStackItems];
for (int i = 0; i < numberOfStackItems; i++) {
typesOfStackItems[i] = new StackMapType(dataInput, constantPool);
}
} else {
/* Can't happen */
throw new ClassFormatException ("Invalid frame type found while parsing stack map table: " + frameType);
throw new ClassFormatException("Invalid frame type found while parsing stack map table: " + frameType);
}
}
@@ -102,17 +113,21 @@ public final class StackMapEntry implements Node, Cloneable
* @param numberOfStackItems NOT USED
* @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool
* @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)}
* instead
* @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead
*/
@java.lang.Deprecated
public StackMapEntry(final int byteCodeOffset, final int numberOfLocals,
final StackMapType[] typesOfLocals, final int numberOfStackItems,
final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems,
final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : new StackMapType[0];
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0];
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
this.constantPool = constantPool;
if (numberOfLocals < 0) {
throw new IllegalArgumentException("numberOfLocals < 0");
}
if (numberOfStackItems < 0) {
throw new IllegalArgumentException("numberOfStackItems < 0");
}
}
/**
@@ -124,29 +139,53 @@ public final class StackMapEntry implements Node, Cloneable
* @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool
*/
public StackMapEntry(final int tag, final int byteCodeOffset,
final StackMapType[] typesOfLocals,
final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems,
final ConstantPool constantPool) {
this.frameType = tag;
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : new StackMapType[0];
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0];
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
this.constantPool = constantPool;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackMapEntry(this);
}
/**
* @return deep copy of this object
*/
public StackMapEntry copy() {
StackMapEntry e;
try {
e = (StackMapEntry) clone();
} catch (final CloneNotSupportedException ex) {
throw new Error("Clone Not Supported");
}
e.typesOfLocals = new StackMapType[typesOfLocals.length];
Arrays.setAll(e.typesOfLocals, i -> typesOfLocals[i].copy());
e.typesOfStackItems = new StackMapType[typesOfStackItems.length];
Arrays.setAll(e.typesOfStackItems, i -> typesOfStackItems[i].copy());
return e;
}
/**
* Dump stack map entry
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
file.write(frameType);
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
// nothing to be done
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
typesOfStackItems[0].dump(file);
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
file.writeShort(byteCodeOffset);
@@ -170,12 +209,154 @@ public final class StackMapEntry implements Node, Cloneable
for (final StackMapType type : typesOfStackItems) {
type.dump(file);
}
} else {
} else if (!(frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX)) {
/* Can't happen */
throw new ClassFormatException ("Invalid Stack map table tag: " + frameType);
throw new ClassFormatException("Invalid Stack map table tag: " + frameType);
}
}
public int getByteCodeOffset() {
return byteCodeOffset;
}
/**
* @return Constant pool used by this object.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
public int getFrameType() {
return frameType;
}
/**
* Calculate stack map entry size
*
*/
int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
return 1;
}
if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
return 1 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
}
if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
return 3 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
}
if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
return 3;
}
if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
int len = 3;
for (final StackMapType typesOfLocal : typesOfLocals) {
len += typesOfLocal.hasIndex() ? 3 : 1;
}
return len;
}
if (frameType != Const.FULL_FRAME) {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
int len = 7;
for (final StackMapType typesOfLocal : typesOfLocals) {
len += typesOfLocal.hasIndex() ? 3 : 1;
}
for (final StackMapType typesOfStackItem : typesOfStackItems) {
len += typesOfStackItem.hasIndex() ? 3 : 1;
}
return len;
}
public int getNumberOfLocals() {
return typesOfLocals.length;
}
public int getNumberOfStackItems() {
return typesOfStackItems.length;
}
public StackMapType[] getTypesOfLocals() {
return typesOfLocals;
}
public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems;
}
private boolean invalidFrameType(final int f) {
// @formatter:off
return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
&& !(f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX)
&& f != Const.SAME_FRAME_EXTENDED
&& !(f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX)
&& f != Const.FULL_FRAME;
// @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.
@@ -186,17 +367,16 @@ public final class StackMapEntry implements Node, Cloneable
buf.append("(");
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
buf.append("SAME");
} 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) {
buf.append("SAME_LOCALS_1_STACK");
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
buf.append("SAME_LOCALS_1_STACK_EXTENDED");
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
buf.append("CHOP ").append(String.valueOf(251-frameType));
buf.append("CHOP ").append(String.valueOf(251 - frameType));
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
buf.append("SAME_EXTENDED");
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
buf.append("APPEND ").append(String.valueOf(frameType-251));
buf.append("APPEND ").append(String.valueOf(frameType - 251));
} else if (frameType == Const.FULL_FRAME) {
buf.append("FULL");
} else {
@@ -227,213 +407,13 @@ public final class StackMapEntry implements Node, Cloneable
return buf.toString();
}
/**
* Calculate stack map entry size
*
*/
int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
return 1;
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
return 1 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
return 3 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
return 3;
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
return 3;
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
int len = 3;
for (final StackMapType types_of_local : typesOfLocals) {
len += types_of_local.hasIndex() ? 3 : 1;
}
return len;
} else if (frameType == Const.FULL_FRAME) {
int len = 7;
for (final StackMapType types_of_local : typesOfLocals) {
len += types_of_local.hasIndex() ? 3 : 1;
}
for (final StackMapType types_of_stack_item : typesOfStackItems) {
len += types_of_stack_item.hasIndex() ? 3 : 1;
}
return len;
} else {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
}
public void setFrameType( final int f ) {
if (f >= Const.SAME_FRAME && f <= Const.SAME_FRAME_MAX) {
byteCodeOffset = f - Const.SAME_FRAME;
} else if (f >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
f <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = f - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
} else if (f == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
} else if (f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
} else if (f == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
} else if (f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
} else if (f == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock
} else {
throw new IllegalArgumentException("Invalid StackMap frameType");
}
frameType = f;
}
public int getFrameType() {
return frameType;
}
public void setByteCodeOffset( final int new_offset ) {
if (new_offset < 0 || new_offset > 32767) {
throw new IllegalArgumentException("Invalid StackMap offset: " + new_offset);
}
if (frameType >= Const.SAME_FRAME &&
frameType <= Const.SAME_FRAME_MAX) {
if (new_offset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_FRAME_EXTENDED;
} else {
frameType = new_offset;
}
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
if (new_offset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
} else {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + new_offset;
}
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
} else if (frameType >= Const.CHOP_FRAME &&
frameType <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
} else if (frameType == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
} else if (frameType >= Const.APPEND_FRAME &&
frameType <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
} else if (frameType == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock
} else {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
byteCodeOffset = new_offset;
}
/**
* Update the distance (as an offset delta) from this StackMap
* entry to the next. Note that this might cause the the
* frame type to change. Note also that delta may be negative.
* Update the distance (as an offset delta) from this StackMap entry to the next. Note that this might cause the
* frame type to change. Note also that delta may be negative.
*
* @param delta offset delta
*/
public void updateByteCodeOffset(final int delta) {
setByteCodeOffset(byteCodeOffset + delta);
}
public int getByteCodeOffset() {
return byteCodeOffset;
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfLocals( final int n ) { // TODO unused
}
public int getNumberOfLocals() {
return typesOfLocals.length;
}
public void setTypesOfLocals( final StackMapType[] types ) {
typesOfLocals = types != null ? types : new StackMapType[0];
}
public StackMapType[] getTypesOfLocals() {
return typesOfLocals;
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfStackItems( final int n ) { // TODO unused
}
public int getNumberOfStackItems() {
return typesOfStackItems.length;
}
public void setTypesOfStackItems( final StackMapType[] types ) {
typesOfStackItems = types != null ? types : new StackMapType[0];
}
public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems;
}
/**
* @return deep copy of this object
*/
public StackMapEntry copy() {
StackMapEntry e;
try {
e = (StackMapEntry) clone();
} catch (final CloneNotSupportedException ex) {
throw new Error("Clone Not Supported");
}
e.typesOfLocals = new StackMapType[typesOfLocals.length];
for (int i = 0; i < typesOfLocals.length; i++) {
e.typesOfLocals[i] = typesOfLocals[i].copy();
}
e.typesOfStackItems = new StackMapType[typesOfStackItems.length];
for (int i = 0; i < typesOfStackItems.length; i++) {
e.typesOfStackItems[i] = typesOfStackItems[i].copy();
}
return e;
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
v.visitStackMapEntry(this);
}
/**
* @return Constant pool used by this object.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool( final ConstantPool constantPool ) {
this.constantPool = constantPool;
}
}

View File

@@ -28,118 +28,51 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents the type of a local variable or item on stack
* used in the StackMap entries.
* This class represents the type of a local variable or item on stack used in the StackMap entries.
*
* @see StackMapEntry
* @see StackMap
* @see Const
* @see StackMapEntry
* @see StackMap
* @see Const
*/
public final class StackMapType implements Cloneable {
public static final StackMapType[] EMPTY_ARRAY = {}; // must be public because BCELifier code generator writes calls to it
private byte type;
private int index = -1; // Index to CONSTANT_Class or offset
private ConstantPool constantPool;
/**
* Construct object from file stream.
* @param file Input stream
* @throws IOException
*/
StackMapType(final DataInput file, final ConstantPool constant_pool) throws IOException {
this(file.readByte(), -1, constant_pool);
if (hasIndex()) {
this.index = file.readShort();
}
this.constantPool = constant_pool;
}
/**
* @param type type tag as defined in the Constants interface
* @param index index to constant pool, or byte code offset
*/
public StackMapType(final byte type, final int index, final ConstantPool constant_pool) {
if ((type < Const.ITEM_Bogus) || (type > Const.ITEM_NewObject)) {
throw new IllegalArgumentException("Illegal type for StackMapType: " + type);
}
this.type = type;
public StackMapType(final byte type, final int index, final ConstantPool constantPool) {
this.type = checkType(type);
this.index = index;
this.constantPool = constant_pool;
this.constantPool = constantPool;
}
public void setType( final byte t ) {
if ((t < Const.ITEM_Bogus) || (t > Const.ITEM_NewObject)) {
throw new IllegalArgumentException("Illegal type for StackMapType: " + t);
/**
* Construct object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
StackMapType(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readByte(), -1, constantPool);
if (hasIndex()) {
this.index = file.readUnsignedShort();
}
type = t;
this.constantPool = constantPool;
}
public byte getType() {
private byte checkType(final byte type) {
if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
throw new ClassFormatException("Illegal type for StackMapType: " + type);
}
return type;
}
public void setIndex( final int t ) {
index = t;
}
/** @return index to constant pool if type == ITEM_Object, or offset
* in byte code, if type == ITEM_NewObject, and -1 otherwise
*/
public int getIndex() {
return index;
}
/**
* Dump type entries to file.
*
* @param file Output file stream
* @throws IOException
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeByte(type);
if (hasIndex()) {
file.writeShort(getIndex());
}
}
/** @return true, if type is either ITEM_Object or ITEM_NewObject
*/
public boolean hasIndex() {
return type == Const.ITEM_Object || type == Const.ITEM_NewObject;
}
private String printIndex() {
if (type == Const.ITEM_Object) {
if (index < 0) {
return ", class=<unknown>";
}
return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
} else if (type == Const.ITEM_NewObject) {
return ", offset=" + index;
} else {
return "";
}
}
/**
* @return String representation
*/
@Override
public String toString() {
return "(type=" + Const.getItemName(type) + printIndex() + ")";
}
/**
* @return deep copy of this object
*/
@@ -152,6 +85,18 @@ public final class StackMapType implements Cloneable {
return null;
}
/**
* Dump type entries to file.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(type);
if (hasIndex()) {
file.writeShort(getIndex());
}
}
/**
* @return Constant pool used by this object.
@@ -160,11 +105,58 @@ public final class StackMapType implements Cloneable {
return constantPool;
}
/**
* @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
* otherwise
*/
public int getIndex() {
return index;
}
public byte getType() {
return type;
}
/**
* @return true, if type is either ITEM_Object or ITEM_NewObject
*/
public boolean hasIndex() {
return type == Const.ITEM_Object || type == Const.ITEM_NewObject;
}
private String printIndex() {
if (type == Const.ITEM_Object) {
if (index < 0) {
return ", class=<unknown>";
}
return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
}
if (type == Const.ITEM_NewObject) {
return ", offset=" + index;
}
return "";
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool( final ConstantPool constantPool ) {
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
*/
@Override
public String toString() {
return "(type=" + Const.getItemName(type) + printIndex() + ")";
}
}

View File

@@ -26,58 +26,42 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and declares this class as
* `synthetic', i.e., it needs special handling. The JVM specification
* states "A class member that does not appear in the source code must be
* marked using a Synthetic attribute." It may appear in the ClassFile
* attribute table, a field_info table or a method_info table. This class
* is intended to be instantiated from the
* <em>Attribute.readAttribute()</em> method.
* This class is derived from <em>Attribute</em> and declares this class as 'synthetic', i.e., it needs special
* handling. The JVM specification states "A class member that does not appear in the source code must be marked using a
* Synthetic attribute." It may appear in the ClassFile attribute table, a field_info table or a method_info table. This
* class is intended to be instantiated from the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
* @see Attribute
*/
public final class Synthetic extends Attribute {
private byte[] bytes;
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use copy() for a physical copy.
*/
public Synthetic(final Synthetic c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* @param name_index 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 bytes Attribute contents
* @param constant_pool The constant pool this attribute is associated
* with.
* @param constantPool The constant pool this attribute is associated with.
*/
public Synthetic(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
super(Const.ATTR_SYNTHETIC, name_index, length, constant_pool);
public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_SYNTHETIC, nameIndex, Args.require0(length, "Synthetic attribute length"), constantPool);
this.bytes = bytes;
}
/**
* Construct object from input stream.
*
* @param name_index Index in constant pool to CONSTANT_Utf8
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Synthetic(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (byte[]) null, constant_pool);
Synthetic(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
@@ -85,35 +69,54 @@ public final class Synthetic extends Attribute {
}
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public Synthetic(final Synthetic c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitSynthetic(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Synthetic c = (Synthetic) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
@@ -121,15 +124,13 @@ public final class Synthetic extends Attribute {
return bytes;
}
/**
* @param bytes
*/
public void setBytes( final byte[] bytes ) {
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -141,19 +142,4 @@ public final class Synthetic extends Attribute {
}
return buf.toString();
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final Synthetic c = (Synthetic) clone();
if (bytes != null) {
c.bytes = new byte[bytes.length];
System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
}
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -24,19 +24,15 @@ package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a reference to an unknown (i.e.,
* application-specific) attribute of a class. It is instantiated from the
* {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method.
* Applications that need to read in application-specific attributes should create an
* {@link UnknownAttributeReader} implementation and attach it via
* This class represents a reference to an unknown (i.e., application-specific) attribute of a class. It is instantiated
* from the {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method. Applications that need to read in
* application-specific attributes should create an {@link UnknownAttributeReader} implementation and attach it via
* {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
*
* @see Attribute
* @see UnknownAttributeReader
@@ -44,93 +40,87 @@ import com.sun.org.apache.bcel.internal.Const;
public final class Unknown extends Attribute {
private byte[] bytes;
private final String name;
private static final Map<String, Unknown> unknownAttributes = new HashMap<>();
/** @return array of unknown attributes, but just one for each kind.
*/
static Unknown[] getUnknownAttributes() {
final Unknown[] unknowns = new Unknown[unknownAttributes.size()];
unknownAttributes.values().toArray(unknowns);
unknownAttributes.clear();
return unknowns;
}
/**
* Initialize from another object. Note that both objects use the same
* references (shallow copy). Use clone() for a physical copy.
*/
public Unknown(final Unknown c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* Create a non-standard attribute.
* Constructs a new instance for a non-standard attribute.
*
* @param name_index Index in constant pool
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param bytes Attribute contents
* @param constant_pool Array of constants
* @param constantPool Array of constants
*/
public Unknown(final int name_index, final int length, final byte[] bytes, final ConstantPool constant_pool) {
super(Const.ATTR_UNKNOWN, name_index, length, constant_pool);
public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
this.bytes = bytes;
name = ((ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8))
.getBytes();
unknownAttributes.put(name, this);
this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
}
/**
* Construct object from input stream.
* Constructs a new instance from an input stream.
*
* @param name_index Index in constant pool
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constant_pool Array of constants
* @throws IOException
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Unknown(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, (byte[]) null, constant_pool);
Unknown(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
}
}
/**
* Constructs a new instance from another instance. Note that both objects use the same references (shallow copy). Use clone() for a physical copy.
*
* @param unknown Source.
*/
public Unknown(final Unknown unknown) {
this(unknown.getNameIndex(), unknown.getLength(), unknown.getBytes(), unknown.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitely
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
* 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.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitUnknown(this);
}
/**
* Dump unknown bytes to file stream.
*
* @param file Output file stream
* @throws IOException
* @return deep copy of this attribute
*/
@Override
public void dump( final DataOutputStream file ) throws IOException {
public Attribute copy(final ConstantPool constantPool) {
final Unknown c = (Unknown) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dumps unknown bytes to file stream.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
@@ -138,7 +128,6 @@ public final class Unknown extends Attribute {
return bytes;
}
/**
* @return name of attribute.
*/
@@ -147,15 +136,13 @@ public final class Unknown extends Attribute {
return name;
}
/**
* @param bytes the bytes to set
*/
public void setBytes( final byte[] bytes ) {
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@@ -165,28 +152,13 @@ public final class Unknown extends Attribute {
return "(Unknown attribute " + name + ")";
}
String hex;
if (super.getLength() > 10) {
final byte[] tmp = new byte[10];
System.arraycopy(bytes, 0, tmp, 0, 10);
final int limit = 10;
if (super.getLength() > limit) {
final byte[] tmp = Arrays.copyOf(bytes, limit);
hex = Utility.toHexString(tmp) + "... (truncated)";
} else {
hex = Utility.toHexString(bytes);
}
return "(Unknown attribute " + name + ": " + hex + ")";
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy( final ConstantPool _constant_pool ) {
final Unknown c = (Unknown) clone();
if (bytes != null) {
c.bytes = new byte[bytes.length];
System.arraycopy(bytes, 0, c.bytes, 0, bytes.length);
}
c.setConstantPool(_constant_pool);
return c;
}
}

View File

@@ -22,9 +22,8 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* Unknown (non-standard) attributes may be read via user-defined factory
* objects that can be registered with the Attribute.addAttributeReader
* method. These factory objects should implement this interface.
* Unknown (non-standard) attributes may be read via user-defined factory objects that can be registered with the
* Attribute.addAttributeReader method. These factory objects should implement this interface.
*
* @see Attribute
* @since 6.0
@@ -32,22 +31,20 @@ package com.sun.org.apache.bcel.internal.classfile;
public interface UnknownAttributeReader {
/**
* When this attribute reader is added via the static method Attribute.addAttributeReader,
* an attribute name is 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.
* When this attribute reader is added via the static method Attribute.addAttributeReader, an attribute name is
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing.
*
* @param name_index An index into the constant pool, indexing a ConstantUtf8
* that represents the name of the attribute.
* @param length The length of the data contained in the attribute. This is written
* into the constant pool and should agree with what the factory expects the length to be.
* @param file This is the data input that the factory needs to read its data from.
* @param constant_pool This is the constant pool associated with the Attribute that we are constructing.
* @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
* @param length The length of the data contained in the attribute. This is written into the constant pool and should
* agree with what the factory expects the length to be.
* @param file This is the data input that the factory needs to read its data from.
* @param constantPool This is the constant pool associated with the Attribute that we are constructing.
*
* @return The user-defined AttributeReader should take this data and use
* it to construct an attribute. In the case of errors, a null can be
* returned which will cause the parsing of the class file to fail.
* @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.
*
* @see Attribute#addAttributeReader(String, UnknownAttributeReader)
*/
Attribute createAttribute( int name_index, int length, java.io.DataInput file, ConstantPool constant_pool );
Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool);
}

View File

@@ -22,13 +22,30 @@
package com.sun.org.apache.bcel.internal.classfile;
/**
* Interface to make use of the Visitor pattern programming style. I.e. a class
* that implements this interface can traverse the contents of a Java class just
* by calling the `accept' method which all classes have.
*
* Interface to make use of the Visitor pattern programming style. I.e. a class that implements this interface can
* traverse the contents of a Java class just by calling the 'accept' method which all classes have.
*/
public interface Visitor
{
public interface Visitor {
/**
* @since 6.0
*/
void visitAnnotation(Annotations obj);
/**
* @since 6.0
*/
void visitAnnotationDefault(AnnotationDefault obj);
/**
* @since 6.0
*/
void visitAnnotationEntry(AnnotationEntry obj);
/**
* @since 6.0
*/
void visitBootstrapMethods(BootstrapMethods obj);
void visitCode(Code obj);
void visitCodeException(CodeException obj);
@@ -37,6 +54,13 @@ public interface Visitor
void visitConstantDouble(ConstantDouble obj);
/**
* @since 6.3
*/
default void visitConstantDynamic(final ConstantDynamic constantDynamic) {
// empty
}
void visitConstantFieldref(ConstantFieldref obj);
void visitConstantFloat(ConstantFloat obj);
@@ -49,10 +73,30 @@ public interface Visitor
void visitConstantLong(ConstantLong obj);
/**
* @since 6.0
*/
void visitConstantMethodHandle(ConstantMethodHandle obj);
void visitConstantMethodref(ConstantMethodref obj);
/**
* @since 6.0
*/
void visitConstantMethodType(ConstantMethodType obj);
/**
* @since 6.1
*/
void visitConstantModule(ConstantModule constantModule);
void visitConstantNameAndType(ConstantNameAndType obj);
/**
* @since 6.1
*/
void visitConstantPackage(ConstantPackage constantPackage);
void visitConstantPool(ConstantPool obj);
void visitConstantString(ConstantString obj);
@@ -63,6 +107,11 @@ public interface Visitor
void visitDeprecated(Deprecated obj);
/**
* @since 6.0
*/
void visitEnclosingMethod(EnclosingMethod obj);
void visitExceptionTable(ExceptionTable obj);
void visitField(Field obj);
@@ -81,59 +130,12 @@ public interface Visitor
void visitLocalVariableTable(LocalVariableTable obj);
void visitMethod(Method obj);
void visitSignature(Signature obj);
void visitSourceFile(SourceFile obj);
void visitSynthetic(Synthetic obj);
void visitUnknown(Unknown obj);
void visitStackMap(StackMap obj);
void visitStackMapEntry(StackMapEntry obj);
/**
* @since 6.0
*/
void visitAnnotation(Annotations obj);
/**
* @since 6.0
*/
void visitParameterAnnotation(ParameterAnnotations obj);
/**
* @since 6.0
*/
void visitAnnotationEntry(AnnotationEntry obj);
/**
* @since 6.0
*/
void visitAnnotationDefault(AnnotationDefault obj);
/**
* @since 6.0
*/
void visitLocalVariableTypeTable(LocalVariableTypeTable obj);
/**
* @since 6.0
*/
void visitEnclosingMethod(EnclosingMethod obj);
/**
* @since 6.0
*/
void visitBootstrapMethods(BootstrapMethods obj);
/**
* @since 6.0
*/
void visitMethodParameters(MethodParameters obj);
void visitMethod(Method obj);
/**
* @since 6.4.0
@@ -145,34 +147,7 @@ public interface Visitor
/**
* @since 6.0
*/
void visitConstantMethodType(ConstantMethodType obj);
/**
* @since 6.0
*/
void visitConstantMethodHandle(ConstantMethodHandle obj);
/**
* @since 6.0
*/
void visitParameterAnnotationEntry(ParameterAnnotationEntry obj);
/**
* @since 6.1
*/
void visitConstantPackage(ConstantPackage constantPackage);
/**
* @since 6.1
*/
void visitConstantModule(ConstantModule constantModule);
/**
* @since 6.3
*/
default void visitConstantDynamic(final ConstantDynamic constantDynamic) {
// empty
}
void visitMethodParameters(MethodParameters obj);
/**
* @since 6.4.0
@@ -181,13 +156,6 @@ public interface Visitor
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleRequires(final ModuleRequires constantModule) {
// empty
}
/**
* @since 6.4.0
*/
@@ -198,14 +166,14 @@ public interface Visitor
/**
* @since 6.4.0
*/
default void visitModuleOpens(final ModuleOpens constantModule) {
default void visitModuleMainClass(final ModuleMainClass obj) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleProvides(final ModuleProvides constantModule) {
default void visitModuleOpens(final ModuleOpens constantModule) {
// empty
}
@@ -219,7 +187,14 @@ public interface Visitor
/**
* @since 6.4.0
*/
default void visitModuleMainClass(final ModuleMainClass obj) {
default void visitModuleProvides(final ModuleProvides constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleRequires(final ModuleRequires constantModule) {
// empty
}
@@ -236,4 +211,26 @@ public interface Visitor
default void visitNestMembers(final NestMembers obj) {
// empty
}
/**
* @since 6.0
*/
void visitParameterAnnotation(ParameterAnnotations obj);
/**
* @since 6.0
*/
void visitParameterAnnotationEntry(ParameterAnnotationEntry obj);
void visitSignature(Signature obj);
void visitSourceFile(SourceFile obj);
void visitStackMap(StackMap obj);
void visitStackMapEntry(StackMapEntry obj);
void visitSynthetic(Synthetic obj);
void visitUnknown(Unknown obj);
}

View File

@@ -23,28 +23,28 @@ package com.sun.org.apache.bcel.internal.generic;
/**
* AALOAD - Load reference from array
* <PRE>Stack: ..., arrayref, index -&gt; value</PRE>
*
* <PRE>
* Stack: ..., arrayref, index -&gt; value
* </PRE>
*/
public class AALOAD extends ArrayInstruction implements StackProducer {
/** Load reference from array
/**
* Load reference from array
*/
public AALOAD() {
super(com.sun.org.apache.bcel.internal.Const.AALOAD);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitStackProducer(this);
v.visitExceptionThrower(this);
v.visitTypedInstruction(this);

View File

@@ -22,29 +22,29 @@
package com.sun.org.apache.bcel.internal.generic;
/**
* AASTORE - Store into reference array
* <PRE>Stack: ..., arrayref, index, value -&gt; ...</PRE>
* AASTORE - Store into reference array
*
* <PRE>
* Stack: ..., arrayref, index, value -&gt; ...
* </PRE>
*/
public class AASTORE extends ArrayInstruction implements StackConsumer {
/** Store into reference array
/**
* Store into reference array
*/
public AASTORE() {
super(com.sun.org.apache.bcel.internal.Const.AASTORE);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitStackConsumer(this);
v.visitExceptionThrower(this);
v.visitTypedInstruction(this);

View File

@@ -23,8 +23,10 @@ package com.sun.org.apache.bcel.internal.generic;
/**
* ACONST_NULL - Push null reference
* <PRE>Stack: ... -&gt; ..., null</PRE>
*
* <PRE>
* Stack: ... -&gt; ..., null
* </PRE>
*/
public class ACONST_NULL extends Instruction implements PushInstruction, TypedInstruction {
@@ -35,28 +37,25 @@ public class ACONST_NULL extends Instruction implements PushInstruction, TypedIn
super(com.sun.org.apache.bcel.internal.Const.ACONST_NULL, (short) 1);
}
/** @return Type.NULL
*/
@Override
public Type getType( final ConstantPoolGen cp ) {
return Type.NULL;
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitStackProducer(this);
v.visitPushInstruction(this);
v.visitTypedInstruction(this);
v.visitACONST_NULL(this);
}
/**
* @return Type.NULL
*/
@Override
public Type getType(final ConstantPoolGen cp) {
return Type.NULL;
}
}

View File

@@ -20,43 +20,40 @@
package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.Const;
/**
* ALOAD - Load reference from local variable
* <PRE>Stack: ... -&gt; ..., objectref</PRE>
*
* <PRE>
* Stack: ... -&gt; ..., objectref
* </PRE>
* @LastModified: Jan 2020
*/
public class ALOAD extends LoadInstruction {
/**
* Empty constructor needed for Instruction.readInstruction.
* Not to be used otherwise.
* Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
*/
ALOAD() {
super(Const.ALOAD, Const.ALOAD_0);
super(com.sun.org.apache.bcel.internal.Const.ALOAD, com.sun.org.apache.bcel.internal.Const.ALOAD_0);
}
/** Load reference from local variable
/**
* Load reference from local variable
*
* @param n index of local variable
*/
public ALOAD(final int n) {
super(Const.ALOAD, Const.ALOAD_0, n);
super(com.sun.org.apache.bcel.internal.Const.ALOAD, com.sun.org.apache.bcel.internal.Const.ALOAD_0, n);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
super.accept(v);
v.visitALOAD(this);
}

View File

@@ -24,43 +24,32 @@ package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.ExceptionConst;
/**
* ANEWARRAY - Create new array of references
* <PRE>Stack: ..., count -&gt; ..., arrayref</PRE>
* ANEWARRAY - Create new array of references
*
* <PRE>
* Stack: ..., count -&gt; ..., arrayref
* </PRE>
*/
public class ANEWARRAY extends CPInstruction implements LoadClass, AllocationInstruction,
ExceptionThrower, StackConsumer, StackProducer {
public class ANEWARRAY extends CPInstruction implements LoadClass, AllocationInstruction, ExceptionThrower, StackConsumer, StackProducer {
/**
* Empty constructor needed for Instruction.readInstruction.
* Not to be used otherwise.
* Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
*/
ANEWARRAY() {
}
public ANEWARRAY(final int index) {
super(com.sun.org.apache.bcel.internal.Const.ANEWARRAY, index);
}
@Override
public Class<?>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION,
ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitLoadClass(this);
v.visitAllocationInstruction(this);
v.visitExceptionThrower(this);
@@ -70,13 +59,17 @@ public class ANEWARRAY extends CPInstruction implements LoadClass, AllocationIns
v.visitANEWARRAY(this);
}
@Override
public Class<?>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION, ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION);
}
@Override
public ObjectType getLoadClassType( final ConstantPoolGen cpg ) {
public ObjectType getLoadClassType(final ConstantPoolGen cpg) {
Type t = getType(cpg);
if (t instanceof ArrayType) {
t = ((ArrayType) t).getBasicType();
}
return (t instanceof ObjectType) ? (ObjectType) t : null;
return t instanceof ObjectType ? (ObjectType) t : null;
}
}

View File

@@ -22,9 +22,11 @@
package com.sun.org.apache.bcel.internal.generic;
/**
* ARETURN - Return reference from method
* <PRE>Stack: ..., objectref -&gt; &lt;empty&gt;</PRE>
* ARETURN - Return reference from method
*
* <PRE>
* Stack: ..., objectref -&gt; &lt;empty&gt;
* </PRE>
*/
public class ARETURN extends ReturnInstruction {
@@ -35,17 +37,14 @@ public class ARETURN extends ReturnInstruction {
super(com.sun.org.apache.bcel.internal.Const.ARETURN);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitExceptionThrower(this);
v.visitTypedInstruction(this);
v.visitStackConsumer(this);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,43 +23,40 @@ package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.ExceptionConst;
/**
* ARRAYLENGTH - Get length of array
* <PRE>Stack: ..., arrayref -&gt; ..., length</PRE>
* ARRAYLENGTH - Get length of array
*
* @LastModified: Jun 2019
* <PRE>
* Stack: ..., arrayref -&gt; ..., length
* </PRE>
* @LastModified: Feb 2023
*/
public class ARRAYLENGTH extends Instruction
implements ExceptionThrower, StackProducer, StackConsumer /* since 6.0 */ {
public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackProducer, StackConsumer /* since 6.0 */ {
/** Get length of array
/**
* Get length of array
*/
public ARRAYLENGTH() {
super(com.sun.org.apache.bcel.internal.Const.ARRAYLENGTH, (short) 1);
}
/** @return exceptions this instruction may cause
*/
@Override
public Class<?>[] getExceptions() {
return new Class<?>[] {
ExceptionConst.NULL_POINTER_EXCEPTION
};
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitExceptionThrower(this);
v.visitStackProducer(this);
v.visitARRAYLENGTH(this);
}
/**
* @return exceptions this instruction may cause
*/
@Override
public Class<?>[] getExceptions() {
return new Class<?>[] {ExceptionConst.NULL_POINTER_EXCEPTION};
}
}

View File

@@ -19,43 +19,40 @@
*/
package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.Const;
/**
* ASTORE - Store reference into local variable
* <PRE>Stack ..., objectref -&gt; ... </PRE>
*
* <PRE>
* Stack ..., objectref -&gt; ...
* </PRE>
* @LastModified: Jan 2020
*/
public class ASTORE extends StoreInstruction {
/**
* Empty constructor needed for Instruction.readInstruction.
* Not to be used otherwise.
* Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
*/
ASTORE() {
super(Const.ASTORE, Const.ASTORE_0);
super(com.sun.org.apache.bcel.internal.Const.ASTORE, com.sun.org.apache.bcel.internal.Const.ASTORE_0);
}
/** Store reference into local variable
/**
* Store reference into local variable
*
* @param n index of local variable
*/
public ASTORE(final int n) {
super(Const.ASTORE, Const.ASTORE_0, n);
super(com.sun.org.apache.bcel.internal.Const.ASTORE, com.sun.org.apache.bcel.internal.Const.ASTORE_0, n);
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
super.accept(v);
v.visitASTORE(this);
}

View File

@@ -23,43 +23,39 @@ package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.ExceptionConst;
/**
* ATHROW - Throw exception
* <PRE>Stack: ..., objectref -&gt; objectref</PRE>
* ATHROW - Throw exception
*
* @LastModified: Jan 2020
* <PRE>
* Stack: ..., objectref -&gt; objectref
* </PRE>
*/
public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower {
/**
* Throw exception
* Throw exception
*/
public ATHROW() {
super(com.sun.org.apache.bcel.internal.Const.ATHROW, (short) 1);
}
/** @return exceptions this instruction may cause
*/
@Override
public Class<?>[] getExceptions() {
return new Class<?>[] {
ExceptionConst.THROWABLE
};
}
/**
* Call corresponding visitor method(s). The order is:
* Call visitor methods of implemented interfaces first, then
* call methods according to the class hierarchy in descending order,
* i.e., the most specific visitXXX() call comes last.
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept( final Visitor v ) {
public void accept(final Visitor v) {
v.visitUnconditionalBranch(this);
v.visitExceptionThrower(this);
v.visitATHROW(this);
}
/**
* @return exceptions this instruction may cause
*/
@Override
public Class<?>[] getExceptions() {
return new Class<?>[] {ExceptionConst.THROWABLE};
}
}

View File

@@ -23,7 +23,6 @@ package com.sun.org.apache.bcel.internal.generic;
/**
* Denote family of instructions that allocates space in the heap.
*
*/
public interface AllocationInstruction {
}

View File

@@ -30,61 +30,48 @@ import com.sun.org.apache.bcel.internal.classfile.ElementValue;
/**
* @since 6.0
*/
public class AnnotationElementValueGen extends ElementValueGen
{
public class AnnotationElementValueGen extends ElementValueGen {
// For annotation element values, this is the annotation
private final AnnotationEntryGen a;
public AnnotationElementValueGen(final AnnotationEntryGen a, final ConstantPoolGen cpool)
{
super(ANNOTATION, cpool);
this.a = a;
}
public AnnotationElementValueGen(final int type, final AnnotationEntryGen annotation,
final ConstantPoolGen cpool)
{
super(type, cpool);
if (type != ANNOTATION) {
throw new IllegalArgumentException(
"Only element values of type annotation can be built with this ctor - type specified: " + type);
}
this.a = annotation;
}
public AnnotationElementValueGen(final AnnotationElementValue value,
final ConstantPoolGen cpool, final boolean copyPoolEntries)
{
public AnnotationElementValueGen(final AnnotationElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
super(ANNOTATION, cpool);
a = new AnnotationEntryGen(value.getAnnotationEntry(), cpool, copyPoolEntries);
}
public AnnotationElementValueGen(final AnnotationEntryGen a, final ConstantPoolGen cpool) {
super(ANNOTATION, cpool);
this.a = a;
}
public AnnotationElementValueGen(final int type, final AnnotationEntryGen annotation, final ConstantPoolGen cpool) {
super(type, cpool);
if (type != ANNOTATION) {
throw new IllegalArgumentException("Only element values of type annotation can be built with this ctor - type specified: " + type);
}
this.a = annotation;
}
@Override
public void dump(final DataOutputStream dos) throws IOException
{
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getElementValueType()); // u1 type of value (ANNOTATION == '@')
a.dump(dos);
}
@Override
public String stringifyValue()
{
throw new UnsupportedOperationException("Not implemented yet");
public AnnotationEntryGen getAnnotation() {
return a;
}
/**
* Return immutable variant of this AnnotationElementValueGen
*/
@Override
public ElementValue getElementValue()
{
return new AnnotationElementValue(super.getElementValueType(),
a.getAnnotation(),
getConstantPool().getConstantPool());
public ElementValue getElementValue() {
return new AnnotationElementValue(super.getElementValueType(), a.getAnnotation(), getConstantPool().getConstantPool());
}
public AnnotationEntryGen getAnnotation()
{
return a;
@Override
public String stringifyValue() {
throw new UnsupportedOperationException("Not implemented yet");
}
}

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