From e45683d05e76b90d5884a4e8b8b96897b7fcc9f8 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Wed, 5 Feb 2014 16:16:41 +0400 Subject: [PATCH] ProperlyGenerate exception table --- .../jet/codegen/asm/InlineAdapter.java | 47 +++++++ .../jet/codegen/asm/MethodInliner.java | 122 +++++++++++------- 2 files changed, 121 insertions(+), 48 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineAdapter.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineAdapter.java index d1274b4b30a..b76fb851df0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineAdapter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineAdapter.java @@ -16,14 +16,22 @@ package org.jetbrains.jet.codegen.asm; +import org.jetbrains.asm4.Label; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.commons.InstructionAdapter; +import java.util.ArrayList; +import java.util.List; + public class InlineAdapter extends InstructionAdapter { private int nextLocalIndex = 0; + private boolean isInlining = false; + + private final List blocks = new ArrayList(); + public InlineAdapter(MethodVisitor mv, int localsSize) { super(mv); nextLocalIndex = localsSize; @@ -51,4 +59,43 @@ public class InlineAdapter extends InstructionAdapter { public int getNextLocalIndex() { return nextLocalIndex; } + + public void setInlining(boolean isInlining) { + this.isInlining = isInlining; + } + + @Override + public void visitTryCatchBlock(Label start, + Label end, Label handler, String type) { + if(!isInlining) { + blocks.add(new CatchBlock(start, end, + handler, type)); + } else { + super.visitTryCatchBlock(start, end, + handler, type); + } + } + + @Override + public void visitMaxs(int stack, int locals) { + for (CatchBlock b : blocks) { + super.visitTryCatchBlock(b.start, b.end, + b.handler, b.type); + } + super.visitMaxs(stack, locals); + } + + private static class CatchBlock { + private final Label start; + private final Label end; + private final Label handler; + private final String type; + + public CatchBlock(Label start, Label end, Label handler, String type) { + this.start = start; + this.end = end; + this.handler = handler; + this.type = type; + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java index 589b0fd8328..5da946457e9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java @@ -153,15 +153,16 @@ public class MethodInliner { Parameters params = new Parameters(lambdaParameters, Parameters.transformList(capturedRemapper.markRecaptured(info.getCapturedVars(), info), lambdaParameters.size())); + this.setInlining(true); MethodInliner inliner = new MethodInliner(info.getNode(), params, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), capturedRemapper); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(params, valueParamShift); inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver - Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod(); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this); + this.setInlining(true); } else if (isLambdaConstructorCall(owner, name)) { //TODO add method assert invocation != null : " call not corresponds to new call" + owner + " " + name; @@ -258,71 +259,96 @@ public class MethodInliner { AbstractInsnNode cur = node.instructions.getFirst(); int index = 0; + Set deadLabels = new HashSet(); + while (cur != null) { - if (cur.getType() == AbstractInsnNode.METHOD_INSN) { - MethodInsnNode methodInsnNode = (MethodInsnNode) cur; - String owner = methodInsnNode.owner; - String desc = methodInsnNode.desc; - String name = methodInsnNode.name; - //TODO check closure - int paramLength = Type.getArgumentTypes(desc).length + 1;//non static - if (isInvokeOnInlinable(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { - Frame frame = sources[index]; - SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength); + Frame frame = sources[index]; - boolean isInlinable = false; - LambdaInfo lambdaInfo = null; - int varIndex = -1; + if (frame != null) { + if (cur.getType() == AbstractInsnNode.METHOD_INSN) { + MethodInsnNode methodInsnNode = (MethodInsnNode) cur; + String owner = methodInsnNode.owner; + String desc = methodInsnNode.desc; + String name = methodInsnNode.name; + //TODO check closure + int paramLength = Type.getArgumentTypes(desc).length + 1;//non static + if (isInvokeOnInlinable(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { + SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength); - if (sourceValue.insns.size() == 1) { - AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); - if (insnNode.getType() == AbstractInsnNode.VAR_INSN) { - assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString(); + boolean isInlinable = false; + LambdaInfo lambdaInfo = null; + int varIndex = -1; - varIndex = ((VarInsnNode) insnNode).var; - lambdaInfo = getLambda(varIndex); - isInlinable = lambdaInfo != null; - - if (isInlinable) { - //remove inlinable access - node.instructions.remove(insnNode); - } - } - } - - inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc))); - } - else if (isLambdaConstructorCall(owner, name)) { - Frame frame = sources[index]; - Map infos = new HashMap(); - int paramStart = frame.getStackSize() - paramLength; - - for (int i = 0; i < paramLength; i++) { - SourceValue sourceValue = frame.getStack(paramStart + i); if (sourceValue.insns.size() == 1) { AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); - if (insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD) { - int varIndex = ((VarInsnNode) insnNode).var; - LambdaInfo lambdaInfo = getLambda(varIndex); - if (lambdaInfo != null) { - InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null); - inlinableAccess.setInfo(lambdaInfo); - infos.put(i, inlinableAccess); + if (insnNode.getType() == AbstractInsnNode.VAR_INSN) { + assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString(); + varIndex = ((VarInsnNode) insnNode).var; + lambdaInfo = getLambda(varIndex); + isInlinable = lambdaInfo != null; + if (isInlinable) { //remove inlinable access node.instructions.remove(insnNode); } } } - } - ConstructorInvocation invocation = new ConstructorInvocation(owner, infos); - constructorInvocationList.add(invocation); + inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc))); + } + else if (isLambdaConstructorCall(owner, name)) { + Map infos = new HashMap(); + int paramStart = frame.getStackSize() - paramLength; + + for (int i = 0; i < paramLength; i++) { + SourceValue sourceValue = frame.getStack(paramStart + i); + if (sourceValue.insns.size() == 1) { + AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); + if (insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD) { + int varIndex = ((VarInsnNode) insnNode).var; + LambdaInfo lambdaInfo = getLambda(varIndex); + if (lambdaInfo != null) { + InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null); + inlinableAccess.setInfo(lambdaInfo); + infos.put(i, inlinableAccess); + + //remove inlinable access + node.instructions.remove(insnNode); + } + } + } + } + + ConstructorInvocation invocation = new ConstructorInvocation(owner, infos); + constructorInvocationList.add(invocation); + } } } + + AbstractInsnNode prevNode = cur; cur = cur.getNext(); index++; + + //given frame is null if and only if the corresponding instruction cannot be reached (dead code). + if (frame == null) { + //clean dead code otherwise there is problems in unreachable finally block, don't touch label it cause try/catch/finally problems + if (prevNode.getType() == AbstractInsnNode.LABEL) { + deadLabels.add((LabelNode) prevNode); + } else { + node.instructions.remove(prevNode); + } + } } + + //clean dead try catch blocks + List blocks = node.tryCatchBlocks; + for (Iterator iterator = blocks.iterator(); iterator.hasNext(); ) { + TryCatchBlockNode block = iterator.next(); + if (deadLabels.contains(block.start) && deadLabels.contains(block.end)) { + iterator.remove(); + } + } + return node; }