ProperlyGenerate exception table
This commit is contained in:
@@ -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<CatchBlock> blocks = new ArrayList<CatchBlock>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 : "<init> call not corresponds to new call" + owner + " " + name;
|
||||
@@ -258,71 +259,96 @@ public class MethodInliner {
|
||||
|
||||
AbstractInsnNode cur = node.instructions.getFirst();
|
||||
int index = 0;
|
||||
Set<LabelNode> deadLabels = new HashSet<LabelNode>();
|
||||
|
||||
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<SourceValue> frame = sources[index];
|
||||
SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength);
|
||||
Frame<SourceValue> 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<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) {
|
||||
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<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();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user