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

Illegal arguments for bootstrap method for invokedynamic #15736

Open
ddtthh opened this issue Jul 22, 2022 · 2 comments · May be fixed by #22632
Open

Illegal arguments for bootstrap method for invokedynamic #15736

ddtthh opened this issue Jul 22, 2022 · 2 comments · May be fixed by #22632

Comments

@ddtthh
Copy link

ddtthh commented Jul 22, 2022

Compiler version

3.1.3

Description

When compiling a lambda, the arguments to the generated bootstrap method in the generated class file violate the rules given in the JDK documentation. While this does not seem to cause any issues on OpenJDK, the Android Dexer d8 cannot handle this.

According to https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html interfaceMethodType and dynamicMethodType have to fullfill the following constraints:

  • Same arity
  • Argument types and return types are either the same as in the interface, or in case of reference may be subtypes.
    There is no type conversion between primitive types and reference types

In the following example, the scala compiler generates a bootstrap method call to LambdaMetafactory.altMetafactory with
interfaceMethodType: (Ljava/lang/Object;)Ljava/lang/Object;
dynamicMethodType: (Ljava/lang/Object;)Z

This clearly violates the specifiaction of LambdaMetafactory.
The dynamicMethodeType should be (Ljava/lang/Object;)Ljava/lang/Boolean;

It is ok for the MethodHandle supplied as implementation to have a MethodType of (Ljava/lang/Object;)Z, LambdaMetafactory will handle boxing, but the dynamicMethodType has to specify the boxed types.

Minimized code

class Foo[T]():
  val f = (x: T) => true

Output

Taken from javap -private -c -v

BootstrapMethods:
  0: #29 REF_invokeStatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #14 (Ljava/lang/Object;)Ljava/lang/Object;
      #19 REF_invokeStatic Foo.$init$$$anonfun$1:(Ljava/lang/Object;)Z
      #20 (Ljava/lang/Object;)Z
      #21 5
      #22 1
      #20 (Ljava/lang/Object;)Z

Expectation

Taken from javap -private -c -v

BootstrapMethods:
  0: #29 REF_invokeStatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #14 (Ljava/lang/Object;)Ljava/lang/Object;
      #19 REF_invokeStatic Foo.$init$$$anonfun$1:(Ljava/lang/Object;)Z
      #20 (Ljava/lang/Object;)Ljava/lang/Boolean;
      #21 5
      #22 1
      #20 (Ljava/lang/Object;)Z
@ddtthh ddtthh added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 22, 2022
@szymon-rd szymon-rd added area:backend and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 25, 2022
ddtthh added a commit to ddtthh/scala3 that referenced this issue Feb 20, 2025
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 ddtthh linked a pull request Feb 20, 2025 that will close this issue
@lrytz
Copy link
Member

lrytz commented Feb 21, 2025

The anonfun method in Scala 2 is also (Object)Z, but then Scala 2 emits an anonfun$adapted bridge with signature (Object)Object which is used in the indy-lambda.

Corresponding code in the compiler: https://github.com/scala/scala/blob/v2.13.16/src/compiler/scala/tools/nsc/transform/Delambdafy.scala#L162-L175

ASM of the Scala 2 compiled class:

public class Foo {
  public final static synthetic $anonfun$f$1(Ljava/lang/Object;)Z
    ...

  public final static synthetic $anonfun$f$1$adapted(Ljava/lang/Object;)Ljava/lang/Object;
    // parameter final  x
   L0
    LINENUMBER 2 L0
    ALOAD 0
    INVOKESTATIC Foo.$anonfun$f$1 (Ljava/lang/Object;)Z
    INVOKESTATIC scala/runtime/BoxesRunTime.boxToBoolean (Z)Ljava/lang/Boolean;
    ARETURN

  public <init>()V
    ...
    INVOKEDYNAMIC apply()Lscala/Function1; [
      // handle kind 0x6 : INVOKESTATIC
      java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
      // arguments:
      (Ljava/lang/Object;)Ljava/lang/Object;, 
      // handle kind 0x6 : INVOKESTATIC
      Foo.$anonfun$f$1$adapted(Ljava/lang/Object;)Ljava/lang/Object;, 
      (Ljava/lang/Object;)Ljava/lang/Object;, 
      1
    ]
}

@lrytz
Copy link
Member

lrytz commented Feb 21, 2025

Oh, I only saw the PR now. Will take a look, probably next week though..

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

Successfully merging a pull request may close this issue.

3 participants