Refined skipping last goto when inlining try/catch/finally block
This commit is contained in:
@@ -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() {
|
||||
|
||||
+4
-27
@@ -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;
|
||||
}
|
||||
|
||||
+4
-1
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user