MethodType runtime API vs constant pool entry of the same type
David Holmes
david.holmes at oracle.com
Tue May 10 13:12:16 UTC 2022
Hi Maxim,
On 10/05/2022 1:08 pm, Maxim Degtyarev wrote:
> 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?
I believe so, yes.
> 2) Which of 2 observed behaviours is correct?
main.TestConstantPool.
In both cases the type designated by the descriptor string has to be
resolved. Resolution includes an access check. The ldc version is
correctly resolving and performing the access check and so throwing the
IllegalAccessError.
It appears there is a bug in MethodType.fromMethodDescriptorString.
Cheers,
David
-----
>
> 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