/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.asm; import com.liferay.portal.kernel.util.CharPool; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.AdviceAdapter; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.RemappingClassAdapter; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; /** * @author Shuyang Zhou */ public class ASMUtil { public static void addDefaultReturnInsns( MethodVisitor methodVisitor, Type returnType) { int sort = returnType.getSort(); if ((sort == Type.BOOLEAN) || (sort == Type.CHAR) || (sort == Type.BYTE) || (sort == Type.INT) || (sort == Type.SHORT)) { methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitInsn(Opcodes.IRETURN); } else if (sort == Type.DOUBLE) { methodVisitor.visitInsn(Opcodes.DCONST_0); methodVisitor.visitInsn(Opcodes.DRETURN); } else if (sort == Type.FLOAT) { methodVisitor.visitInsn(Opcodes.FCONST_0); methodVisitor.visitInsn(Opcodes.FRETURN); } else if (sort == Type.LONG) { methodVisitor.visitInsn(Opcodes.LCONST_0); methodVisitor.visitInsn(Opcodes.LRETURN); } else if (sort == Type.VOID) { methodVisitor.visitInsn(Opcodes.RETURN); } else { methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); } } public static List<FieldNode> addFieldNodes( List<FieldNode> fieldNodes, List<FieldNode> newFieldNodes) { List<FieldNode> addedFieldNodes = new ArrayList<>(); newFieldNode: for (FieldNode newFieldNode : newFieldNodes) { String newFieldNodeName = newFieldNode.name; for (FieldNode fieldNode : fieldNodes) { if (newFieldNodeName.equals(fieldNode.name)) { continue newFieldNode; } } addedFieldNodes.add(newFieldNode); } fieldNodes.addAll(addedFieldNodes); return addedFieldNodes; } public static FieldNode findFieldNode( List<FieldNode> fieldNodes, String name) { for (FieldNode fieldNode : fieldNodes) { if (name.equals(fieldNode.name)) { return fieldNode; } } return null; } public static MethodNode findMethodNode( List<MethodNode> methodNodes, String name, Type returnType, Type... argumentTypes) { String desc = Type.getMethodDescriptor(returnType, argumentTypes); for (MethodNode methodNode : methodNodes) { if (name.equals(methodNode.name) && desc.equals(methodNode.desc)) { return methodNode; } } return null; } public static ClassNode loadAndRename(Class<?> clazz, String newName) { ClassLoader classLoader = clazz.getClassLoader(); String name = clazz.getName(); name = name.replace(CharPool.PERIOD, CharPool.SLASH); ClassReader classReader = null; try { classReader = new ClassReader( classLoader.getResourceAsStream(name.concat(".class"))); } catch (IOException ioe) { throw new RuntimeException(ioe); } ClassNode classNode = new ClassNode(); ClassVisitor classVisitor = new RemappingClassAdapter( classNode, new RenameClassRemapper(name, newName)) { @Override public void visitInnerClass( String name, String outerName, String innerName, int access) { } }; classReader.accept( classVisitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); return classNode; } public static void mergeMethods( MethodNode containerMethodNode, MethodNode headMethodNode, MethodNode tailMethodNode) { final MethodNode methodNode = new MethodNode(); headMethodNode.accept( new AdviceAdapter( Opcodes.ASM5, methodNode, headMethodNode.access, headMethodNode.name, headMethodNode.desc) { @Override protected void onMethodExit(int opcode) { mv = _emptyMethodVisitor; } }); tailMethodNode.accept( new AdviceAdapter( Opcodes.ASM5, _emptyMethodVisitor, tailMethodNode.access, tailMethodNode.name, tailMethodNode.desc) { @Override protected void onMethodEnter() { mv = methodNode; } }); containerMethodNode.instructions = methodNode.instructions; } public static MethodNode removeMethodNode( List<MethodNode> methodNodes, String name, Type returnType, Type... argumentTypes) { String desc = Type.getMethodDescriptor(returnType, argumentTypes); for (MethodNode methodNode : methodNodes) { if (name.equals(methodNode.name) && desc.equals(methodNode.desc)) { methodNodes.remove(methodNode); return methodNode; } } return null; } public static List<MethodNode> removeMethodNodes( List<MethodNode> methodNodes, int access) { List<MethodNode> removedMethodNodes = new ArrayList<>(); for (MethodNode methodNode : methodNodes) { if ((access & methodNode.access) != 0) { removedMethodNodes.add(methodNode); } } methodNodes.removeAll(removedMethodNodes); return removedMethodNodes; } public static List<MethodNode> removeMethodNodes( List<MethodNode> methodNodes, Set<String> annotations) { List<MethodNode> removedMethodNodes = new ArrayList<>(); for (MethodNode methodNode : methodNodes) { List<AnnotationNode> annotationNodes = methodNode.visibleAnnotations; if (annotationNodes != null) { for (AnnotationNode annotationNode : annotationNodes) { if (annotations.contains(annotationNode.desc)) { removedMethodNodes.add(methodNode); break; } } } } methodNodes.removeAll(removedMethodNodes); return removedMethodNodes; } public static List<MethodNode> removeMethodNodes( List<MethodNode> methodNodes, String name) { List<MethodNode> removedMethodNodes = new ArrayList<>(); for (MethodNode methodNode : methodNodes) { if (name.equals(methodNode.name)) { removedMethodNodes.add(methodNode); } } methodNodes.removeAll(removedMethodNodes); return removedMethodNodes; } private static final MethodVisitor _emptyMethodVisitor = new MethodVisitor(Opcodes.ASM5) { }; private static class RenameClassRemapper extends Remapper { public RenameClassRemapper(String oldClassName, String newClassName) { _oldClassName = oldClassName; _newClassName = newClassName; } @Override public String map(String typeName) { if (typeName.equals(_oldClassName)) { return _newClassName; } return typeName; } private final String _newClassName; private final String _oldClassName; } }