Generate local variable table for inlined lambda
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user