Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.multiverse.instrumentation.asm.AsmUtils Maven / Gradle / Ivy
package org.multiverse.instrumentation.asm;
import org.multiverse.instrumentation.DebugInfo;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.commons.RemappingMethodAdapter;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.util.TraceMethodVisitor;
import java.io.*;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import static java.lang.String.format;
import static org.multiverse.utils.IOUtils.closeQuietly;
import static org.multiverse.utils.SystemOut.println;
import static org.objectweb.asm.Type.*;
public final class AsmUtils implements Opcodes {
public static MethodNode cloneMethodWithoutInstructions(MethodNode originalMethod, CloneMap cloneMap) {
if (originalMethod == null || cloneMap == null) {
throw new NullPointerException();
}
MethodNode result = new MethodNode();
result.name = originalMethod.name;
result.access = originalMethod.access;
result.desc = originalMethod.desc;
result.signature = originalMethod.signature;
result.exceptions = originalMethod.exceptions;
result.annotationDefault = originalMethod.annotationDefault;
result.invisibleParameterAnnotations = originalMethod.invisibleParameterAnnotations;
result.visibleParameterAnnotations = originalMethod.visibleParameterAnnotations;
result.localVariables = cloneLocalVariableTable(originalMethod, cloneMap);
result.tryCatchBlocks = cloneTryCatchBlocks(originalMethod, cloneMap);
return result;
}
public static List cloneLocalVariableTable(MethodNode originalMethod, CloneMap cloneMap) {
if (originalMethod.localVariables == null) {
return null;
}
List localVariableTable = new LinkedList();
for (LocalVariableNode localVariableNode : (List) originalMethod.localVariables) {
LocalVariableNode cloned = new LocalVariableNode(
localVariableNode.name,
localVariableNode.desc,
localVariableNode.signature,
cloneMap.get(localVariableNode.start),
cloneMap.get(localVariableNode.end),
localVariableNode.index
);
localVariableTable.add(cloned);
}
return localVariableTable;
}
public static List cloneTryCatchBlocks(MethodNode originalMethod, CloneMap cloneMap) {
if (originalMethod.tryCatchBlocks == null) {
return null;
}
List tryCatchBlocks = new LinkedList();
for (TryCatchBlockNode tryCatchBlockNode : (List) originalMethod.tryCatchBlocks) {
TryCatchBlockNode cloned = new TryCatchBlockNode(
cloneMap.get(tryCatchBlockNode.start),
cloneMap.get(tryCatchBlockNode.end),
cloneMap.get(tryCatchBlockNode.handler),
tryCatchBlockNode.type
);
tryCatchBlocks.add(cloned);
}
return tryCatchBlocks;
}
public static void printClassOfTopItem(InsnList instructions) {
instructions.add(new MethodInsnNode(
INVOKEVIRTUAL,
Type.getInternalName(Object.class),
"getClass",
"()Ljava/lang/Class;"));
instructions.add(new MethodInsnNode(
INVOKESTATIC,
Type.getInternalName(AsmUtils.class),
"printClazz",
"(Ljava/lang/Class;)V"
));
}
public static void printClass(Class clazz) {
println(" class on top: " + clazz.getName());
}
public static DebugInfo findDebugInfo(MethodNode method) {
DebugInfo info = new DebugInfo();
for (ListIterator iterator = method.instructions.iterator(); iterator.hasNext();) {
AbstractInsnNode node = iterator.next();
if (node instanceof LineNumberNode) {
LineNumberNode lineNumberNode = (LineNumberNode) node;
if (lineNumberNode.line > info.endLine) {
info.endLine = lineNumberNode.line;
}
if (info.beginLine == -1) {
info.beginLine = lineNumberNode.line;
} else if (lineNumberNode.line < info.beginLine) {
info.beginLine = lineNumberNode.line;
}
}
}
return info;
}
public static int getInvokeOpcode(MethodNode methodNode) {
//todo: invoke special is ignored.
if (isStatic(methodNode.access)) {
return INVOKESTATIC;
} else if (methodNode.name.equals("")) {
return INVOKESPECIAL;
} else {
return INVOKEVIRTUAL;
}
}
public static List cloneTryCatchBlockNodes(List originalBlocks, CloneMap cloneMap) {
List result = new LinkedList();
for (TryCatchBlockNode originalBlock : originalBlocks) {
TryCatchBlockNode clonedBlock = new TryCatchBlockNode(
cloneMap.get(originalBlock.start),
cloneMap.get(originalBlock.end),
cloneMap.get(originalBlock.handler),
originalBlock.type
);
result.add(clonedBlock);
}
return result;
}
public static List cloneVariableTable(MethodNode methodNode, CloneMap cloneMap) {
List result = new LinkedList();
//copy all the rest of the local variables.
for (LocalVariableNode originalLocalVar : (List) methodNode.localVariables) {
LocalVariableNode clonedLocalVar = new LocalVariableNode(
originalLocalVar.name,
originalLocalVar.desc,
originalLocalVar.signature,
cloneMap.get(originalLocalVar.start),
cloneMap.get(originalLocalVar.end),
originalLocalVar.index);
result.add(clonedLocalVar);
}
return result;
}
public static int firstIndexAfterSuper(String methodName, InsnList instructions, String superClass) {
if (!methodName.equals("")) {
throw new RuntimeException();
}
if (instructions == null) {
return -1;
}
int depth = 0;
for (int k = 0; k < instructions.size(); k++) {
AbstractInsnNode insn = instructions.get(k);
if (insn.getOpcode() == INVOKESPECIAL) {
MethodInsnNode methodInsn = (MethodInsnNode) insn;
if (methodInsn.name.equals("") && methodInsn.owner.endsWith(superClass)) {
if (depth == 0) {
return k + 1;
} else {
depth--;
}
}
} else if (insn.getOpcode() == NEW) {
TypeInsnNode typeInsn = (TypeInsnNode) insn;
if (typeInsn.desc.equals(superClass)) {
depth++;
}
}
}
return -1;
}
public static int firstIndexAfterSuper(MethodNode methodNode, String superClass) {
return firstIndexAfterSuper(methodNode.name, methodNode.instructions, superClass);
}
public static String toString(AbstractInsnNode insnNode) {
TraceMethodVisitor asmifier = new TraceMethodVisitor();
insnNode.accept(asmifier);
StringBuffer sb = new StringBuffer();
for (String line : (List) asmifier.getText()) {
sb.append(line);
}
return sb.toString();
}
public static int sizeOfFormalParameters(String desc) {
int size = 0;
for (Type argType : Type.getArgumentTypes(desc)) {
size += argType.getSize();
}
return size;
}
public static boolean isCategory2(String valueDesc) {
return valueDesc.equals("J") || valueDesc.equals("D");
}
public static int upgradeToPublic(int access) {
if (isPublic(access)) {
return access;
}
if (isPrivate(access)) {
access = access - ACC_PRIVATE;
} else if (isProtected(access)) {
access = access - ACC_PROTECTED;
}
return access + ACC_PUBLIC;
}
public static int upgradeToProtected(int access) {
if (isProtected(access)) {
return access;
}
if (isPublic(access)) {
return access;
}
if (isPrivate(access)) {
access = access - ACC_PRIVATE;
}
return access + ACC_PROTECTED;
}
/**
* @param methodDesc the original method descriptor
* @param extraArgType internal name of extra argument to add to the right
* @return the new method descripion
*/
public static String createMethodDescriptorWithRightIntroducedVariable(String methodDesc, String extraArgType) {
Type returnType = Type.getReturnType(methodDesc);
Type[] argTypes = Type.getArgumentTypes(methodDesc);
Type[] newArgTypes = new Type[argTypes.length + 1];
System.arraycopy(argTypes, 0, newArgTypes, 0, argTypes.length);
newArgTypes[argTypes.length] = Type.getObjectType(extraArgType);
return getMethodDescriptor(returnType, newArgTypes);
}
public static MethodNode remap(MethodNode originalMethod, Remapper remapper) {
String[] exceptions = getExceptions(originalMethod);
MethodNode mappedMethod = new MethodNode(
originalMethod.access,
originalMethod.name,
remapper.mapMethodDesc(originalMethod.desc),
remapper.mapSignature(originalMethod.signature, false),
remapper.mapTypes(exceptions));
RemappingMethodAdapter remapVisitor = new RemappingMethodAdapter(
mappedMethod.access,
mappedMethod.desc,
mappedMethod,
remapper);
originalMethod.accept(remapVisitor);
return mappedMethod;
}
public static String[] getExceptions(MethodNode originalMethod) {
if (originalMethod.exceptions == null) {
return new String[]{};
}
String[] exceptions = new String[originalMethod.exceptions.size()];
originalMethod.exceptions.toArray(exceptions);
return exceptions;
}
/**
* Loads a Class as ClassNode. The ClassLoader of the Class is used to retrieve a resource stream.
*
* @param clazz the Class to load as ClassNode.
* @return the loaded ClassNode.
*/
public static ClassNode loadAsClassNode(Class clazz) {
return loadAsClassNode(clazz.getClassLoader(), getInternalName(clazz));
}
/**
* Loads a Class as ClassNode.
*
* @param loader the ClassLoader to getClassMetadata the resource stream of.
* @param classInternalName the internal name of the Class to load.
* @return the loaded ClassNode.
*/
public static ClassNode loadAsClassNode(ClassLoader loader, String classInternalName) {
if (loader == null || classInternalName == null) {
throw new NullPointerException();
}
String fileName = classInternalName + ".class";
InputStream is = loader.getResourceAsStream(fileName);
try {
ClassNode classNode = new ClassNode();
ClassReader reader = new ClassReader(is);
reader.accept(classNode, ClassReader.EXPAND_FRAMES);
return classNode;
} catch (FileNotFoundException ex) {
throw new RuntimeException(format("Could not find file '%s' for class '%s': ",
fileName,
classInternalName));
} catch (IOException e) {
throw new RuntimeException("A problem ocurred while loading class: " + fileName, e);
} finally {
closeQuietly(is);
}
}
/**
* Loads a Class as ClassNode.
*
* todo: code of this method is very nasty with closing streams.
*
* @return the loaded ClassNode.
*/
public static ClassNode loadAsClassNode(File file) {
InputStream is = null;
try {
is = new FileInputStream(file);
ClassNode classNode = new ClassNode();
ClassReader reader = new ClassReader(is);
reader.accept(classNode, ClassReader.EXPAND_FRAMES);
return classNode;
} catch (IOException e) {
throw new RuntimeException("A problem ocurred while loading class: " + file, e);
} finally {
closeQuietly(is);
}
}
public static byte[] loadAsBytecode(File file) {
InputStream is = null;
try {
is = new FileInputStream(file);
ClassNode classNode = new ClassNode();
ClassReader reader = new ClassReader(is);
reader.accept(classNode, ClassReader.EXPAND_FRAMES);
return toBytecode(classNode);
} catch (IOException e) {
throw new RuntimeException("A problem ocurred while loading class: " + file, e);
} finally {
closeQuietly(is);
}
}
/**
* Checks if a ClassNode has the specified visible annotation.
*
* @param memberNode the ClassNode to check
* @param annotationClass the Annotation class that is checked for.
* @return true if classNode has the specified annotation, false otherwise.
*/
public static boolean hasVisibleAnnotation(MemberNode memberNode, Class annotationClass) {
return getVisibleAnnotation(memberNode, annotationClass) != null;
}
public static AnnotationNode getVisibleAnnotation(MemberNode memberNode, Class annotationClass) {
if (memberNode == null || annotationClass == null) {
throw new NullPointerException();
}
if (memberNode.visibleAnnotations == null) {
return null;
}
String annotationClassDescriptor = getDescriptor(annotationClass);
for (AnnotationNode node : (List) memberNode.visibleAnnotations) {
if (annotationClassDescriptor.equals(node.desc)) {
return node;
}
}
return null;
}
public static Object getAnnotationValue(AnnotationNode annotationNode, String valueName) {
List values = annotationNode.values;
if (values == null) {
return null;
}
for (int k = 0; k < values.size(); k += 2) {
if (values.get(k).equals(valueName)) {
return values.get(k + 1);
}
}
return null;
}
public static String internalToDesc(String internalForm) {
return format("L%s;", internalForm);
}
public static Field getField(Class clazz, String fieldName) {
try {
return clazz.getField(fieldName);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
public static boolean isAbstract(MethodNode methodNode) {
return isAbstract(methodNode.access);
}
public static boolean isInterface(ClassNode classNode) {
return (classNode.access & Opcodes.ACC_INTERFACE) != 0;
}
public static boolean isNative(MethodNode methodNode) {
return isNative(methodNode.access);
}
public static boolean isFinal(FieldNode fieldNode) {
return isFinal(fieldNode.access);
}
public static boolean isStatic(FieldNode fieldNode) {
return isStatic(fieldNode.access);
}
public static boolean isStatic(MethodNode methodNode) {
return isStatic(methodNode.access);
}
public static boolean isPrivate(MethodNode methodNode) {
return isPrivate(methodNode.access);
}
public static boolean isPrivate(int access) {
return (access & Opcodes.ACC_PRIVATE) != 0;
}
public static boolean isPublic(int access) {
return (access & Opcodes.ACC_PUBLIC) != 0;
}
public static boolean isProtected(int access) {
return (access & Opcodes.ACC_PROTECTED) != 0;
}
public static boolean isFinal(int access) {
return (access & Opcodes.ACC_FINAL) != 0;
}
public static boolean isSynthetic(int access) {
return (access & Opcodes.ACC_SYNTHETIC) != 0;
}
public static boolean isNative(int access) {
return (access & Opcodes.ACC_NATIVE) != 0;
}
public static boolean isStatic(int access) {
return (access & Opcodes.ACC_STATIC) != 0;
}
public static boolean isAbstract(int access) {
return (access & Opcodes.ACC_ABSTRACT) != 0;
}
public static ClassNode loadAsClassNode(byte[] bytecode) {
if (bytecode == null) {
throw new NullPointerException();
}
ClassNode classNode = new ClassNode();
ClassReader cr = new ClassReader(bytecode);
cr.accept(classNode, ClassReader.EXPAND_FRAMES);
return classNode;
}
public static byte[] toBytecode(ClassNode classNode) {
if (classNode == null) {
throw new NullPointerException();
}
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
classNode.accept(cw);
return cw.toByteArray();
}
public static String getTmpDir() {
return System.getProperty("java.io.tmpdir");
}
public static void writeToFile(File file, byte[] bytecode) {
if (file == null || bytecode == null) {
throw new NullPointerException();
}
try {
ensureExistingParent(file);
OutputStream writer = new FileOutputStream(file);
try {
writer.write(bytecode);
} finally {
closeQuietly(writer);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void ensureExistingParent(File file) throws IOException {
File parent = file.getParentFile();
if (parent.isDirectory()) {
return;
}
if (!parent.mkdirs()) {
throw new IOException("Failed to make parent directories for file " + file);
}
}
private AsmUtils() {
}
}