• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 package org.objectweb.asm.util;
31 
32 import java.io.FileInputStream;
33 import java.io.PrintWriter;
34 
35 import org.objectweb.asm.AnnotationVisitor;
36 import org.objectweb.asm.ClassReader;
37 import org.objectweb.asm.ClassVisitor;
38 import org.objectweb.asm.TypeAnnotationVisitor;
39 import org.objectweb.asm.FieldVisitor;
40 import org.objectweb.asm.MethodVisitor;
41 import org.objectweb.asm.Opcodes;
42 import org.objectweb.asm.Type;
43 
44 /**
45  * A {@link ClassVisitor} that prints the ASM code that generates the classes it
46  * visits. This class visitor can be used to quickly write ASM code to generate
47  * some given bytecode: <ul> <li>write the Java source code equivalent to the
48  * bytecode you want to generate;</li> <li>compile it with <tt>javac</tt>;</li>
49  * <li>make a {@link ASMifierClassVisitor} visit this compiled class (see the
50  * {@link #main main} method);</li> <li>edit the generated source code, if
51  * necessary.</li> </ul> The source code printed when visiting the
52  * <tt>Hello</tt> class is the following: <p> <blockquote>
53  *
54  * <pre>
55  * import org.objectweb.asm.*;
56  *
57  * public class HelloDump implements Opcodes {
58  *
59  *     public static byte[] dump() throws Exception {
60  *
61  *         ClassWriter cw = new ClassWriter(false);
62  *         FieldVisitor fv;
63  *         MethodVisitor mv;
64  *         AnnotationVisitor av0;
65  *
66  *         cw.visit(49,
67  *                 ACC_PUBLIC + ACC_SUPER,
68  *                 &quot;Hello&quot;,
69  *                 null,
70  *                 &quot;java/lang/Object&quot;,
71  *                 null);
72  *
73  *         cw.visitSource(&quot;Hello.java&quot;, null);
74  *
75  *         {
76  *             mv = cw.visitMethod(ACC_PUBLIC, &quot;&lt;init&gt;&quot;, &quot;()V&quot;, null, null);
77  *             mv.visitVarInsn(ALOAD, 0);
78  *             mv.visitMethodInsn(INVOKESPECIAL,
79  *                     &quot;java/lang/Object&quot;,
80  *                     &quot;&lt;init&gt;&quot;,
81  *                     &quot;()V&quot;);
82  *             mv.visitInsn(RETURN);
83  *             mv.visitMaxs(1, 1);
84  *             mv.visitEnd();
85  *         }
86  *         {
87  *             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
88  *                     &quot;main&quot;,
89  *                     &quot;([Ljava/lang/String;)V&quot;,
90  *                     null,
91  *                     null);
92  *             mv.visitFieldInsn(GETSTATIC,
93  *                     &quot;java/lang/System&quot;,
94  *                     &quot;out&quot;,
95  *                     &quot;Ljava/io/PrintStream;&quot;);
96  *             mv.visitLdcInsn(&quot;hello&quot;);
97  *             mv.visitMethodInsn(INVOKEVIRTUAL,
98  *                     &quot;java/io/PrintStream&quot;,
99  *                     &quot;println&quot;,
100  *                     &quot;(Ljava/lang/String;)V&quot;);
101  *             mv.visitInsn(RETURN);
102  *             mv.visitMaxs(2, 1);
103  *             mv.visitEnd();
104  *         }
105  *         cw.visitEnd();
106  *
107  *         return cw.toByteArray();
108  *     }
109  * }
110  *
111  * </pre>
112  *
113  * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote>
114  *
115  * <pre>
116  * public class Hello {
117  *
118  *     public static void main(String[] args) {
119  *         System.out.println(&quot;hello&quot;);
120  *     }
121  * }
122  * </pre>
123  *
124  * </blockquote>
125  *
126  * @author Eric Bruneton
127  * @author Eugene Kuleshov
128  */
129 public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements
130         ClassVisitor
131 {
132     /**
133      * Pseudo access flag used to distinguish class access flags.
134      */
135     private final static int ACCESS_CLASS = 262144;
136 
137     /**
138      * Pseudo access flag used to distinguish field access flags.
139      */
140     private final static int ACCESS_FIELD = 524288;
141 
142     /**
143      * Pseudo access flag used to distinguish inner class flags.
144      */
145     private static final int ACCESS_INNER = 1048576;
146 
147     /**
148      * The print writer to be used to print the class.
149      */
150     protected final PrintWriter pw;
151 
152     /**
153      * Prints the ASM source code to generate the given class to the standard
154      * output. <p> Usage: ASMifierClassVisitor [-debug] &lt;fully qualified
155      * class name or class file name&gt;
156      *
157      * @param args the command line arguments.
158      *
159      * @throws Exception if the class cannot be found, or if an IO exception
160      *         occurs.
161      */
main(final String[] args)162     public static void main(final String[] args) throws Exception {
163         int i = 0;
164         boolean skipDebug = true;
165 
166         boolean ok = true;
167         if (args.length < 1 || args.length > 2) {
168             ok = false;
169         }
170         if (ok && args[0].equals("-debug")) {
171             i = 1;
172             skipDebug = false;
173             if (args.length != 2) {
174                 ok = false;
175             }
176         }
177         if (!ok) {
178             System.err.println("Prints the ASM code to generate the given class.");
179             System.err.println("Usage: ASMifierClassVisitor [-debug] "
180                     + "<fully qualified class name or class file name>");
181             return;
182         }
183         ClassReader cr;
184         if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
185                 || args[i].indexOf('/') > -1) {
186             cr = new ClassReader(new FileInputStream(args[i]));
187         } else {
188             cr = new ClassReader(args[i]);
189         }
190         cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)),
191                 getDefaultAttributes(),
192                 skipDebug);
193     }
194 
195     /**
196      * Constructs a new {@link ASMifierClassVisitor} object.
197      *
198      * @param pw the print writer to be used to print the class.
199      */
ASMifierClassVisitor(final PrintWriter pw)200     public ASMifierClassVisitor(final PrintWriter pw) {
201         super("cw");
202         this.pw = pw;
203     }
204 
205     // ------------------------------------------------------------------------
206     // Implementation of the ClassVisitor interface
207     // ------------------------------------------------------------------------
208 
visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)209     public void visit(
210         final int version,
211         final int access,
212         final String name,
213         final String signature,
214         final String superName,
215         final String[] interfaces)
216     {
217         String simpleName;
218         int n = name.lastIndexOf('/');
219         if (n != -1) {
220             text.add("package asm." + name.substring(0, n).replace('/', '.')
221                     + ";\n");
222             simpleName = name.substring(n + 1);
223         } else {
224             simpleName = name;
225         }
226         text.add("import java.util.*;\n");
227         text.add("import org.objectweb.asm.*;\n");
228         text.add("import org.objectweb.asm.attrs.*;\n");
229         text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
230         text.add("public static byte[] dump () throws Exception {\n\n");
231         text.add("ClassWriter cw = new ClassWriter(false);\n");
232         text.add("FieldVisitor fv;\n");
233         text.add("MethodVisitor mv;\n");
234         text.add("AnnotationVisitor av0;\n");
235         text.add("TypeAnnotationVisitor xav0;\n\n");
236 
237         buf.setLength(0);
238         buf.append("cw.visit(");
239         switch (version) {
240             case Opcodes.V1_1:
241                 buf.append("V1_1");
242                 break;
243             case Opcodes.V1_2:
244                 buf.append("V1_2");
245                 break;
246             case Opcodes.V1_3:
247                 buf.append("V1_3");
248                 break;
249             case Opcodes.V1_4:
250                 buf.append("V1_4");
251                 break;
252             case Opcodes.V1_5:
253                 buf.append("V1_5");
254                 break;
255             case Opcodes.V1_6:
256                 buf.append("V1_6");
257                 break;
258             default:
259                 buf.append(version);
260                 break;
261         }
262         buf.append(", ");
263         appendAccess(access | ACCESS_CLASS);
264         buf.append(", ");
265         appendConstant(name);
266         buf.append(", ");
267         appendConstant(signature);
268         buf.append(", ");
269         appendConstant(superName);
270         buf.append(", ");
271         if (interfaces != null && interfaces.length > 0) {
272             buf.append("new String[] {");
273             for (int i = 0; i < interfaces.length; ++i) {
274                 buf.append(i == 0 ? " " : ", ");
275                 appendConstant(interfaces[i]);
276             }
277             buf.append(" }");
278         } else {
279             buf.append("null");
280         }
281         buf.append(");\n\n");
282         text.add(buf.toString());
283     }
284 
visitSource(final String file, final String debug)285     public void visitSource(final String file, final String debug) {
286         buf.setLength(0);
287         buf.append("cw.visitSource(");
288         appendConstant(file);
289         buf.append(", ");
290         appendConstant(debug);
291         buf.append(");\n\n");
292         text.add(buf.toString());
293     }
294 
visitOuterClass( final String owner, final String name, final String desc)295     public void visitOuterClass(
296         final String owner,
297         final String name,
298         final String desc)
299     {
300         buf.setLength(0);
301         buf.append("cw.visitOuterClass(");
302         appendConstant(owner);
303         buf.append(", ");
304         appendConstant(name);
305         buf.append(", ");
306         appendConstant(desc);
307         buf.append(");\n\n");
308         text.add(buf.toString());
309     }
310 
visitInnerClass( final String name, final String outerName, final String innerName, final int access)311     public void visitInnerClass(
312         final String name,
313         final String outerName,
314         final String innerName,
315         final int access)
316     {
317         buf.setLength(0);
318         buf.append("cw.visitInnerClass(");
319         appendConstant(name);
320         buf.append(", ");
321         appendConstant(outerName);
322         buf.append(", ");
323         appendConstant(innerName);
324         buf.append(", ");
325         appendAccess(access | ACCESS_INNER);
326         buf.append(");\n\n");
327         text.add(buf.toString());
328     }
329 
visitField( final int access, final String name, final String desc, final String signature, final Object value)330     public FieldVisitor visitField(
331         final int access,
332         final String name,
333         final String desc,
334         final String signature,
335         final Object value)
336     {
337         buf.setLength(0);
338         buf.append("{\n");
339         buf.append("fv = cw.visitField(");
340         appendAccess(access | ACCESS_FIELD);
341         buf.append(", ");
342         appendConstant(name);
343         buf.append(", ");
344         appendConstant(desc);
345         buf.append(", ");
346         appendConstant(signature);
347         buf.append(", ");
348         appendConstant(value);
349         buf.append(");\n");
350         text.add(buf.toString());
351         ASMifierFieldVisitor aav = new ASMifierFieldVisitor();
352         text.add(aav.getText());
353         text.add("}\n");
354         return aav;
355     }
356 
visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions)357     public MethodVisitor visitMethod(
358         final int access,
359         final String name,
360         final String desc,
361         final String signature,
362         final String[] exceptions)
363     {
364         buf.setLength(0);
365         buf.append("{\n");
366         buf.append("mv = cw.visitMethod(");
367         appendAccess(access);
368         buf.append(", ");
369         appendConstant(name);
370         buf.append(", ");
371         appendConstant(desc);
372         buf.append(", ");
373         appendConstant(signature);
374         buf.append(", ");
375         if (exceptions != null && exceptions.length > 0) {
376             buf.append("new String[] {");
377             for (int i = 0; i < exceptions.length; ++i) {
378                 buf.append(i == 0 ? " " : ", ");
379                 appendConstant(exceptions[i]);
380             }
381             buf.append(" }");
382         } else {
383             buf.append("null");
384         }
385         buf.append(");\n");
386         text.add(buf.toString());
387         ASMifierMethodVisitor acv = new ASMifierMethodVisitor();
388         text.add(acv.getText());
389         text.add("}\n");
390         return acv;
391     }
392 
visitAnnotation( final String desc, final boolean visible)393     public AnnotationVisitor visitAnnotation(
394         final String desc,
395         final boolean visible)
396     {
397         buf.setLength(0);
398         buf.append("{\n");
399         buf.append("av0 = cw.visitAnnotation(");
400         appendConstant(desc);
401         buf.append(", ");
402         buf.append(visible);
403         buf.append(");\n");
404         text.add(buf.toString());
405         ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
406         text.add(av.getText());
407         text.add("}\n");
408         return av;
409     }
410 
visitTypeAnnotation( final String desc, final boolean visible, final boolean inCode)411     public TypeAnnotationVisitor visitTypeAnnotation(
412         final String desc,
413         final boolean visible,
414         final boolean inCode)
415     {
416       buf.setLength(0);
417       buf.append("{\n");
418       buf.append("xav0 = cw.visitTypeAnnotation(");
419       appendConstant(desc);
420       buf.append(", ");
421       buf.append(visible);
422       buf.append(", ");
423       buf.append(inCode);
424       buf.append(");\n");
425       text.add(buf.toString());
426       ASMifierTypeAnnotationVisitor xav =
427         new ASMifierTypeAnnotationVisitor(0);
428       text.add(xav.getText());
429       text.add("}\n");
430       return xav;
431     }
432 
visitEnd()433     public void visitEnd() {
434         text.add("cw.visitEnd();\n\n");
435         text.add("return cw.toByteArray();\n");
436         text.add("}\n");
437         text.add("}\n");
438         printList(pw, text);
439         pw.flush();
440     }
441 
442     // ------------------------------------------------------------------------
443     // Utility methods
444     // ------------------------------------------------------------------------
445 
446     /**
447      * Appends a string representation of the given access modifiers to {@link
448      * #buf buf}.
449      *
450      * @param access some access modifiers.
451      */
appendAccess(final int access)452     void appendAccess(final int access) {
453         boolean first = true;
454         if ((access & Opcodes.ACC_PUBLIC) != 0) {
455             buf.append("ACC_PUBLIC");
456             first = false;
457         }
458         if ((access & Opcodes.ACC_PRIVATE) != 0) {
459             if (!first) {
460                 buf.append(" + ");
461             }
462             buf.append("ACC_PRIVATE");
463             first = false;
464         }
465         if ((access & Opcodes.ACC_PROTECTED) != 0) {
466             if (!first) {
467                 buf.append(" + ");
468             }
469             buf.append("ACC_PROTECTED");
470             first = false;
471         }
472         if ((access & Opcodes.ACC_FINAL) != 0) {
473             if (!first) {
474                 buf.append(" + ");
475             }
476             buf.append("ACC_FINAL");
477             first = false;
478         }
479         if ((access & Opcodes.ACC_STATIC) != 0) {
480             if (!first) {
481                 buf.append(" + ");
482             }
483             buf.append("ACC_STATIC");
484             first = false;
485         }
486         if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
487             if (!first) {
488                 buf.append(" + ");
489             }
490             if ((access & ACCESS_CLASS) != 0) {
491                 buf.append("ACC_SUPER");
492             } else {
493                 buf.append("ACC_SYNCHRONIZED");
494             }
495             first = false;
496         }
497         if ((access & Opcodes.ACC_VOLATILE) != 0
498                 && (access & ACCESS_FIELD) != 0)
499         {
500             if (!first) {
501                 buf.append(" + ");
502             }
503             buf.append("ACC_VOLATILE");
504             first = false;
505         }
506         if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0
507                 && (access & ACCESS_FIELD) == 0)
508         {
509             if (!first) {
510                 buf.append(" + ");
511             }
512             buf.append("ACC_BRIDGE");
513             first = false;
514         }
515         if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
516                 && (access & ACCESS_FIELD) == 0)
517         {
518             if (!first) {
519                 buf.append(" + ");
520             }
521             buf.append("ACC_VARARGS");
522             first = false;
523         }
524         if ((access & Opcodes.ACC_TRANSIENT) != 0
525                 && (access & ACCESS_FIELD) != 0)
526         {
527             if (!first) {
528                 buf.append(" + ");
529             }
530             buf.append("ACC_TRANSIENT");
531             first = false;
532         }
533         if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
534                 && (access & ACCESS_FIELD) == 0)
535         {
536             if (!first) {
537                 buf.append(" + ");
538             }
539             buf.append("ACC_NATIVE");
540             first = false;
541         }
542         if ((access & Opcodes.ACC_ENUM) != 0
543                 && ((access & ACCESS_CLASS) != 0
544                         || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0))
545         {
546             if (!first) {
547                 buf.append(" + ");
548             }
549             buf.append("ACC_ENUM");
550             first = false;
551         }
552         if ((access & Opcodes.ACC_ANNOTATION) != 0
553                 && ((access & ACCESS_CLASS) != 0))
554         {
555             if (!first) {
556                 buf.append(" + ");
557             }
558             buf.append("ACC_ANNOTATION");
559             first = false;
560         }
561         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
562             if (!first) {
563                 buf.append(" + ");
564             }
565             buf.append("ACC_ABSTRACT");
566             first = false;
567         }
568         if ((access & Opcodes.ACC_INTERFACE) != 0) {
569             if (!first) {
570                 buf.append(" + ");
571             }
572             buf.append("ACC_INTERFACE");
573             first = false;
574         }
575         if ((access & Opcodes.ACC_STRICT) != 0) {
576             if (!first) {
577                 buf.append(" + ");
578             }
579             buf.append("ACC_STRICT");
580             first = false;
581         }
582         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
583             if (!first) {
584                 buf.append(" + ");
585             }
586             buf.append("ACC_SYNTHETIC");
587             first = false;
588         }
589         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
590             if (!first) {
591                 buf.append(" + ");
592             }
593             buf.append("ACC_DEPRECATED");
594             first = false;
595         }
596         if (first) {
597             buf.append("0");
598         }
599     }
600 
601     /**
602      * Appends a string representation of the given constant to the given
603      * buffer.
604      *
605      * @param buf a string buffer.
606      * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float
607      *        Float}, {@link java.lang.Long Long},
608      *        {@link java.lang.Double Double} or {@link String String} object.
609      *        May be <tt>null</tt>.
610      */
appendConstant(final StringBuffer buf, final Object cst)611     static void appendConstant(final StringBuffer buf, final Object cst) {
612         if (cst == null) {
613             buf.append("null");
614         } else if (cst instanceof String) {
615             AbstractVisitor.appendString(buf, (String) cst);
616         } else if (cst instanceof Type) {
617             buf.append("Type.getType(\"")
618                     .append(((Type) cst).getDescriptor())
619                     .append("\")");
620         } else if (cst instanceof Integer) {
621             buf.append("new Integer(").append(cst).append(")");
622         } else if (cst instanceof Float) {
623             buf.append("new Float(\"").append(cst).append("\")");
624         } else if (cst instanceof Long) {
625             buf.append("new Long(").append(cst).append("L)");
626         } else if (cst instanceof Double) {
627             buf.append("new Double(\"").append(cst).append("\")");
628         }
629     }
630 }
631