diff options
author | jgreene <jgreene@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2008-06-03 03:47:18 +0000 |
---|---|---|
committer | jgreene <jgreene@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2008-06-03 03:47:18 +0000 |
commit | 55210d8936096c3625af2662ea90f23842a94182 (patch) | |
tree | 623857d4aea645b6e5fb5dc4dcb77cc8a3c2e914 | |
parent | 3ddcbaa6c71ce84e817529a3f88d52c47257afa2 (diff) | |
download | javassist-55210d8936096c3625af2662ea90f23842a94182.tar.gz javassist-55210d8936096c3625af2662ea90f23842a94182.zip |
Fix small naming bug (classinfo expects a jvm name)
Add test to catch it
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@441 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r-- | src/main/javassist/convert/TransformAccessArrayField.java | 358 | ||||
-rw-r--r-- | src/test/test/javassist/convert/ArrayAccessReplaceTest.java | 28 |
2 files changed, 207 insertions, 179 deletions
diff --git a/src/main/javassist/convert/TransformAccessArrayField.java b/src/main/javassist/convert/TransformAccessArrayField.java index 1af424ed..7ea4ffe4 100644 --- a/src/main/javassist/convert/TransformAccessArrayField.java +++ b/src/main/javassist/convert/TransformAccessArrayField.java @@ -15,39 +15,41 @@ package javassist.convert; import javassist.CannotCompileException; +import javassist.ClassPool; 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.Descriptor; 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@jboss.com">Kabir Khan</a> * @author Jason T. Greene - * @version $Revision: 1.5 $ + * @version $Revision: 1.6 $ */ public final class TransformAccessArrayField extends Transformer { - private final String methodClassname; - private final ArrayAccessReplacementMethodNames names; - private Frame[] frames; - private int offset; + private final String methodClassname; + private final ArrayAccessReplacementMethodNames names; + private Frame[] frames; + private int offset; - public TransformAccessArrayField(Transformer next, String methodClassname, - ArrayAccessReplacementMethodNames names) throws NotFoundException { - super(next); - this.methodClassname = methodClassname; - this.names = names; + public TransformAccessArrayField(Transformer next, String methodClassname, + ArrayAccessReplacementMethodNames names) throws NotFoundException { + super(next); + this.methodClassname = methodClassname; + this.names = names; - } + } - public void initialize(ConstPool cp, CtClass clazz, MethodInfo minfo) throws CannotCompileException { - /* + 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 @@ -56,7 +58,7 @@ public final class TransformAccessArrayField extends Transformer { * 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 { @@ -82,183 +84,183 @@ public final class TransformAccessArrayField extends Transformer { } } - public void clean() { - frames = null; - offset = -1; - } + 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; - } + public int transform(CtClass tclazz, int pos, CodeIterator iterator, + ConstPool cp) throws BadBytecode { + // Do nothing, see above comment + return pos; + } - private Frame getFrame(int pos) throws BadBytecode { - return frames[pos - offset]; // Adjust pos - } + 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 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; + private int updatePos(int pos, int increment) { + if (offset > -1) + offset += increment; - return pos + 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 String getTopType(int pos) throws BadBytecode { + Frame frame = getFrame(pos); + if (frame == null) + return 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) { - // 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; - } + CtClass clazz = frame.peek().getCtClass(); + return clazz != null ? Descriptor.toJvmName(clazz) : 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); - } + 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) { + // 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; + } - return pos; - } + // The gap may include extra padding + int gapLength = iterator.insertGap(pos, castType != null ? 5 : 2); - private String getMethodName(int opcode) { - String methodName = null; - switch (opcode) { - case AALOAD: - methodName = names.objectRead(); - break; - case BALOAD: - methodName = names.byteOrBooleanRead(); - break; - case CALOAD: - methodName = names.charRead(); - break; - case DALOAD: - methodName = names.doubleRead(); - break; - case FALOAD: - methodName = names.floatRead(); - break; - case IALOAD: - methodName = names.intRead(); - break; - case SALOAD: - methodName = names.shortRead(); - break; - case LALOAD: - methodName = names.longRead(); - break; - case AASTORE: - methodName = names.objectWrite(); - break; - case BASTORE: - methodName = names.byteOrBooleanWrite(); - break; - case CASTORE: - methodName = names.charWrite(); - break; - case DASTORE: - methodName = names.doubleWrite(); - break; - case FASTORE: - methodName = names.floatWrite(); - break; - case IASTORE: - methodName = names.intWrite(); - break; - case SASTORE: - methodName = names.shortWrite(); - break; - case LASTORE: - methodName = names.longWrite(); - break; - } + int mi = cp.addClassInfo(methodClassname); + int methodref = cp.addMethodrefInfo(mi, methodName, signature); + iterator.writeByte(INVOKESTATIC, pos); + iterator.write16bit(methodref, pos + 1); - if (methodName.equals("")) - methodName = null; + if (castType != null) { + int index = cp.addClassInfo(castType); + iterator.writeByte(CHECKCAST, pos + 3); + iterator.write16bit(index, pos + 4); + } - return methodName; - } + pos = updatePos(pos, gapLength); + } - private String getLoadReplacementSignature(int opcode) throws BadBytecode { - switch (opcode) { - case AALOAD: - return "(Ljava/lang/Object;I)Ljava/lang/Object;"; - case BALOAD: - return "(Ljava/lang/Object;I)B"; - case CALOAD: - return "(Ljava/lang/Object;I)C"; - case DALOAD: - return "(Ljava/lang/Object;I)D"; - case FALOAD: - return "(Ljava/lang/Object;I)F"; - case IALOAD: - return "(Ljava/lang/Object;I)I"; - case SALOAD: - return "(Ljava/lang/Object;I)S"; - case LALOAD: - return "(Ljava/lang/Object;I)J"; - } + return pos; + } + + private String getMethodName(int opcode) { + String methodName = null; + switch (opcode) { + case AALOAD: + methodName = names.objectRead(); + break; + case BALOAD: + methodName = names.byteOrBooleanRead(); + break; + case CALOAD: + methodName = names.charRead(); + break; + case DALOAD: + methodName = names.doubleRead(); + break; + case FALOAD: + methodName = names.floatRead(); + break; + case IALOAD: + methodName = names.intRead(); + break; + case SALOAD: + methodName = names.shortRead(); + break; + case LALOAD: + methodName = names.longRead(); + break; + case AASTORE: + methodName = names.objectWrite(); + break; + case BASTORE: + methodName = names.byteOrBooleanWrite(); + break; + case CASTORE: + methodName = names.charWrite(); + break; + case DASTORE: + methodName = names.doubleWrite(); + break; + case FASTORE: + methodName = names.floatWrite(); + break; + case IASTORE: + methodName = names.intWrite(); + break; + case SASTORE: + methodName = names.shortWrite(); + break; + case LASTORE: + methodName = names.longWrite(); + break; + } - throw new BadBytecode(opcode); - } + if (methodName.equals("")) + methodName = null; - private String getStoreReplacementSignature(int opcode) throws BadBytecode { - switch (opcode) { - case AASTORE: - return "(Ljava/lang/Object;ILjava/lang/Object;)V"; - case BASTORE: - return "(Ljava/lang/Object;IB)V"; - case CASTORE: - return "(Ljava/lang/Object;IC)V"; - case DASTORE: - return "(Ljava/lang/Object;ID)V"; - case FASTORE: - return "(Ljava/lang/Object;IF)V"; - case IASTORE: - return "(Ljava/lang/Object;II)V"; - case SASTORE: - return "(Ljava/lang/Object;IS)V"; - case LASTORE: - return "(Ljava/lang/Object;IJ)V"; - } + return methodName; + } + + private String getLoadReplacementSignature(int opcode) throws BadBytecode { + switch (opcode) { + case AALOAD: + return "(Ljava/lang/Object;I)Ljava/lang/Object;"; + case BALOAD: + return "(Ljava/lang/Object;I)B"; + case CALOAD: + return "(Ljava/lang/Object;I)C"; + case DALOAD: + return "(Ljava/lang/Object;I)D"; + case FALOAD: + return "(Ljava/lang/Object;I)F"; + case IALOAD: + return "(Ljava/lang/Object;I)I"; + case SALOAD: + return "(Ljava/lang/Object;I)S"; + case LALOAD: + return "(Ljava/lang/Object;I)J"; + } - throw new BadBytecode(opcode); - } + throw new BadBytecode(opcode); + } + + private String getStoreReplacementSignature(int opcode) throws BadBytecode { + switch (opcode) { + case AASTORE: + return "(Ljava/lang/Object;ILjava/lang/Object;)V"; + case BASTORE: + return "(Ljava/lang/Object;IB)V"; + case CASTORE: + return "(Ljava/lang/Object;IC)V"; + case DASTORE: + return "(Ljava/lang/Object;ID)V"; + case FASTORE: + return "(Ljava/lang/Object;IF)V"; + case IASTORE: + return "(Ljava/lang/Object;II)V"; + case SASTORE: + return "(Ljava/lang/Object;IS)V"; + case LASTORE: + return "(Ljava/lang/Object;IJ)V"; + } + + throw new BadBytecode(opcode); + } } diff --git a/src/test/test/javassist/convert/ArrayAccessReplaceTest.java b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java index 4c40849c..50795240 100644 --- a/src/test/test/javassist/convert/ArrayAccessReplaceTest.java +++ b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java @@ -20,6 +20,7 @@ public class ArrayAccessReplaceTest extends TestCase { CodeConverter converter = new CodeConverter(); converter.replaceArrayAccess(echoClass, new CodeConverter.DefaultArrayAccessReplacementMethodNames()); simpleClass.instrument(converter); + //simpleClass.writeFile("/tmp"); simple = (SimpleInterface) simpleClass.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).newInstance(); } @@ -30,7 +31,6 @@ public class ArrayAccessReplaceTest extends TestCase { CodeConverter converter = new CodeConverter(); converter.replaceArrayAccess(clazz, new CodeConverter.DefaultArrayAccessReplacementMethodNames()); clazz.instrument(converter); - clazz.writeFile("/tmp"); ComplexInterface instance = (ComplexInterface) clazz.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).newInstance(); assertEquals(Integer.valueOf(5), instance.complexRead(4)); } @@ -137,6 +137,16 @@ public class ArrayAccessReplaceTest extends TestCase { } } + public void testMulti() throws Exception { + for (int i = 2; i < 100; i++) { + simple.setMultiFoo(0, 1, i, new Foo(i)); + } + + for (int i = 2; i < 100; i++) { + assertEquals(new Foo(i), simple.getMultiFoo(0, 1, i)); + } + } + public static class Echo { public static Map byteMap = new HashMap(); public static Map charMap = new HashMap(); @@ -261,6 +271,9 @@ public class ArrayAccessReplaceTest extends TestCase { public void setFoo(int pos, Foo value); public Foo getFoo(int pos); + + public void setMultiFoo(int one, int two, int three, Foo foo); + public Foo getMultiFoo(int one, int two, int three); } public static class Simple implements SimpleInterface { @@ -274,6 +287,12 @@ public class ArrayAccessReplaceTest extends TestCase { private double[] doubles; private Object[] objects; private Foo[] foos; + private Foo[][][] multi; + + public Simple() { + multi[0] = new Foo[0][0]; + multi[0][1] = new Foo[0]; + } public boolean getBoolean(int pos) { return booleans[pos]; @@ -315,6 +334,10 @@ public class ArrayAccessReplaceTest extends TestCase { return shorts[pos]; } + public Foo getMultiFoo(int one, int two, int three) { + return multi[one][two][three]; + } + public void setBoolean(int pos, boolean value) { booleans[pos] = value; } @@ -355,6 +378,9 @@ public class ArrayAccessReplaceTest extends TestCase { shorts[pos] = value; } + public void setMultiFoo(int one, int two, int three, Foo foo) { + multi[one][two][three] = foo; + } } public static interface ComplexInterface { |