proper try/catch/finally

This commit is contained in:
Alex Tkachman
2011-11-16 14:26:16 +02:00
parent 3b17b3fac7
commit 1b04870fa4
7 changed files with 188 additions and 28 deletions
@@ -39,7 +39,18 @@ public interface ClassBuilderFactory {
ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
@Override
public ClassBuilder newClassBuilder() {
return new ClassBuilder.Concrete(new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
return new ClassBuilder.Concrete(new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS){
@Override
protected String getCommonSuperClass(String type1, String type2) {
try {
return super.getCommonSuperClass(type1, type2);
}
catch (Throwable t) {
// @todo we might need at some point do more sofisticated handling
return "java/lang/Object";
}
}
});
}
@Override
@@ -64,6 +64,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private final CodegenContext context;
private final IntrinsicMethods intrinsics;
private final ArrayList<JetTryExpression> stackOfFinallyBlocks = new ArrayList<JetTryExpression>();
public ExpressionCodegen(MethodVisitor v,
FrameMap myMap,
Type returnType,
@@ -712,11 +714,21 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
private void doFinallyOnReturnOrThrow() {
if(stackOfFinallyBlocks.size() > 0) {
JetTryExpression jetTryExpression = stackOfFinallyBlocks.remove(stackOfFinallyBlocks.size()-1);
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
doFinallyOnReturnOrThrow();
stackOfFinallyBlocks.add(jetTryExpression);
}
}
@Override
public StackValue visitReturnExpression(JetReturnExpression expression, StackValue receiver) {
final JetExpression returnedExpression = expression.getReturnedExpression();
if (returnedExpression != null) {
gen(returnedExpression, returnType);
doFinallyOnReturnOrThrow();
v.areturn(returnType);
}
else {
@@ -1857,16 +1869,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
DeclarationDescriptor cls = op.getContainingDeclaration();
if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) {
receiver.put(receiver.type, v);
//noinspection ConstantConditions
if (bindingContext.get(BindingContext.STATEMENT, expression)) {
generateIncrement(op, asmType, expression.getBaseExpression(), receiver);
return StackValue.none();
}
else {
gen(expression.getBaseExpression(), asmType); // old value
generateIncrement(op, asmType, expression.getBaseExpression(), receiver); // increment in-place
return StackValue.onStack(asmType); // old value
}
gen(expression.getBaseExpression(), asmType); // old value
generateIncrement(op, asmType, expression.getBaseExpression(), receiver); // increment in-place
return StackValue.onStack(asmType); // old value
}
}
throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
@@ -2164,6 +2169,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitThrowExpression(JetThrowExpression expression, StackValue receiver) {
gen(expression.getThrownExpression(), JetTypeMapper.TYPE_OBJECT);
doFinallyOnReturnOrThrow();
v.athrow();
return StackValue.none();
}
@@ -2184,14 +2190,31 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitTryExpression(JetTryExpression expression, StackValue receiver) {
/*
The "returned" value of try expression with no finally is either the last expression in the try block or the last expression in the catch block
(or blocks).
If finally block is present, its last expression is the value of try expression.
*/
JetFinallySection finallyBlock = expression.getFinallyBlock();
if(finallyBlock != null) {
stackOfFinallyBlocks.add(expression);
}
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
Type expectedAsmType = typeMapper.mapType(jetType);
Label tryStart = new Label();
v.mark(tryStart);
gen(expression.getTryBlock(), Type.VOID_TYPE);
v.nop(); // prevent verify error on empty try
if(finallyBlock == null)
gen(expression.getTryBlock(), expectedAsmType);
else
gen(expression.getTryBlock(), Type.VOID_TYPE);
Label tryEnd = new Label();
v.mark(tryEnd);
JetFinallySection finallyBlock = expression.getFinallyBlock();
if (finallyBlock != null) {
gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE);
gen(finallyBlock.getFinalExpression(), expectedAsmType);
}
Label end = new Label();
v.goTo(end); // TODO don't generate goto if there's no code following try/catch
@@ -2206,31 +2229,36 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
int index = lookupLocal(descriptor);
v.store(index, descriptorType);
gen(clause.getCatchBody(), Type.VOID_TYPE);
v.goTo(end); // TODO don't generate goto if there's no code following try/catch
gen(clause.getCatchBody(), finallyBlock != null ? Type.VOID_TYPE : expectedAsmType);
myFrameMap.leave(descriptor);
if (finallyBlock != null) {
gen(finallyBlock.getFinalExpression(), expectedAsmType);
}
v.goTo(end); // TODO don't generate goto if there's no code following try/catch
v.visitTryCatchBlock(tryStart, tryEnd, clauseStart, descriptorType.getInternalName());
}
if (finallyBlock != null) {
Label finallyStart = new Label();
v.mark(finallyStart);
int index = myFrameMap.enterTemp();
v.store(index, THROWABLE_TYPE);
gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE);
v.load(index, THROWABLE_TYPE);
v.athrow();
myFrameMap.leaveTemp();
v.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null);
}
v.mark(end);
v.nop();
return StackValue.none();
if(finallyBlock != null) {
stackOfFinallyBlocks.remove(stackOfFinallyBlocks.size()-1);
}
return StackValue.onStack(expectedAsmType);
}
@Override
@@ -2661,4 +2689,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
super(message);
}
}
@Override
public String toString() {
return context.getContextDescriptor().toString();
}
}
@@ -126,12 +126,8 @@ public class FunctionCodegen {
codegen.returnExpression(bodyExpressions);
}
try {
mv.visitMaxs(0, 0);
}
catch (Throwable t) {
System.out.println(t);
}
mv.visitEnd();
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
@@ -0,0 +1,52 @@
fun test1() : Boolean {
try {
return true
} finally {
if(true) // otherwise we wisely have unreachable code
return false
}
}
var x = true
fun test2() : Boolean {
try {
} finally {
x = false;
}
return x
}
fun test3() : Int {
var y = 0
try {
++y
} finally {
++y
}
return y
}
var z = 0
fun test4() : Int {
z = 0
return try {
try {
z++
}
finally {
z++
}
} finally {
++z
}
}
fun box() : String {
if(test1()) return "test1 failed"
if(test2()) return "test2 failed"
if(test3() != 2) return "test3 failed"
System.out?.println(test4())
if(test4() != 3) return "test4 failed"
return "OK"
}
@@ -0,0 +1,30 @@
var GUEST_USER_ID = 3
val USER_ID =
try {
getUserIdFromEnvironment()
}
catch (e : UnsupportedOperationException) {
++GUEST_USER_ID
}
val USER_ID_2 =
try {
getUserIdFromEnvironment()
}
catch (e : UnsupportedOperationException) {
GUEST_USER_ID
}
finally {
GUEST_USER_ID++
}
fun getUserIdFromEnvironment() : Int = throw UnsupportedOperationException()
fun box() : String {
System.out?.println("G: " + GUEST_USER_ID + " U1:" + USER_ID + " U2: " + USER_ID_2)
if(USER_ID != 4) return "test0 failed"
if(USER_ID_2 != 4) return "test2 failed"
if(GUEST_USER_ID != 5) return "test3 failed"
return "OK"
}
@@ -0,0 +1,24 @@
class Reluctant() {
{
throw Exception("I'm not coming out")
}
}
fun p(o : Any?) = System.out?.println(o)
fun test1() : String {
try {
val b = Reluctant()
return "Surprise!"
}
catch (ex : Exception) {
return "I told you so"
}
}
fun box() : String {
if(test1() != "I told you so") return "test1 failed"
return "OK"
}
@@ -7,6 +7,7 @@ import java.util.List;
/**
* @author yole
* @author alex.tkachman
*/
public class ClassGenTest extends CodegenTestCase {
public void testPSVMClass() throws Exception {
@@ -208,4 +209,17 @@ public class ClassGenTest extends CodegenTestCase {
System.out.println(generateToText());
blackBox();
}
public void testKt501 () throws Exception {
blackBoxFile("regressions/kt501.jet");
}
public void testKt496 () throws Exception {
blackBoxFile("regressions/kt496.jet");
System.out.println(generateToText());
}
public void testKt500 () throws Exception {
blackBoxFile("regressions/kt500.jet");
}
}