Updated exception table generation: try block return moved to uncatched interval

#KT-8148 Fixed
This commit is contained in:
Michael Bogdanov
2015-06-09 16:25:03 +03:00
parent 11ab2148b2
commit 93c5a52d13
7 changed files with 154 additions and 25 deletions
@@ -1197,16 +1197,20 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
public StackValue visitBreakExpression(@NotNull JetBreakExpression expression, StackValue receiver) {
return generateBreakOrContinueExpression(expression, true);
return generateBreakOrContinueExpression(expression, true, new Label());
}
@Override
public StackValue visitContinueExpression(@NotNull JetContinueExpression expression, StackValue receiver) {
return generateBreakOrContinueExpression(expression, false);
return generateBreakOrContinueExpression(expression, false, new Label());
}
@NotNull
private StackValue generateBreakOrContinueExpression(@NotNull JetExpressionWithLabel expression, boolean isBreak) {
private StackValue generateBreakOrContinueExpression(
@NotNull JetExpressionWithLabel expression,
boolean isBreak,
@NotNull Label afterBreakContinueLabel
) {
assert expression instanceof JetContinueExpression || expression instanceof JetBreakExpression;
if (!blockStackElements.isEmpty()) {
@@ -1215,7 +1219,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (stackElement instanceof FinallyBlockStackElement) {
FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
//noinspection ConstantConditions
genFinallyBlockOrGoto(finallyBlockStackElement, null);
genFinallyBlockOrGoto(finallyBlockStackElement, null, afterBreakContinueLabel);
}
else if (stackElement instanceof LoopBlockStackElement) {
LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement;
@@ -1225,6 +1229,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
loopBlockStackElement.targetLabel != null &&
labelElement.getReferencedName().equals(loopBlockStackElement.targetLabel.getReferencedName())) {
v.goTo(isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel);
v.mark(afterBreakContinueLabel);
return StackValue.none();
}
}
@@ -1233,7 +1238,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
blockStackElements.pop();
StackValue result = generateBreakOrContinueExpression(expression, isBreak);
StackValue result = generateBreakOrContinueExpression(expression, isBreak, afterBreakContinueLabel);
blockStackElements.push(stackElement);
return result;
}
@@ -1754,12 +1759,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
private void doFinallyOnReturn() {
private void doFinallyOnReturn(Label afterReturnLabel) {
if(!blockStackElements.isEmpty()) {
BlockStackElement stackElement = blockStackElements.peek();
if (stackElement instanceof FinallyBlockStackElement) {
FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
genFinallyBlockOrGoto(finallyBlockStackElement, null);
genFinallyBlockOrGoto(finallyBlockStackElement, null, afterReturnLabel);
}
else if (stackElement instanceof LoopBlockStackElement) {
@@ -1768,7 +1773,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
blockStackElements.pop();
doFinallyOnReturn();
doFinallyOnReturn(afterReturnLabel);
blockStackElements.push(stackElement);
}
}
@@ -1784,7 +1789,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private void genFinallyBlockOrGoto(
@Nullable FinallyBlockStackElement finallyBlockStackElement,
@Nullable Label tryCatchBlockEnd
@Nullable Label tryCatchBlockEnd,
@Nullable Label afterReturnLabel
) {
if (finallyBlockStackElement != null) {
assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent";
@@ -1809,8 +1815,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
if (finallyBlockStackElement != null) {
Label finallyEnd = new Label();
v.mark(finallyEnd);
Label finallyEnd = afterReturnLabel != null ? afterReturnLabel : new Label();
if (afterReturnLabel == null) {
v.mark(finallyEnd);
}
finallyBlockStackElement.addGapLabel(finallyEnd);
blockStackElements.push(finallyBlockStackElement);
@@ -1835,28 +1843,30 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
gen(returnedExpression, returnType);
}
generateFinallyBlocksIfNeeded(returnType);
Label afterReturnLabel = new Label();
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
if (isNonLocalReturn) {
InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
}
v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
v.mark(afterReturnLabel);
return StackValue.none();
}
public void generateFinallyBlocksIfNeeded(Type returnType) {
public void generateFinallyBlocksIfNeeded(Type returnType, @NotNull Label afterReturnLabel) {
if (hasFinallyBlocks()) {
if (!Type.VOID_TYPE.equals(returnType)) {
int returnValIndex = myFrameMap.enterTemp(returnType);
StackValue.Local localForReturnValue = StackValue.local(returnValIndex, returnType);
localForReturnValue.store(StackValue.onStack(returnType), v);
doFinallyOnReturn();
doFinallyOnReturn(afterReturnLabel);
localForReturnValue.put(returnType, v);
myFrameMap.leaveTemp(returnType);
}
else {
doFinallyOnReturn();
doFinallyOnReturn(afterReturnLabel);
}
}
}
@@ -3571,7 +3581,7 @@ The "returned" value of try expression with no finally is either the last expres
Label end = new Label();
genFinallyBlockOrGoto(finallyBlockStackElement, end);
genFinallyBlockOrGoto(finallyBlockStackElement, end, null);
List<JetCatchClause> clauses = expression.getCatchClauses();
for (int i = 0, size = clauses.size(); i < size; i++) {
@@ -3601,7 +3611,7 @@ The "returned" value of try expression with no finally is either the last expres
v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd,
index);
genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null);
genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null, null);
generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
}
@@ -3621,7 +3631,7 @@ The "returned" value of try expression with no finally is either the last expres
List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
genFinallyBlockOrGoto(finallyBlockStackElement, null);
genFinallyBlockOrGoto(finallyBlockStackElement, null, null);
v.load(savedException, JAVA_THROWABLE_TYPE);
myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
@@ -668,7 +668,7 @@ public class InlineCodegen extends CallGenerator {
MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
if (extension != null) {
Label start = new Label();
Label end = new Label();
//Label end = new Label();
MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
finallyNode.visitLabel(start);
@@ -684,12 +684,12 @@ public class InlineCodegen extends CallGenerator {
frameMap.enterTemp(Type.INT_TYPE);
}
finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
finallyNode.visitLabel(end);
finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.labelNode.getLabel());
//finallyNode.visitLabel(end);
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, (LabelNode) end.info);
SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.labelNode);
processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false);
processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false);
@@ -699,8 +699,10 @@ public class MethodInliner {
}
//genetate finally block before nonLocalReturn flag/return/goto
result.add(new PointForExternalFinallyBlocks(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode())
));
LabelNode label = new LabelNode();
instructions.insert(insnNode, label);
result.add(new PointForExternalFinallyBlocks(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode()),
label));
}
insnNode = insnNode.getNext();
}
@@ -714,9 +716,12 @@ public class MethodInliner {
final Type returnType;
public PointForExternalFinallyBlocks(AbstractInsnNode beforeIns, Type returnType) {
final LabelNode labelNode;
public PointForExternalFinallyBlocks(@NotNull AbstractInsnNode beforeIns, @NotNull Type returnType, @NotNull LabelNode labelNode) {
this.beforeIns = beforeIns;
this.returnType = returnType;
this.labelNode = labelNode;
}
}
@@ -0,0 +1,29 @@
class A(var value: String)
fun box(): String {
val a = A("start")
try {
test(a)
} catch(e: java.lang.RuntimeException) {
}
if (a.value != "start, try, finally1, finally2") return "fail: ${a.value}"
return "OK"
}
fun test(a: A) : String {
try {
try {
a.value += ", try"
return a.value
} finally {
a.value += ", finally1"
}
} finally {
a.value += ", finally2"
throw RuntimeException("fail")
}
}
@@ -0,0 +1,33 @@
class A(var value: String)
fun box(): String {
val a = A("start")
try {
test(a)
} catch(e: java.lang.RuntimeException) {
}
if (a.value != "start, try, finally1, finally2") return "fail: ${a.value}"
return "OK"
}
fun test(a: A) : String {
while (true) {
try {
try {
a.value += ", try"
break
}
finally {
a.value += ", finally1"
}
}
finally {
a.value += ", finally2"
throw RuntimeException("fail")
}
}
}
@@ -0,0 +1,34 @@
class A(var value: String)
fun box(): String {
val a = A("start")
try {
test(a)
} catch(e: java.lang.RuntimeException) {
}
if (a.value != "start, try, finally1, finally2") return "fail: ${a.value}"
return "OK"
}
fun test(a: A) : String {
while (a.value == "start") {
try {
try {
a.value += ", try"
continue
}
finally {
a.value += ", finally1"
}
}
finally {
a.value += ", finally2"
throw RuntimeException("fail")
}
}
return "fail"
}
@@ -2143,6 +2143,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt8148.kt")
public void testKt8148() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt8148.kt");
doTest(fileName);
}
@TestMetadata("kt8148_break.kt")
public void testKt8148_break() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt8148_break.kt");
doTest(fileName);
}
@TestMetadata("kt8148_continue.kt")
public void testKt8148_continue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt8148_continue.kt");
doTest(fileName);
}
@TestMetadata("kt870.kt")
public void testKt870() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt870.kt");