Refined skipping last goto when inlining try/catch/finally block

This commit is contained in:
Denis Zharkov
2015-01-13 20:28:52 +03:00
parent 5a0a05e5c7
commit aecb925b7b
5 changed files with 28 additions and 28 deletions
@@ -1746,6 +1746,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
if (tryCatchBlockEnd != null) {
if (context.isInlineFunction()) {
InlineCodegenUtil.generateGoToTryCatchBlockEndMarker(v);
}
v.goTo(tryCatchBlockEnd);
}
@@ -75,6 +75,7 @@ public class InlineCodegenUtil {
public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
public static final String INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END = "goToTryCatchBlockEnd";
@Nullable
public static MethodNode getMethodNode(
@@ -391,6 +392,18 @@ public class InlineCodegenUtil {
}
}
public static void generateGoToTryCatchBlockEndMarker(@NotNull InstructionAdapter v) {
v.invokestatic(INLINE_MARKER_CLASS_NAME, INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END, "()V", false);
}
public static boolean isGoToTryCatchBlockEnd(@NotNull AbstractInsnNode node) {
if (!(node.getPrevious() instanceof MethodInsnNode)) return false;
MethodInsnNode previous = (MethodInsnNode) node.getPrevious();
return node.getOpcode() == Opcodes.GOTO &&
INLINE_MARKER_CLASS_NAME.equals(previous.owner) &&
INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END.equals(previous.name);
}
public static class LabelTextifier extends Textifier {
public LabelTextifier() {
@@ -470,8 +470,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1);
AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end;
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().handler,
nextIntervalWithSameDefaultHandler.getNode().start);
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().start);
FinallyBlockInfo finallyInfo = new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive);
@@ -483,37 +482,15 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
}
@NotNull
private AbstractInsnNode skipLastGotoIfNeeded(
@NotNull LabelNode defaultHandlerStartLabel,
private static AbstractInsnNode skipLastGotoIfNeeded(
@NotNull AbstractInsnNode lastFinallyInsExclusive
) {
AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true);
assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive;
if (prevLast.getOpcode() == Opcodes.GOTO) {
//There we should understand whether goto is jump over catches or last break/continue command inside finally.
//If it's a jump over catches so next is true:
// 1. jump label should go after default catch handler start label
// AND
// 2. it shouldn't be present in default catch block, otherwise it break/continue
LabelNode targetJump = ((JumpInsnNode) prevLast).label;
InsnList instructions = inlineFun.instructions;
if (instructions.indexOf(defaultHandlerStartLabel) < instructions.indexOf(targetJump)) { //1 condition
AbstractInsnNode cur = defaultHandlerStartLabel;
while (cur != targetJump) {
if (cur.getOpcode() == Opcodes.GOTO) {
//noinspection ConstantConditions
if (((JumpInsnNode) cur).label == targetJump) { //fail of 2 condition
return lastFinallyInsExclusive;
}
}
cur = cur.getNext();
}
return prevLast;
}
if (InlineCodegenUtil.isGoToTryCatchBlockEnd(prevLast)) {
return prevLast.getPrevious();
}
return lastFinallyInsExclusive;
}
@@ -75,7 +75,10 @@ private fun isInlineMarker(insn: AbstractInsnNode, markerName: String? = null):
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
insn is MethodInsnNode &&
insn.owner == InlineCodegenUtil.INLINE_MARKER_CLASS_NAME &&
if (markerName != null) markerName == insn.name else true
if (markerName != null) markerName == insn.name else (
insn.name == InlineCodegenUtil.INLINE_MARKER_BEFORE_METHOD_NAME ||
insn.name == InlineCodegenUtil.INLINE_MARKER_AFTER_METHOD_NAME
)
}
private fun process(methodNode: MethodNode, frames: Array<Frame<BasicValue>?>) {
@@ -25,4 +25,8 @@ public class InlineMarker {
public static void afterInlineCall() {
}
public static void goToTryCatchBlockEnd() {
}
}