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,
146 new RenameClassRemapper(name, newName)) {
147
148 @Override
149 public void visitInnerClass(
150 String name, String outerName, String innerName,
151 int access) {
152 }
153
154 };
155
156 classReader.accept(
157 classVisitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
158
159 return classNode;
160 }
161
162 public static void mergeMethods(
163 MethodNode containerMethodNode, MethodNode headMethodNode,
164 MethodNode tailMethodNode) {
165
166 final MethodNode methodNode = new MethodNode();
167
168 headMethodNode.accept(
169 new AdviceAdapter(
170 Opcodes.ASM5, methodNode, headMethodNode.access,
171 headMethodNode.name, headMethodNode.desc) {
172
173 @Override
174 protected void onMethodExit(int opcode) {
175 mv = _emptyMethodVisitor;
176 }
177
178 });
179
180 tailMethodNode.accept(
181 new AdviceAdapter(
182 Opcodes.ASM5, _emptyMethodVisitor, tailMethodNode.access,
183 tailMethodNode.name, tailMethodNode.desc) {
184
185 @Override
186 protected void onMethodEnter() {
187 mv = methodNode;
188 }
189
190 });
191
192 containerMethodNode.instructions = methodNode.instructions;
193 }
194
195 public static MethodNode removeMethodNode(
196 List<MethodNode> methodNodes, String name, Type returnType,
197 Type... argumentTypes) {
198
199 String desc = Type.getMethodDescriptor(returnType, argumentTypes);
200
201 for (MethodNode methodNode : methodNodes) {
202 if (name.equals(methodNode.name) && desc.equals(methodNode.desc)) {
203 methodNodes.remove(methodNode);
204
205 return methodNode;
206 }
207 }
208
209 return null;
210 }
211
212 public static List<MethodNode> removeMethodNodes(
213 List<MethodNode> methodNodes, int access) {
214
215 List<MethodNode> removedMethodNodes = new ArrayList<>();
216
217 for (MethodNode methodNode : methodNodes) {
218 if ((access & methodNode.access) != 0) {
219 removedMethodNodes.add(methodNode);
220 }
221 }
222
223 methodNodes.removeAll(removedMethodNodes);
224
225 return removedMethodNodes;
226 }
227
228 public static List<MethodNode> removeMethodNodes(
229 List<MethodNode> methodNodes, Set<String> annotations) {
230
231 List<MethodNode> removedMethodNodes = new ArrayList<>();
232
233 for (MethodNode methodNode : methodNodes) {
234 List<AnnotationNode> annotationNodes =
235 methodNode.visibleAnnotations;
236
237 if (annotationNodes != null) {
238 for (AnnotationNode annotationNode : annotationNodes) {
239 if (annotations.contains(annotationNode.desc)) {
240 removedMethodNodes.add(methodNode);
241
242 break;
243 }
244 }
245 }
246 }
247
248 methodNodes.removeAll(removedMethodNodes);
249
250 return removedMethodNodes;
251 }
252
253 public static List<MethodNode> removeMethodNodes(
254 List<MethodNode> methodNodes, String name) {
255
256 List<MethodNode> removedMethodNodes = new ArrayList<>();
257
258 for (MethodNode methodNode : methodNodes) {
259 if (name.equals(methodNode.name)) {
260 removedMethodNodes.add(methodNode);
261 }
262 }
263
264 methodNodes.removeAll(removedMethodNodes);
265
266 return removedMethodNodes;
267 }
268
269 private static final MethodVisitor _emptyMethodVisitor =
270 new MethodVisitor(Opcodes.ASM5) {
271 };
272
273 private static class RenameClassRemapper extends Remapper {
274
275 public RenameClassRemapper(String oldClassName, String newClassName) {
276 _oldClassName = oldClassName;
277 _newClassName = newClassName;
278 }
279
280 @Override
281 public String map(String typeName) {
282 if (typeName.equals(_oldClassName)) {
283 return _newClassName;
284 }
285
286 return typeName;
287 }
288
289 private final String _newClassName;
290 private final String _oldClassName;
291
292 }
293
294 }