proper try/catch/finally
This commit is contained in:
@@ -39,7 +39,18 @@ public interface ClassBuilderFactory {
|
|||||||
ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
|
ClassBuilderFactory BINARIES = new ClassBuilderFactory() {
|
||||||
@Override
|
@Override
|
||||||
public ClassBuilder newClassBuilder() {
|
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
|
@Override
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
private final CodegenContext context;
|
private final CodegenContext context;
|
||||||
private final IntrinsicMethods intrinsics;
|
private final IntrinsicMethods intrinsics;
|
||||||
|
|
||||||
|
private final ArrayList<JetTryExpression> stackOfFinallyBlocks = new ArrayList<JetTryExpression>();
|
||||||
|
|
||||||
public ExpressionCodegen(MethodVisitor v,
|
public ExpressionCodegen(MethodVisitor v,
|
||||||
FrameMap myMap,
|
FrameMap myMap,
|
||||||
Type returnType,
|
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
|
@Override
|
||||||
public StackValue visitReturnExpression(JetReturnExpression expression, StackValue receiver) {
|
public StackValue visitReturnExpression(JetReturnExpression expression, StackValue receiver) {
|
||||||
final JetExpression returnedExpression = expression.getReturnedExpression();
|
final JetExpression returnedExpression = expression.getReturnedExpression();
|
||||||
if (returnedExpression != null) {
|
if (returnedExpression != null) {
|
||||||
gen(returnedExpression, returnType);
|
gen(returnedExpression, returnType);
|
||||||
|
doFinallyOnReturnOrThrow();
|
||||||
v.areturn(returnType);
|
v.areturn(returnType);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1857,16 +1869,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
DeclarationDescriptor cls = op.getContainingDeclaration();
|
DeclarationDescriptor cls = op.getContainingDeclaration();
|
||||||
if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) {
|
if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) {
|
||||||
receiver.put(receiver.type, v);
|
receiver.put(receiver.type, v);
|
||||||
//noinspection ConstantConditions
|
gen(expression.getBaseExpression(), asmType); // old value
|
||||||
if (bindingContext.get(BindingContext.STATEMENT, expression)) {
|
generateIncrement(op, asmType, expression.getBaseExpression(), receiver); // increment in-place
|
||||||
generateIncrement(op, asmType, expression.getBaseExpression(), receiver);
|
return StackValue.onStack(asmType); // old value
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
|
throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
|
||||||
@@ -2164,6 +2169,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
@Override
|
@Override
|
||||||
public StackValue visitThrowExpression(JetThrowExpression expression, StackValue receiver) {
|
public StackValue visitThrowExpression(JetThrowExpression expression, StackValue receiver) {
|
||||||
gen(expression.getThrownExpression(), JetTypeMapper.TYPE_OBJECT);
|
gen(expression.getThrownExpression(), JetTypeMapper.TYPE_OBJECT);
|
||||||
|
doFinallyOnReturnOrThrow();
|
||||||
v.athrow();
|
v.athrow();
|
||||||
return StackValue.none();
|
return StackValue.none();
|
||||||
}
|
}
|
||||||
@@ -2184,14 +2190,31 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitTryExpression(JetTryExpression expression, StackValue receiver) {
|
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();
|
Label tryStart = new Label();
|
||||||
v.mark(tryStart);
|
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();
|
Label tryEnd = new Label();
|
||||||
v.mark(tryEnd);
|
v.mark(tryEnd);
|
||||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
|
||||||
if (finallyBlock != null) {
|
if (finallyBlock != null) {
|
||||||
gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE);
|
gen(finallyBlock.getFinalExpression(), expectedAsmType);
|
||||||
}
|
}
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
v.goTo(end); // TODO don't generate goto if there's no code following try/catch
|
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);
|
int index = lookupLocal(descriptor);
|
||||||
v.store(index, descriptorType);
|
v.store(index, descriptorType);
|
||||||
|
|
||||||
gen(clause.getCatchBody(), Type.VOID_TYPE);
|
gen(clause.getCatchBody(), finallyBlock != null ? Type.VOID_TYPE : expectedAsmType);
|
||||||
v.goTo(end); // TODO don't generate goto if there's no code following try/catch
|
|
||||||
|
|
||||||
myFrameMap.leave(descriptor);
|
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());
|
v.visitTryCatchBlock(tryStart, tryEnd, clauseStart, descriptorType.getInternalName());
|
||||||
}
|
}
|
||||||
if (finallyBlock != null) {
|
if (finallyBlock != null) {
|
||||||
Label finallyStart = new Label();
|
Label finallyStart = new Label();
|
||||||
v.mark(finallyStart);
|
v.mark(finallyStart);
|
||||||
|
|
||||||
int index = myFrameMap.enterTemp();
|
|
||||||
v.store(index, THROWABLE_TYPE);
|
|
||||||
|
|
||||||
gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE);
|
gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE);
|
||||||
|
|
||||||
v.load(index, THROWABLE_TYPE);
|
|
||||||
v.athrow();
|
v.athrow();
|
||||||
|
|
||||||
myFrameMap.leaveTemp();
|
|
||||||
|
|
||||||
v.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null);
|
v.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null);
|
||||||
}
|
}
|
||||||
v.mark(end);
|
v.mark(end);
|
||||||
|
v.nop();
|
||||||
|
|
||||||
return StackValue.none();
|
if(finallyBlock != null) {
|
||||||
|
stackOfFinallyBlocks.remove(stackOfFinallyBlocks.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackValue.onStack(expectedAsmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -2661,4 +2689,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return context.getContextDescriptor().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,12 +126,8 @@ public class FunctionCodegen {
|
|||||||
|
|
||||||
codegen.returnExpression(bodyExpressions);
|
codegen.returnExpression(bodyExpressions);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
mv.visitMaxs(0, 0);
|
mv.visitMaxs(0, 0);
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
System.out.println(t);
|
|
||||||
}
|
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
|
|
||||||
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
|
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 yole
|
||||||
|
* @author alex.tkachman
|
||||||
*/
|
*/
|
||||||
public class ClassGenTest extends CodegenTestCase {
|
public class ClassGenTest extends CodegenTestCase {
|
||||||
public void testPSVMClass() throws Exception {
|
public void testPSVMClass() throws Exception {
|
||||||
@@ -208,4 +209,17 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
blackBox();
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user