ProperlyGenerate exception table
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user