git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@371 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -45,6 +45,12 @@ public final class ClassFile { | |||
String[] cachedInterfaces; | |||
String cachedSuperclass; | |||
/** | |||
* The major version number of class files created | |||
* from scratch. The value is 45 (JDK 1.1). | |||
*/ | |||
public static final int MAJOR_VERSION = 45; | |||
/** | |||
* Constructs a class file from a byte stream. | |||
*/ | |||
@@ -63,7 +69,7 @@ public final class ClassFile { | |||
* a fully-qualified super class name | |||
*/ | |||
public ClassFile(boolean isInterface, String classname, String superclass) { | |||
major = 45; | |||
major = MAJOR_VERSION; | |||
minor = 3; // JDK 1.1 or later | |||
constPool = new ConstPool(classname); | |||
thisClass = constPool.getThisClassInfo(); |
@@ -1547,6 +1547,15 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
cname = MemberResolver.jvmToJavaName(cname); | |||
} | |||
atClassObject2(cname); | |||
exprType = CLASS; | |||
arrayDim = 0; | |||
className = "java/lang/Class"; | |||
} | |||
/* MemberCodeGen overrides this method. | |||
*/ | |||
protected void atClassObject2(String cname) throws CompileError { | |||
int start = bytecode.currentPc(); | |||
bytecode.addLdc(cname); | |||
bytecode.addInvokestatic("java.lang.Class", "forName", | |||
@@ -1581,10 +1590,6 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { | |||
+ "Ljava/lang/NoClassDefFoundError;"); | |||
bytecode.addOpcode(ATHROW); | |||
bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); | |||
exprType = CLASS; | |||
arrayDim = 0; | |||
className = "java/lang/Class"; | |||
} | |||
public void atArrayRead(ASTree array, ASTree index) |
@@ -24,9 +24,13 @@ import java.util.ArrayList; | |||
/* Code generator methods depending on javassist.* classes. | |||
*/ | |||
public class MemberCodeGen extends CodeGen { | |||
public static final int JAVA5_VER = 49; | |||
public static final int JAVA6_VER = 50; | |||
protected MemberResolver resolver; | |||
protected CtClass thisClass; | |||
protected MethodInfo thisMethod; | |||
protected int version; // the major version of a class file. | |||
protected boolean resultStatic; | |||
@@ -35,6 +39,11 @@ public class MemberCodeGen extends CodeGen { | |||
resolver = new MemberResolver(cp); | |||
thisClass = cc; | |||
thisMethod = null; | |||
ClassFile cf = cc.getClassFile2(); | |||
if (cf == null) | |||
version = 0; | |||
else | |||
version = cf.getMajorVersion(); | |||
} | |||
/** | |||
@@ -71,17 +80,27 @@ public class MemberCodeGen extends CodeGen { | |||
static class JsrHook extends ReturnHook { | |||
ArrayList jsrList; | |||
CodeGen cgen; | |||
int var; | |||
JsrHook(CodeGen gen) { | |||
super(gen); | |||
jsrList = new ArrayList(); | |||
var = gen.getMaxLocals(); | |||
gen.incMaxLocals(1); | |||
cgen = gen; | |||
var = -1; | |||
} | |||
private int getVar(int size) { | |||
if (var < 0) { | |||
var = cgen.getMaxLocals(); | |||
cgen.incMaxLocals(size); | |||
} | |||
return var; | |||
} | |||
private void jsrJmp(Bytecode b) { | |||
b.addOpcode(JSR); | |||
b.addOpcode(Opcode.GOTO); | |||
jsrList.add(new Integer(b.currentPc())); | |||
b.addIndex(0); | |||
} | |||
@@ -92,27 +111,27 @@ public class MemberCodeGen extends CodeGen { | |||
jsrJmp(b); | |||
break; | |||
case ARETURN : | |||
b.addAstore(var); | |||
b.addAstore(getVar(1)); | |||
jsrJmp(b); | |||
b.addAload(var); | |||
break; | |||
case IRETURN : | |||
b.addIstore(var); | |||
b.addIstore(getVar(1)); | |||
jsrJmp(b); | |||
b.addIload(var); | |||
break; | |||
case LRETURN : | |||
b.addLstore(var); | |||
b.addLstore(getVar(2)); | |||
jsrJmp(b); | |||
b.addLload(var); | |||
break; | |||
case DRETURN : | |||
b.addDstore(var); | |||
b.addDstore(getVar(2)); | |||
jsrJmp(b); | |||
b.addDload(var); | |||
break; | |||
case FRETURN : | |||
b.addFstore(var); | |||
b.addFstore(getVar(1)); | |||
jsrJmp(b); | |||
b.addFload(var); | |||
break; | |||
@@ -177,7 +196,6 @@ public class MemberCodeGen extends CodeGen { | |||
} | |||
} | |||
int pcFinally = -1; | |||
if (finallyBlock != null) { | |||
jsrHook.remove(this); | |||
// catch (any) clause | |||
@@ -185,38 +203,42 @@ public class MemberCodeGen extends CodeGen { | |||
bc.addExceptionHandler(start, pcAnyCatch, pcAnyCatch, 0); | |||
bc.growStack(1); | |||
bc.addAstore(var); | |||
bc.addOpcode(JSR); | |||
int pcJsrIndex = bc.currentPc(); | |||
bc.addIndex(0); // correct later | |||
bc.addAload(var); | |||
bc.addOpcode(ATHROW); | |||
// finally clause | |||
pcFinally = bc.currentPc(); | |||
bc.write16bit(pcJsrIndex, pcFinally - pcJsrIndex + 1); | |||
int retAddr = getMaxLocals(); | |||
incMaxLocals(1); | |||
bc.growStack(1); // return address | |||
bc.addAstore(retAddr); | |||
hasReturned = false; | |||
finallyBlock.accept(this); | |||
if (!hasReturned) { | |||
bc.addOpcode(RET); | |||
bc.add(retAddr); | |||
bc.addAload(var); | |||
bc.addOpcode(ATHROW); | |||
} | |||
addFinally(jsrHook.jsrList, finallyBlock); | |||
} | |||
int pcEnd = bc.currentPc(); | |||
patchGoto(gotoList, pcEnd); | |||
hasReturned = !tryNotReturn; | |||
if (finallyBlock != null) { | |||
patchGoto(jsrHook.jsrList, pcFinally); | |||
if (tryNotReturn) { | |||
bc.addOpcode(JSR); | |||
bc.addIndex(pcFinally - pcEnd); | |||
} | |||
if (tryNotReturn) | |||
finallyBlock.accept(this); | |||
} | |||
} | |||
hasReturned = !tryNotReturn; | |||
/** | |||
* Adds a finally clause for earch return statement. | |||
*/ | |||
private void addFinally(ArrayList returnList, Stmnt finallyBlock) | |||
throws CompileError | |||
{ | |||
Bytecode bc = bytecode; | |||
int n = returnList.size(); | |||
for (int i = 0; i < n; ++i) { | |||
int pc = ((Integer)returnList.get(i)).intValue(); | |||
bc.write16bit(pc, bc.currentPc() - pc + 1); | |||
finallyBlock.accept(this); | |||
if (!hasReturned) { | |||
bc.addOpcode(Opcode.GOTO); | |||
bc.addIndex(pc + 3 - bc.currentPc()); | |||
} | |||
} | |||
} | |||
public void atNewExpr(NewExpr expr) throws CompileError { | |||
@@ -895,6 +917,10 @@ public class MemberCodeGen extends CodeGen { | |||
return cp.addFieldrefInfo(ci, name, type); | |||
} | |||
protected void atClassObject2(String cname) throws CompileError { | |||
super.atClassObject2(cname); | |||
} | |||
protected void atFieldPlusPlus(int token, boolean isPost, | |||
ASTree oprand, Expr expr, boolean doDup) | |||
throws CompileError |
@@ -23,7 +23,7 @@ Shigeru Chiba | |||
<br>3. <a href="#load">Class loader</a> | |||
<br>4. <a href="tutorial2.html#intro">Introspection and customization</a> | |||
<br>5. <a href="tutorial3.html#intro">Bytecode level API</a> | |||
<br>6. <a href="tutorial3.html#generics">Generics</a> | |||
</ul> | |||
<p><br> |
@@ -22,6 +22,7 @@ | |||
</ul> | |||
<p><a href="#generics">6. Generics</a> | |||
<p><br> | |||
@@ -217,6 +218,70 @@ on those objects. For more details, see the javadoc manual | |||
of <code>javassist.bytecode.AnnotationsAttribute</code> class | |||
and the <code>javassist.bytecode.annotation</code> package. | |||
<p>Javassist also let you access annotations by the higher-level | |||
API. | |||
If you want to access annotations through <code>CtClass</code>, | |||
call <code>getAnnotations()</code> in <code>CtClass</code> or | |||
<code>CtBehavior</code>. | |||
<p><br> | |||
<h2><a name="generics">6. Generics</a></h2> | |||
<p>The lower-level API of Javassist fully supports generics | |||
introduced by Java 5. On the other hand, the higher-level | |||
API such as <code>CtClass</code> does not directly support | |||
generics. However, this is not a serious problem for bytecode | |||
transformation. | |||
<p>The generics of Java is implemented by the erasure technique. | |||
After compilation, all type parameters are dropped off. For | |||
example, suppose that your source code declare a parameterized | |||
type <code>Vector<String></code>: | |||
<ul><pre> | |||
Vector<String> v = new Vector<String>(); | |||
: | |||
String s = v.get(0); | |||
</pre></ul> | |||
<p>The compiled bytecode is equivalent to the following code: | |||
<ul><pre> | |||
Vector v = new Vector(); | |||
: | |||
String s = (String)v.get(0); | |||
</pre></ul> | |||
<p>So when you write a bytecode transformer, you can just drop | |||
off all type parameters. For example, if you have a class: | |||
<ul><pre> | |||
public class Wrapper<T> { | |||
T value; | |||
public Wrapper(T t) { value = t; } | |||
} | |||
</pre></ul> | |||
<p>and want to add an interface <code>Getter<T></code> to the | |||
class <code>Wrapper<T></code>: | |||
<ul><pre> | |||
public interface Getter<T> { | |||
T get(); | |||
} | |||
</pre></ul> | |||
<p>Then the interface you really have to add is <code>Getter</code> | |||
(the type parameters <code><T><code> drops off) | |||
and the method you also have to add to the <code>Wrapper</code> | |||
class is this simple one: | |||
<ul><pre> | |||
public Object get() { return value; } | |||
</pre></ul> | |||
<p>Note that no type parameters are necessary. | |||
<p><br> | |||