Generate local variable table for inlined lambda

This commit is contained in:
Mikhael Bogdanov
2014-03-19 17:45:46 +04:00
parent 75c57f9827
commit 93367ffd3b
9 changed files with 162 additions and 31 deletions
@@ -229,28 +229,20 @@ public class MethodInliner {
node.instructions.resetLabels();
MethodNode transformedNode = new MethodNode(node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) {
private final boolean keepLineNumbers = nodeRemapper.isInsideInliningLambda();
private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();
private int getNewIndex(int var) {
return var + (var < realParametersSize ? 0 : capturedParamsSize);
}
@Override
public void visitVarInsn(int opcode, int var) {
int newIndex;
if (var < realParametersSize) {
newIndex = var;
} else {
newIndex = var + capturedParamsSize;
}
super.visitVarInsn(opcode, newIndex);
super.visitVarInsn(opcode, getNewIndex(var));
}
@Override
public void visitIincInsn(int var, int increment) {
int newIndex;
if (var < realParametersSize) {
newIndex = var;
} else {
newIndex = var + capturedParamsSize;
}
super.visitIincInsn(newIndex, increment);
super.visitIincInsn(getNewIndex(var), increment);
}
@Override
@@ -260,10 +252,19 @@ public class MethodInliner {
@Override
public void visitLineNumber(int line, Label start) {
if(keepLineNumbers) {
if(isInliningLambda) {
super.visitLineNumber(line, start);
}
}
@Override
public void visitLocalVariable(
String name, String desc, String signature, Label start, Label end, int index
) {
if (isInliningLambda) {
super.visitLocalVariable(name, desc, signature, start, end, getNewIndex(index));
}
}
};
node.accept(transformedNode);
@@ -34,6 +34,8 @@ public class RemapVisitor extends InstructionAdapter {
private final FieldRemapper nodeRemapper;
private final InstructionAdapter instructionAdapter;
protected RemapVisitor(
MethodVisitor mv,
Label end,
@@ -42,6 +44,7 @@ public class RemapVisitor extends InstructionAdapter {
FieldRemapper nodeRemapper
) {
super(InlineCodegenUtil.API, mv);
this.instructionAdapter = new InstructionAdapter(mv);
this.end = end;
this.remapper = varRemapper;
this.remapReturn = remapReturn;
@@ -65,7 +68,14 @@ public class RemapVisitor extends InstructionAdapter {
@Override
public void visitVarInsn(int opcode, int var) {
remapper.visitVarInsn(opcode, var, new InstructionAdapter(mv));
remapper.visitVarInsn(opcode, var, instructionAdapter);
}
@Override
public void visitLocalVariable(
String name, String desc, String signature, Label start, Label end, int index
) {
remapper.visitLocalVariable(name, desc, signature, start, end, index, mv);
}
@Override
@@ -86,13 +96,6 @@ public class RemapVisitor extends InstructionAdapter {
}
}
@Override
public void visitLocalVariable(
String name, String desc, String signature, Label start, Label end, int index
) {
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
return null;
@@ -18,12 +18,15 @@ package org.jetbrains.jet.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import static org.jetbrains.jet.codegen.inline.VarRemapper.RemapStatus.*;
public class VarRemapper {
private final int allParamsSize;
@@ -63,10 +66,10 @@ public class VarRemapper {
ParameterInfo info = params.get(index);
StackValue remapped = remapValues[index];
if (info.isSkipped || remapped == null) {
throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index);
return new RemapInfo(info);
}
if (info.isRemapped()) {
return new RemapInfo(remapped, info);
return new RemapInfo(remapped, info, REMAPPED);
} else {
remappedIndex = ((StackValue.Local)remapped).index;
}
@@ -74,11 +77,16 @@ public class VarRemapper {
remappedIndex = actualParamsSize - params.totalSize() + index; //captured params not used directly in this inlined method, they used in closure
}
return new RemapInfo(StackValue.local(remappedIndex + additionalShift, AsmTypeConstants.OBJECT_TYPE), null);
return new RemapInfo(StackValue.local(remappedIndex + additionalShift, AsmTypeConstants.OBJECT_TYPE), null, SHIFT);
}
public RemapInfo remap(int index) {
return doRemap(index);
RemapInfo info = doRemap(index);
if (FAIL == info.status) {
assert info.parameterInfo != null : "Parameter info should be not null";
throw new RuntimeException("Trying to access skipped parameter: " + info.parameterInfo.type + " at " +index);
}
return info;
}
public void visitIincInsn(int var, int increment, MethodVisitor mv) {
@@ -87,6 +95,15 @@ public class VarRemapper {
mv.visitIincInsn(((StackValue.Local) remap.value).index, increment);
}
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index, MethodVisitor mv) {
RemapInfo info = doRemap(index);
if (SHIFT == info.status) {
//add entries only for shifted vars
mv.visitLocalVariable(name, desc, signature, start, end, ((StackValue.Local) info.value).index);
}
}
public void visitVarInsn(int opcode, int var, InstructionAdapter mv) {
RemapInfo remapInfo = remap(var);
StackValue value = remapInfo.value;
@@ -104,15 +121,30 @@ public class VarRemapper {
}
}
public static class RemapInfo {
public enum RemapStatus {
SHIFT,
REMAPPED,
FAIL
}
private static class RemapInfo {
public final StackValue value;
public final ParameterInfo parameterInfo;
public RemapInfo(@NotNull StackValue value, @Nullable ParameterInfo info) {
public final RemapStatus status;
public RemapInfo(@NotNull StackValue value, @Nullable ParameterInfo info, RemapStatus remapStatus) {
this.value = value;
parameterInfo = info;
this.status = remapStatus;
}
public RemapInfo(@NotNull ParameterInfo info) {
this.value = null;
parameterInfo = info;
this.status = FAIL;
}
}
}
@@ -0,0 +1,16 @@
class A {
inline fun inlineFun(s: (s: Int) -> Unit) {
s(11)
}
fun foo() {
inlineFun ({
var zzz = it;
})
}
}
// METHOD : A.foo()V
// VARIABLE : NAME=zzz TYPE=I INDEX=3
// VARIABLE : NAME=it TYPE=I INDEX=2
// VARIABLE : NAME=this TYPE=LA; INDEX=0
@@ -0,0 +1,20 @@
class A {
inline fun inlineFun(s: (s: Int) -> Unit, p : Int) {
s(11)
s(p)
}
fun foo() {
inlineFun ({ l ->
var zzz = l;
}, 11)
}
}
// METHOD : A.foo()V
// VARIABLE : NAME=zzz TYPE=I INDEX=4
// VARIABLE : NAME=l TYPE=I INDEX=3
// VARIABLE : NAME=zzz TYPE=I INDEX=4
// VARIABLE : NAME=l TYPE=I INDEX=3
// VARIABLE : NAME=this TYPE=LA; INDEX=0
@@ -0,0 +1,17 @@
class A {
inline fun inlineFun(s: () -> Unit) {
s()
}
fun foo() {
var s = 1;
inlineFun ({
var zzz = 2;
})
}
}
// METHOD : A.foo()V
// VARIABLE : NAME=zzz TYPE=I INDEX=3
// VARIABLE : NAME=s TYPE=I INDEX=1
// VARIABLE : NAME=this TYPE=LA; INDEX=0
@@ -0,0 +1,22 @@
class A {
inline fun inlineFun(s: () -> Unit) {
s()
}
fun foo() {
var s = 0;
inlineFun {
var z = 1;
inlineFun {
var zz2 = 2;
}
}
}
}
// METHOD : A.foo()V
// VARIABLE : NAME=zz2 TYPE=I INDEX=5
// VARIABLE : NAME=z TYPE=I INDEX=3
// VARIABLE : NAME=s TYPE=I INDEX=1
// VARIABLE : NAME=this TYPE=LA; INDEX=0
@@ -137,7 +137,7 @@ public abstract class AbstractCheckLocalVariablesTableTest extends TestCaseWithT
private List<LocalVariable> parseExpectations() throws IOException {
List<String> lines = Files.readLines(ktFile, Charset.forName("utf-8"));
List<LocalVariable> expectedLocalVariables = new ArrayList<LocalVariable>();
for (int i = lines.size() - 3; i < lines.size(); ++i) {
for (int i = Math.max(lines.size() - 10, 0); i < lines.size(); ++i) {
Matcher nameMatcher = namePattern.matcher(lines.get(i));
if (nameMatcher.matches()) {
Matcher typeMatcher = typePattern.matcher(lines.get(i));
@@ -41,6 +41,26 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar
doTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt");
}
@TestMetadata("inlineLambdaWithItParam.kt")
public void testInlineLambdaWithItParam() throws Exception {
doTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithItParam.kt");
}
@TestMetadata("inlineLambdaWithParam.kt")
public void testInlineLambdaWithParam() throws Exception {
doTest("compiler/testData/checkLocalVariablesTable/inlineLambdaWithParam.kt");
}
@TestMetadata("inlineSimple.kt")
public void testInlineSimple() throws Exception {
doTest("compiler/testData/checkLocalVariablesTable/inlineSimple.kt");
}
@TestMetadata("inlineSimpleChain.kt")
public void testInlineSimpleChain() throws Exception {
doTest("compiler/testData/checkLocalVariablesTable/inlineSimpleChain.kt");
}
@TestMetadata("itInLambda.kt")
public void testItInLambda() throws Exception {
doTest("compiler/testData/checkLocalVariablesTable/itInLambda.kt");