Skip to content

Massage implementation of structural calls to avoid: "WARNING: Illegal reflective access by scala.reflect.package$ " #11368

Open
@retronym

Description

@retronym

WARNING: Illegal reflective access by scala.reflect.package$ (file:/Users/andrew/workspace/scala/build/quick/classes/library/) to method java.lang.Object.clone()

We need to tweak the desugaring of structural calls a little bit to avoid this.

Instead of:

  /** Make a java reflection object accessible, if it is not already
   *  and it is possible to do so. If a SecurityException is thrown in the
   *  attempt, it is caught and discarded.
   */
  def ensureAccessible[T <: jAccessibleObject](m: T): T = {
    if (!m.isAccessible) {
      try m setAccessible true
      catch { case _: SecurityException => } // does nothing
    }
    m
  }

Which is called from, e.g.

scala> class Reflect { def foo = ""; def bar = { this.asInstanceOf[{ def foo: String }].foo }}
defined class Reflect

Which compiles to:

scala> :javap -c Reflect#bar
  public java.lang.String bar();
    Code:
       0: aload_0
       1: astore_1
       2: aload_1
       3: invokevirtual #82                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
       6: invokestatic  #84                 // Method reflMethod$Method1:(Ljava/lang/Class;)Ljava/lang/reflect/Method;
       9: aload_1
      10: iconst_0
      11: anewarray     #4                  // class java/lang/Object
      14: invokevirtual #88                 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
...

scala> :javap -c Reflect#reflMethod$Method1
  public static java.lang.reflect.Method reflMethod$Method1(java.lang.Class);
    Code:
       0: invokedynamic #34,  0             // InvokeDynamic #0:apply:()Lscala/runtime/StructuralCallSite;
       5: astore_1
       6: aload_1
       7: aload_0
       8: invokevirtual #37                 // Method scala/runtime/StructuralCallSite.find:(Ljava/lang/Class;)Ljava/lang/reflect/Method;
      11: astore_2
      12: aload_2
      13: ifnull        18
      16: aload_2
      17: areturn
      18: getstatic     #43                 // Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$;
      21: aload_0
      22: ldc           #45                 // String foo
      24: aload_1
      25: invokevirtual #49                 // Method scala/runtime/StructuralCallSite.parameterTypes:()[Ljava/lang/Class;
      28: invokevirtual #55                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
      31: invokevirtual #59                 // Method scala/runtime/ScalaRunTime$.ensureAccessible:(Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method;
      34: astore_2
      35: aload_1
      36: aload_0
      37: aload_2
      38: invokevirtual #63                 // Method scala/runtime/StructuralCallSite.add:(Ljava/lang/Class;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method;
      41: pop
      42: aload_2
      43: areturn

When running on JDK9+, we should call m.canAccess(receiver) rather than m.canAccess(receiverClass).

First, we'll need to put some JDK-dependent code in ensureAccessible, and call canAccess via reflection or via a helper method that we compile under JDK9 in our build.

Then, we need to change the compilation of structural calls to pass the receiver, rather than reciever class down.

For source compatibility, we should probably leave the current signature of ensureAccessible alone (it could be used from userland) and create a new method.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions