aboutsummaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
authorjgreene <jgreene@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2008-05-24 05:13:20 +0000
committerjgreene <jgreene@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2008-05-24 05:13:20 +0000
commit2bae8b13291b8ef8fc3df24af627424f344581df (patch)
tree7d68840873257ab78ae69cc9ed9570adc18bc2d8 /src/test
parente48604525140c746404a637282cb7b1dd97c18c4 (diff)
downloadjavassist-2bae8b13291b8ef8fc3df24af627424f344581df.tar.gz
javassist-2bae8b13291b8ef8fc3df24af627424f344581df.zip
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 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@437 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/test')
-rw-r--r--src/test/test/Test.java10
-rw-r--r--src/test/test/javassist/bytecode/analysis/AnalyzerTest.java411
-rw-r--r--src/test/test/javassist/bytecode/analysis/ErrorFinder.java62
-rw-r--r--src/test/test/javassist/bytecode/analysis/ScannerTest.java185
-rw-r--r--src/test/test/javassist/convert/ArrayAccessReplaceTest.java407
5 files changed, 1065 insertions, 10 deletions
diff --git a/src/test/test/Test.java b/src/test/test/Test.java
deleted file mode 100644
index 6d34165c..00000000
--- a/src/test/test/Test.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package test;
-
-import javassist.*;
-
-public class Test {
- public static void main(String[] args) throws Exception {
- CtClass ctClass = ClassPool.getDefault().get("JavassistTarget");
- ctClass.getMethod("method", "(Ljava/lang/String;)V").insertAfter("");
- }
-}
diff --git a/src/test/test/javassist/bytecode/analysis/AnalyzerTest.java b/src/test/test/javassist/bytecode/analysis/AnalyzerTest.java
new file mode 100644
index 00000000..0c5a77e6
--- /dev/null
+++ b/src/test/test/javassist/bytecode/analysis/AnalyzerTest.java
@@ -0,0 +1,411 @@
+package test.javassist.bytecode.analysis;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.BadBytecode;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.Opcode;
+import javassist.bytecode.analysis.Analyzer;
+import javassist.bytecode.analysis.Frame;
+import javassist.bytecode.analysis.Type;
+import junit.framework.TestCase;
+
+/**
+ * Tests Analyzer
+ *
+ * @author Jason T. Greene
+ */
+public class AnalyzerTest extends TestCase {
+
+ public void testCommonSupperArray() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass clazz = pool.get(getClass().getName() + "$Dummy");
+ CtMethod method = clazz.getDeclaredMethod("commonSuperArray");
+ verifyArrayLoad(clazz, method, "java.lang.Number");
+ }
+
+ public void testCommonInterfaceArray() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ CtClass clazz = pool.get(getClass().getName() + "$Dummy");
+ CtMethod method = clazz.getDeclaredMethod("commonInterfaceArray");
+ verifyArrayLoad(clazz, method, "java.io.Serializable");
+ }
+
+ public void testSharedInterfaceAndSuperClass() throws Exception {
+ CtMethod method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "sharedInterfaceAndSuperClass");
+ verifyReturn(method, "java.io.Serializable");
+
+ method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "sharedOffsetInterfaceAndSuperClass");
+ verifyReturn(method, "java.io.Serializable");
+
+ method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "sharedSuperWithSharedInterface");
+ verifyReturn(method, getClass().getName() + "$Dummy$A");
+ }
+
+ public void testArrayDifferentDims() throws Exception {
+ CtMethod method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "arrayDifferentDimensions1");
+ verifyReturn(method, "java.lang.Cloneable[]");
+
+ method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "arrayDifferentDimensions2");
+ verifyReturn(method, "java.lang.Object[][]");
+ }
+
+ public void testReusedLocalMerge() throws Exception {
+ CtMethod method = ClassPool.getDefault().getMethod(
+ getClass().getName() + "$Dummy", "reusedLocalMerge");
+
+ MethodInfo info = method.getMethodInfo2();
+ Analyzer analyzer = new Analyzer();
+ Frame[] frames = analyzer.analyze(method.getDeclaringClass(), info);
+ assertNotNull(frames);
+ int pos = findOpcode(info, Opcode.RETURN);
+ Frame frame = frames[pos];
+ assertEquals("java.lang.Object", frame.getLocal(2).getCtClass().getName());
+ }
+
+ private static int findOpcode(MethodInfo info, int opcode) throws BadBytecode {
+ CodeIterator iter = info.getCodeAttribute().iterator();
+
+ // find return
+ int pos = 0;
+ while (iter.hasNext()) {
+ pos = iter.next();
+ if (iter.byteAt(pos) == opcode)
+ break;
+ }
+ return pos;
+ }
+
+
+ private static void verifyReturn(CtMethod method, String expected) throws BadBytecode {
+ MethodInfo info = method.getMethodInfo2();
+ CodeIterator iter = info.getCodeAttribute().iterator();
+
+ // find areturn
+ int pos = 0;
+ while (iter.hasNext()) {
+ pos = iter.next();
+ if (iter.byteAt(pos) == Opcode.ARETURN)
+ break;
+ }
+
+ Analyzer analyzer = new Analyzer();
+ Frame[] frames = analyzer.analyze(method.getDeclaringClass(), info);
+ assertNotNull(frames);
+ Frame frame = frames[pos];
+ assertEquals(expected, frame.peek().getCtClass().getName());
+ }
+
+ private static void verifyArrayLoad(CtClass clazz, CtMethod method, String component)
+ throws BadBytecode {
+ MethodInfo info = method.getMethodInfo2();
+ CodeIterator iter = info.getCodeAttribute().iterator();
+
+ // find aaload
+ int pos = 0;
+ while (iter.hasNext()) {
+ pos = iter.next();
+ if (iter.byteAt(pos) == Opcode.AALOAD)
+ break;
+ }
+
+ Analyzer analyzer = new Analyzer();
+ Frame[] frames = analyzer.analyze(clazz, info);
+ assertNotNull(frames);
+ Frame frame = frames[pos];
+ assertNotNull(frame);
+
+ Type type = frame.getStack(frame.getTopIndex() - 1);
+ assertEquals(component + "[]", type.getCtClass().getName());
+
+ pos = iter.next();
+ frame = frames[pos];
+ assertNotNull(frame);
+
+ type = frame.getStack(frame.getTopIndex());
+ assertEquals(component, type.getCtClass().getName());
+ }
+
+ private static void addJump(Bytecode code, int opcode, int pos) {
+ int current = code.currentPc();
+ code.addOpcode(opcode);
+ code.addIndex(pos - current);
+ }
+
+ public void testDeadCode() throws Exception {
+ CtMethod method = generateDeadCode(ClassPool.getDefault());
+ Analyzer analyzer = new Analyzer();
+ Frame[] frames = analyzer.analyze(method.getDeclaringClass(), method.getMethodInfo2());
+ assertNotNull(frames);
+ assertNull(frames[4]);
+ assertNotNull(frames[5]);
+ verifyReturn(method, "java.lang.String");
+ }
+
+ public void testInvalidCode() throws Exception {
+ CtMethod method = generateInvalidCode(ClassPool.getDefault());
+ Analyzer analyzer = new Analyzer();
+ try {
+ analyzer.analyze(method.getDeclaringClass(), method.getMethodInfo2());
+ } catch (BadBytecode e) {
+ return;
+ }
+
+ fail("Invalid code should have triggered a BadBytecode exception");
+ }
+
+ public void testCodeFalloff() throws Exception {
+ CtMethod method = generateCodeFalloff(ClassPool.getDefault());
+ Analyzer analyzer = new Analyzer();
+ try {
+ analyzer.analyze(method.getDeclaringClass(), method.getMethodInfo2());
+ } catch (BadBytecode e) {
+ return;
+ }
+
+ fail("Code falloff should have triggered a BadBytecode exception");
+ }
+
+ public void testJsrMerge() throws Exception {
+ CtMethod method = generateJsrMerge(ClassPool.getDefault());
+ Analyzer analyzer = new Analyzer();
+ analyzer.analyze(method.getDeclaringClass(), method.getMethodInfo2());
+ verifyReturn(method, "java.lang.String");
+ }
+
+ public void testJsrMerge2() throws Exception {
+ CtMethod method = generateJsrMerge2(ClassPool.getDefault());
+ Analyzer analyzer = new Analyzer();
+ analyzer.analyze(method.getDeclaringClass(), method.getMethodInfo2());
+ verifyReturn(method, "java.lang.String");
+ }
+
+ private CtMethod generateDeadCode(ClassPool pool) throws Exception {
+ CtClass clazz = pool.makeClass(getClass().getName() + "$Generated0");
+ CtClass stringClass = pool.get("java.lang.String");
+ CtMethod method = new CtMethod(stringClass, "foo", new CtClass[0], clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ Bytecode code = new Bytecode(info.getConstPool(), 1, 2);
+ /* 0 */ code.addIconst(1);
+ /* 1 */ addJump(code, Opcode.GOTO, 5);
+ /* 4 */ code.addIconst(0); // DEAD
+ /* 5 */ code.addIconst(1);
+ /* 6 */ code.addInvokestatic(stringClass, "valueOf", stringClass, new CtClass[]{CtClass.intType});
+ /* 9 */ code.addOpcode(Opcode.ARETURN);
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+
+ return method;
+ }
+
+ private CtMethod generateInvalidCode(ClassPool pool) throws Exception {
+ CtClass clazz = pool.makeClass(getClass().getName() + "$Generated4");
+ CtClass intClass = pool.get("java.lang.Integer");
+ CtClass stringClass = pool.get("java.lang.String");
+ CtMethod method = new CtMethod(stringClass, "foo", new CtClass[0], clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ Bytecode code = new Bytecode(info.getConstPool(), 1, 2);
+ /* 0 */ code.addIconst(1);
+ /* 1 */ code.addInvokestatic(intClass, "valueOf", intClass, new CtClass[]{CtClass.intType});
+ /* 4 */ code.addOpcode(Opcode.ARETURN);
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+
+ return method;
+ }
+
+
+ private CtMethod generateCodeFalloff(ClassPool pool) throws Exception {
+ CtClass clazz = pool.makeClass(getClass().getName() + "$Generated3");
+ CtClass stringClass = pool.get("java.lang.String");
+ CtMethod method = new CtMethod(stringClass, "foo", new CtClass[0], clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ Bytecode code = new Bytecode(info.getConstPool(), 1, 2);
+ /* 0 */ code.addIconst(1);
+ /* 1 */ code.addInvokestatic(stringClass, "valueOf", stringClass, new CtClass[]{CtClass.intType});
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+
+ return method;
+ }
+
+ private CtMethod generateJsrMerge(ClassPool pool) throws Exception {
+ CtClass clazz = pool.makeClass(getClass().getName() + "$Generated1");
+ CtClass stringClass = pool.get("java.lang.String");
+ CtMethod method = new CtMethod(stringClass, "foo", new CtClass[0], clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ Bytecode code = new Bytecode(info.getConstPool(), 1, 2);
+ /* 0 */ code.addIconst(5);
+ /* 1 */ code.addIstore(0);
+ /* 2 */ addJump(code, Opcode.JSR, 7);
+ /* 5 */ code.addAload(0);
+ /* 6 */ code.addOpcode(Opcode.ARETURN);
+ /* 7 */ code.addAstore(1);
+ /* 8 */ code.addIconst(3);
+ /* 9 */ code.addInvokestatic(stringClass, "valueOf", stringClass, new CtClass[]{CtClass.intType});
+ /* 12 */ code.addAstore(0);
+ /* 12 */ code.addRet(1);
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+ //System.out.println(clazz.toClass().getMethod("foo", new Class[0]).invoke(null, new Object[0]));
+
+ return method;
+ }
+
+ private CtMethod generateJsrMerge2(ClassPool pool) throws Exception {
+ CtClass clazz = pool.makeClass(getClass().getName() + "$Generated2");
+ CtClass stringClass = pool.get("java.lang.String");
+ CtMethod method = new CtMethod(stringClass, "foo", new CtClass[0], clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ Bytecode code = new Bytecode(info.getConstPool(), 1, 2);
+ /* 0 */ addJump(code, Opcode.JSR, 5);
+ /* 3 */ code.addAload(0);
+ /* 4 */ code.addOpcode(Opcode.ARETURN);
+ /* 5 */ code.addAstore(1);
+ /* 6 */ code.addIconst(4);
+ /* 7 */ code.addInvokestatic(stringClass, "valueOf", stringClass, new CtClass[]{CtClass.intType});
+ /* 10 */ code.addAstore(0);
+ /* 11 */ code.addRet(1);
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+
+ return method;
+ }
+
+ public static class Dummy {
+ public Serializable commonSuperArray(int x) {
+ Number[] n;
+
+ if (x > 5) {
+ n = new Long[10];
+ } else {
+ n = new Double[5];
+ }
+
+ return n[x];
+ }
+
+ public Serializable commonInterfaceArray(int x) {
+ Serializable[] n;
+
+ if (x > 5) {
+ n = new Long[10];
+ } else if (x > 3) {
+ n = new Double[5];
+ } else {
+ n = new String[3];
+ }
+
+ return n[x];
+ }
+
+
+ public static class A {};
+ public static class B1 extends A implements Serializable {};
+ public static class B2 extends A implements Serializable {};
+ public static class A2 implements Serializable, Cloneable {};
+ public static class A3 implements Serializable, Cloneable {};
+
+ public static class B3 extends A {};
+ public static class C31 extends B3 implements Serializable {};
+
+
+ public void dummy(Serializable s) {}
+
+ public Object sharedInterfaceAndSuperClass(int x) {
+ Serializable s;
+
+ if (x > 5) {
+ s = new B1();
+ } else {
+ s = new B2();
+ }
+
+ dummy(s);
+
+ return s;
+ }
+
+ public A sharedSuperWithSharedInterface(int x) {
+ A a;
+
+ if (x > 5) {
+ a = new B1();
+ } else if (x > 3) {
+ a = new B2();
+ } else {
+ a = new C31();
+ }
+
+ return a;
+ }
+
+
+ public void reusedLocalMerge() {
+ ArrayList list = new ArrayList();
+ try {
+ Iterator i = list.iterator();
+ i.hasNext();
+ } catch (Exception e) {
+ }
+ }
+
+ public Object sharedOffsetInterfaceAndSuperClass(int x) {
+ Serializable s;
+
+ if (x > 5) {
+ s = new B1();
+ } else {
+ s = new C31();
+ }
+
+ dummy(s);
+
+ return s;
+ }
+
+
+ public Object arrayDifferentDimensions1(int x) {
+ Object[] n;
+
+ if ( x > 5) {
+ n = new Number[1][1];
+ } else {
+ n = new Cloneable[1];
+ }
+
+
+ return n;
+ }
+
+ public Object arrayDifferentDimensions2(int x) {
+ Object[] n;
+
+ if ( x> 5) {
+ n = new String[1][1];
+ } else {
+ n = new Number[1][1][1][1];
+ }
+
+ return n;
+ }
+ }
+}
diff --git a/src/test/test/javassist/bytecode/analysis/ErrorFinder.java b/src/test/test/javassist/bytecode/analysis/ErrorFinder.java
new file mode 100644
index 00000000..a2128325
--- /dev/null
+++ b/src/test/test/javassist/bytecode/analysis/ErrorFinder.java
@@ -0,0 +1,62 @@
+package test.javassist.bytecode.analysis;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.bytecode.analysis.Analyzer;
+
+/**
+ * Simple testing tool that verifies class files can be analyzed.
+ *
+ * @author Jason T. Greene
+ */
+public class ErrorFinder {
+
+ public static void main(String[] args) throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+
+ String className = args[0];
+ if (!className.equals("-file")) {
+ analyzeClass(pool, className);
+ return;
+ }
+
+ FileReader reader = new FileReader(args[1]);
+ BufferedReader lineReader = new BufferedReader(reader);
+
+
+ String line = lineReader.readLine();
+ while (line != null) {
+ analyzeClass(pool, line);
+ line = lineReader.readLine();
+ }
+ }
+
+ private static void analyzeClass(ClassPool pool, String className) {
+ try {
+
+ CtClass clazz = pool.get(className);
+ CtMethod[] methods = clazz.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i++)
+ analyzeMethod(clazz, methods[i]);
+ } catch (Throwable e) {
+ System.out.println("FAIL: CLASS: " + className + " " + e.getClass() + ":" + e.getMessage());
+ }
+ }
+
+ private static void analyzeMethod(CtClass clazz, CtMethod method) {
+ String methodName = clazz.getName() + "." + method.getName() + method.getSignature();
+ System.out.println("START: " + methodName);
+ Analyzer analyzer = new Analyzer();
+
+ try {
+ analyzer.analyze(clazz, method.getMethodInfo2());
+ System.out.println("SUCCESS: " + methodName);
+ } catch (Exception e) {
+ System.out.println("FAIL: " + methodName + " - " + (e.getMessage() == null ? e.getClass().getName() : e.getMessage()));
+ }
+ }
+}
diff --git a/src/test/test/javassist/bytecode/analysis/ScannerTest.java b/src/test/test/javassist/bytecode/analysis/ScannerTest.java
new file mode 100644
index 00000000..56114baf
--- /dev/null
+++ b/src/test/test/javassist/bytecode/analysis/ScannerTest.java
@@ -0,0 +1,185 @@
+package test.javassist.bytecode.analysis;
+
+import java.io.IOException;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.Opcode;
+import javassist.bytecode.analysis.Subroutine;
+import javassist.bytecode.analysis.SubroutineScanner;
+import junit.framework.TestCase;
+
+/**
+ * Tests Subroutine Scanner
+ *
+ * @author Jason T. Greene
+ */
+public class ScannerTest extends TestCase {
+
+ public void testNestedFinally() throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ generate(pool);
+ CtClass clazz = pool.get("test.ScannerTest$GeneratedTest");
+ CtMethod method = clazz.getDeclaredMethod("doit");
+
+ SubroutineScanner scanner = new SubroutineScanner();
+ Subroutine[] subs = scanner.scan(method.getMethodInfo2());
+
+ verifySubroutine(subs, 31, 31, new int[]{125, 25});
+ verifySubroutine(subs, 32, 31, new int[]{125, 25});
+ verifySubroutine(subs, 33, 31, new int[]{125, 25});
+ verifySubroutine(subs, 60, 31, new int[]{125, 25});
+ verifySubroutine(subs, 61, 31, new int[]{125, 25});
+ verifySubroutine(subs, 63, 31, new int[]{125, 25});
+ verifySubroutine(subs, 66, 31, new int[]{125, 25});
+ verifySubroutine(subs, 69, 31, new int[]{125, 25});
+ verifySubroutine(subs, 71, 31, new int[]{125, 25});
+ verifySubroutine(subs, 74, 31, new int[]{125, 25});
+ verifySubroutine(subs, 76, 31, new int[]{125, 25});
+ verifySubroutine(subs, 77, 77, new int[]{111, 71});
+ verifySubroutine(subs, 79, 77, new int[]{111, 71});
+ verifySubroutine(subs, 80, 77, new int[]{111, 71});
+ verifySubroutine(subs, 82, 77, new int[]{111, 71});
+ verifySubroutine(subs, 85, 77, new int[]{111, 71});
+ verifySubroutine(subs, 88, 77, new int[]{111, 71});
+ verifySubroutine(subs, 90, 77, new int[]{111, 71});
+ verifySubroutine(subs, 93, 77, new int[]{111, 71});
+ verifySubroutine(subs, 95, 77, new int[]{111, 71});
+ verifySubroutine(subs, 96, 96, new int[]{106, 90});
+ verifySubroutine(subs, 98, 96, new int[]{106, 90});
+ verifySubroutine(subs, 99, 96, new int[]{106, 90});
+ verifySubroutine(subs, 101, 96, new int[]{106, 90});
+ verifySubroutine(subs, 104, 96, new int[]{106, 90});
+ verifySubroutine(subs, 106, 77, new int[]{111, 71});
+ verifySubroutine(subs, 109, 77, new int[]{111, 71});
+ verifySubroutine(subs, 111, 31, new int[]{125, 25});
+ verifySubroutine(subs, 114, 31, new int[]{125, 25});
+ verifySubroutine(subs, 117, 31, new int[]{125, 25});
+ verifySubroutine(subs, 118, 31, new int[]{125, 25});
+ verifySubroutine(subs, 120, 31, new int[]{125, 25});
+ verifySubroutine(subs, 123, 31, new int[]{125, 25});
+ }
+
+ private static void verifySubroutine(Subroutine[] subs, int pos, int start,
+ int[] callers) {
+ Subroutine sub = subs[pos];
+ assertNotNull(sub);
+ assertEquals(sub.start(), start);
+ for (int i = 0; i < callers.length; i++)
+ assertTrue(sub.callers().contains(Integer.valueOf(callers[i])));
+ }
+
+ private static void generate(ClassPool pool) throws CannotCompileException, IOException, NotFoundException {
+ // Generated from eclipse JDK4 compiler:
+ // public void doit(int x) {
+ // println("null");
+ // try {
+ // println("try");
+ // } catch (RuntimeException e) {
+ // e.printStackTrace();
+ // } finally {
+ // switch (x) {
+ // default:
+ // case 15:
+ // try {
+ // println("inner-try");
+ // } finally {
+ // try {
+ // println("inner-inner-try");
+ // } finally {
+ // println("inner-finally");
+ // }
+ // }
+ // break;
+ // case 1789:
+ // println("switch -17");
+ // }
+ // }
+ //}
+
+ CtClass clazz = pool.makeClass("test.ScannerTest$GeneratedTest");
+ CtMethod method = new CtMethod(CtClass.voidType, "doit", new CtClass[] {CtClass.intType}, clazz);
+ MethodInfo info = method.getMethodInfo2();
+ info.setAccessFlags(AccessFlag.PUBLIC);
+ CtClass stringClass = pool.get("java.lang.String");
+ Bytecode code = new Bytecode(info.getConstPool(), 2, 9);
+ /* 0 */ code.addAload(0);
+ /* 1 */ code.addLdc("start");
+ /* 3 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 6 */ code.addAload(0);
+ /* 7 */ code.addLdc("try");
+ /* 9 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 12 */ addJump(code, Opcode.GOTO, 125);
+ /* 14 */ code.addAstore(2);
+ /* 16 */ code.addAload(2);
+ /* 17 */ code.addInvokevirtual("java.lang.Exception", "printStackTrace", "()V");
+ /* 20 */ addJump(code, Opcode.GOTO, 125);
+ /* 23 */ code.addAstore(4);
+ /* 25 */ addJump(code, Opcode.JSR, 31);
+ /* 28 */ code.addAload(4);
+ /* 30 */ code.addOpcode(Opcode.ATHROW);
+ /* 31 */ code.addAstore(3);
+ /* 32 */ code.addIload(1);
+ int spos = code.currentPc();
+ /* 33 */ code.addOpcode(Opcode.LOOKUPSWITCH);
+ code.addIndex(0); // 2 bytes pad - gets us to 36
+ code.add32bit(60 - spos); // default
+ code.add32bit(2); // 2 pairs
+ code.add32bit(15); code.add32bit(60 - spos);
+ code.add32bit(1789); code.add32bit(117 - spos);
+ /* 60 */ code.addAload(0);
+ /* 61 */ code.addLdc("inner-try");
+ /* 63 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 66 */ addJump(code, Opcode.GOTO, 111);
+ /* 69 */ code.addAstore(6);
+ /* 71 */ addJump(code, Opcode.JSR, 77);
+ /* 74 */ code.addAload(6);
+ /* 76 */ code.add(Opcode.ATHROW);
+ /* 77 */ code.addAstore(5);
+ /* 79 */ code.addAload(0);
+ /* 80 */ code.addLdc("inner-inner-try");
+ /* 82 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 85 */ addJump(code, Opcode.GOTO, 106);
+ /* 88 */ code.addAstore(8);
+ /* 90 */ addJump(code, Opcode.JSR, 96);
+ /* 93 */ code.addAload(8);
+ /* 95 */ code.add(Opcode.ATHROW);
+ /* 96 */ code.addAstore(7);
+ /* 98 */ code.addAload(0);
+ /* 99 */ code.addLdc("inner-finally");
+ /* 101 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 104 */ code.addRet(7);
+ /* 106 */ addJump(code, Opcode.JSR, 96);
+ /* 109 */ code.addRet(5);
+ /* 111 */ addJump(code, Opcode.JSR, 77);
+ /* 114 */ addJump(code, Opcode.GOTO, 123);
+ /* 117 */ code.addAload(0);
+ /* 118 */ code.addLdc("switch - 1789");
+ /* 120 */ code.addInvokevirtual(clazz, "println", CtClass.voidType, new CtClass[] {stringClass});
+ /* 123 */ code.addRet(3);
+ /* 125 */ addJump(code, Opcode.JSR, 31);
+ /* 128 */ code.addOpcode(Opcode.RETURN);
+ code.addExceptionHandler(6, 12, 15, "java.lang.RuntimeException");
+ code.addExceptionHandler(6, 20, 23, 0);
+ code.addExceptionHandler(125, 128, 23, 0);
+ code.addExceptionHandler(60, 69, 69, 0);
+ code.addExceptionHandler(111, 114, 69, 0);
+ code.addExceptionHandler(79, 88, 88, 0);
+ code.addExceptionHandler(106, 109, 88, 0);
+ info.setCodeAttribute(code.toCodeAttribute());
+ clazz.addMethod(method);
+ clazz.writeFile("/tmp");
+ }
+
+ private static void addJump(Bytecode code, int opcode, int pos) {
+ int current = code.currentPc();
+ code.addOpcode(opcode);
+ code.addIndex(pos - current);
+ }
+}
diff --git a/src/test/test/javassist/convert/ArrayAccessReplaceTest.java b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java
new file mode 100644
index 00000000..4c40849c
--- /dev/null
+++ b/src/test/test/javassist/convert/ArrayAccessReplaceTest.java
@@ -0,0 +1,407 @@
+package test.javassist.convert;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashMap;
+import java.util.Map;
+
+import javassist.ClassPool;
+import javassist.CodeConverter;
+import javassist.CtClass;
+import junit.framework.TestCase;
+
+public class ArrayAccessReplaceTest extends TestCase {
+ private static SimpleInterface simple;
+
+ public void setUp() throws Exception {
+ ClassPool pool = new ClassPool(true);
+ CtClass echoClass = pool.get(ArrayAccessReplaceTest.class.getName() + "$Echo");
+ CtClass simpleClass = pool.get(ArrayAccessReplaceTest.class.getName() + "$Simple");
+ CodeConverter converter = new CodeConverter();
+ converter.replaceArrayAccess(echoClass, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
+ simpleClass.instrument(converter);
+ simple = (SimpleInterface) simpleClass.toClass(new URLClassLoader(new URL[0], getClass().getClassLoader()), Class.class.getProtectionDomain()).newInstance();
+ }
+
+ public void testComplex() throws Exception {
+ ClassPool pool = new ClassPool(true);
+ CtClass clazz = pool.get(ArrayAccessReplaceTest.class.getName() + "$Complex");
+
+ 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));
+ }
+
+ public void testBoolean() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ boolean value = i % 5 == 0;
+ simple.setBoolean(i, value);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ boolean value = i % 5 == 0;
+ assertEquals(value, simple.getBoolean(i));
+ }
+ }
+
+ public void testByte() throws Exception {
+ for (byte i = 0; i < 100; i++) {
+ simple.setByte(i, i);
+ }
+
+ for (byte i = 0; i < 100; i++) {
+ assertEquals(i, simple.getByte(i));
+ }
+ }
+
+ public void testShort() throws Exception {
+ for (short i = 0; i < 100; i++) {
+ simple.setShort(i, i);
+ }
+
+ for (short i = 0; i < 100; i++) {
+ assertEquals(i, simple.getShort(i));
+ }
+ }
+
+ public void testChar() throws Exception {
+ for (char i = 0; i < 100; i++) {
+ simple.setChar(i, i);
+ }
+
+ for (char i = 0; i < 100; i++) {
+ assertEquals(i, simple.getChar(i));
+ }
+ }
+
+ public void testInt() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setInt(i, i);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals(i, simple.getInt(i));
+ }
+ }
+
+ public void testLong() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setLong(i, i);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals(i, simple.getLong(i));
+ }
+ }
+
+ public void testFloat() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setFloat(i, i);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals((float)i, simple.getFloat(i), 0);
+ }
+ }
+
+ public void testDouble() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setDouble(i, i);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals((double)i, simple.getDouble(i), 0);
+ }
+ }
+
+ public void testObject() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setObject(i, Integer.valueOf(i));
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals(Integer.valueOf(i), simple.getObject(i));
+ }
+ }
+
+ public void testFoo() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ simple.setFoo(i, new Foo(i));
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals(new Foo(i), simple.getFoo(i));
+ }
+ }
+
+ public static class Echo {
+ public static Map byteMap = new HashMap();
+ public static Map charMap = new HashMap();
+ public static Map doubleMap = new HashMap();
+ public static Map floatMap = new HashMap();
+ public static Map intMap = new HashMap();
+ public static Map longMap = new HashMap();
+ public static Map objectMap = new HashMap();
+ public static Map shortMap = new HashMap();
+
+ public static Object arrayReadObject(Object array, int index) {
+ return objectMap.get(Integer.valueOf(index));
+ }
+
+ public static void arrayWriteObject(Object array, int index, Object element) {
+ objectMap.put(Integer.valueOf(index), element);
+ }
+
+ public static byte arrayReadByteOrBoolean(Object array, int index) {
+ return ((Byte)byteMap.get(Integer.valueOf(index))).byteValue();
+ }
+
+ public static void arrayWriteByteOrBoolean(Object array, int index, byte element) {
+ byteMap.put(Integer.valueOf(index), Byte.valueOf(element));
+ }
+
+ public static char arrayReadChar(Object array, int index) {
+ return ((Character)charMap.get(Integer.valueOf(index))).charValue();
+ }
+
+ public static void arrayWriteChar(Object array, int index, char element) {
+ charMap.put(Integer.valueOf(index), Character.valueOf(element));
+ }
+
+ public static double arrayReadDouble(Object array, int index) {
+ return ((Double)doubleMap.get(Integer.valueOf(index))).doubleValue();
+ }
+
+ public static void arrayWriteDouble(Object array, int index, double element) {
+ doubleMap.put(Integer.valueOf(index), Double.valueOf(element));
+ }
+
+ public static float arrayReadFloat(Object array, int index) {
+ return ((Float)floatMap.get(Integer.valueOf(index))).floatValue();
+ }
+
+ public static void arrayWriteFloat(Object array, int index, float element) {
+ floatMap.put(Integer.valueOf(index), Float.valueOf(element));
+ }
+
+ public static int arrayReadInt(Object array, int index) {
+ return ((Integer)intMap.get(Integer.valueOf(index))).intValue();
+ }
+
+ public static void arrayWriteInt(Object array, int index, int element) {
+ intMap.put(Integer.valueOf(index), Integer.valueOf(element));
+ }
+
+ public static long arrayReadLong(Object array, int index) {
+ return ((Long)longMap.get(Integer.valueOf(index))).longValue();
+ }
+
+ public static void arrayWriteLong(Object array, int index, long element) {
+ longMap.put(Integer.valueOf(index), Long.valueOf(element));
+ }
+
+ public static short arrayReadShort(Object array, int index) {
+ return ((Short)shortMap.get(Integer.valueOf(index))).shortValue();
+ }
+
+ public static void arrayWriteShort(Object array, int index, short element) {
+ shortMap.put(Integer.valueOf(index), Short.valueOf(element));
+ }
+ }
+
+ public static class Foo {
+ public int bar;
+
+ public Foo(int bar) {
+ this.bar = bar;
+ }
+
+ public int hashCode() {
+ return bar;
+ }
+
+ public boolean equals(Object o) {
+ if (! (o instanceof Foo))
+ return false;
+
+ return ((Foo)o).bar == bar;
+ }
+ }
+
+ public static interface SimpleInterface {
+ public void setBoolean(int pos, boolean value);
+ public boolean getBoolean(int pos);
+
+ public void setByte(int pos, byte value);
+ public byte getByte(int pos);
+
+ public void setShort(int pos, short value);
+ public short getShort(int pos);
+
+ public void setChar(int pos, char value);
+ public char getChar(int pos);
+
+ public void setInt(int pos, int value);
+ public int getInt(int pos);
+
+ public void setLong(int pos, long value);
+ public long getLong(int pos);
+
+ public void setFloat(int pos, float value);
+ public float getFloat(int pos);
+
+ public void setDouble(int pos, double value);
+ public double getDouble(int pos);
+
+ public void setObject(int pos, Object value);
+ public Object getObject(int pos);
+
+ public void setFoo(int pos, Foo value);
+ public Foo getFoo(int pos);
+ }
+
+ public static class Simple implements SimpleInterface {
+ private boolean[] booleans;
+ private byte[] bytes;
+ private short[] shorts;
+ private char[] chars;
+ private int[] ints;
+ private long[] longs;
+ private float[] floats;
+ private double[] doubles;
+ private Object[] objects;
+ private Foo[] foos;
+
+ public boolean getBoolean(int pos) {
+ return booleans[pos];
+ }
+
+ public byte getByte(int pos) {
+ return bytes[pos];
+ }
+
+ public char getChar(int pos) {
+ return chars[pos];
+ }
+
+ public double getDouble(int pos) {
+ return doubles[pos];
+ }
+
+ public float getFloat(int pos) {
+ return floats[pos];
+ }
+
+ public Foo getFoo(int pos) {
+ return foos[pos];
+ }
+
+ public int getInt(int pos) {
+ return ints[pos];
+ }
+
+ public long getLong(int pos) {
+ return longs[pos];
+ }
+
+ public Object getObject(int pos) {
+ return objects[pos];
+ }
+
+ public short getShort(int pos) {
+ return shorts[pos];
+ }
+
+ public void setBoolean(int pos, boolean value) {
+ booleans[pos] = value;
+ }
+
+ public void setByte(int pos, byte value) {
+ bytes[pos] = value;
+ }
+
+ public void setChar(int pos, char value) {
+ chars[pos] = value;
+ }
+
+ public void setDouble(int pos, double value) {
+ doubles[pos] = value;
+ }
+
+ public void setFloat(int pos, float value) {
+ floats[pos] = value;
+ }
+
+ public void setFoo(int pos, Foo value) {
+ foos[pos] = value;
+ }
+
+ public void setInt(int pos, int value) {
+ ints[pos] = value;
+ }
+
+ public void setLong(int pos, long value) {
+ longs[pos] = value;
+ }
+
+ public void setObject(int pos, Object value) {
+ objects[pos] = value;
+ }
+
+ public void setShort(int pos, short value) {
+ shorts[pos] = value;
+ }
+
+ }
+
+ public static interface ComplexInterface {
+ public Number complexRead(int x);
+ }
+
+ public static class Complex implements ComplexInterface {
+ private Integer[] nums;
+ private Long[] longNums;
+ private static Integer justRead;
+
+ public static Object arrayReadObject(Object array, int offset) {
+ return Integer.valueOf(justRead.intValue() + offset);
+ }
+
+ public static void arrayWriteObject(Object array, int offset, Object element) {
+ justRead = (Integer) element;
+ }
+
+ public Object getInteger(int i) {
+ return (Object) Integer.valueOf(i);
+ }
+
+ public Number complexRead(int x) {
+ Number[] ns = null;
+ Number n1, n2, n3, n4;
+ try {
+ ((Object[])ns)[1] = getInteger(x);
+ // We have to throw an error since we can't intercept
+ // a guaranteed null array read yet (likely never will be able to)
+ throw new Error("hi");
+ } catch (Error error) {
+ ns = nums;
+ } catch (Exception exception) {
+ ns = longNums;
+ } finally {
+ n1 = ns[1];
+ n2 = ns[2];
+ n3 = ns[3];
+ n4 = ns[4];
+
+ n2.intValue();
+ n3.intValue();
+ n4.intValue();
+ }
+
+ return n1;
+ }
+ }
+} \ No newline at end of file