mirror of
https://github.com/FranzHaidnor/haidnorJVM.git
synced 2026-04-09 09:47:37 +00:00
refactor bcel lib
This commit is contained in:
21
pom.xml
21
pom.xml
@@ -15,6 +15,13 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.12.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
|
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-cli</groupId>
|
<groupId>commons-cli</groupId>
|
||||||
@@ -22,20 +29,6 @@
|
|||||||
<version>1.5.0</version>
|
<version>1.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.bcel/bcel -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.bcel</groupId>
|
|
||||||
<artifactId>bcel</artifactId>
|
|
||||||
<version>6.7.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
<version>1.18.26</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
|
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
package haidnor.jvm;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.*;
|
|
||||||
|
|
||||||
import haidnor.jvm.classloader.ClassLoader;
|
|
||||||
import haidnor.jvm.core.JavaExecutionEngine;
|
|
||||||
import haidnor.jvm.rtda.Klass;
|
|
||||||
import haidnor.jvm.rtda.KlassMethod;
|
|
||||||
import haidnor.jvm.rtda.Metaspace;
|
|
||||||
import haidnor.jvm.runtime.JVMThread;
|
|
||||||
import haidnor.jvm.util.JavaClassUtil;
|
|
||||||
import haidnor.jvm.util.JvmThreadHolder;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author wang xiang
|
|
||||||
*/
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String banner = """
|
|
||||||
██╗ ██╗ █████╗ ██╗██████╗ ███╗ ██╗ ██████╗ ██████╗ ██╗██╗ ██╗███╗ ███╗
|
|
||||||
██║ ██║██╔══██╗██║██╔══██╗████╗ ██║██╔═══██╗██╔══██╗ ██║██║ ██║████╗ ████║
|
|
||||||
███████║███████║██║██║ ██║██╔██╗ ██║██║ ██║██████╔╝ ██║██║ ██║██╔████╔██║
|
|
||||||
██╔══██║██╔══██║██║██║ ██║██║╚██╗██║██║ ██║██╔══██╗ ██ ██║╚██╗ ██╔╝██║╚██╔╝██║
|
|
||||||
██║ ██║██║ ██║██║██████╔╝██║ ╚████║╚██████╔╝██║ ██║ ╚█████╔╝ ╚████╔╝ ██║ ╚═╝ ██║
|
|
||||||
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚════╝ ╚═══╝ ╚═╝ ╚═╝
|
|
||||||
""";
|
|
||||||
|
|
||||||
System.out.println(banner);
|
|
||||||
|
|
||||||
CommandLine cmd = initCommandLine(args);
|
|
||||||
|
|
||||||
// 指定从 .jar 文件运行
|
|
||||||
if (cmd.hasOption("jar")) {
|
|
||||||
String jarFilePath = cmd.getOptionValue("jar");
|
|
||||||
try (JarFile jarFile = new JarFile(jarFilePath)) {
|
|
||||||
ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader");
|
|
||||||
String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class");
|
|
||||||
|
|
||||||
Enumeration<JarEntry> entries = jarFile.entries();
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
JarEntry entry = entries.nextElement();
|
|
||||||
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
|
|
||||||
String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6);
|
|
||||||
if (className.equals(mainClass)) {
|
|
||||||
JvmThreadHolder.set(new JVMThread());
|
|
||||||
Klass mainMeteKlass = bootClassLoader.loadClass(jarFile, entry);
|
|
||||||
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
|
|
||||||
Metaspace.registerJavaClass(mainMeteKlass);
|
|
||||||
JavaExecutionEngine.callMainMethod(mainKlassMethod);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 指定从 .class 文件运行
|
|
||||||
if (cmd.hasOption("class")) {
|
|
||||||
JvmThreadHolder.set(new JVMThread());
|
|
||||||
String path = cmd.getOptionValue("class");
|
|
||||||
ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader");
|
|
||||||
Klass mainMeteKlass = bootClassLoader.loadClassWithAbsolutePath(path);
|
|
||||||
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
|
|
||||||
Metaspace.registerJavaClass(mainMeteKlass);
|
|
||||||
|
|
||||||
JavaExecutionEngine.callMainMethod(mainKlassMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CommandLine initCommandLine(String[] args) throws ParseException {
|
|
||||||
Option jarOption = new Option("jar", true, "运行 jar 程序");
|
|
||||||
Option classOption = new Option("class", true, "运行 .class 字节码文件");
|
|
||||||
|
|
||||||
OptionGroup optionGroup = new OptionGroup();
|
|
||||||
optionGroup.addOption(jarOption).addOption(classOption);
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
options.addOptionGroup(optionGroup);
|
|
||||||
|
|
||||||
CommandLineParser parser = new DefaultParser();
|
|
||||||
return parser.parse(options, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
3234
src/main/java/haidnor/jvm/bcel/Const.java
Normal file
3234
src/main/java/haidnor/jvm/bcel/Const.java
Normal file
File diff suppressed because it is too large
Load Diff
128
src/main/java/haidnor/jvm/bcel/ExceptionConst.java
Normal file
128
src/main/java/haidnor/jvm/bcel/ExceptionConst.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception constants.
|
||||||
|
*
|
||||||
|
* @since 6.0 (intended to replace the InstructionConstant interface)
|
||||||
|
*/
|
||||||
|
public final class ExceptionConst {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum corresponding to the various Exception Class arrays, used by
|
||||||
|
* {@link ExceptionConst#createExceptions(EXCS, Class...)}
|
||||||
|
*/
|
||||||
|
public enum EXCS {
|
||||||
|
EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mother of all exceptions
|
||||||
|
*/
|
||||||
|
public static final Class<Throwable> THROWABLE = Throwable.class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Super class of any run-time exception
|
||||||
|
*/
|
||||||
|
public static final Class<RuntimeException> RUNTIME_EXCEPTION = RuntimeException.class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Super class of any linking exception (aka Linkage Error)
|
||||||
|
*/
|
||||||
|
public static final Class<LinkageError> LINKING_EXCEPTION = LinkageError.class;
|
||||||
|
/**
|
||||||
|
* Linking Exceptions
|
||||||
|
*/
|
||||||
|
public static final Class<ClassCircularityError> CLASS_CIRCULARITY_ERROR = ClassCircularityError.class;
|
||||||
|
public static final Class<ClassFormatError> CLASS_FORMAT_ERROR = ClassFormatError.class;
|
||||||
|
public static final Class<ExceptionInInitializerError> EXCEPTION_IN_INITIALIZER_ERROR = ExceptionInInitializerError.class;
|
||||||
|
public static final Class<IncompatibleClassChangeError> INCOMPATIBLE_CLASS_CHANGE_ERROR = IncompatibleClassChangeError.class;
|
||||||
|
public static final Class<AbstractMethodError> ABSTRACT_METHOD_ERROR = AbstractMethodError.class;
|
||||||
|
public static final Class<IllegalAccessError> ILLEGAL_ACCESS_ERROR = IllegalAccessError.class;
|
||||||
|
public static final Class<InstantiationError> INSTANTIATION_ERROR = InstantiationError.class;
|
||||||
|
public static final Class<NoSuchFieldError> NO_SUCH_FIELD_ERROR = NoSuchFieldError.class;
|
||||||
|
public static final Class<NoSuchMethodError> NO_SUCH_METHOD_ERROR = NoSuchMethodError.class;
|
||||||
|
public static final Class<NoClassDefFoundError> NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class;
|
||||||
|
public static final Class<UnsatisfiedLinkError> UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class;
|
||||||
|
|
||||||
|
public static final Class<VerifyError> VERIFY_ERROR = VerifyError.class;
|
||||||
|
/* UnsupportedClassVersionError is new in JDK 1.2 */
|
||||||
|
// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
|
||||||
|
/**
|
||||||
|
* Run-Time Exceptions
|
||||||
|
*/
|
||||||
|
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<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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty array.
|
||||||
|
*/
|
||||||
|
private static final Class<?>[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty array.
|
||||||
|
*/
|
||||||
|
private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class[0];
|
||||||
|
|
||||||
|
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.)
|
||||||
|
private static final Class<?>[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of the specified Exception Class array combined with any additional Exception classes.
|
||||||
|
*
|
||||||
|
* @param type the basic array type
|
||||||
|
* @param extraClasses additional classes, if any
|
||||||
|
* @return the merged array
|
||||||
|
*/
|
||||||
|
public static Class<?>[] createExceptions(final EXCS type, final Class<?>... extraClasses) {
|
||||||
|
switch (type) {
|
||||||
|
case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
|
||||||
|
return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
|
||||||
|
case EXCS_ARRAY_EXCEPTION:
|
||||||
|
return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses);
|
||||||
|
case EXCS_FIELD_AND_METHOD_RESOLUTION:
|
||||||
|
return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses);
|
||||||
|
case EXCS_INTERFACE_METHOD_RESOLUTION:
|
||||||
|
return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses);
|
||||||
|
case EXCS_STRING_RESOLUTION:
|
||||||
|
return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses);
|
||||||
|
default:
|
||||||
|
throw new AssertionError("Cannot happen; unexpected enum value: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper method to merge exception class arrays
|
||||||
|
private static Class<?>[] mergeExceptions(final Class<?>[] input, final Class<?>... extraClasses) {
|
||||||
|
return ArrayUtils.addAll(input, extraClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
215
src/main/java/haidnor/jvm/bcel/Repository.java
Normal file
215
src/main/java/haidnor/jvm/bcel/Repository.java
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.classfile.JavaClass;
|
||||||
|
import haidnor.jvm.bcel.util.ClassPath;
|
||||||
|
import haidnor.jvm.bcel.util.SyntheticRepository;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 haidnor.jvm.bcel.util.Repository
|
||||||
|
* @see SyntheticRepository
|
||||||
|
*/
|
||||||
|
public abstract class Repository {
|
||||||
|
|
||||||
|
private static haidnor.jvm.bcel.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
|
||||||
|
*/
|
||||||
|
public static haidnor.jvm.bcel.util.Repository getRepository() {
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 true, if clazz is an instance of superclass
|
||||||
|
* @throws ClassNotFoundException if any superclasses or superinterfaces of clazz can't be found
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public static JavaClass lookupClass(final Class<?> clazz) throws ClassNotFoundException {
|
||||||
|
return repository.loadClass(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookups class somewhere found on your CLASSPATH, or whereever the repository instance looks for it.
|
||||||
|
*
|
||||||
|
* @return class object for given fully qualified class name
|
||||||
|
* @throws ClassNotFoundException if the class could not be found or parsed correctly
|
||||||
|
*/
|
||||||
|
public static JavaClass lookupClass(final String className) throws ClassNotFoundException {
|
||||||
|
return repository.loadClass(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return class file object for given Java class by looking on the system class path; returns null if the class file
|
||||||
|
* can't be found
|
||||||
|
*/
|
||||||
|
public static ClassPath.ClassFile lookupClassFile(final String className) {
|
||||||
|
try (ClassPath path = repository.getClassPath()) {
|
||||||
|
return path == null ? null : path.getClassFile(className);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes given class from repository.
|
||||||
|
*/
|
||||||
|
public static void removeClass(final JavaClass clazz) {
|
||||||
|
repository.removeClass(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes class with given (fully qualified) name from repository.
|
||||||
|
*/
|
||||||
|
public static void removeClass(final String clazz) {
|
||||||
|
repository.removeClass(repository.findClass(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets repository instance to be used for class loading
|
||||||
|
*/
|
||||||
|
public static void setRepository(final haidnor.jvm.bcel.util.Repository rep) {
|
||||||
|
repository = rep;
|
||||||
|
}
|
||||||
|
}
|
||||||
211
src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java
Normal file
211
src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Super class for all objects that have modifiers like private, final, ... I.e. classes, fields, and methods.
|
||||||
|
*/
|
||||||
|
public abstract class AccessFlags {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 initial access flags
|
||||||
|
*/
|
||||||
|
public AccessFlags(final int a) {
|
||||||
|
access_flags = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Access flags of the object aka. "modifiers".
|
||||||
|
*/
|
||||||
|
public final int getAccessFlags() {
|
||||||
|
return access_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Access flags of the object aka. "modifiers".
|
||||||
|
*/
|
||||||
|
public final int getModifiers() {
|
||||||
|
return 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 accessFlags Access flags of the object.
|
||||||
|
*/
|
||||||
|
public final void setAccessFlags(final int accessFlags) {
|
||||||
|
this.access_flags = accessFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFlag(final int flag, final boolean set) {
|
||||||
|
if ((access_flags & flag) != 0) { // Flag is set already
|
||||||
|
if (!set) {
|
||||||
|
access_flags ^= flag;
|
||||||
|
}
|
||||||
|
} else if (set) {
|
||||||
|
access_flags |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set access flags aka "modifiers".
|
||||||
|
*
|
||||||
|
* @param accessFlags Access flags of the object.
|
||||||
|
*/
|
||||||
|
public final void setModifiers(final int accessFlags) {
|
||||||
|
setAccessFlags(accessFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the default value of a annotation for a method info.
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class AnnotationDefault extends Attribute {
|
||||||
|
|
||||||
|
private ElementValue defaultValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
|
||||||
|
this(nameIndex, length, (ElementValue) null, constantPool);
|
||||||
|
defaultValue = ElementValue.readElementValue(input, constantPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 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 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.visitAnnotationDefault(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the default value
|
||||||
|
*/
|
||||||
|
public final ElementValue getDefaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param defaultValue the default value of this methodinfo's annotation
|
||||||
|
*/
|
||||||
|
public final void setDefaultValue(final ElementValue defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotationEntry getAnnotationEntry() {
|
||||||
|
return annotationEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String stringifyValue() {
|
||||||
|
return annotationEntry.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return stringifyValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
162
src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java
Normal file
162
src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents one annotation in the annotation table
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class AnnotationEntry implements Node {
|
||||||
|
|
||||||
|
public static final AnnotationEntry[] EMPTY_ARRAY = {};
|
||||||
|
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
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 < numElementValuePairs; i++) {
|
||||||
|
annotationEntry.elementValuePairs
|
||||||
|
.add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
|
||||||
|
}
|
||||||
|
return annotationEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int typeIndex;
|
||||||
|
|
||||||
|
private final ConstantPool constantPool;
|
||||||
|
|
||||||
|
private final boolean isRuntimeVisible;
|
||||||
|
|
||||||
|
private List<ElementValuePair> elementValuePairs;
|
||||||
|
|
||||||
|
public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
|
||||||
|
this.typeIndex = typeIndex;
|
||||||
|
this.constantPool = constantPool;
|
||||||
|
this.isRuntimeVisible = isRuntimeVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
|
||||||
|
* 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.visitAnnotationEntry(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
|
||||||
|
elementValuePairs.add(elementNameValuePair);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(final DataOutputStream dos) throws IOException {
|
||||||
|
dos.writeShort(typeIndex); // u2 index of type name in cpool
|
||||||
|
dos.writeShort(elementValuePairs.size()); // u2 element_value pair
|
||||||
|
// count
|
||||||
|
for (final ElementValuePair envp : elementValuePairs) {
|
||||||
|
envp.dump(dos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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() {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
result.append("@");
|
||||||
|
result.append(getAnnotationType());
|
||||||
|
final ElementValuePair[] evPairs = getElementValuePairs();
|
||||||
|
if (evPairs.length > 0) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toShortString();
|
||||||
|
}
|
||||||
|
}
|
||||||
158
src/main/java/haidnor/jvm/bcel/classfile/Annotations.java
Normal file
158
src/main/java/haidnor/jvm/bcel/classfile/Annotations.java
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base class for annotations
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public abstract class Annotations extends Attribute implements Iterable<AnnotationEntry> {
|
||||||
|
|
||||||
|
private AnnotationEntry[] annotationTable;
|
||||||
|
private final boolean isRuntimeVisible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
super(annotationType, nameIndex, length, constantPool);
|
||||||
|
this.annotationTable = annotationTable;
|
||||||
|
this.isRuntimeVisible = isRuntimeVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(final Visitor v) {
|
||||||
|
v.visitAnnotation(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Attribute copy(final ConstantPool constantPool) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
if (annotationTable == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return annotationTable.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRuntimeVisible() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
dos.writeShort(annotationTable.length);
|
||||||
|
for (final AnnotationEntry element : annotationTable) {
|
||||||
|
element.dump(dos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class ArrayElementValue extends ElementValue {
|
||||||
|
// For array types, this is the array
|
||||||
|
private final ElementValue[] elementValues;
|
||||||
|
|
||||||
|
public ArrayElementValue(final int type, final ElementValue[] datums, final ConstantPool cpool) {
|
||||||
|
super(type, cpool);
|
||||||
|
if (type != ARRAY) {
|
||||||
|
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 {
|
||||||
|
dos.writeByte(super.getType()); // u1 type of value (ARRAY == '[')
|
||||||
|
dos.writeShort(elementValues.length);
|
||||||
|
for (final ElementValue evalue : elementValues) {
|
||||||
|
evalue.dump(dos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElementValue[] getElementValuesArray() {
|
||||||
|
return elementValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getElementValuesArraySize() {
|
||||||
|
return elementValues.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String stringifyValue() {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[");
|
||||||
|
for (int i = 0; i < elementValues.length; i++) {
|
||||||
|
sb.append(elementValues[i].stringifyValue());
|
||||||
|
if (i + 1 < elementValues.length) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
367
src/main/java/haidnor/jvm/bcel/classfile/Attribute.java
Normal file
367
src/main/java/haidnor/jvm/bcel/classfile/Attribute.java
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @see Code
|
||||||
|
* @see Unknown
|
||||||
|
* @see ExceptionTable
|
||||||
|
* @see LineNumberTable
|
||||||
|
* @see LocalVariableTable
|
||||||
|
* @see InnerClasses
|
||||||
|
* @see Synthetic
|
||||||
|
* @see Deprecated
|
||||||
|
* @see Signature
|
||||||
|
*/
|
||||||
|
public abstract class Attribute implements Cloneable, Node {
|
||||||
|
|
||||||
|
private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off
|
||||||
|
|
||||||
|
private static final Map<String, Object> READERS = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty array.
|
||||||
|
*
|
||||||
|
* @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 unknownAttributeReader the reader object
|
||||||
|
*/
|
||||||
|
public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
|
||||||
|
READERS.put(name, unknownAttributeReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void println(final String msg) {
|
||||||
|
if (debug) {
|
||||||
|
System.err.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
|
||||||
|
* is called by the Field and Method constructor methods.
|
||||||
|
*
|
||||||
|
* @see JavaField
|
||||||
|
* @see JavaMethod
|
||||||
|
*
|
||||||
|
* @param dataInput Input stream
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
* @return Attribute
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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 nameIndex = dataInput.readUnsignedShort();
|
||||||
|
final String name = constantPool.getConstantUtf8(nameIndex).getBytes();
|
||||||
|
|
||||||
|
// Length of data in bytes
|
||||||
|
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))) {
|
||||||
|
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(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.
|
||||||
|
*
|
||||||
|
* @see JavaField
|
||||||
|
* @see JavaMethod
|
||||||
|
*
|
||||||
|
* @param dataInputStream Input stream
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
* @return Attribute
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
|
||||||
|
return readAttribute((DataInput) dataInputStream, constantPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove attribute reader
|
||||||
|
*
|
||||||
|
* @param name the name of the attribute as stored in the class file
|
||||||
|
*/
|
||||||
|
public static void removeAttributeReader(final String name) {
|
||||||
|
READERS.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected int length; // Content length of attribute field TODO make private (has getter & setter)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected ConstantPool constant_pool; // TODO make private (has getter & setter)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* attribute_info {
|
||||||
|
* u2 attribute_name_index;
|
||||||
|
* u4 attribute_length;
|
||||||
|
* u1 info[attribute_length];
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param tag tag.
|
||||||
|
* @param nameIndex u2 name index.
|
||||||
|
* @param length u4 length.
|
||||||
|
* @param constantPool constant pool.
|
||||||
|
*/
|
||||||
|
protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
|
||||||
|
this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
|
||||||
|
this.constant_pool = constantPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return shallow copy of this attribute
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object clone() {
|
||||||
|
Attribute attr = null;
|
||||||
|
try {
|
||||||
|
attr = (Attribute) super.clone();
|
||||||
|
} catch (final CloneNotSupportedException e) {
|
||||||
|
throw new Error("Clone Not Supported"); // never happens
|
||||||
|
}
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param constantPool constant pool to save.
|
||||||
|
* @return deep copy of this attribute.
|
||||||
|
*/
|
||||||
|
public abstract Attribute copy(ConstantPool constantPool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps 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(name_index);
|
||||||
|
file.writeInt(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Constant pool used by this object.
|
||||||
|
* @see ConstantPool
|
||||||
|
*/
|
||||||
|
public final ConstantPool getConstantPool() {
|
||||||
|
return constant_pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Length of attribute field in bytes.
|
||||||
|
*/
|
||||||
|
public final int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Name of attribute
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return constant_pool.getConstantUtf8(name_index).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Name index in constant pool of attribute name.
|
||||||
|
*/
|
||||||
|
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() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param constantPool Constant pool to be used for this object.
|
||||||
|
* @see ConstantPool
|
||||||
|
*/
|
||||||
|
public final void setConstantPool(final ConstantPool constantPool) {
|
||||||
|
this.constant_pool = constantPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param length length in bytes.
|
||||||
|
*/
|
||||||
|
public final void setLength(final int length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex of attribute.
|
||||||
|
*/
|
||||||
|
public final void setNameIndex(final int nameIndex) {
|
||||||
|
this.name_index = nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return attribute name.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Const.getAttributeName(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
166
src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java
Normal file
166
src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class BootstrapMethod implements Cloneable {
|
||||||
|
|
||||||
|
/** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
|
||||||
|
private int bootstrapMethodRef;
|
||||||
|
|
||||||
|
/** 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct object from input stream.
|
||||||
|
*
|
||||||
|
* @param input Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
BootstrapMethod(final DataInput input) throws IOException {
|
||||||
|
this(input.readUnsignedShort(), input.readUnsignedShort());
|
||||||
|
|
||||||
|
for (int i = 0; i < bootstrapArguments.length; i++) {
|
||||||
|
bootstrapArguments[i] = input.readUnsignedShort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper method
|
||||||
|
private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
|
||||||
|
this(bootstrapMethodRef, new int[numBootstrapArguments]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
|
||||||
|
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
|
||||||
|
*/
|
||||||
|
public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
|
||||||
|
this.bootstrapMethodRef = bootstrapMethodRef;
|
||||||
|
this.bootstrapArguments = bootstrapArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return deep copy of this object
|
||||||
|
*/
|
||||||
|
public BootstrapMethod copy() {
|
||||||
|
try {
|
||||||
|
return (BootstrapMethod) clone();
|
||||||
|
} catch (final CloneNotSupportedException e) {
|
||||||
|
// TODO should this throw?
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump object to file stream in 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(bootstrapMethodRef);
|
||||||
|
file.writeShort(bootstrapArguments.length);
|
||||||
|
for (final int bootstrapArgument : bootstrapArguments) {
|
||||||
|
file.writeShort(bootstrapArgument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info
|
||||||
|
*/
|
||||||
|
public int[] getBootstrapArguments() {
|
||||||
|
return bootstrapArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return index into constant_pool of bootstrap_method
|
||||||
|
*/
|
||||||
|
public int getBootstrapMethodRef() {
|
||||||
|
return bootstrapMethodRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return count of number of boostrap arguments
|
||||||
|
*/
|
||||||
|
public int getNumBootstrapArguments() {
|
||||||
|
return bootstrapArguments.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
|
||||||
|
*/
|
||||||
|
public void setBootstrapArguments(final int[] bootstrapArguments) {
|
||||||
|
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 Resolved string representation
|
||||||
|
*/
|
||||||
|
public final String toString(final ConstantPool constantPool) {
|
||||||
|
final StringBuilder buf = new StringBuilder();
|
||||||
|
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 < bootstrapArgumentsLen; i++) {
|
||||||
|
buf.append("\n ").append(i).append(": ");
|
||||||
|
buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
159
src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java
Normal file
159
src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param c Source to copy.
|
||||||
|
*/
|
||||||
|
public BootstrapMethods(final BootstrapMethods c) {
|
||||||
|
this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex Index in constant pool to CONSTANT_Utf8
|
||||||
|
* @param length Content length in bytes
|
||||||
|
* @param bootstrapMethods array of bootstrap methods
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
*/
|
||||||
|
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 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.
|
||||||
|
*/
|
||||||
|
BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
|
||||||
|
this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
|
||||||
|
|
||||||
|
final int numBootstrapMethods = input.readUnsignedShort();
|
||||||
|
bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
|
||||||
|
for (int i = 0; i < numBootstrapMethods; i++) {
|
||||||
|
bootstrapMethods[i] = new BootstrapMethod(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(final Visitor v) {
|
||||||
|
v.visitBootstrapMethods(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return deep copy of this attribute
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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(constantPool);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump bootstrap methods attribute to file stream in binary format.
|
||||||
|
*
|
||||||
|
* @param file Output file stream
|
||||||
|
* @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 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.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
final StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append("BootstrapMethods(");
|
||||||
|
buf.append(bootstrapMethods.length);
|
||||||
|
buf.append("):");
|
||||||
|
for (int i = 0; i < bootstrapMethods.length; i++) {
|
||||||
|
buf.append("\n");
|
||||||
|
final int start = buf.length();
|
||||||
|
buf.append(" ").append(i).append(": ");
|
||||||
|
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(" ", 0, indentCount).append(lines[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
super(type, cpool);
|
||||||
|
this.idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
288
src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java
Normal file
288
src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
private String zipFile;
|
||||||
|
private int classNameIndex;
|
||||||
|
private int superclassNameIndex;
|
||||||
|
private int major; // Compiler version
|
||||||
|
private int minor; // Compiler version
|
||||||
|
private int accessFlags; // Access rights of parsed class
|
||||||
|
private int[] interfaces; // Names of implemented interfaces
|
||||||
|
private ConstantPool constantPool; // collection of constants
|
||||||
|
private JavaField[] fields; // class fields, i.e., its variables
|
||||||
|
private JavaMethod[] methods; // methods defined in the class
|
||||||
|
private Attribute[] attributes; // attributes defined in the class
|
||||||
|
private final boolean isZip; // Loaded from zip file
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses class from the given stream.
|
||||||
|
*
|
||||||
|
* @param inputStream Input stream
|
||||||
|
* @param fileName File name
|
||||||
|
*/
|
||||||
|
public ClassParser(final InputStream inputStream, final String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.fileOwned = false;
|
||||||
|
final String clazz = inputStream.getClass().getName(); // Not a very clean solution ...
|
||||||
|
this.isZip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
|
||||||
|
if (inputStream instanceof DataInputStream) {
|
||||||
|
this.dataInputStream = (DataInputStream) inputStream;
|
||||||
|
} else {
|
||||||
|
this.dataInputStream = new DataInputStream(new BufferedInputStream(inputStream, BUFSIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses class from given .class file.
|
||||||
|
*
|
||||||
|
* @param fileName file name
|
||||||
|
*/
|
||||||
|
public ClassParser(final String fileName) {
|
||||||
|
this.isZip = false;
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.fileOwned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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).
|
||||||
|
*
|
||||||
|
* @return Class object representing the parsed class file
|
||||||
|
* @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;
|
||||||
|
try {
|
||||||
|
if (fileOwned) {
|
||||||
|
if (isZip) {
|
||||||
|
zip = new ZipFile(zipFile);
|
||||||
|
final ZipEntry entry = zip.getEntry(fileName);
|
||||||
|
|
||||||
|
if (entry == null) {
|
||||||
|
throw new IOException("File " + fileName + " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), BUFSIZE));
|
||||||
|
} else {
|
||||||
|
dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(fileName), BUFSIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/****************** Read headers ********************************/
|
||||||
|
// Check magic tag of class file
|
||||||
|
readID();
|
||||||
|
// Get compiler version
|
||||||
|
readVersion();
|
||||||
|
/****************** Read constant pool and related **************/
|
||||||
|
// Read constant pool entries
|
||||||
|
readConstantPool();
|
||||||
|
// Get class information
|
||||||
|
readClassInfo();
|
||||||
|
// Get interface information, i.e., implemented interfaces
|
||||||
|
readInterfaces();
|
||||||
|
/****************** Read class fields and methods ***************/
|
||||||
|
// Read class fields, i.e., the variables of the class
|
||||||
|
readFields();
|
||||||
|
// Read class methods, i.e., the functions in the class
|
||||||
|
readMethods();
|
||||||
|
// 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]);
|
||||||
|
// 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));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} finally {
|
||||||
|
// Read everything of interest, so close the file
|
||||||
|
if (fileOwned) {
|
||||||
|
try {
|
||||||
|
if (dataInputStream != null) {
|
||||||
|
dataInputStream.close();
|
||||||
|
}
|
||||||
|
} catch (final IOException ignored) {
|
||||||
|
// ignore close exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (zip != null) {
|
||||||
|
zip.close();
|
||||||
|
}
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads information about the attributes of the class.
|
||||||
|
*
|
||||||
|
* @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 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 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 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) {
|
||||||
|
throw new ClassFormatException("Class " + fileName + " can't be both final and abstract");
|
||||||
|
}
|
||||||
|
classNameIndex = dataInputStream.readUnsignedShort();
|
||||||
|
superclassNameIndex = dataInputStream.readUnsignedShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads constant pool entries.
|
||||||
|
*
|
||||||
|
* @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 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 fieldsCount = dataInputStream.readUnsignedShort();
|
||||||
|
fields = new JavaField[fieldsCount];
|
||||||
|
for (int i = 0; i < fieldsCount; i++) {
|
||||||
|
fields[i] = new JavaField(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 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) {
|
||||||
|
throw new ClassFormatException(fileName + " is not a Java .class file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads information about the interfaces implemented by this class.
|
||||||
|
*
|
||||||
|
* @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 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 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 {
|
||||||
|
final int methodsCount = dataInputStream.readUnsignedShort();
|
||||||
|
methods = new JavaMethod[methodsCount];
|
||||||
|
for (int i = 0; i < methodsCount; i++) {
|
||||||
|
methods[i] = new JavaMethod(dataInputStream, constantPool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads major and minor version of compiler which created the file.
|
||||||
|
*
|
||||||
|
* @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();
|
||||||
|
major = dataInputStream.readUnsignedShort();
|
||||||
|
}
|
||||||
|
}
|
||||||
347
src/main/java/haidnor/jvm/bcel/classfile/Code.java
Normal file
347
src/main/java/haidnor/jvm/bcel/classfile/Code.java
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
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 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.
|
||||||
|
*
|
||||||
|
* @param code The source Code.
|
||||||
|
*/
|
||||||
|
public Code(final Code code) {
|
||||||
|
this(code.getNameIndex(), code.getLength(), code.getMaxStack(), code.getMaxLocals(), code.getCode(), code.getExceptionTable(), code.getAttributes(),
|
||||||
|
code.getConstantPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex Index pointing to the name <em>Code</em>
|
||||||
|
* @param length Content length in bytes
|
||||||
|
* @param file Input stream
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
*/
|
||||||
|
Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
|
||||||
|
// Initialize with some default values which will be overwritten later
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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'
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
super.setLength(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 constantPool Array of constants
|
||||||
|
*/
|
||||||
|
public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
|
||||||
|
final Attribute[] attributes, final ConstantPool constantPool) {
|
||||||
|
super(Const.ATTR_CODE, nameIndex, length, constantPool);
|
||||||
|
this.maxStack = Args.requireU2(maxStack, "maxStack");
|
||||||
|
this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
|
||||||
|
this.code = code != null ? code : ArrayUtils.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 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.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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dump(final DataOutputStream file) throws IOException {
|
||||||
|
super.dump(file);
|
||||||
|
file.writeShort(maxStack);
|
||||||
|
file.writeShort(maxLocals);
|
||||||
|
file.writeInt(code.length);
|
||||||
|
file.write(code, 0, code.length);
|
||||||
|
file.writeShort(exceptionTable.length);
|
||||||
|
for (final CodeException exception : exceptionTable) {
|
||||||
|
exception.dump(file);
|
||||||
|
}
|
||||||
|
file.writeShort(attributes.length);
|
||||||
|
for (final Attribute attribute : attributes) {
|
||||||
|
attribute.dump(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection of code attributes.
|
||||||
|
* @see Attribute
|
||||||
|
*/
|
||||||
|
public Attribute[] getAttributes() {
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public LineNumberTable getLineNumberTable() {
|
||||||
|
for (final Attribute attribute : attributes) {
|
||||||
|
if (attribute instanceof LineNumberTable) {
|
||||||
|
return (LineNumberTable) attribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LocalVariableTable of Code, if it has one
|
||||||
|
*/
|
||||||
|
public LocalVariableTable getLocalVariableTable() {
|
||||||
|
for (final Attribute attribute : attributes) {
|
||||||
|
if (attribute instanceof LocalVariableTable) {
|
||||||
|
return (LocalVariableTable) attribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of local variables.
|
||||||
|
*/
|
||||||
|
public int getMaxLocals() {
|
||||||
|
return maxLocals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Maximum size of stack used by this method.
|
||||||
|
*/
|
||||||
|
public int getMaxStack() {
|
||||||
|
return maxStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param attributes the attributes to set for this Code
|
||||||
|
*/
|
||||||
|
public void setAttributes(final Attribute[] attributes) {
|
||||||
|
this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
|
||||||
|
super.setLength(calculateLength()); // Adjust length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param code byte code
|
||||||
|
*/
|
||||||
|
public void setCode(final byte[] code) {
|
||||||
|
this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY;
|
||||||
|
super.setLength(calculateLength()); // Adjust length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param exceptionTable exception table
|
||||||
|
*/
|
||||||
|
public void setExceptionTable(final CodeException[] exceptionTable) {
|
||||||
|
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
|
||||||
|
super.setLength(calculateLength()); // Adjust length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param maxLocals maximum number of local variables
|
||||||
|
*/
|
||||||
|
public void setMaxLocals(final int maxLocals) {
|
||||||
|
this.maxLocals = maxLocals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param maxStack maximum stack size
|
||||||
|
*/
|
||||||
|
public void setMaxStack(final int maxStack) {
|
||||||
|
this.maxStack = maxStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation of code chunk.
|
||||||
|
*/
|
||||||
|
@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));
|
||||||
|
if (exceptionTable.length > 0) {
|
||||||
|
buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
|
||||||
|
for (final CodeException exception : exceptionTable) {
|
||||||
|
buf.append(exception.toString(super.getConstantPool(), verbose)).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attributes.length > 0) {
|
||||||
|
buf.append("\nAttribute(s) = ");
|
||||||
|
for (final Attribute attribute : attributes) {
|
||||||
|
buf.append("\n").append(attribute.getName()).append(":");
|
||||||
|
buf.append("\n").append(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
232
src/main/java/haidnor/jvm/bcel/classfile/CodeException.java
Normal file
232
src/main/java/haidnor/jvm/bcel/classfile/CodeException.java
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
public final class CodeException implements Cloneable, Node {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance from a DataInput.
|
||||||
|
*
|
||||||
|
* @param file Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
CodeException(final DataInput file) throws IOException {
|
||||||
|
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
public CodeException(final int startPc, final int endPc, final int handlerPc, final int 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 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.visitCodeException(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return deep copy of this object
|
||||||
|
*/
|
||||||
|
public CodeException copy() {
|
||||||
|
try {
|
||||||
|
return (CodeException) clone();
|
||||||
|
} catch (final CloneNotSupportedException e) {
|
||||||
|
// TODO should this throw?
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
199
src/main/java/haidnor/jvm/bcel/classfile/Constant.java
Normal file
199
src/main/java/haidnor/jvm/bcel/classfile/Constant.java
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.BCELComparator;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract superclass for classes to represent the different constant types in the constant pool of a class file. The
|
||||||
|
* classes keep closely to the JVM specification.
|
||||||
|
*/
|
||||||
|
public abstract class Constant implements Cloneable, Node {
|
||||||
|
|
||||||
|
private static BCELComparator bcelComparator = new BCELComparator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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) {
|
||||||
|
final Constant THIS = (Constant) o;
|
||||||
|
return THIS.toString().hashCode();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Comparison strategy object
|
||||||
|
*/
|
||||||
|
public static BCELComparator getComparator() {
|
||||||
|
return bcelComparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads one constant from the given input, the type depends on a tag byte.
|
||||||
|
*
|
||||||
|
* @param dataInput Input stream
|
||||||
|
* @return Constant object
|
||||||
|
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
|
||||||
|
* @throws ClassFormatException if the next byte is not recognized
|
||||||
|
* @since 6.0 made public
|
||||||
|
*/
|
||||||
|
public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
|
||||||
|
final byte b = dataInput.readByte(); // Read tag byte
|
||||||
|
switch (b) {
|
||||||
|
case Const.CONSTANT_Class:
|
||||||
|
return new ConstantClass(dataInput);
|
||||||
|
case Const.CONSTANT_Fieldref:
|
||||||
|
return new ConstantFieldref(dataInput);
|
||||||
|
case Const.CONSTANT_Methodref:
|
||||||
|
return new ConstantMethodref(dataInput);
|
||||||
|
case Const.CONSTANT_InterfaceMethodref:
|
||||||
|
return new ConstantInterfaceMethodref(dataInput);
|
||||||
|
case Const.CONSTANT_String:
|
||||||
|
return new ConstantString(dataInput);
|
||||||
|
case Const.CONSTANT_Integer:
|
||||||
|
return new ConstantInteger(dataInput);
|
||||||
|
case Const.CONSTANT_Float:
|
||||||
|
return new ConstantFloat(dataInput);
|
||||||
|
case Const.CONSTANT_Long:
|
||||||
|
return new ConstantLong(dataInput);
|
||||||
|
case Const.CONSTANT_Double:
|
||||||
|
return new ConstantDouble(dataInput);
|
||||||
|
case Const.CONSTANT_NameAndType:
|
||||||
|
return new ConstantNameAndType(dataInput);
|
||||||
|
case Const.CONSTANT_Utf8:
|
||||||
|
return ConstantUtf8.getInstance(dataInput);
|
||||||
|
case Const.CONSTANT_MethodHandle:
|
||||||
|
return new ConstantMethodHandle(dataInput);
|
||||||
|
case Const.CONSTANT_MethodType:
|
||||||
|
return new ConstantMethodType(dataInput);
|
||||||
|
case Const.CONSTANT_Dynamic:
|
||||||
|
return new ConstantDynamic(dataInput);
|
||||||
|
case Const.CONSTANT_InvokeDynamic:
|
||||||
|
return new ConstantInvokeDynamic(dataInput);
|
||||||
|
case Const.CONSTANT_Module:
|
||||||
|
return new ConstantModule(dataInput);
|
||||||
|
case Const.CONSTANT_Package:
|
||||||
|
return new ConstantPackage(dataInput);
|
||||||
|
default:
|
||||||
|
throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param comparator Comparison strategy object
|
||||||
|
*/
|
||||||
|
public static void setComparator(final BCELComparator comparator) {
|
||||||
|
bcelComparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via
|
||||||
|
* 'instanceof'. In some places we will use the tag for switch()es anyway.
|
||||||
|
*
|
||||||
|
* 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return bcelComparator.hashCode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Const.getConstantName(tag) + "[" + tag + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
140
src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java
Normal file
140
src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract super class for Fieldref, Methodref, InterfaceMethodref and InvokeDynamic constants.
|
||||||
|
*
|
||||||
|
* @see ConstantFieldref
|
||||||
|
* @see ConstantMethodref
|
||||||
|
* @see ConstantInterfaceMethodref
|
||||||
|
* @see ConstantInvokeDynamic
|
||||||
|
*/
|
||||||
|
public abstract class ConstantCP extends Constant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References to the constants containing the class and the field signature
|
||||||
|
*/
|
||||||
|
// Note that this field is used to store the
|
||||||
|
// bootstrap_method_attr_index of a ConstantInvokeDynamic.
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
|
||||||
|
*/
|
||||||
|
@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 file Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantCP(final byte tag, final DataInput file) throws IOException {
|
||||||
|
this(tag, file.readUnsignedShort(), file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classIndex Reference to the class containing the field
|
||||||
|
* @param nameAndTypeIndex and the field signature
|
||||||
|
*/
|
||||||
|
protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) {
|
||||||
|
super(tag);
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public final int getClassIndex() {
|
||||||
|
return class_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Reference (index) to signature of the field.
|
||||||
|
*/
|
||||||
|
public final int getNameAndTypeIndex() {
|
||||||
|
return name_and_type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classIndex points to Constant_class
|
||||||
|
*/
|
||||||
|
public final void setClassIndex(final int classIndex) {
|
||||||
|
this.class_index = classIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameAndTypeIndex points to Constant_NameAndType
|
||||||
|
*/
|
||||||
|
public final void setNameAndTypeIndex(final int nameAndTypeIndex) {
|
||||||
|
this.name_and_type_index = nameAndTypeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*
|
||||||
|
* 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 + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
120
src/main/java/haidnor/jvm/bcel/classfile/ConstantClass.java
Normal file
120
src/main/java/haidnor/jvm/bcel/classfile/ConstantClass.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a (external) class.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* @param dataInput Input stream
|
||||||
|
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
|
||||||
|
*/
|
||||||
|
ConstantClass(final DataInput dataInput) throws IOException {
|
||||||
|
this(dataInput.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 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.visitConstantClass(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps constant class to file stream in binary format.
|
||||||
|
*
|
||||||
|
* @param file Output file stream
|
||||||
|
* @throws IOException if an I/O error occurs writing to the DataOutputStream.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public int getNameIndex() {
|
||||||
|
return nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex the name index in the constant pool of this Constant Class
|
||||||
|
*/
|
||||||
|
public void setNameIndex(final int nameIndex) {
|
||||||
|
this.nameIndex = nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(nameIndex = " + nameIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java
Normal file
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a Double object.
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public ConstantDouble(final double bytes) {
|
||||||
|
super(Const.CONSTANT_Double);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantDouble(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump constant double 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 {
|
||||||
|
file.writeByte(super.getTag());
|
||||||
|
file.writeDouble(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return data, i.e., 8 bytes.
|
||||||
|
*/
|
||||||
|
public double getBytes() {
|
||||||
|
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) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(bytes = " + bytes + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance from file data.
|
||||||
|
*
|
||||||
|
* @param file Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantDynamic(final DataInput file) throws IOException {
|
||||||
|
this(file.readShort(), file.readShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public int getBootstrapMethodAttrIndex() {
|
||||||
|
return super.getClassIndex(); // AKA bootstrap_method_attr_index
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString().replace("class_index", "bootstrap_method_attr_index");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantFieldref(final DataInput input) throws IOException {
|
||||||
|
super(Const.CONSTANT_Fieldref, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classIndex Reference to the class containing the Field
|
||||||
|
* @param nameAndTypeIndex and the Field signature
|
||||||
|
*/
|
||||||
|
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 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) {
|
||||||
|
v.visitConstantFieldref(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java
Normal file
114
src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a float object.
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public ConstantFloat(final float bytes) {
|
||||||
|
super(Const.CONSTANT_Float);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantFloat(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump constant float 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 {
|
||||||
|
file.writeByte(super.getTag());
|
||||||
|
file.writeFloat(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return data, i.e., 4 bytes.
|
||||||
|
*/
|
||||||
|
public float getBytes() {
|
||||||
|
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) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(bytes = " + bytes + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java
Normal file
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to an int object.
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public ConstantInteger(final int bytes) {
|
||||||
|
super(Const.CONSTANT_Integer);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantInteger(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump constant integer 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 {
|
||||||
|
file.writeByte(super.getTag());
|
||||||
|
file.writeInt(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return data, i.e., 4 bytes.
|
||||||
|
*/
|
||||||
|
public int getBytes() {
|
||||||
|
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) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(bytes = " + bytes + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantInterfaceMethodref(final DataInput input) throws IOException {
|
||||||
|
super(Const.CONSTANT_InterfaceMethodref, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classIndex Reference to the class containing the method
|
||||||
|
* @param nameAndTypeIndex and the method signature
|
||||||
|
*/
|
||||||
|
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 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.visitConstantInterfaceMethodref(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* @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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantInvokeDynamic(final DataInput file) throws IOException {
|
||||||
|
this(file.readUnsignedShort(), file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public int getBootstrapMethodAttrIndex() {
|
||||||
|
return super.getClassIndex(); // AKA bootstrap_method_attr_index
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString().replace("class_index", "bootstrap_method_attr_index");
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java
Normal file
113
src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a long object.
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public ConstantLong(final long bytes) {
|
||||||
|
super(Const.CONSTANT_Long);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantLong(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump constant long 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 {
|
||||||
|
file.writeByte(super.getTag());
|
||||||
|
file.writeLong(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return data, i.e., 8 bytes.
|
||||||
|
*/
|
||||||
|
public long getBytes() {
|
||||||
|
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) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(bytes = " + bytes + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a method handle.
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantMethodHandle(final DataInput file) throws IOException {
|
||||||
|
this(file.readUnsignedByte(), file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMethodHandle(final int referenceKind, final int referenceIndex) {
|
||||||
|
super(Const.CONSTANT_MethodHandle);
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 setReferenceIndex(final int referenceIndex) {
|
||||||
|
this.referenceIndex = referenceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReferenceKind(final int referenceKind) {
|
||||||
|
this.referenceKind = referenceKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(referenceKind = " + referenceKind + ", referenceIndex = " + referenceIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a method type.
|
||||||
|
*
|
||||||
|
* @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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantMethodType(final DataInput file) throws IOException {
|
||||||
|
this(file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMethodType(final int descriptorIndex) {
|
||||||
|
super(Const.CONSTANT_MethodType);
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 descriptorIndex) {
|
||||||
|
this.descriptorIndex = descriptorIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(descriptorIndex = " + descriptorIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantMethodref(final DataInput input) throws IOException {
|
||||||
|
super(Const.CONSTANT_Methodref, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param classIndex Reference to the class containing the method
|
||||||
|
* @param nameAndTypeIndex and the method signature
|
||||||
|
*/
|
||||||
|
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 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.visitConstantMethodref(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/main/java/haidnor/jvm/bcel/classfile/ConstantModule.java
Normal file
125
src/main/java/haidnor/jvm/bcel/classfile/ConstantModule.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
*
|
||||||
|
* @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 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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public int getNameIndex() {
|
||||||
|
return nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex the name index in the constant pool of this Constant Module
|
||||||
|
*/
|
||||||
|
public void setNameIndex(final int nameIndex) {
|
||||||
|
this.nameIndex = nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(nameIndex = " + nameIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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 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
|
||||||
|
*/
|
||||||
|
public ConstantNameAndType(final int nameIndex, final int signatureIndex) {
|
||||||
|
super(Const.CONSTANT_NameAndType);
|
||||||
|
this.nameIndex = nameIndex;
|
||||||
|
this.signatureIndex = signatureIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantNameAndType(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump name and signature index 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 {
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public int getNameIndex() {
|
||||||
|
return nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return signature
|
||||||
|
*/
|
||||||
|
public String getSignature(final ConstantPool cp) {
|
||||||
|
return cp.constantToString(getSignatureIndex(), Const.CONSTANT_Utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Index in constant pool of field/method signature.
|
||||||
|
*/
|
||||||
|
public int getSignatureIndex() {
|
||||||
|
return signatureIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex the name index of this constant
|
||||||
|
*/
|
||||||
|
public void setNameIndex(final int nameIndex) {
|
||||||
|
this.nameIndex = nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param signatureIndex the signature index in the constant pool of this type
|
||||||
|
*/
|
||||||
|
public void setSignatureIndex(final int signatureIndex) {
|
||||||
|
this.signatureIndex = signatureIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(nameIndex = " + nameIndex + ", signatureIndex = " + signatureIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/main/java/haidnor/jvm/bcel/classfile/ConstantObject.java
Normal file
30
src/main/java/haidnor/jvm/bcel/classfile/ConstantObject.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface denotes those constants that have a "natural" value, such as ConstantLong, ConstantString, etc..
|
||||||
|
*
|
||||||
|
* @see Constant
|
||||||
|
*/
|
||||||
|
public interface ConstantObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return object representing the constant, e.g., Long for ConstantLong
|
||||||
|
*/
|
||||||
|
Object getConstantValue(ConstantPool cp);
|
||||||
|
}
|
||||||
125
src/main/java/haidnor/jvm/bcel/classfile/ConstantPackage.java
Normal file
125
src/main/java/haidnor/jvm/bcel/classfile/ConstantPackage.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
*
|
||||||
|
* @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 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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param v Visitor object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public int getNameIndex() {
|
||||||
|
return nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex the name index in the constant pool of this Constant Package
|
||||||
|
*/
|
||||||
|
public void setNameIndex(final int nameIndex) {
|
||||||
|
this.nameIndex = nameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(nameIndex = " + nameIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
433
src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java
Normal file
433
src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.generic.ConstantPoolGen;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ConstantPoolGen
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
*/
|
||||||
|
public ConstantPool(final Constant[] constantPool) {
|
||||||
|
this.constantPool = constantPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads constants from given input stream.
|
||||||
|
*
|
||||||
|
* @param input Input stream
|
||||||
|
* @throws IOException if problem in readUnsignedShort or readConstant
|
||||||
|
*/
|
||||||
|
public ConstantPool(final DataInput input) throws IOException {
|
||||||
|
byte tag;
|
||||||
|
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 < 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"
|
||||||
|
*
|
||||||
|
* Thus we have to increment the index counter.
|
||||||
|
*/
|
||||||
|
tag = constantPool[i].getTag();
|
||||||
|
if (tag == Const.CONSTANT_Double || tag == Const.CONSTANT_Long) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantPool(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves constant to a string representation.
|
||||||
|
*
|
||||||
|
* @param c Constant to be printed
|
||||||
|
* @return String representation
|
||||||
|
* @throws IllegalArgumentException if c is unknown constant type
|
||||||
|
*/
|
||||||
|
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 = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
public String constantToString(final int index, final byte tag) {
|
||||||
|
return constantToString(getConstant(index, tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return deep copy of this constant pool
|
||||||
|
*/
|
||||||
|
public ConstantPool copy() {
|
||||||
|
ConstantPool c = null;
|
||||||
|
try {
|
||||||
|
c = (ConstantPool) clone();
|
||||||
|
c.constantPool = new Constant[constantPool.length];
|
||||||
|
for (int i = 1; i < constantPool.length; i++) {
|
||||||
|
if (constantPool[i] != null) {
|
||||||
|
c.constantPool[i] = constantPool[i].copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final CloneNotSupportedException e) {
|
||||||
|
// TODO should this throw?
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
120
src/main/java/haidnor/jvm/bcel/classfile/ConstantString.java
Normal file
120
src/main/java/haidnor/jvm/bcel/classfile/ConstantString.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is derived from the abstract {@link Constant} and represents a reference to a String object.
|
||||||
|
*
|
||||||
|
* @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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantString(final DataInput file) throws IOException {
|
||||||
|
this(file.readUnsignedShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param stringIndex Index of Constant_Utf8 in constant pool
|
||||||
|
*/
|
||||||
|
public ConstantString(final int stringIndex) {
|
||||||
|
super(Const.CONSTANT_String);
|
||||||
|
this.stringIndex = stringIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.visitConstantString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump constant field reference 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 {
|
||||||
|
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).
|
||||||
|
*/
|
||||||
|
public int getStringIndex() {
|
||||||
|
return stringIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param stringIndex the index into the constant of the string value
|
||||||
|
*/
|
||||||
|
public void setStringIndex(final int stringIndex) {
|
||||||
|
this.stringIndex = stringIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(stringIndex = " + stringIndex + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
259
src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java
Normal file
259
src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public final class ConstantUtf8 extends Constant {
|
||||||
|
|
||||||
|
private static class Cache {
|
||||||
|
|
||||||
|
private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS);
|
||||||
|
private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue();
|
||||||
|
private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75);
|
||||||
|
|
||||||
|
private static final HashMap<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8506975356158971766L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean removeEldestEntry(final Map.Entry<String, ConstantUtf8> eldest) {
|
||||||
|
return size() > MAX_ENTRIES;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the size to 0 or below to skip caching entirely
|
||||||
|
private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue();
|
||||||
|
|
||||||
|
static boolean isEnabled() {
|
||||||
|
return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO these should perhaps be AtomicInt?
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @since 6.4.0
|
||||||
|
*/
|
||||||
|
public static synchronized void clearCache() {
|
||||||
|
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>
|
||||||
|
* See {@link ConstantUtf8} class Javadoc for details.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the value.
|
||||||
|
* @return a new or cached instance of the given value.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
Cache.CACHE.put(value, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a new or cached instance of the given value.
|
||||||
|
* <p>
|
||||||
|
* See {@link ConstantUtf8} class Javadoc for details.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param dataInput the value.
|
||||||
|
* @return a new or cached instance of the given value.
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public static ConstantUtf8 getInstance(final DataInput dataInput) throws IOException {
|
||||||
|
return getInstance(dataInput.readUTF());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a new or cached instance of the given value.
|
||||||
|
* <p>
|
||||||
|
* See {@link ConstantUtf8} class Javadoc for details.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value the value.
|
||||||
|
* @return a new or cached instance of the given value.
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public static ConstantUtf8 getInstance(final String value) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes from another object.
|
||||||
|
*
|
||||||
|
* @param constantUtf8 the value.
|
||||||
|
*/
|
||||||
|
public ConstantUtf8(final ConstantUtf8 constantUtf8) {
|
||||||
|
this(constantUtf8.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes instance from file data.
|
||||||
|
*
|
||||||
|
* @param dataInput Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantUtf8(final DataInput dataInput) throws IOException {
|
||||||
|
super(Const.CONSTANT_Utf8);
|
||||||
|
value = dataInput.readUTF();
|
||||||
|
created++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param value Data
|
||||||
|
*/
|
||||||
|
public ConstantUtf8(final String value) {
|
||||||
|
super(Const.CONSTANT_Utf8);
|
||||||
|
this.value = Objects.requireNonNull(value, "value");
|
||||||
|
created++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
|
||||||
|
* 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.visitConstantUtf8(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps String in Utf8 format 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 {
|
||||||
|
file.writeByte(super.getTag());
|
||||||
|
file.writeUTF(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Data converted to string.
|
||||||
|
*/
|
||||||
|
public String getBytes() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bytes the raw bytes of this UTF-8
|
||||||
|
* @deprecated (since 6.0)
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
public void setBytes(final String bytes) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(\"" + Utility.replace(value, "\n", "\\n") + "\")";
|
||||||
|
}
|
||||||
|
}
|
||||||
156
src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java
Normal file
156
src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <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.
|
||||||
|
*
|
||||||
|
* @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 nameIndex Name index in constant pool
|
||||||
|
* @param length Content length in bytes
|
||||||
|
* @param input Input stream
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
ConstantValue(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
|
||||||
|
this(nameIndex, length, input.readUnsignedShort(), constantPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex Name index in constant pool
|
||||||
|
* @param length Content length in bytes
|
||||||
|
* @param constantValueIndex Index in constant pool
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
*/
|
||||||
|
public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) {
|
||||||
|
super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool);
|
||||||
|
this.constantValueIndex = constantValueIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dump(final DataOutputStream file) throws IOException {
|
||||||
|
super.dump(file);
|
||||||
|
file.writeShort(constantValueIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Index in constant pool of constant value.
|
||||||
|
*/
|
||||||
|
public int getConstantValueIndex() {
|
||||||
|
return constantValueIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param constantValueIndex the index info the constant pool of this constant value
|
||||||
|
*/
|
||||||
|
public void setConstantValueIndex(final int constantValueIndex) {
|
||||||
|
this.constantValueIndex = constantValueIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation of constant value.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
Constant c = super.getConstantPool().getConstant(constantValueIndex);
|
||||||
|
String buf;
|
||||||
|
int i;
|
||||||
|
// Print constant to string depending on its type
|
||||||
|
switch (c.getTag()) {
|
||||||
|
case Const.CONSTANT_Long:
|
||||||
|
buf = String.valueOf(((ConstantLong) c).getBytes());
|
||||||
|
break;
|
||||||
|
case Const.CONSTANT_Float:
|
||||||
|
buf = String.valueOf(((ConstantFloat) c).getBytes());
|
||||||
|
break;
|
||||||
|
case Const.CONSTANT_Double:
|
||||||
|
buf = String.valueOf(((ConstantDouble) c).getBytes());
|
||||||
|
break;
|
||||||
|
case Const.CONSTANT_Integer:
|
||||||
|
buf = String.valueOf(((ConstantInteger) c).getBytes());
|
||||||
|
break;
|
||||||
|
case Const.CONSTANT_String:
|
||||||
|
i = ((ConstantString) c).getStringIndex();
|
||||||
|
c = super.getConstantPool().getConstantUtf8(i);
|
||||||
|
buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Type of ConstValue invalid: " + c);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
134
src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java
Normal file
134
src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param c Source to copy.
|
||||||
|
*/
|
||||||
|
public Deprecated(final Deprecated c) {
|
||||||
|
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nameIndex Index in constant pool to CONSTANT_Utf8
|
||||||
|
* @param length Content length in bytes
|
||||||
|
* @param bytes Attribute contents
|
||||||
|
* @param constantPool Array of constants
|
||||||
|
*/
|
||||||
|
public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
|
||||||
|
super(Const.ATTR_DEPRECATED, nameIndex, Args.require0(length, "Deprecated attribute length"), constantPool);
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
println("Deprecated attribute with length > 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.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 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.
|
||||||
|
*/
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bytes the raw bytes that represents this byte array
|
||||||
|
*/
|
||||||
|
public void setBytes(final byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return attribute name
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Const.getAttributeName(Const.ATTR_DEPRECATED) + ": true";
|
||||||
|
}
|
||||||
|
}
|
||||||
547
src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java
Normal file
547
src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java
Normal file
File diff suppressed because it is too large
Load Diff
174
src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java
Normal file
174
src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public abstract class ElementValue {
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an {@code element_value} as an {@code ElementValue}.
|
||||||
|
*
|
||||||
|
* @param input Raw data input.
|
||||||
|
* @param cpool Constant pool.
|
||||||
|
* @return a new ElementValue.
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
|
||||||
|
return readElementValue(input, cpool, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an {@code element_value} as an {@code ElementValue}.
|
||||||
|
*
|
||||||
|
* @param input Raw data input.
|
||||||
|
* @param cpool Constant pool.
|
||||||
|
* @param arrayNesting level of current array nesting.
|
||||||
|
* @return a new ElementValue.
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
* @since 6.7.0
|
||||||
|
*/
|
||||||
|
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
|
||||||
|
throws IOException {
|
||||||
|
final byte tag = input.readByte();
|
||||||
|
switch (tag) {
|
||||||
|
case PRIMITIVE_BYTE:
|
||||||
|
case PRIMITIVE_CHAR:
|
||||||
|
case PRIMITIVE_DOUBLE:
|
||||||
|
case PRIMITIVE_FLOAT:
|
||||||
|
case PRIMITIVE_INT:
|
||||||
|
case PRIMITIVE_LONG:
|
||||||
|
case PRIMITIVE_SHORT:
|
||||||
|
case PRIMITIVE_BOOLEAN:
|
||||||
|
case STRING:
|
||||||
|
return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
|
||||||
|
|
||||||
|
case ENUM_CONSTANT:
|
||||||
|
return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
|
||||||
|
|
||||||
|
case CLASS:
|
||||||
|
return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
|
||||||
|
|
||||||
|
case ANNOTATION:
|
||||||
|
// TODO isRuntimeVisible
|
||||||
|
return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
|
||||||
|
|
||||||
|
case ARRAY:
|
||||||
|
arrayNesting++;
|
||||||
|
if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
|
||||||
|
// JVM spec 4.4.1
|
||||||
|
throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
|
||||||
|
}
|
||||||
|
final int numArrayVals = input.readUnsignedShort();
|
||||||
|
final ElementValue[] evalues = new ElementValue[numArrayVals];
|
||||||
|
for (int j = 0; j < numArrayVals; j++) {
|
||||||
|
evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
|
||||||
|
}
|
||||||
|
return new ArrayElementValue(ARRAY, evalues, cpool);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected int type; // TODO should be final
|
||||||
|
/**
|
||||||
|
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
|
||||||
|
*/
|
||||||
|
@java.lang.Deprecated
|
||||||
|
protected ConstantPool cpool; // TODO should be final
|
||||||
|
|
||||||
|
protected ElementValue(final int type, final ConstantPool cpool) {
|
||||||
|
this.type = type;
|
||||||
|
this.cpool = cpool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void dump(DataOutputStream dos) throws IOException;
|
||||||
|
|
||||||
|
/** @since 6.0 */
|
||||||
|
final ConstantPool getConstantPool() {
|
||||||
|
return cpool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getElementValueType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.0 */
|
||||||
|
final int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String stringifyValue();
|
||||||
|
|
||||||
|
public String toShortString() {
|
||||||
|
return stringifyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return stringifyValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An annotation's element value pair.
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
this.elementValue = elementValue;
|
||||||
|
this.elementNameIndex = elementNameIndex;
|
||||||
|
this.constantPool = constantPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
320
src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java
Normal file
320
src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitAnnotation(final Annotations obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitAnnotationDefault(final AnnotationDefault obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitAnnotationEntry(final AnnotationEntry obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitBootstrapMethods(final BootstrapMethods obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitCode(final Code obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitCodeException(final CodeException obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitConstantClass(final ConstantClass obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitConstantDouble(final ConstantDouble obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void visitConstantDynamic(final ConstantDynamic 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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 JavaField 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 JavaMethod 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 visitModule(final Module obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModuleExports(final ModuleExports obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModuleMainClass(final ModuleMainClass obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModuleOpens(final ModuleOpens obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModulePackages(final ModulePackages obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModuleProvides(final ModuleProvides obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitModuleRequires(final ModuleRequires obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@Override
|
||||||
|
public void visitNestHost(final NestHost obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @since 6.4.0 */
|
||||||
|
@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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java
Normal file
102
src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This attribute exists for local or anonymous classes and ... there can be only one.
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public class EnclosingMethod extends Attribute {
|
||||||
|
|
||||||
|
// Pointer to the CONSTANT_Class_info structure representing the
|
||||||
|
// innermost class that encloses the declaration of the current class.
|
||||||
|
private int classIndex;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// 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
|
||||||
|
// ensure that the method identified by this index is the closest
|
||||||
|
// lexically enclosing method that includes the local/anonymous class.
|
||||||
|
private int methodIndex;
|
||||||
|
|
||||||
|
// Ctors - and code to read an attribute in.
|
||||||
|
EnclosingMethod(final int nameIndex, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
|
||||||
|
this(nameIndex, len, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setEnclosingClassIndex(final int idx) {
|
||||||
|
classIndex = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setEnclosingMethodIndex(final int idx) {
|
||||||
|
methodIndex = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
super(type, cpool);
|
||||||
|
if (type != ENUM_CONSTANT) {
|
||||||
|
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 {
|
||||||
|
dos.writeByte(super.getType()); // u1 type of value (ENUM_CONSTANT == 'e')
|
||||||
|
dos.writeShort(typeIdx); // u2
|
||||||
|
dos.writeShort(valueIdx); // u2
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnumTypeString() {
|
||||||
|
return super.getConstantPool().getConstantUtf8(typeIdx).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnumValueString() {
|
||||||
|
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTypeIndex() {
|
||||||
|
return typeIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValueIndex() {
|
||||||
|
return valueIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String stringifyValue() {
|
||||||
|
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
176
src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java
Normal file
176
src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import haidnor.jvm.bcel.Const;
|
||||||
|
import haidnor.jvm.bcel.util.Args;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* Exceptions_attribute {
|
||||||
|
* u2 attribute_name_index;
|
||||||
|
* u4 attribute_length;
|
||||||
|
* u2 number_of_exceptions;
|
||||||
|
* u2 exception_index_table[number_of_exceptions];
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* @see Code
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param c Source to copy.
|
||||||
|
*/
|
||||||
|
public ExceptionTable(final ExceptionTable c) {
|
||||||
|
this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
|
||||||
|
this(nameIndex, length, (int[]) null, constantPool);
|
||||||
|
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 : ArrayUtils.EMPTY_INT_ARRAY;
|
||||||
|
Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.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.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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dump(final DataOutputStream file) throws IOException {
|
||||||
|
super.dump(file);
|
||||||
|
file.writeShort(exceptionIndexTable.length);
|
||||||
|
for (final int index : exceptionIndexTable) {
|
||||||
|
file.writeShort(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Array of indices into constant pool of thrown exceptions.
|
||||||
|
*/
|
||||||
|
public int[] getExceptionIndexTable() {
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public int getNumberOfExceptions() {
|
||||||
|
return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
|
||||||
|
* length.
|
||||||
|
*/
|
||||||
|
public void setExceptionIndexTable(final int[] exceptionIndexTable) {
|
||||||
|
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String representation, i.e., a list of thrown exceptions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder buf = new StringBuilder();
|
||||||
|
String str;
|
||||||
|
buf.append("Exceptions: ");
|
||||||
|
for (int i = 0; i < exceptionIndexTable.length; i++) {
|
||||||
|
str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
|
||||||
|
buf.append(Utility.compactClassName(str, false));
|
||||||
|
if (i < exceptionIndexTable.length - 1) {
|
||||||
|
buf.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
260
src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java
Normal file
260
src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package haidnor.jvm.bcel.classfile;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract super class for fields and methods.
|
||||||
|
*/
|
||||||
|
public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
private boolean searchedForSignatureAttribute;
|
||||||
|
|
||||||
|
FieldOrMethod() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct object from file stream.
|
||||||
|
*
|
||||||
|
* @param file Input stream
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
* @deprecated (6.0) Use {@link #FieldOrMethod(DataInput, ConstantPool)} instead.
|
||||||
|
*/
|
||||||
|
@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 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
|
||||||
|
*/
|
||||||
|
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 if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
public final void dump(final DataOutputStream file) throws IOException {
|
||||||
|
file.writeShort(super.getAccessFlags());
|
||||||
|
file.writeShort(name_index);
|
||||||
|
file.writeShort(signature_index);
|
||||||
|
file.writeShort(attributes_count);
|
||||||
|
if (attributes != null) {
|
||||||
|
for (final Attribute attribute : attributes) {
|
||||||
|
attribute.dump(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Annotations on the field or method
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
public AnnotationEntry[] getAnnotationEntries() {
|
||||||
|
if (annotationEntries == null) {
|
||||||
|
annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
return annotationEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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<Ljava/lang/String>;' Coded for
|
||||||
|
* performance - searches for the attribute only when requested - only searches for it once.
|
||||||
|
*
|
||||||
|
* @since 6.0
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchedForSignatureAttribute = true;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user