MethodType runtime API vs constant pool entry of the same type

Maxim Degtyarev mdegtyarev at gmail.com
Tue May 10 03:08:36 UTC 2022


Inspired by https://mail.openjdk.java.net/pipermail/compiler-dev/2022-May/019558.html

According to the JDK 17 `j.l.i.MethodType` javadoc [1]:

Like classes and strings, method types can also be represented
directly in a class file's constant pool as constants.
A method type may be loaded by an ldc instruction which refers to a
suitable CONSTANT_MethodType constant pool entry.
The entry refers to a CONSTANT_Utf8 spelling for the descriptor
string. (For full details on method type constants,
see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)


If I understand it correctly, this implies that any `MethodType`
instance that can be successfully created with the
call to `MethodType.fromMethodDescriptorString()` method can be also
represented as a constant pool entry of type MethodType.


Now consider the following example:


// main/TestRuntime.java
package main;

import java.lang.invoke.MethodType;

public class TestRuntime {

    public static void main(String... args) {
        System.out.println(
            MethodType.fromMethodDescriptorString(
                "()Lfoo/Foo$Bar;",
                TestRuntime.class.getClassLoader()
            )
        );
    }

}


// main/TestConstantPool.jasm
/**
 *
 * You need <a href="https://wiki.openjdk.java.net/display/CodeTools/asmtools">asmtools</a>
to assemble this example.
 *
 * To assemble run:
 * <code>
 *        java -jar asmtools.jar jasm -g TestConstantPool.jasm
 * </code>
 *
 */
package  main;

super public class TestConstantPool
    version 52:0
{
  public Method "<init>":"()V"
    stack 1 locals 1
  {
        aload_0;
        invokespecial    Method java/lang/Object."<init>":"()V";
        return;
  }

  public static varargs Method main:"([Ljava/lang/String;)V"
    stack 2 locals 1
  {
        getstatic    Field java/lang/System.out:"Ljava/io/PrintStream;";
        ldc MethodType "()Lfoo/Foo$Bar;";
        invokevirtual    Method
java/io/PrintStream.println:"(Ljava/lang/Object;)V";
        return;

  }
} // end Class TestConstantPool


// foo/Foo.java
package foo;

public class Foo {
    public static Bar bar() {
        return new Bar();
    }

    static class Bar {}
}


Both `main.TestRuntime` and `main.TestConstantPool` are functionally
equal and should print
string representation of the `MethodType` instance.


While `main.TestRuntime` behaves as expected:

$ java main.TestRuntime
()Bar


The `main.TestConstantPool` failed with `j.l.IllegalAccessError`:

$ java main.TestConstantPool
Exception in thread "main" java.lang.IllegalAccessError: tried to
access class foo.Foo$Bar from class main.TestConstantPool
        at main.TestConstantPool.main(TestConstantPool.jasm:18)


However, if we declare class `foo.Foo.Bar` public then both
`TestRuntime` and `TestConstantPool` run without exceptions.


Checked both with `Java(TM) SE Runtime Environment (build
1.8.0_152-b16)` and `OpenJDK Runtime Environment (build
19-ea+21-1482)`.


Questions:

1) Shouldn't both examples expose equal behaviour?

2) Which of 2 observed behaviours is correct?


Examples from this message can be found at [2]


[1] https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MethodType.html
[2] https://github.com/Maccimo/MethodType-API-vs-ConstantPool


More information about the hotspot-runtime-dev mailing list