[jboss-cvs] javassist/src/main/javassist/convert ...

Jason Thomas Greene jgreene at jboss.com
Sat May 24 01:12:59 EDT 2008


  User: jgreene 
  Date: 08/05/24 01:12:59

  Modified:    src/main/javassist/convert   TransformAccessArrayField.java
                        Transformer.java
  Log:
  Fix subtypeOf in CtArray
  Introduce full data-flow analysis API
  Fix AALOAD by using data-flow analysis to determine the type
  Introduce a testsuite to the project
  Add a framedump toolp
  
  Revision  Changes    Path
  1.5       +233 -150  javassist/src/main/javassist/convert/TransformAccessArrayField.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: TransformAccessArrayField.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/convert/TransformAccessArrayField.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -b -r1.4 -r1.5
  --- TransformAccessArrayField.java	4 Jun 2007 03:11:11 -0000	1.4
  +++ TransformAccessArrayField.java	24 May 2008 05:12:59 -0000	1.5
  @@ -14,60 +14,147 @@
    */
   package javassist.convert;
   
  +import javassist.CannotCompileException;
   import javassist.CtClass;
   import javassist.NotFoundException;
   import javassist.CodeConverter.ArrayAccessReplacementMethodNames;
   import javassist.bytecode.BadBytecode;
   import javassist.bytecode.CodeIterator;
   import javassist.bytecode.ConstPool;
  +import javassist.bytecode.MethodInfo;
  +import javassist.bytecode.analysis.Analyzer;
  +import javassist.bytecode.analysis.Frame;
   
   /**
  + * A transformer which replaces array access with static method invocations.
    *  
    * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
  - * @version $Revision: 1.4 $ 
  + * @author Jason T. Greene
  + * @version $Revision: 1.5 $
    */
  -public class TransformAccessArrayField extends Transformer {
  -// CtClass componentType;
  -
  -   String methodClassname;
  -   ArrayAccessReplacementMethodNames names;
  +public final class TransformAccessArrayField extends Transformer {
  +	private final String methodClassname;
  +	private final ArrayAccessReplacementMethodNames names;
  +	private Frame[] frames;
  +	private int offset;
   
      public TransformAccessArrayField(Transformer next, String methodClassname,
  -                                    ArrayAccessReplacementMethodNames names)
  -       throws NotFoundException
  -   {
  +			ArrayAccessReplacementMethodNames names) throws NotFoundException {
          super(next);
          this.methodClassname = methodClassname;
          this.names = names;
  +
      }
   
  -   public int transform(CtClass tclazz, int pos, CodeIterator iterator,
  -                        ConstPool cp) throws BadBytecode
  -   {
  +	public void initialize(ConstPool cp, CtClass clazz, MethodInfo minfo) throws CannotCompileException {
  +	    /*
  +         * This transformer must be isolated from other transformers, since some
  +         * of them affect the local variable and stack maximums without updating
  +         * the code attribute to reflect the changes. This screws up the
  +         * data-flow analyzer, since it relies on consistent code state. Even
  +         * if the attribute values were updated correctly, we would have to
  +         * detect it, and redo analysis, which is not cheap. Instead, we are
  +         * better off doing all changes in initialize() before everyone else has
  +         * a chance to muck things up.
  +         */ 
  +        CodeIterator iterator = minfo.getCodeAttribute().iterator();
  +        while (iterator.hasNext()) {
  +            try {
  +                int pos = iterator.next();
         int c = iterator.byteAt(pos);
         
  +                if (c == AALOAD)
  +                    initFrames(clazz, minfo);
  +
         if (c == AALOAD || c == BALOAD || c == CALOAD || c == DALOAD
  -          || c == FALOAD || c == IALOAD || c == LALOAD || c == SALOAD)
  -         replace(cp, iterator, pos, c, getLoadReplacementSignature(c));
  -      else if (c == AASTORE || c == BASTORE || c == CASTORE || c == DASTORE
  -               || c == FASTORE || c == IASTORE || c == LASTORE || c == SASTORE)
  -         replace(cp, iterator, pos, c, getStoreReplacementSignature(c));
  +                        || c == FALOAD || c == IALOAD || c == LALOAD
  +                        || c == SALOAD) {
  +                    pos = replace(cp, iterator, pos, c, getLoadReplacementSignature(c));
  +                } else if (c == AASTORE || c == BASTORE || c == CASTORE
  +                        || c == DASTORE || c == FASTORE || c == IASTORE
  +                        || c == LASTORE || c == SASTORE) {
  +                    pos = replace(cp, iterator, pos, c, getStoreReplacementSignature(c));
  +                }
   
  +            } catch (Exception e) {
  +                throw new CannotCompileException(e);
  +            }
  +        }
  +    }
  +
  +	public void clean() {
  +		frames = null;
  +		offset = -1;
  +	}
  +
  +	public int transform(CtClass tclazz, int pos, CodeIterator iterator,
  +			ConstPool cp) throws BadBytecode {
  +	    // Do nothing, see above comment
         return pos;
      }
      
  -   private void replace(ConstPool cp, CodeIterator iterator,
  -                        int pos, int opcode, String signature)
  -       throws BadBytecode
  -   {
  +	private Frame getFrame(int pos) throws BadBytecode {
  +		return frames[pos - offset]; // Adjust pos
  +	}
  +
  +	private void initFrames(CtClass clazz, MethodInfo minfo) throws BadBytecode {
  +		if (frames == null) {
  +			frames = ((new Analyzer())).analyze(clazz, minfo);
  +			offset = 0; // start tracking changes
  +		}
  +	}
  +
  +	private int updatePos(int pos, int increment) {
  +		if (offset > -1)
  +			offset += increment;
  +
  +		return pos + increment;
  +	}
  +
  +	private String getTopType(int pos) throws BadBytecode {
  +	    Frame frame = getFrame(pos);
  +	    if (frame == null)
  +	        return null;
  +	    
  +	    CtClass clazz = frame.peek().getCtClass();
  +	    return clazz != null ? clazz.getName() : null;
  +	}
  +
  +	private int replace(ConstPool cp, CodeIterator iterator, int pos,
  +			int opcode, String signature) throws BadBytecode {
  +	    String castType = null;
         String methodName = getMethodName(opcode);
         if (methodName != null) {
  -         iterator.insertGap(2);
  +		    // See if the object must be cast
  +		    if (opcode == AALOAD) {
  +		        castType = getTopType(iterator.lookAhead());
  +		        // Do not replace an AALOAD instruction that we do not have a type for
  +		        // This happens when the state is guaranteed to be null (Type.UNINIT)
  +		        // So we don't really care about this case. 
  +		        if (castType == null)
  +		            return pos; 
  +		        if ("java.lang.Object".equals(castType))
  +		            castType = null;
  +		    }
  +
  +		    // The gap may include extra padding
  +		    int gapLength = iterator.insertGap(pos, castType != null ? 5 : 2);
  +			
            int mi = cp.addClassInfo(methodClassname);
            int methodref = cp.addMethodrefInfo(mi, methodName, signature);
            iterator.writeByte(INVOKESTATIC, pos);
            iterator.write16bit(methodref, pos + 1);
  +			
  +			if (castType != null) {
  +			    int index = cp.addClassInfo(castType);
  +			    iterator.writeByte(CHECKCAST, pos + 3);
  +			    iterator.write16bit(index, pos + 4);
         }
  +			
  +			pos = updatePos(pos, gapLength);
  +		}
  +
  +		return pos;
      }
   
      private String getMethodName(int opcode) {
  @@ -129,9 +216,7 @@
           return methodName;
       }
   
  -   private String getLoadReplacementSignature(int opcode)
  -       throws BadBytecode
  -   {
  +	private String getLoadReplacementSignature(int opcode) throws BadBytecode {
           switch (opcode) {
           case AALOAD:
               return "(Ljava/lang/Object;I)Ljava/lang/Object;";
  @@ -154,9 +239,7 @@
           throw new BadBytecode(opcode);
       }
      
  -   private String getStoreReplacementSignature(int opcode)
  -       throws BadBytecode
  -   {
  +	private String getStoreReplacementSignature(int opcode) throws BadBytecode {
           switch (opcode) {
           case AASTORE:
               return "(Ljava/lang/Object;ILjava/lang/Object;)V";
  
  
  
  1.8       +11 -2     javassist/src/main/javassist/convert/Transformer.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Transformer.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/convert/Transformer.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -b -r1.7 -r1.8
  --- Transformer.java	4 Jun 2007 03:11:11 -0000	1.7
  +++ Transformer.java	24 May 2008 05:12:59 -0000	1.8
  @@ -15,9 +15,14 @@
   
   package javassist.convert;
   
  -import javassist.bytecode.*;
  -import javassist.CtClass;
   import javassist.CannotCompileException;
  +import javassist.CtClass;
  +import javassist.bytecode.BadBytecode;
  +import javassist.bytecode.CodeAttribute;
  +import javassist.bytecode.CodeIterator;
  +import javassist.bytecode.ConstPool;
  +import javassist.bytecode.MethodInfo;
  +import javassist.bytecode.Opcode;
   
   /**
    * Transformer and its subclasses are used for executing
  @@ -36,6 +41,10 @@
   
       public void initialize(ConstPool cp, CodeAttribute attr) {}
   
  +    public void initialize(ConstPool cp, CtClass clazz, MethodInfo minfo) throws CannotCompileException { 
  +    	initialize(cp, minfo.getCodeAttribute());
  +    }
  +
       public void clean() {}
   
       public abstract int transform(CtClass clazz, int pos, CodeIterator it,
  
  
  



More information about the jboss-cvs-commits mailing list