RFR: 8342967: Lambda deduplication fails with non-metafactory BSMs and mismatched local variables names [v2]

Jan Lahoda jlahoda at openjdk.org
Fri Oct 25 12:05:07 UTC 2024


On Fri, 25 Oct 2024 11:36:36 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java line 693:
>> 
>>> 691:                         && scan(tree.init, that.init);
>>> 692: 
>>> 693:         if (!tree.sym.owner.type.hasTag(TypeTag.METHOD) && result) {
>> 
>> I would rewrite this (for improved readability) as:
>> 
>> 
>> JCVariableDecl that = (JCVariableDecl) parameter;
>>  result =
>>                 scan(tree.mods, that.mods)
>>                         && scan(tree.nameexpr, that.nameexpr)
>>                         && scan(tree.vartype, that.vartype)
>>                         && scan(tree.init, that.init);
>> 
>> if (tree.sym.owner.type.hasTag(TypeTag.CLASS)) {
>>     // field names are important!
>>     result &= tree.name == that.name;
>> }
>> 
>> if (result) {
>>      equiv.put(tree.sym, that.sym);
>> }
>
> And, now that I wrote that I realize there's another issue in the code (from before your changes). I don't think `equiv` is really meant to be for non-local variables. IMHO the logic should be:
> 1. if we're comparing two local variables, do a structural comparison (and ignore the names)
> 2. if we're comparing fields, just check the symbols are the same.
> And... I'm not sure there's ever a case where (2) applies? E.g. do we really want to deduplicate lambdas containing similar local class definitions? @cushon what do you think? What was the original intention for this code?

FWIW, I doubt we meaningfully deduplicate lambdas with local class definitions. I suspect we deduplicate them only if the declarations are not used, like:

         Runnable r1 = () -> {class C {}};
         Runnable r2 = () -> {class C {}};


But not when they are used, like:

         Runnable r1 = () -> {class C {} new C();};
         Runnable r2 = () -> {class C {} new C();};


because the use site (`new C();`) uses different `Symbol`s, and these `Symbol`s are not `equiv`-ed.

So, possibly, simply using `false` once we see a `JCClassDecl` might be a more direct, open, answer.

(Besides aliasing local variables, there are probably other cases where we don't detect semantically equivalent duplicates. Like `Object` and `java.lang.Object`. It is not clear to me if those are important in practice, though.)

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/21687#discussion_r1816554212


More information about the compiler-dev mailing list