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