ProperlyGenerate exception table

This commit is contained in:
Mikhael Bogdanov
2014-02-05 16:16:41 +04:00
parent e013a65a2c
commit e45683d05e
2 changed files with 121 additions and 48 deletions
@@ -16,14 +16,22 @@
package org.jetbrains.jet.codegen.asm; package org.jetbrains.jet.codegen.asm;
import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import java.util.ArrayList;
import java.util.List;
public class InlineAdapter extends InstructionAdapter { public class InlineAdapter extends InstructionAdapter {
private int nextLocalIndex = 0; private int nextLocalIndex = 0;
private boolean isInlining = false;
private final List<CatchBlock> blocks = new ArrayList<CatchBlock>();
public InlineAdapter(MethodVisitor mv, int localsSize) { public InlineAdapter(MethodVisitor mv, int localsSize) {
super(mv); super(mv);
nextLocalIndex = localsSize; nextLocalIndex = localsSize;
@@ -51,4 +59,43 @@ public class InlineAdapter extends InstructionAdapter {
public int getNextLocalIndex() { public int getNextLocalIndex() {
return nextLocalIndex; 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;
}
}
} }
@@ -153,15 +153,16 @@ public class MethodInliner {
Parameters params = new Parameters(lambdaParameters, Parameters.transformList(capturedRemapper.markRecaptured(info.getCapturedVars(), info), lambdaParameters.size())); 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(), MethodInliner inliner = new MethodInliner(info.getNode(), params, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(),
capturedRemapper); capturedRemapper);
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(params, valueParamShift); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(params, valueParamShift);
inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver
Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();
Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod(); Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this); StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
this.setInlining(true);
} }
else if (isLambdaConstructorCall(owner, name)) { //TODO add method else if (isLambdaConstructorCall(owner, name)) { //TODO add method
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name; assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
@@ -258,71 +259,96 @@ public class MethodInliner {
AbstractInsnNode cur = node.instructions.getFirst(); AbstractInsnNode cur = node.instructions.getFirst();
int index = 0; int index = 0;
Set<LabelNode> deadLabels = new HashSet<LabelNode>();
while (cur != null) { while (cur != null) {
if (cur.getType() == AbstractInsnNode.METHOD_INSN) { Frame<SourceValue> frame = sources[index];
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<SourceValue> frame = sources[index];
SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength);
boolean isInlinable = false; if (frame != null) {
LambdaInfo lambdaInfo = null; if (cur.getType() == AbstractInsnNode.METHOD_INSN) {
int varIndex = -1; 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) { boolean isInlinable = false;
AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); LambdaInfo lambdaInfo = null;
if (insnNode.getType() == AbstractInsnNode.VAR_INSN) { int varIndex = -1;
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);
}
}
}
inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc)));
}
else if (isLambdaConstructorCall(owner, name)) {
Frame<SourceValue> frame = sources[index];
Map<Integer, InlinableAccess> infos = new HashMap<Integer, InlinableAccess>();
int paramStart = frame.getStackSize() - paramLength;
for (int i = 0; i < paramLength; i++) {
SourceValue sourceValue = frame.getStack(paramStart + i);
if (sourceValue.insns.size() == 1) { if (sourceValue.insns.size() == 1) {
AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); AbstractInsnNode insnNode = sourceValue.insns.iterator().next();
if (insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD) { if (insnNode.getType() == AbstractInsnNode.VAR_INSN) {
int varIndex = ((VarInsnNode) insnNode).var; assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString();
LambdaInfo lambdaInfo = getLambda(varIndex); varIndex = ((VarInsnNode) insnNode).var;
if (lambdaInfo != null) { lambdaInfo = getLambda(varIndex);
InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null); isInlinable = lambdaInfo != null;
inlinableAccess.setInfo(lambdaInfo);
infos.put(i, inlinableAccess);
if (isInlinable) {
//remove inlinable access //remove inlinable access
node.instructions.remove(insnNode); node.instructions.remove(insnNode);
} }
} }
} }
}
ConstructorInvocation invocation = new ConstructorInvocation(owner, infos); inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc)));
constructorInvocationList.add(invocation); }
else if (isLambdaConstructorCall(owner, name)) {
Map<Integer, InlinableAccess> infos = new HashMap<Integer, InlinableAccess>();
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(); cur = cur.getNext();
index++; index++;
//given frame is <tt>null</tt> 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<TryCatchBlockNode> blocks = node.tryCatchBlocks;
for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
TryCatchBlockNode block = iterator.next();
if (deadLabels.contains(block.start) && deadLabels.contains(block.end)) {
iterator.remove();
}
}
return node; return node;
} }