LuciferYang commented on PR #57768:
URL: https://github.com/apache/spark/pull/57768#issuecomment-5189915613

   Thanks for the review @cloud-fan. Mapping your three comments to what 
changed:
   
   **`CodeCompiler.scala:146`** — fixed, now `merely slower at compiling`.
   
   **`CodeCompiler.scala:149`** — fixed, reworded to `all involving classes the 
JDK compiler cannot name`. The count also went from two to three, since the 
routing gained an arm.
   
   **`CodeCompiler.scala:780`** — took the second option you offered (route to 
Janino). The first one is not reachable from where the name is produced: the 
unnameable name arrives through `addReferenceObj`'s `className` parameter from 
`Literal.doGenCode`, and its source is `ObjectType`. `Literal.fromObject(obj)` 
has no declared type in its signature to preserve, so threading one down would 
mean changing `DeserializerBuildHelper` / `SerializerBuildHelper` and the 
encoder path rather than a local fix. So `active` gained a third 
deterministic-routing arm and `canNarrowSafely` decides it.
   
   While implementing it I found the check has to be stricter than "the 
accessed members are available" in three ways. Flagging them separately since 
they go past what you asked for.
   
   **1. Member matching is exact-signature plus a bridge allowance, not 
name+arity.** Name+arity conflates overriding with overloading. An override of 
a generic method carries a bridge with the supertype's erased signature, so 
narrowing still dispatches to the override; an overload has no bridge and javac 
binds statically to the supertype's method. That does not surface as a compile 
error, because `Invoke.doGenCode` always wraps the call in an explicit cast. On 
`new CBase() { public String conv(String) }` over `CBase.conv(Object)`, javac 
compiles with zero diagnostics and the result changes from `ANON-x` to 
`BASE-x`: a silent wrong answer rather than a failure. The tightening is free — 
over the 980 anonymous/local classes in scala-library, scala-reflect and 
scala-compiler, the two rules have identical trigger sets (52 / 48 / 147).
   
   **2. The replacement type must itself be referenceable.** Members lining up 
is not enough if javac cannot spell the type. In scala-library, 36 of 299 
anonymous/local classes narrow to a non-public target, e.g. 
`mutable.LinkedHashSet$$anon$1` to the `private abstract` 
`LinkedHashSet$LinkedHashSetIterator`; scala-reflect is 21 of 154. The check 
now requires the target and all its enclosing classes to be public. 
Same-package cannot be exempted: with a package-private target in 
`org.apache.spark.sql.catalyst.expressions` javac accepts the cast, but it 
fails at runtime with `IllegalAccessError`, because the generated class is 
loaded by `InMemoryClassLoader` and its runtime package differs from the 
same-named package on the application loader.
   
   **3. A named class nested inside an anonymous or local class is neither.** 
`Outer$1$Inner` reports `isAnonymousClass == false`, `isLocalClass == false`, 
`isMemberClass == true` and `getCanonicalName == null`, so the old climb 
returned it unchanged and emitted its binary name, which javac rejects. 
`nameableSupertype` now climbs while `getCanonicalName` is null. That predicate 
is a superset at no observed cost: all 299 null-canonical classes in 
scala-library are exactly the anonymous/local ones, and the single extra one in 
scala-reflect (`Positions$worker$1$solidChildrenCollector$`) is a member of a 
local class, so equally unnameable. Object-nested case classes, operator-named 
classes, `Map$Entry` and specialized names all have non-null canonical names, 
so the existing rewrite tests are unaffected.
   
   Two smaller items also outside your comments. The refactor had moved 
`nameableSupertype` and `getCanonicalName` out of the `try` that used to catch 
`LinkageError`, so a `NoClassDefFoundError` from a partial or shaded jar could 
escape past the codegen fallbacks — `NonFatal` does not cover it, and 
`WholeStageCodegenEvaluatorFactory.eval` has no try at all. Both call sites 
catch it now. And `spark.sql.codegen.compiler`'s doc still enumerated two 
always-Janino cases; it lists three.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to