001
014
015 package com.liferay.portal.asm;
016
017 import com.liferay.portal.kernel.util.CharPool;
018
019 import java.io.IOException;
020
021 import java.util.ArrayList;
022 import java.util.List;
023 import java.util.Set;
024
025 import org.objectweb.asm.ClassReader;
026 import org.objectweb.asm.ClassVisitor;
027 import org.objectweb.asm.MethodVisitor;
028 import org.objectweb.asm.Opcodes;
029 import org.objectweb.asm.Type;
030 import org.objectweb.asm.commons.AdviceAdapter;
031 import org.objectweb.asm.commons.Remapper;
032 import org.objectweb.asm.commons.RemappingClassAdapter;
033 import org.objectweb.asm.tree.AnnotationNode;
034 import org.objectweb.asm.tree.ClassNode;
035 import org.objectweb.asm.tree.FieldNode;
036 import org.objectweb.asm.tree.MethodNode;
037
038
041 public class ASMUtil {
042
043 public static void addDefaultReturnInsns(
044 MethodVisitor methodVisitor, Type returnType) {
045
046 int sort = returnType.getSort();
047
048 if ((sort == Type.BOOLEAN) || (sort == Type.CHAR) ||
049 (sort == Type.BYTE) || (sort == Type.INT) || (sort == Type.SHORT)) {
050
051 methodVisitor.visitInsn(Opcodes.ICONST_0);
052 methodVisitor.visitInsn(Opcodes.IRETURN);
053 }
054 else if (sort == Type.DOUBLE) {
055 methodVisitor.visitInsn(Opcodes.DCONST_0);
056 methodVisitor.visitInsn(Opcodes.DRETURN);
057 }
058 else if (sort == Type.FLOAT) {
059 methodVisitor.visitInsn(Opcodes.FCONST_0);
060 methodVisitor.visitInsn(Opcodes.FRETURN);
061 }
062 else if (sort == Type.LONG) {
063 methodVisitor.visitInsn(Opcodes.LCONST_0);
064 methodVisitor.visitInsn(Opcodes.LRETURN);
065 }
066 else if (sort == Type.VOID) {
067 methodVisitor.visitInsn(Opcodes.RETURN);
068 }
069 else {
070 methodVisitor.visitInsn(Opcodes.ACONST_NULL);
071 methodVisitor.visitInsn(Opcodes.ARETURN);
072 }
073 }
074
075 public static List<FieldNode> addFieldNodes(
076 List<FieldNode> fieldNodes, List<FieldNode> newFieldNodes) {
077
078 List<FieldNode> addedFieldNodes = new ArrayList<>();
079
080 newFieldNode:
081 for (FieldNode newFieldNode : newFieldNodes) {
082 String newFieldNodeName = newFieldNode.name;
083
084 for (FieldNode fieldNode : fieldNodes) {
085 if (newFieldNodeName.equals(fieldNode.name)) {
086 continue newFieldNode;
087 }
088 }
089
090 addedFieldNodes.add(newFieldNode);
091 }
092
093 fieldNodes.addAll(addedFieldNodes);
094
095 return addedFieldNodes;
096 }
097
098 public static FieldNode findFieldNode(
099 List<FieldNode> fieldNodes, String name) {
100
101 for (FieldNode fieldNode : fieldNodes) {
102 if (name.equals(fieldNode.name)) {
103 return fieldNode;
104 }
105 }
106
107 return null;
108 }
109
110 public static MethodNode findMethodNode(
111 List<MethodNode> methodNodes, String name, Type returnType,
112 Type... argumentTypes) {
113
114 String desc = Type.getMethodDescriptor(returnType, argumentTypes);
115
116 for (MethodNode methodNode : methodNodes) {
117 if (name.equals(methodNode.name) && desc.equals(methodNode.desc)) {
118 return methodNode;
119 }
120 }
121
122 return null;
123 }
124
125 public static ClassNode loadAndRename(Class<?> clazz, String newName) {
126 ClassLoader classLoader = clazz.getClassLoader();
127
128 String name = clazz.getName();
129
130 name = name.replace(CharPool.PERIOD, CharPool.SLASH);
131
132 ClassReader classReader = null;
133
134 try {
135 classReader = new ClassReader(
136 classLoader.getResourceAsStream(name.concat(".class")));
137 }
138 catch (IOException ioe) {
139 throw new RuntimeException(ioe);
140 }
141
142 ClassNode classNode = new ClassNode();
143
144 ClassVisitor classVisitor = new RemappingClassAdapter(
145 classNode, new RenameClassRemapper(name, newName)) {
146
147 @Override
148 public void visitInnerClass(
149 String name, String outerName, String innerName, int access) {
150 }
151
152 };
153
154 classReader.accept(
155 classVisitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
156
157 return classNode;
158 }
159
160 public static void mergeMethods(
161 MethodNode containerMethodNode, MethodNode headMethodNode,
162 MethodNode tailMethodNode) {
163
164 final MethodNode methodNode = new MethodNode();
165
166 headMethodNode.accept(
167 new AdviceAdapter(
168 Opcodes.ASM5, methodNode, headMethodNode.access,
169 headMethodNode.name, headMethodNode.desc) {
170
171 @Override
172 protected void onMethodExit(int opcode) {
173 mv = _emptyMethodVisitor;
174 }
175
176 });
177
178 tailMethodNode.accept(
179 new AdviceAdapter(
180 Opcodes.ASM5, _emptyMethodVisitor, tailMethodNode.access,
181 tailMethodNode.name, tailMethodNode.desc) {
182
183 @Override
184 protected void onMethodEnter() {
185 mv = methodNode;
186 }
187
188 });
189
190 containerMethodNode.instructions = methodNode.instructions;
191 }
192
193 public static MethodNode removeMethodNode(
194 List<MethodNode> methodNodes, String name, Type returnType,
195 Type... argumentTypes) {
196
197 String desc = Type.getMethodDescriptor(returnType, argumentTypes);
198
199 for (MethodNode methodNode : methodNodes) {
200 if (name.equals(methodNode.name) && desc.equals(methodNode.desc)) {
201 methodNodes.remove(methodNode);
202
203 return methodNode;
204 }
205 }
206
207 return null;
208 }
209
210 public static List<MethodNode> removeMethodNodes(
211 List<MethodNode> methodNodes, int access) {
212
213 List<MethodNode> removedMethodNodes = new ArrayList<>();
214
215 for (MethodNode methodNode : methodNodes) {
216 if ((access & methodNode.access) != 0) {
217 removedMethodNodes.add(methodNode);
218 }
219 }
220
221 methodNodes.removeAll(removedMethodNodes);
222
223 return removedMethodNodes;
224 }
225
226 public static List<MethodNode> removeMethodNodes(
227 List<MethodNode> methodNodes, Set<String> annotations) {
228
229 List<MethodNode> removedMethodNodes = new ArrayList<>();
230
231 for (MethodNode methodNode : methodNodes) {
232 List<AnnotationNode> annotationNodes =
233 methodNode.visibleAnnotations;
234
235 if (annotationNodes != null) {
236 for (AnnotationNode annotationNode : annotationNodes) {
237 if (annotations.contains(annotationNode.desc)) {
238 removedMethodNodes.add(methodNode);
239
240 break;
241 }
242 }
243 }
244 }
245
246 methodNodes.removeAll(removedMethodNodes);
247
248 return removedMethodNodes;
249 }
250
251 public static List<MethodNode> removeMethodNodes(
252 List<MethodNode> methodNodes, String name) {
253
254 List<MethodNode> removedMethodNodes = new ArrayList<>();
255
256 for (MethodNode methodNode : methodNodes) {
257 if (name.equals(methodNode.name)) {
258 removedMethodNodes.add(methodNode);
259 }
260 }
261
262 methodNodes.removeAll(removedMethodNodes);
263
264 return removedMethodNodes;
265 }
266
267 private static final MethodVisitor _emptyMethodVisitor =
268 new MethodVisitor(Opcodes.ASM5) {
269 };
270
271 private static class RenameClassRemapper extends Remapper {
272
273 public RenameClassRemapper(String oldClassName, String newClassName) {
274 _oldClassName = oldClassName;
275 _newClassName = newClassName;
276 }
277
278 @Override
279 public String map(String typeName) {
280 if (typeName.equals(_oldClassName)) {
281 return _newClassName;
282 }
283
284 return typeName;
285 }
286
287 private final String _newClassName;
288 private final String _oldClassName;
289
290 }
291
292 }