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 (tryCatchBlockEnd != null) {
|
||||||
|
if (context.isInlineFunction()) {
|
||||||
|
InlineCodegenUtil.generateGoToTryCatchBlockEndMarker(v);
|
||||||
|
}
|
||||||
v.goTo(tryCatchBlockEnd);
|
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_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
||||||
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
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_AFTER_METHOD_NAME = "afterInlineCall";
|
||||||
|
public static final String INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END = "goToTryCatchBlockEnd";
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static MethodNode getMethodNode(
|
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 static class LabelTextifier extends Textifier {
|
||||||
|
|
||||||
public LabelTextifier() {
|
public LabelTextifier() {
|
||||||
|
|||||||
+4
-27
@@ -470,8 +470,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
|
|||||||
|
|
||||||
TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1);
|
TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1);
|
||||||
AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end;
|
AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end;
|
||||||
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().handler,
|
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().start);
|
||||||
nextIntervalWithSameDefaultHandler.getNode().start);
|
|
||||||
|
|
||||||
FinallyBlockInfo finallyInfo = new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive);
|
FinallyBlockInfo finallyInfo = new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive);
|
||||||
|
|
||||||
@@ -483,37 +482,15 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private AbstractInsnNode skipLastGotoIfNeeded(
|
private static AbstractInsnNode skipLastGotoIfNeeded(
|
||||||
@NotNull LabelNode defaultHandlerStartLabel,
|
|
||||||
@NotNull AbstractInsnNode lastFinallyInsExclusive
|
@NotNull AbstractInsnNode lastFinallyInsExclusive
|
||||||
) {
|
) {
|
||||||
|
|
||||||
AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true);
|
AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true);
|
||||||
assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive;
|
assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive;
|
||||||
|
|
||||||
if (prevLast.getOpcode() == Opcodes.GOTO) {
|
if (InlineCodegenUtil.isGoToTryCatchBlockEnd(prevLast)) {
|
||||||
//There we should understand whether goto is jump over catches or last break/continue command inside finally.
|
return prevLast.getPrevious();
|
||||||
//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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return lastFinallyInsExclusive;
|
return lastFinallyInsExclusive;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -75,7 +75,10 @@ private fun isInlineMarker(insn: AbstractInsnNode, markerName: String? = null):
|
|||||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||||
insn is MethodInsnNode &&
|
insn is MethodInsnNode &&
|
||||||
insn.owner == InlineCodegenUtil.INLINE_MARKER_CLASS_NAME &&
|
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>?>) {
|
private fun process(methodNode: MethodNode, frames: Array<Frame<BasicValue>?>) {
|
||||||
|
|||||||
@@ -25,4 +25,8 @@ public class InlineMarker {
|
|||||||
public static void afterInlineCall() {
|
public static void afterInlineCall() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void goToTryCatchBlockEnd() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user