You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bcel-dev@jakarta.apache.org by md...@apache.org on 2002/03/12 18:52:00 UTC

cvs commit: jakarta-bcel/src/java/org/apache/bcel/util BCELFactory.java BCELifier.java

mdahm       02/03/12 09:52:00

  Added:       src/java/org/apache/bcel/util BCELFactory.java
                        BCELifier.java
  Log:
  Generate BCEL-Java code from class
  
  Revision  Changes    Path
  1.1                  jakarta-bcel/src/java/org/apache/bcel/util/BCELFactory.java
  
  Index: BCELFactory.java
  ===================================================================
  package org.apache.bcel.util;
  
  import org.apache.bcel.generic.*;
  import org.apache.bcel.classfile.Utility;
  import org.apache.bcel.Constants;
  import java.io.PrintWriter;
  import java.util.*;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache BCEL" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache BCEL", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
   * ITS 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.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /**
   * Factory creates il.append() statements, and sets instruction targets.
   * A helper class for BCELifier.
   *
   * @see BCELifier
   * @version $Id: BCELFactory.java,v 1.1 2002/03/12 17:52:00 mdahm Exp $
   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
   */
  class BCELFactory extends EmptyVisitor {
    private MethodGen       _mg;
    private PrintWriter     _out;
    private ConstantPoolGen _cp;
  
    BCELFactory(MethodGen mg, PrintWriter out) {
      _mg  = mg;
      _cp  = mg.getConstantPool();
      _out = out;
    }
  
    private HashMap branch_map = new HashMap(); // Map<Instruction, InstructionHandle>
  
    public void start() {
      for(InstructionHandle ih = _mg.getInstructionList().getStart();
  	ih != null; ih = ih.getNext()) {
        Instruction i = ih.getInstruction();
  
        if(i instanceof BranchInstruction) {
  	branch_map.put(i, ih); // memorize container
        }
  
        if(ih.hasTargeters()) {
  	if(i instanceof BranchInstruction) {
  	  _out.println("    InstructionHandle ih_" + ih.getPosition() + ";");
  	} else {
  	  _out.print("    InstructionHandle ih_" + ih.getPosition() + " = ");
  	}
        } else {
  	_out.print("    ");
        }
  
        if(!visitInstruction(i))
  	i.accept(this);
      }
  
      updateBranchTargets();
      updateExceptionHandlers();
    }
  
    private boolean visitInstruction(Instruction i) {
      short opcode = i.getOpcode();
      
      if((InstructionConstants.INSTRUCTIONS[opcode] != null) &&
         !(i instanceof ConstantPushInstruction) &&
         !(i instanceof ReturnInstruction)) { // Handled below
        _out.println("il.append(InstructionConstants." +
  		   i.getName().toUpperCase() + ");");
        return true;
      }
  
      return false;
    }
  
    public void visitLocalVariableInstruction(LocalVariableInstruction i) {
      short  opcode = i.getOpcode();
      Type   type   = i.getType(_cp);
  
      if(opcode == Constants.IINC) {
      _out.println("il.append(new IINC(" + i.getIndex() + ", " +
  		 ((IINC)i).getIncrement() + "));");
      } else {
        String kind   = (opcode < Constants.ISTORE)? "Load" : "Store";
        _out.println("il.append(_factory.create" + kind + "(" +
  		   BCELifier.printType(type) + ", " +
  		   i.getIndex() + "));");
      }
    }
  
    public void visitArrayInstruction(ArrayInstruction i) {
      short  opcode = i.getOpcode();
      Type   type   = i.getType(_cp);
      String kind   = (opcode < Constants.IASTORE)? "Load" : "Store";
  
      _out.println("il.append(_factory.createArray" + kind + "(" +
  		 BCELifier.printType(type) + "));");
    }
  
    public void visitFieldInstruction(FieldInstruction i) {
      short  opcode = i.getOpcode();
  
      String class_name = i.getClassName(_cp);
      String field_name = i.getFieldName(_cp);
      Type   type       = i.getFieldType(_cp);
  
      _out.println("il.append(_factory.createFieldAccess(\"" +
  		 class_name + "\", \"" + field_name + "\", " +
  		 BCELifier.printType(type) + ", " +
  		 "Constants." + Constants.OPCODE_NAMES[opcode].toUpperCase() +
  		 "));");
    }
  
    public void visitInvokeInstruction(InvokeInstruction i) {
      short  opcode      = i.getOpcode();
      String class_name  = i.getClassName(_cp);
      String method_name = i.getMethodName(_cp);
      Type   type        = i.getReturnType(_cp);
      Type[] arg_types   = i.getArgumentTypes(_cp);
  
      _out.println("il.append(_factory.createInvoke(\"" +
  		 class_name + "\", \"" + method_name + "\", " +
  		 BCELifier.printType(type) + ", " +
  		 BCELifier.printArgumentTypes(arg_types) + ", " +
  		 "Constants." + Constants.OPCODE_NAMES[opcode].toUpperCase() +
  		 "));");
    }
  
    public void visitAllocationInstruction(AllocationInstruction i) {
      CPInstruction in     = (CPInstruction)i;
      Type          type   = in.getType(_cp);
      short         opcode = in.getOpcode();
      int           dim    = 1;
  
      switch(opcode) {
      case Constants.NEW:
        _out.println("il.append(_factory.createNew(\"" +
  		   ((ObjectType)type).getClassName() + "\"));");
        break;
  
      case Constants.MULTIANEWARRAY:
        dim = ((MULTIANEWARRAY)i).getDimensions();
  
      case Constants.ANEWARRAY:
      case Constants.NEWARRAY:
        _out.println("il.append(_factory.createNewArray(\"" +
  		   BCELifier.printType(type) + ", " + dim + "));");
        break;
  
      default:
        throw new RuntimeException("Oops: " + opcode);
      }
    }
  
    private void createConstant(Object value) {
      String embed = value.toString();
  
      if(value instanceof String)
        embed = '"' + Utility.convertString(value.toString()) + '"';
      else if(value instanceof Character)
        embed = "(char)0x" + Integer.toHexString(((Character)value).charValue());
  
      _out.println("il.append(new PUSH(_cp, " + embed + "));");
    }
  
    public void visitLDC(LDC i) {
      createConstant(i.getValue(_cp));
    }
  
    public void visitLDC2_W(LDC2_W i) {
      createConstant(i.getValue(_cp));
    }
  
    public void visitConstantPushInstruction(ConstantPushInstruction i) {
      createConstant(i.getValue());
    }
  
    public void visitINSTANCEOF(INSTANCEOF i) {
      Type type = i.getType(_cp);
  
      _out.println("il.append(new INSTANCEOF(_cp.addClass(" +
  		 BCELifier.printType(type) + ")));");
    }
  
    public void visitCHECKCAST(CHECKCAST i) {
      Type type = i.getType(_cp);
  
      _out.println("il.append(_factory.createCheckCast(" +
  		 BCELifier.printType(type) + "));");
    }
  
    public void visitReturnInstruction(ReturnInstruction i) {
      Type type = i.getType(_cp);
  
      _out.println("il.append(_factory.createReturn(" +
  		 BCELifier.printType(type) + "));");
    }
  
    // Memorize BranchInstructions that need an update
    private ArrayList branches = new ArrayList();
  
    public void visitBranchInstruction(BranchInstruction bi) {
      BranchHandle bh   = (BranchHandle)branch_map.get(bi);
      int          pos  = bh.getPosition();
      String       name = bi.getName() + "_" + pos;
  
      if(bi instanceof Select) {
        Select s = (Select)bi;
        branches.add(bi);
  
        StringBuffer args   = new StringBuffer("new int[] { ");
        int[]        matchs = s.getMatchs();
  
        for(int i=0; i < matchs.length; i++) {
  	args.append(matchs[i]);
  
  	if(i < matchs.length - 1)
  	  args.append(", ");
        }
  
        args.append(" }");
        
        _out.print("    Select " + name + " = new " +
  		 bi.getName().toUpperCase() + "(" + args +
  		 ", new InstructionHandle[] { ");
  	
        for(int i=0; i < matchs.length; i++) {
  	_out.print("null");
  	
  	if(i < matchs.length - 1)
  	  _out.print(", ");
        } 
  
        _out.println(");");
      } else {
        int    t_pos  = bh.getTarget().getPosition();
        String target;
  
        if(pos > t_pos) {
  	target = "ih_" + t_pos;
        } else {
  	branches.add(bi);
  	target = "null";
        }
  
        _out.println("    BranchInstruction " + name +
  		   " = _factory.createBranchInstruction(" +
  		   "Constants." + bi.getName().toUpperCase() + ", " +
  		   target + ");");
      }  
  
      if(bh.hasTargeters())
        _out.println("    ih_" + pos + " = il.append(" + name + ");");
      else
        _out.println("    il.append(" + name + ");");
    }
  
    public void visitRET(RET i) {
      _out.println("il.append(new RET(" + i.getIndex() + ")));");
    }
  
    private void updateBranchTargets() {
      for(Iterator i = branches.iterator(); i.hasNext(); ) {
        BranchInstruction bi    = (BranchInstruction)i.next();
        BranchHandle      bh    = (BranchHandle)branch_map.get(bi);
        int               pos   = bh.getPosition();
        String            name  = bi.getName() + "_" + pos;
        int               t_pos = bh.getTarget().getPosition();
  
        _out.println("    " + name + ".setTarget(ih_" + t_pos + ");");
  
        if(bi instanceof Select) {
  	InstructionHandle[] ihs = ((Select)bi).getTargets();
  
  	for(int j = 0; j < ihs.length; j++) {
  	  t_pos = ihs[j].getPosition();
  
  	  _out.println("    " + name + ".setTarget(" + j +
  		       ", ih_" + t_pos + ");");
  	}
        }
      }
    }
  
    private void updateExceptionHandlers() {
      CodeExceptionGen[] handlers = _mg.getExceptionHandlers();
  
      for(int i=0; i < handlers.length; i++) {
        CodeExceptionGen h = handlers[i];
  
        _out.println("    method.addExceptionHandler(" +
  		   "ih_" + h.getStartPC().getPosition() + ", " +
  		   "ih_" + h.getEndPC().getPosition() + ", " +
  		   "ih_" + h.getHandlerPC().getPosition() + ", " +
  		   BCELifier.printType(h.getCatchType()) + ");");
      }
    }
  }
  
  
  
  1.1                  jakarta-bcel/src/java/org/apache/bcel/util/BCELifier.java
  
  Index: BCELifier.java
  ===================================================================
  package org.apache.bcel.util;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache BCEL" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache BCEL", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
   * ITS 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.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  import org.apache.bcel.classfile.*;
  import org.apache.bcel.generic.*;
  import org.apache.bcel.Repository;
  import org.apache.bcel.Constants;
  import java.io.*;
  
  /** 
   * This class takes a given JavaClass object and converts it to a
   * Java program that creates that very class using BCEL. This
   * gives new users of BCEL a useful example showing how things
   * are done with BCEL. It does not cover all features of BCEL,
   * but tries to mimic hand-written code as close as possible.
   *
   * @version $Id: BCELifier.java,v 1.1 2002/03/12 17:52:00 mdahm Exp $
   * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 
   */
  public class BCELifier extends org.apache.bcel.classfile.EmptyVisitor {
    private JavaClass         _clazz;
    private PrintWriter       _out;
    private DescendingVisitor _visitor;
    private ConstantPoolGen   _cp;
  
    /** @param clazz Java class to "decompile"
     * @param out where to output Java program
     */
    public BCELifier(JavaClass clazz, OutputStream out) {
      _clazz = clazz;
      _out = new PrintWriter(out);
      _cp = new ConstantPoolGen(_clazz.getConstantPool());
    }
  
    /** Start Java code generation
     */
    public void start() {
      visitJavaClass(_clazz);
      _out.flush();
    }
  
    public void visitJavaClass(JavaClass clazz) {
      String class_name   = clazz.getClassName();
      String super_name   = clazz.getSuperclassName();
      String package_name = clazz.getPackageName();
      String inter        = Utility.printArray(clazz.getInterfaceNames(),
  					     false, true);
  
      _out.println("import org.apache.bcel.generic.*;");
      _out.println("import org.apache.bcel.classfile.*;");
      _out.println("import org.apache.bcel.*;");
      _out.println("import java.io.*;\n");
  
      _out.println("public class " + class_name + "Creator implements Constants {");
      _out.println("  private InstructionFactory _factory;");
      _out.println("  private ConstantPoolGen   _cp;");
      _out.println("  private ClassGen          _cg;\n");
  
      _out.println("  public " + class_name  + "Creator() {");
      _out.println("    _cg = new ClassGen(\"" +
  		 (("".equals(package_name))? class_name :
  		  package_name + "." + class_name) +
  		 "\", \"" + super_name + "\", " +
  		 "\"" + clazz.getSourceFileName() + "\", " +
  		 printFlags(clazz.getAccessFlags(), true) + ", " +
  		 "new String[] { " + inter + " });\n");
  
      _out.println("    _cp = _cg.getConstantPool();");
      _out.println("    _factory = new InstructionFactory(_cg, _cp);");
      _out.println("  }\n");
  
      printCreate();
  
      Field[] fields = clazz.getFields();
  
      if(fields.length > 0) {
        _out.println("  private void createFields() {");   
        _out.println("    FieldGen field;");
  
        for(int i=0; i < fields.length; i++) {
  	fields[i].accept(this);
        }
  
        _out.println("  }\n");   
      }
  
      Method[] methods = clazz.getMethods();
  
      for(int i=0; i < methods.length; i++) {
        _out.println("  private void createMethod_" + i + "() {");   
  
        methods[i].accept(this);
        _out.println("  }\n");   
      }
  
      printMain();
      _out.println("}");
    }
    
    private void printCreate() {
      _out.println("  public void create(OutputStream out) throws IOException {");
  
      Field[] fields = _clazz.getFields();
      if(fields.length > 0) {
        _out.println("    createFields();");   
      }
  
      Method[] methods = _clazz.getMethods();
      for(int i=0; i < methods.length; i++) {
        _out.println("    createMethod_" + i + "();");   
      }
  
      _out.println("    _cg.getJavaClass().dump(out);");   
    
      _out.println("  }\n");     
    }
  
    private void printMain() {
      String   class_name   = _clazz.getClassName();
      
      _out.println("  public static void main(String[] args) throws Exception {");
      _out.println("    " + class_name + "Creator creator = new " +
  		 class_name + "Creator();");
      _out.println("    creator.create(new FileOutputStream(\"" + class_name +
  		 ".class\"));");
      _out.println("  }");     
    }
  
    public void visitField(Field field) {
      _out.println("\n    field = new FieldGen(" +
  		 printFlags(field.getAccessFlags()) +
  		 ", " + printType(field.getSignature()) + ", \"" +
  		 field.getName() + "\", _cp);");
  
      ConstantValue cv = field.getConstantValue();
  
      if(cv != null) {
        String value = cv.toString();
        _out.println("    field.setInitValue(" + value + ")");
      }
  
      _out.println("    _cg.addField(field.getField());");
    }
  
    public void visitMethod(Method method) {
      MethodGen mg = new MethodGen(method, _clazz.getClassName(), _cp);
  
      Type   result_type = mg.getReturnType();
      Type[] arg_types   = mg.getArgumentTypes();
  
      _out.println("    InstructionList il = new InstructionList();");
      _out.println("    MethodGen method = new MethodGen(" +
  		 printFlags(method.getAccessFlags()) +
  		 ", " + printType(result_type) +
  		 ", " + printArgumentTypes(arg_types) + ", " +
  		 "new String[] { " +
  		 Utility.printArray(mg.getArgumentNames(), false, true) +
  		 " }, \"" + method.getName() + "\", \"" +
  		 _clazz.getClassName() + "\", il, _cp);\n");
      
      BCELFactory factory = new BCELFactory(mg, _out);
      factory.start();
  
      _out.println("    method.setMaxStack();");
      _out.println("    method.setMaxLocals();");
      _out.println("    _cg.addMethod(method.getMethod());");
      _out.println("    il.dispose();");
    }
  
    static String printFlags(int flags) {
      return printFlags(flags, false);
    }
  
    static String printFlags(int flags, boolean for_class) {
      if(flags == 0)
        return "0";
  
      StringBuffer buf = new StringBuffer();
      for(int i=0, pow=1; i <= Constants.MAX_ACC_FLAG; i++) {
        if((flags & pow) != 0) {
  	if((pow == Constants.ACC_SYNCHRONIZED) && for_class)
  	  buf.append("ACC_SUPER | ");
  	else
  	  buf.append("ACC_" + Constants.ACCESS_NAMES[i].toUpperCase() + " | ");
        }
  
        pow <<= 1;
      }
  
      String str = buf.toString();
      return str.substring(0, str.length() - 3);
    }
  
    static String printArgumentTypes(Type[] arg_types) {
      if(arg_types.length == 0)
        return "Type.NO_ARGS";
  
      StringBuffer args = new StringBuffer();
  
      for(int i=0; i < arg_types.length; i++) {
        args.append(printType(arg_types[i]));
  
        if(i < arg_types.length - 1)
  	args.append(", ");
      }
  
      return "new Type[] { " + args.toString() + " }";
    }
  
    static String printType(Type type) {
      return printType(type.getSignature());
    }
  
    static String printType(String signature) {
      Type type = Type.getType(signature);
      byte t    = type.getType();
  
      if(t <= Constants.T_VOID) {
        return "Type." + Constants.TYPE_NAMES[t].toUpperCase();
      } else if(type.toString().equals("java.lang.String")) {
        return "Type.STRING";
      } else if(type.toString().equals("java.lang.Object")) {
        return "Type.OBJECT";
      } else if(type.toString().equals("java.lang.StringBuffer")) {
        return "Type.STRINGBUFFER";
      } else if(type instanceof ArrayType) {
        ArrayType at = (ArrayType)type;
  
        return "new ArrayType(" + printType(at.getBasicType()) +
  	", " + at.getDimensions() + ")";
      } else {
        return "new ObjectType(\"" + Utility.signatureToString(signature, false) +
  	"\")";
      }
    }
  
    /** Default main method
     */
    public static void main(String[] argv) throws Exception {
      JavaClass java_class;
      String    name = argv[0];
  
      if((java_class = Repository.lookupClass(name)) == null)
        java_class = new ClassParser(name).parse(); // May throw IOException
  
      BCELifier bcelifier = new BCELifier(java_class, System.out);
      bcelifier.start();
    }
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>