[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