Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #15736 blocking scala 3 on android #22632

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ddtthh
Copy link

@ddtthh ddtthh commented Feb 20, 2025

Fixes #15736

Box native instantiated method return type if sam method return type is not a primitive type to satisfy conditions specified in
https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html
Condition is not enforced by JVM but by Android ART.

Box native instantiated method return type if sam method return type
is not a primitive type to satisfy conditions specified in
  https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html
Condition is not enforced by JVM but by Android ART.
@ddtthh
Copy link
Author

ddtthh commented Feb 21, 2025

Just to provide some more information on my reasoning for the fix:

  • Scala represents primitive types as the respective Scala types, so there is no difference between boxed and primitive.
  • The JVM backend converts those to Java primitive types in method and function signatures, so there is no java.lang.Boolean in signatures ever unless it was in the original Scala code.
  • If the sam method type contains primitive types, the respective types on the implementing method have to be primitive as well, so there is no issue in that direction.
  • If the sam method type contains more general reference types, the implementation method type can contain primitive parameters
  • For argument types this is not an issue, as argument types cannot be narrowed on implementation, scala will generate a bridge method with the reference types.
  • For the return type it is an issue, as an implementation may have a narrowed return type, this is probably why scala 3 does not generate the bridge method in that case. And even if a bridge method is generated due to parameter types, it still has the same return type.
  • JVM metafactory does automatically adapt the implementing method to the sam type for primitive parameters, so calling a function returning boolean for a sam method signature returning a ref type is fine.
  • The instantiated method type is checked at runtime. The JVM adapts this type as well, but the specification does not state that. Android D3 emits a runtime check for the primitive type even if the sam method returns a ref type.

Following these observations I've only added a assertion to check the condition for the whole signature and just implemented boxing of the return type in the instantiated method type.

I've also compiled most of the compiler run tests into an android app to check whether there are more bytecode issues with android, and there seem not to be any.

@lrytz
Copy link
Member

lrytz commented Feb 21, 2025

I have some memory of a semantic mismatch in null unboxing between Scala and LambdaMetaFactory: scala/scala#4463 (comment). Just posting that as-is, I haven't looked at this PR or the ticket in detail yet.

@ddtthh
Copy link
Author

ddtthh commented Feb 21, 2025

I have some memory of a semantic mismatch in null unboxing between Scala and LambdaMetaFactory: scala/scala#4463 (comment). Just posting that as-is, I haven't looked at this PR or the ticket in detail yet.

Interesting, yes current scala 3 still does the unboxing manually in the adapted method for the parameters. It does not do the boxing for the return value and it does not need to as there is not special null case for boxing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Illegal arguments for bootstrap method for invokedynamic
2 participants