From: chiba Date: Thu, 4 Nov 2004 16:26:15 +0000 (+0000) Subject: supports finally clauses X-Git-Tag: rel_3_17_1_ga~469 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=be2809ffa541cca972f70c6001d0d4e666ab11c0;p=javassist.git supports finally clauses git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@147 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java index 7dc3d973..18718f54 100644 --- a/src/main/javassist/compiler/CodeGen.java +++ b/src/main/javassist/compiler/CodeGen.java @@ -53,7 +53,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { */ protected static abstract class ReturnHook { ReturnHook next; - protected abstract void doit(Bytecode b); + protected abstract void doit(Bytecode b, int opcode); protected ReturnHook(CodeGen gen) { next = gen.returnHooks; gen.returnHooks = this; @@ -437,7 +437,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { hasReturned = alwaysBranch; } - private void patchGoto(ArrayList list, int targetPc) { + protected void patchGoto(ArrayList list, int targetPc) { int n = list.size(); for (int i = 0; i < n; ++i) { int pc = ((Integer)list.get(i)).intValue(); @@ -607,7 +607,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } for (ReturnHook har = returnHooks; har != null; har = har.next) - har.doit(bytecode); + har.doit(bytecode, op); bytecode.addOpcode(op); hasReturned = true; @@ -623,6 +623,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { hasReturned = true; } + /* overridden in MemberCodeGen + */ protected void atTryStmnt(Stmnt st) throws CompileError { hasReturned = false; } @@ -643,7 +645,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bc.addOpcode(MONITORENTER); ReturnHook rh = new ReturnHook(this) { - protected void doit(Bytecode b) { + protected void doit(Bytecode b, int opcode) { b.addAload(var); b.addOpcode(MONITOREXIT); } @@ -657,14 +659,14 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int pc2 = bc.currentPc(); int pc3 = 0; if (!hasReturned) { - rh.doit(bc); + rh.doit(bc, 0); // the 2nd arg is ignored. bc.addOpcode(Opcode.GOTO); pc3 = bc.currentPc(); bc.addIndex(0); } int pc4 = bc.currentPc(); - rh.doit(bc); + rh.doit(bc, 0); // the 2nd arg is ignored. bc.addOpcode(ATHROW); bc.addExceptionHandler(pc, pc2, pc4, 0); if (!hasReturned) diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index 14e14438..b2e8d6fe 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -18,6 +18,7 @@ package javassist.compiler; import javassist.*; import javassist.bytecode.*; import javassist.compiler.ast.*; +import java.util.ArrayList; /* Code generator methods depending on javassist.* classes. */ @@ -68,25 +69,90 @@ public class MemberCodeGen extends CodeGen { "", "()V"); } + static class JsrHook extends ReturnHook { + ArrayList jsrList; + int var; + + JsrHook(CodeGen gen) { + super(gen); + jsrList = new ArrayList(); + var = gen.getMaxLocals(); + gen.incMaxLocals(1); + } + + private void jsrJmp(Bytecode b) { + b.addOpcode(JSR); + jsrList.add(new Integer(b.currentPc())); + b.addIndex(0); + } + + protected void doit(Bytecode b, int opcode) { + switch (opcode) { + case Opcode.RETURN : + jsrJmp(b); + break; + case ARETURN : + b.addAstore(var); + jsrJmp(b); + b.addAload(var); + break; + case IRETURN : + b.addIstore(var); + jsrJmp(b); + b.addIload(var); + break; + case LRETURN : + b.addLstore(var); + jsrJmp(b); + b.addLload(var); + break; + case DRETURN : + b.addDstore(var); + jsrJmp(b); + b.addDload(var); + break; + case FRETURN : + b.addFstore(var); + jsrJmp(b); + b.addFload(var); + break; + default : + throw new RuntimeException("fatal"); + } + } + } + protected void atTryStmnt(Stmnt st) throws CompileError { + Bytecode bc = bytecode; Stmnt body = (Stmnt)st.getLeft(); if (body == null) return; - int start = bytecode.currentPc(); + ASTList catchList = (ASTList)st.getRight().getLeft(); + Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft(); + ArrayList gotoList = new ArrayList(); + + JsrHook jsrHook = null; + if (finallyBlock != null) + jsrHook = new JsrHook(this); + + int start = bc.currentPc(); body.accept(this); - int end = bytecode.currentPc(); + int end = bc.currentPc(); if (start == end) throw new CompileError("empty try block"); - bytecode.addOpcode(Opcode.GOTO); - int pc = bytecode.currentPc(); - bytecode.addIndex(0); // correct later + boolean tryNotReturn = !hasReturned; + if (tryNotReturn) { + bc.addOpcode(Opcode.GOTO); + gotoList.add(new Integer(bc.currentPc())); + bc.addIndex(0); // correct later + } int var = getMaxLocals(); incMaxLocals(1); - ASTList catchList = (ASTList)st.getRight().getLeft(); while (catchList != null) { + // catch clause Pair p = (Pair)catchList.head(); catchList = catchList.tail(); Declarator decl = (Declarator)p.getLeft(); @@ -96,24 +162,61 @@ public class MemberCodeGen extends CodeGen { CtClass type = resolver.lookupClassByJvmName(decl.getClassName()); decl.setClassName(MemberResolver.javaToJvmName(type.getName())); - bytecode.addExceptionHandler(start, end, bytecode.currentPc(), - type); - bytecode.growStack(1); - bytecode.addAstore(var); + bc.addExceptionHandler(start, end, bc.currentPc(), type); + bc.growStack(1); + bc.addAstore(var); + hasReturned = false; if (block != null) block.accept(this); - bytecode.addOpcode(Opcode.GOTO); - bytecode.addIndex(pc - bytecode.currentPc()); + if (!hasReturned) { + bc.addOpcode(Opcode.GOTO); + gotoList.add(new Integer(bc.currentPc())); + bc.addIndex(0); // correct later + tryNotReturn = true; + } } - Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft(); - if (finallyBlock != null) - throw new CompileError( - "sorry, finally has not been supported yet"); + int pcFinally = -1; + if (finallyBlock != null) { + jsrHook.remove(this); + // catch (any) clause + int pcAnyCatch = bc.currentPc(); + 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); + } + } + + int pcEnd = bc.currentPc(); + patchGoto(gotoList, pcEnd); + if (finallyBlock != null) { + patchGoto(jsrHook.jsrList, pcFinally); + if (tryNotReturn) { + bc.addOpcode(JSR); + bc.addIndex(pcFinally - pcEnd); + } + } - bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); - hasReturned = false; + hasReturned = !tryNotReturn; } public void atNewExpr(NewExpr expr) throws CompileError {