提交 2ee2a0ae 编写于 作者: J jlahoda

8026861: Wrong LineNumberTable for variable declarations in lambdas

Summary: Setting or correcting positions for many trees produced by LambdaToMethod.
Reviewed-by: vromero, rfield
上级 8008dc49
...@@ -156,12 +156,15 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -156,12 +156,15 @@ public class LambdaToMethod extends TreeTranslator {
*/ */
private final VarSymbol deserParamSym; private final VarSymbol deserParamSym;
private KlassInfo(Symbol kSym) { private final JCClassDecl clazz;
private KlassInfo(JCClassDecl clazz) {
this.clazz = clazz;
appendedMethodList = new ListBuffer<>(); appendedMethodList = new ListBuffer<>();
deserializeCases = new HashMap<String, ListBuffer<JCStatement>>(); deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
List.<Type>nil(), syms.methodClass); List.<Type>nil(), syms.methodClass);
deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, kSym); deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
syms.serializedLambdaType, deserMethodSym); syms.serializedLambdaType, deserMethodSym);
} }
...@@ -221,10 +224,16 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -221,10 +224,16 @@ public class LambdaToMethod extends TreeTranslator {
} }
KlassInfo prevKlassInfo = kInfo; KlassInfo prevKlassInfo = kInfo;
try { try {
kInfo = new KlassInfo(tree.sym); kInfo = new KlassInfo(tree);
super.visitClassDef(tree); super.visitClassDef(tree);
if (!kInfo.deserializeCases.isEmpty()) { if (!kInfo.deserializeCases.isEmpty()) {
kInfo.addMethod(makeDeserializeMethod(tree.sym)); int prevPos = make.pos;
try {
make.at(tree);
kInfo.addMethod(makeDeserializeMethod(tree.sym));
} finally {
make.at(prevPos);
}
} }
//add all translated instance methods here //add all translated instance methods here
List<JCTree> newMethods = kInfo.appendedMethodList.toList(); List<JCTree> newMethods = kInfo.appendedMethodList.toList();
...@@ -400,14 +409,21 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -400,14 +409,21 @@ public class LambdaToMethod extends TreeTranslator {
if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) { if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
super.visitIdent(tree); super.visitIdent(tree);
} else { } else {
LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; int prevPos = make.pos;
JCTree ltree = lambdaContext.translate(tree); try {
if (ltree != null) { make.at(tree);
result = ltree;
} else { LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
//access to untranslated symbols (i.e. compile-time constants, JCTree ltree = lambdaContext.translate(tree);
//members defined inside the lambda body, etc.) ) if (ltree != null) {
super.visitIdent(tree); result = ltree;
} else {
//access to untranslated symbols (i.e. compile-time constants,
//members defined inside the lambda body, etc.) )
super.visitIdent(tree);
}
} finally {
make.at(prevPos);
} }
} }
} }
...@@ -417,11 +433,21 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -417,11 +433,21 @@ public class LambdaToMethod extends TreeTranslator {
LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
JCExpression init = translate(tree.init); JCExpression init = translate(tree.init);
result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init); int prevPos = make.pos;
try {
result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
} finally {
make.at(prevPos);
}
} else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
JCExpression init = translate(tree.init); JCExpression init = translate(tree.init);
VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
result = make.VarDef(xsym, init); int prevPos = make.pos;
try {
result = make.at(tree).VarDef(xsym, init);
} finally {
make.at(prevPos);
}
// Replace the entered symbol for this variable // Replace the entered symbol for this variable
Scope sc = tree.sym.owner.members(); Scope sc = tree.sym.owner.members();
if (sc != null) { if (sc != null) {
...@@ -448,23 +474,28 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -448,23 +474,28 @@ public class LambdaToMethod extends TreeTranslator {
boolean isLambda_void = expr.type.hasTag(VOID); boolean isLambda_void = expr.type.hasTag(VOID);
boolean isTarget_void = restype.hasTag(VOID); boolean isTarget_void = restype.hasTag(VOID);
boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
if (isTarget_void) { int prevPos = make.pos;
//target is void: try {
// BODY; if (isTarget_void) {
JCStatement stat = make.Exec(expr); //target is void:
return make.Block(0, List.<JCStatement>of(stat)); // BODY;
} else if (isLambda_void && isTarget_Void) { JCStatement stat = make.at(expr).Exec(expr);
//void to Void conversion: return make.Block(0, List.<JCStatement>of(stat));
// BODY; return null; } else if (isLambda_void && isTarget_Void) {
ListBuffer<JCStatement> stats = new ListBuffer<>(); //void to Void conversion:
stats.append(make.Exec(expr)); // BODY; return null;
stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); ListBuffer<JCStatement> stats = new ListBuffer<>();
return make.Block(0, stats.toList()); stats.append(make.at(expr).Exec(expr));
} else { stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
//non-void to non-void conversion: return make.Block(0, stats.toList());
// return (TYPE)BODY; } else {
JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); //non-void to non-void conversion:
return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr))); // return (TYPE)BODY;
JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
}
} finally {
make.at(prevPos);
} }
} }
...@@ -966,8 +997,14 @@ public class LambdaToMethod extends TreeTranslator { ...@@ -966,8 +997,14 @@ public class LambdaToMethod extends TreeTranslator {
} }
} }
if (context.isSerializable()) { if (context.isSerializable()) {
addDeserializationCase(refKind, refSym, tree.type, samSym, int prevPos = make.pos;
tree, staticArgs, indyType); try {
make.at(kInfo.clazz);
addDeserializationCase(refKind, refSym, tree.type, samSym,
tree, staticArgs, indyType);
} finally {
make.at(prevPos);
}
} }
} }
......
...@@ -25,11 +25,11 @@ ...@@ -25,11 +25,11 @@
/* /*
* @test * @test
* @bug 8019486 * @bug 8019486 8026861
* @summary javac, generates erroneous LVT for a test case with lambda code * @summary javac, generates erroneous LVT for a test case with lambda code
* @library /tools/javac/lib * @library /tools/javac/lib
* @build ToolBox * @build ToolBox
* @run main WrongLVTForLambdaTest * @run main WrongLNTForLambdaTest
*/ */
import java.io.File; import java.io.File;
...@@ -41,7 +41,7 @@ import com.sun.tools.classfile.LineNumberTable_attribute; ...@@ -41,7 +41,7 @@ import com.sun.tools.classfile.LineNumberTable_attribute;
import com.sun.tools.classfile.Method; import com.sun.tools.classfile.Method;
import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Assert;
public class WrongLVTForLambdaTest { public class WrongLNTForLambdaTest {
static final String testSource = static final String testSource =
/* 01 */ "import java.util.List;\n" + /* 01 */ "import java.util.List;\n" +
...@@ -54,21 +54,72 @@ public class WrongLVTForLambdaTest { ...@@ -54,21 +54,72 @@ public class WrongLVTForLambdaTest {
/* 08 */ " final List<Integer> numbersPlusOne = \n" + /* 08 */ " final List<Integer> numbersPlusOne = \n" +
/* 09 */ " numbers.stream().map(number -> number / 1).collect(Collectors.toList());\n" + /* 09 */ " numbers.stream().map(number -> number / 1).collect(Collectors.toList());\n" +
/* 10 */ " }\n" + /* 10 */ " }\n" +
/* 11 */ "}"; /* 11 */ " void variablesInLambdas(int value) {\n" +
/* 12 */ " Runnable r1 = () -> {\n" +
/* 13 */ " int i = value;\n" +
/* 14 */ " class FooBar<T extends CharSequence> {\n" +
/* 15 */ " public void run() {\n" +
/* 16 */ " T t = null;\n" +
/* 17 */ " }\n" +
/* 18 */ " }\n" +
/* 19 */ " };\n" +
/* 20 */ " Runnable r2 = () -> System.err.println(1);\n" +
/* 21 */ " Runnable r3 = (Runnable & java.io.Serializable) this::foo;\n" +
/* 22 */ " Runnable r4 = super :: notify;\n" +
/* 23 */ " }\n" +
/* 24 */ " private void foo() {}\n" +
/* 25 */ "}";
static final int[][] expectedLNT = { static final int[][] simpleLambdaExpectedLNT = {
// {line-number, start-pc}, // {line-number, start-pc},
{9, 0}, //number -> number / 1 {9, 0}, //number -> number / 1
}; };
static final int[][] lambdaWithVarsExpectedLNT = {
// {line-number, start-pc},
{13, 0}, //number -> number / 1
{19, 2}, //number -> number / 1
};
static final int[][] insideLambdaWithVarsExpectedLNT = {
// {line-number, start-pc},
{16, 0}, //number -> number / 1
{17, 2}, //number -> number / 1
};
static final int[][] lambdaVoid2VoidExpectedLNT = {
// {line-number, start-pc},
{20, 0}, //number -> number / 1
};
static final int[][] deserializeExpectedLNT = {
// {line-number, start-pc},
{05, 0}, //number -> number / 1
};
static final int[][] lambdaBridgeExpectedLNT = {
// {line-number, start-pc},
{22, 0}, //number -> number / 1
};
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new WrongLVTForLambdaTest().run(); new WrongLNTForLambdaTest().run();
} }
void run() throws Exception { void run() throws Exception {
compileTestClass(); compileTestClass();
checkClassFile(new File(Paths.get(System.getProperty("user.dir"), checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo.class").toUri())); "Foo.class").toUri()), "lambda$bar$0", simpleLambdaExpectedLNT);
checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo.class").toUri()), "lambda$variablesInLambdas$1", lambdaWithVarsExpectedLNT);
checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo$1FooBar.class").toUri()), "run", insideLambdaWithVarsExpectedLNT);
checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo.class").toUri()), "lambda$variablesInLambdas$2", lambdaVoid2VoidExpectedLNT);
checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo.class").toUri()), "$deserializeLambda$", deserializeExpectedLNT);
checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
"Foo.class").toUri()), "lambda$MR$variablesInLambdas$notify$8bc4f5bd$1", lambdaBridgeExpectedLNT);
} }
void compileTestClass() throws Exception { void compileTestClass() throws Exception {
...@@ -77,12 +128,12 @@ public class WrongLVTForLambdaTest { ...@@ -77,12 +128,12 @@ public class WrongLVTForLambdaTest {
ToolBox.javac(javacSuccessArgs); ToolBox.javac(javacSuccessArgs);
} }
void checkClassFile(final File cfile) throws Exception { void checkClassFile(final File cfile, String methodToFind, int[][] expectedLNT) throws Exception {
ClassFile classFile = ClassFile.read(cfile); ClassFile classFile = ClassFile.read(cfile);
int methodsFound = 0; boolean methodFound = false;
for (Method method : classFile.methods) { for (Method method : classFile.methods) {
if (method.getName(classFile.constant_pool).startsWith("lambda$")) { if (method.getName(classFile.constant_pool).equals(methodToFind)) {
++methodsFound; methodFound = true;
Code_attribute code = (Code_attribute) method.attributes.get("Code"); Code_attribute code = (Code_attribute) method.attributes.get("Code");
LineNumberTable_attribute lnt = LineNumberTable_attribute lnt =
(LineNumberTable_attribute) code.attributes.get("LineNumberTable"); (LineNumberTable_attribute) code.attributes.get("LineNumberTable");
...@@ -99,7 +150,7 @@ public class WrongLVTForLambdaTest { ...@@ -99,7 +150,7 @@ public class WrongLVTForLambdaTest {
} }
} }
} }
Assert.check(methodsFound == 1, "Expected to find one lambda method, found " + methodsFound); Assert.check(methodFound, "The seek method was not found");
} }
void error(String msg) { void error(String msg) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册