mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-30 21:18:25 +00:00
8026508: Invokedynamic instructions don't get line number table entries
Setting or correcting positions for many trees produced by LambdaToMethod. Reviewed-by: vromero, rfield
This commit is contained in:
parent
806a84e4de
commit
5ea357c66e
@ -156,12 +156,15 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
*/
|
||||
private final VarSymbol deserParamSym;
|
||||
|
||||
private KlassInfo(Symbol kSym) {
|
||||
private final JCClassDecl clazz;
|
||||
|
||||
private KlassInfo(JCClassDecl clazz) {
|
||||
this.clazz = clazz;
|
||||
appendedMethodList = new ListBuffer<>();
|
||||
deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
|
||||
MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
|
||||
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"),
|
||||
syms.serializedLambdaType, deserMethodSym);
|
||||
}
|
||||
@ -221,10 +224,16 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
}
|
||||
KlassInfo prevKlassInfo = kInfo;
|
||||
try {
|
||||
kInfo = new KlassInfo(tree.sym);
|
||||
kInfo = new KlassInfo(tree);
|
||||
super.visitClassDef(tree);
|
||||
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
|
||||
List<JCTree> newMethods = kInfo.appendedMethodList.toList();
|
||||
@ -400,14 +409,21 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
|
||||
super.visitIdent(tree);
|
||||
} else {
|
||||
LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
|
||||
JCTree ltree = lambdaContext.translate(tree);
|
||||
if (ltree != null) {
|
||||
result = ltree;
|
||||
} else {
|
||||
//access to untranslated symbols (i.e. compile-time constants,
|
||||
//members defined inside the lambda body, etc.) )
|
||||
super.visitIdent(tree);
|
||||
int prevPos = make.pos;
|
||||
try {
|
||||
make.at(tree);
|
||||
|
||||
LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
|
||||
JCTree ltree = lambdaContext.translate(tree);
|
||||
if (ltree != null) {
|
||||
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 {
|
||||
LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
|
||||
if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
|
||||
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)) {
|
||||
JCExpression init = translate(tree.init);
|
||||
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
|
||||
Scope sc = tree.sym.owner.members();
|
||||
if (sc != null) {
|
||||
@ -448,23 +474,28 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
boolean isLambda_void = expr.type.hasTag(VOID);
|
||||
boolean isTarget_void = restype.hasTag(VOID);
|
||||
boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
|
||||
if (isTarget_void) {
|
||||
//target is void:
|
||||
// BODY;
|
||||
JCStatement stat = make.Exec(expr);
|
||||
return make.Block(0, List.<JCStatement>of(stat));
|
||||
} else if (isLambda_void && isTarget_Void) {
|
||||
//void to Void conversion:
|
||||
// BODY; return null;
|
||||
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
||||
stats.append(make.Exec(expr));
|
||||
stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
|
||||
return make.Block(0, stats.toList());
|
||||
} else {
|
||||
//non-void to non-void conversion:
|
||||
// return (TYPE)BODY;
|
||||
JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
|
||||
return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
|
||||
int prevPos = make.pos;
|
||||
try {
|
||||
if (isTarget_void) {
|
||||
//target is void:
|
||||
// BODY;
|
||||
JCStatement stat = make.at(expr).Exec(expr);
|
||||
return make.Block(0, List.<JCStatement>of(stat));
|
||||
} else if (isLambda_void && isTarget_Void) {
|
||||
//void to Void conversion:
|
||||
// BODY; return null;
|
||||
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
||||
stats.append(make.at(expr).Exec(expr));
|
||||
stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
|
||||
return make.Block(0, stats.toList());
|
||||
} else {
|
||||
//non-void to non-void conversion:
|
||||
// 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 {
|
||||
}
|
||||
}
|
||||
if (context.isSerializable()) {
|
||||
addDeserializationCase(refKind, refSym, tree.type, samSym,
|
||||
tree, staticArgs, indyType);
|
||||
int prevPos = make.pos;
|
||||
try {
|
||||
make.at(kInfo.clazz);
|
||||
addDeserializationCase(refKind, refSym, tree.type, samSym,
|
||||
tree, staticArgs, indyType);
|
||||
} finally {
|
||||
make.at(prevPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,11 +25,11 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8019486
|
||||
* @bug 8019486 8026861
|
||||
* @summary javac, generates erroneous LVT for a test case with lambda code
|
||||
* @library /tools/javac/lib
|
||||
* @build ToolBox
|
||||
* @run main WrongLVTForLambdaTest
|
||||
* @run main WrongLNTForLambdaTest
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
@ -41,7 +41,7 @@ import com.sun.tools.classfile.LineNumberTable_attribute;
|
||||
import com.sun.tools.classfile.Method;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
|
||||
public class WrongLVTForLambdaTest {
|
||||
public class WrongLNTForLambdaTest {
|
||||
|
||||
static final String testSource =
|
||||
/* 01 */ "import java.util.List;\n" +
|
||||
@ -54,21 +54,72 @@ public class WrongLVTForLambdaTest {
|
||||
/* 08 */ " final List<Integer> numbersPlusOne = \n" +
|
||||
/* 09 */ " numbers.stream().map(number -> number / 1).collect(Collectors.toList());\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},
|
||||
{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 {
|
||||
new WrongLVTForLambdaTest().run();
|
||||
new WrongLNTForLambdaTest().run();
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
compileTestClass();
|
||||
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 {
|
||||
@ -77,12 +128,12 @@ public class WrongLVTForLambdaTest {
|
||||
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);
|
||||
int methodsFound = 0;
|
||||
boolean methodFound = false;
|
||||
for (Method method : classFile.methods) {
|
||||
if (method.getName(classFile.constant_pool).startsWith("lambda$")) {
|
||||
++methodsFound;
|
||||
if (method.getName(classFile.constant_pool).equals(methodToFind)) {
|
||||
methodFound = true;
|
||||
Code_attribute code = (Code_attribute) method.attributes.get("Code");
|
||||
LineNumberTable_attribute lnt =
|
||||
(LineNumberTable_attribute) code.attributes.get("LineNumberTable");
|
||||
@ -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) {
|
||||
Loading…
x
Reference in New Issue
Block a user