All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.toplink.libraries.asm.util.ASMifierClassVisitor Maven / Gradle / Ivy

The newest version!
/***
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000,2002,2003 INRIA, France Telecom 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package oracle.toplink.libraries.asm.util;

import java.io.FileInputStream;
import java.io.PrintWriter;

import oracle.toplink.libraries.asm.Attribute;
import oracle.toplink.libraries.asm.ClassReader;
import oracle.toplink.libraries.asm.CodeVisitor;
import oracle.toplink.libraries.asm.Constants;
import oracle.toplink.libraries.asm.Type;
import oracle.toplink.libraries.asm.util.attrs.ASMifiable;

/**
 * A {@link PrintClassVisitor PrintClassVisitor} that prints the ASM code that
 * generates the classes it visits. This class visitor can be used to quickly
 * write ASM code to generate some given bytecode:
 * 
    *
  • write the Java source code equivalent to the bytecode you want to * generate;
  • *
  • compile it with javac;
  • *
  • make a {@link ASMifierClassVisitor} visit this compiled * class (see the {@link #main main} method);
  • *
  • edit the generated source code, if necessary.
  • *
* The source code printed when visiting the Hello class is the * following: *

*

*
 * import oracle.toplink.libraries.asm.*;
 * import java.io.FileOutputStream;
 *
 * public class Dump implements Constants {
 *
 * public static void main (String[] args) throws Exception {
 *
 * ClassWriter cw = new ClassWriter(false);
 * CodeVisitor cv;
 *
 * cw.visit(ACC_PUBLIC + ACC_SUPER, "Hello", "java/lang/Object", null, "Hello.java");
 *
 * {
 * cv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
 * cv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 * cv.visitLdcInsn("hello");
 * cv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
 * cv.visitInsn(RETURN);
 * cv.visitMaxs(2, 1);
 * }
 * {
 * cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 * cv.visitVarInsn(ALOAD, 0);
 * cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
 * cv.visitInsn(RETURN);
 * cv.visitMaxs(1, 1);
 * }
 * cw.visitEnd();
 *
 * FileOutputStream os = new FileOutputStream("Dumped.class");
 * os.write(cw.toByteArray());
 * os.close();
 * }
 * }
 * 
*
* where Hello is defined by: *

*

*
 * public class Hello {
 *
 *   public static void main (String[] args) {
 *     System.out.println("hello");
 *   }
 * }
 * 
*
* * @author Eric Bruneton, Eugene Kuleshov */ public class ASMifierClassVisitor extends PrintClassVisitor { private static final int ACCESS_CLASS = 262144; private static final int ACCESS_FIELD = 524288; private static final int ACCESS_INNER = 1048576; /** * Prints the ASM source code to generate the given class to the standard * output. *

* Usage: ASMifierClassVisitor [-debug] * <fully qualified class name or class file name> * * @param args the command line arguments. * * @throws Exception if the class cannot be found, or if an IO exception * occurs. */ public static void main (final String[] args) throws Exception { if (args.length < 1 || args.length > 2) { printUsage(); } int i = 0; boolean skipDebug = true; if (args[0].equals("-debug")) { i = 1; skipDebug = false; if (args.length != 2) { printUsage(); } } ClassReader cr; if (args[i].endsWith(".class")) { cr = new ClassReader(new FileInputStream(args[i])); } else { cr = new ClassReader(args[i]); } cr.accept(new ASMifierClassVisitor( new PrintWriter(System.out)), getDefaultAttributes(), skipDebug); } private static void printUsage () { System.err.println("Prints the ASM code to generate the given class."); System.err.println("Usage: ASMifierClassVisitor [-debug] " + ""); System.exit(-1); } /** * Constructs a new {@link ASMifierClassVisitor} object. * * @param pw the print writer to be used to print the class. */ public ASMifierClassVisitor (final PrintWriter pw) { super(pw); } public void visit ( final int version, final int access, final String name, final String superName, final String[] interfaces, final String sourceFile) { int n = name.lastIndexOf( "/"); if( n>-1) { text.add("package asm."+name.substring( 0, n).replace( '/', '.')+";\n"); } text.add("import oracle.toplink.libraries.asm.*;\n"); text.add("import oracle.toplink.libraries.asm.attrs.*;\n"); text.add("import java.util.*;\n\n"); text.add("public class "+(n==-1 ? name : name.substring( n+1))+"Dump implements Constants {\n\n"); text.add("public static byte[] dump () throws Exception {\n\n"); text.add("ClassWriter cw = new ClassWriter(false);\n"); text.add("CodeVisitor cv;\n\n"); buf.setLength(0); buf.append("cw.visit("); switch(version) { case Constants.V1_1: buf.append("V1_1"); break; case Constants.V1_2: buf.append("V1_2"); break; case Constants.V1_3: buf.append("V1_3"); break; case Constants.V1_4: buf.append("V1_4"); break; case Constants.V1_5: buf.append("V1_5"); break; default: buf.append(version); break; } buf.append(", "); appendAccess(access | ACCESS_CLASS); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, superName); buf.append(", "); if (interfaces != null && interfaces.length > 0) { buf.append("new String[] {"); for (int i = 0; i < interfaces.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(buf, interfaces[i]); } buf.append(" }"); } else { buf.append("null"); } buf.append(", "); appendConstant(buf, sourceFile); buf.append(");\n\n"); text.add(buf.toString()); } public void visitInnerClass ( final String name, final String outerName, final String innerName, final int access) { buf.setLength(0); buf.append("cw.visitInnerClass("); appendConstant(buf, name); buf.append(", "); appendConstant(buf, outerName); buf.append(", "); appendConstant(buf, innerName); buf.append(", "); appendAccess(access | ACCESS_INNER); buf.append(");\n\n"); text.add(buf.toString()); } public void visitField ( final int access, final String name, final String desc, final Object value, final Attribute attrs) { buf.setLength(0); int n = 1; if (attrs != null) { buf.append("{\n"); buf.append("// FIELD ATTRIBUTES\n"); Attribute a = attrs; while (a != null) { if (a instanceof ASMifiable) { ((ASMifiable)a).asmify(buf, "fieldAttrs" + n, null); if (n > 1) { buf.append("fieldAttrs" + (n - 1) + " = fieldAttrs" + n + ";\n"); } n++; } else { buf.append("// WARNING! skipped non standard field attribute of type "); buf.append(a.type).append("\n"); } a = a.next; } } buf.append("cw.visitField("); appendAccess(access | ACCESS_FIELD); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, desc); buf.append(", "); appendConstant(buf, value); if (n==1) { buf.append(", null);\n\n"); } else { buf.append(", fieldAttrs1);\n"); buf.append("}\n\n"); } text.add(buf.toString()); } public CodeVisitor visitMethod ( final int access, final String name, final String desc, final String[] exceptions, final Attribute attrs) { buf.setLength(0); buf.append("{\n"); int n = 1; if (attrs != null) { buf.append("// METHOD ATTRIBUTES\n"); Attribute a = attrs; while (a != null) { if (a instanceof ASMifiable) { ((ASMifiable)a).asmify(buf, "methodAttrs" + n, null); if (n > 1) { buf.append("methodAttrs" + (n - 1) + ".next = methodAttrs" + n + ";\n"); } n++; } else { buf.append("// WARNING! skipped non standard method attribute of type "); buf.append(a.type).append("\n"); } a = a.next; } } buf.append("cv = cw.visitMethod("); appendAccess(access); buf.append(", "); appendConstant(buf, name); buf.append(", "); appendConstant(buf, desc); buf.append(", "); if (exceptions != null && exceptions.length > 0) { buf.append("new String[] {"); for (int i = 0; i < exceptions.length; ++i) { buf.append(i == 0 ? " " : ", "); appendConstant(buf, exceptions[i]); } buf.append(" }"); } else { buf.append("null"); } if (n==1) { buf.append(", null);\n"); } else { buf.append(", methodAttrs1);\n"); } text.add(buf.toString()); PrintCodeVisitor pcv = new ASMifierCodeVisitor(); text.add(pcv.getText()); text.add("}\n"); return pcv; } public void visitAttribute (final Attribute attr) { buf.setLength(0); if (attr instanceof ASMifiable) { buf.append("{\n"); buf.append("// CLASS ATRIBUTE\n"); ((ASMifiable)attr).asmify(buf, "attr", null); buf.append("cw.visitAttribute(attr);\n"); buf.append("}\n"); } else { buf.append("// WARNING! skipped a non standard class attribute of type \""); buf.append(attr.type).append("\"\n"); } text.add(buf.toString()); } public void visitEnd () { text.add("cw.visitEnd();\n\n"); // text.add("FileOutputStream os = new FileOutputStream(\"Dumped.class\");\n"); // text.add("os.write(cw.toByteArray());\n"); // text.add("os.close();\n"); text.add("return cw.toByteArray();\n"); text.add("}\n"); text.add("}\n"); super.visitEnd(); } /** * Appends a string representation of the given access modifiers to {@link * #buf buf}. * * @param access some access modifiers. */ void appendAccess (final int access) { boolean first = true; if ((access & Constants.ACC_PUBLIC) != 0) { buf.append("ACC_PUBLIC"); first = false; } if ((access & Constants.ACC_PRIVATE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_PRIVATE"); first = false; } if ((access & Constants.ACC_PROTECTED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_PROTECTED"); first = false; } if ((access & Constants.ACC_FINAL) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_FINAL"); first = false; } if ((access & Constants.ACC_STATIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STATIC"); first = false; } if ((access & Constants.ACC_SYNCHRONIZED) != 0) { if (!first) { buf.append(" + "); } if ((access & ACCESS_CLASS) != 0) { buf.append("ACC_SUPER"); } else { buf.append("ACC_SYNCHRONIZED"); } first = false; } if ((access & Constants.ACC_VOLATILE) != 0 && (access & ACCESS_FIELD) != 0 ) { if (!first) { buf.append(" + "); } buf.append("ACC_VOLATILE"); first = false; } if ((access & Constants.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_BRIDGE"); first = false; } if ((access & Constants.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_VARARGS"); first = false; } if ((access & Constants.ACC_TRANSIENT) != 0 && (access & ACCESS_FIELD) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_TRANSIENT"); first = false; } if ((access & Constants.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) { if (!first) { buf.append(" + "); } buf.append("ACC_NATIVE"); first = false; } if ((access & Constants.ACC_ENUM) != 0 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { if (!first) { buf.append(" + "); } buf.append("ACC_ENUM"); first = false; } if ((access & Constants.ACC_ANNOTATION) != 0 && ((access & ACCESS_CLASS) != 0)) { if (!first) { buf.append(" + "); } buf.append("ACC_ANNOTATION"); first = false; } if ((access & Constants.ACC_ABSTRACT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_ABSTRACT"); first = false; } if ((access & Constants.ACC_INTERFACE) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_INTERFACE"); first = false; } if ((access & Constants.ACC_STRICT) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_STRICT"); first = false; } if ((access & Constants.ACC_SYNTHETIC) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_SYNTHETIC"); first = false; } if ((access & Constants.ACC_DEPRECATED) != 0) { if (!first) { buf.append(" + "); } buf.append("ACC_DEPRECATED"); first = false; } if (first) { buf.append("0"); } } /** * Appends a string representation of the given constant to the given buffer. * * @param buf a string buffer. * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float * Float}, {@link java.lang.Long Long}, {@link java.lang.Double Double} * or {@link String String} object. May be null. */ static void appendConstant (final StringBuffer buf, final Object cst) { if (cst == null) { buf.append("null"); } else if (cst instanceof String) { String s = (String)cst; buf.append("\""); for (int i = 0; i < s.length(); ++i) { char c = s.charAt(i); if (c == '\n') { buf.append("\\n"); } else if (c == '\r') { buf.append("\\r"); } else if (c == '\\') { buf.append("\\\\"); } else if (c == '"') { buf.append("\\\""); } else if( c<0x20 || c>0x7f) { buf.append( "\\u"); if( c<0x10) { buf.append( "000"); } else if( c<0x100) { buf.append( "00"); } else if( c<0x1000) { buf.append( "0"); } buf.append( Integer.toString( c, 16)); } else { buf.append(c); } } buf.append("\""); } else if (cst instanceof Type) { buf.append("Type.getType(\""); buf.append(((Type)cst).getDescriptor()); buf.append("\")"); } else if (cst instanceof Integer) { buf.append("new Integer(") .append(cst) .append(")"); } else if (cst instanceof Float) { buf.append("new Float(\"") .append(cst).append("\")"); } else if (cst instanceof Long) { buf.append("new Long(") .append(cst) .append("L)"); } else if (cst instanceof Double) { buf.append("new Double(\"") .append(cst).append("\")"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy