-
Bug
-
Resolution: Fixed
-
P3
-
asm_tools_7.0
-
None
Reported by Vladimir Parfinenko <vladimir.parfinenko@gmail.com>:
There are some problems with generation of CP entries for
invokedynamic of non-interface metafactory method
Minimal example:
------- Interf.jasm -------
@+java/lang/FunctionalInterface { }
public interface Interf
version 52:0
{
public Method callerDynamic:"(LInterf;)LInterf;"
stack 2 locals 2
{
aload_0;
aload_1;
invokedynamic InvokeDynamic
REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":bar:"(LInterf;LInterf;)LInterf;"
MethodType "()Ljava/lang/Object;", MethodHandle
REF_invokeSpecial:Interf.foo:"(LInterf;)Ljava/lang/Object;",
MethodType "()Ljava/lang/Object;";
areturn;
}
public Method callerSpecial:"(LInterf;)LInterf;"
stack 2 locals 2
{
aload_0;
aload_1;
invokespecial Interf.foo:"(LInterf;)Ljava/lang/Object;";
areturn;
}
private synthetic Method foo:"(LInterf;)Ljava/lang/Object;"
stack 1 locals 2
{
aconst_null;
areturn;
}
public abstract Method bar:"()Ljava/lang/Object;";
}
--------------------------
The resulting class Interf looks like the following after compilation
with the latest asmtools (changeset 41):
---------- Interf.javap --------------
Classfile /tmp/asmtools-bugs/Interf.class
Last modified Mar 30, 2020; size 768 bytes
MD5 checksum 95fb63d2b77ed98e4fd1a478666a7965
Compiled from "Interf.jasm"
public interface Interf
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Methodref #4.#11 //
Interf.foo:(LInterf;)Ljava/lang/Object;
#2 = InvokeDynamic #0:#8 // #0:bar:(LInterf;LInterf;)LInterf;
#3 = Utf8 (LInterf;)Ljava/lang/Object;
#4 = Class #18 // Interf
#5 = Utf8 (LInterf;)LInterf;
#6 = Utf8 bar
#7 = Utf8 Interf.jasm
#8 = NameAndType #6:#14 // bar:(LInterf;LInterf;)LInterf;
#9 = MethodHandle #6:#28 // invokestatic
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#10 = Utf8 SourceFile
#11 = NameAndType #13:#3 // foo:(LInterf;)Ljava/lang/Object;
#12 = MethodHandle #7:#23 // invokespecial
Interf.foo:(LInterf;)Ljava/lang/Object;
#13 = Utf8 foo
#14 = Utf8 (LInterf;LInterf;)LInterf;
#15 = NameAndType #16:#29 //
metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#16 = Utf8 metafactory
#17 = Utf8 callerDynamic
#18 = Utf8 Interf
#19 = Class #30 // java/lang/Object
#20 = Class #31 // java/lang/invoke/LambdaMetafactory
#21 = Utf8 Ljava/lang/FunctionalInterface;
#22 = Utf8 RuntimeVisibleAnnotations
#23 = InterfaceMethodref #4.#11 //
Interf.foo:(LInterf;)Ljava/lang/Object;
#24 = MethodType #26 // ()Ljava/lang/Object;
#25 = Utf8 BootstrapMethods
#26 = Utf8 ()Ljava/lang/Object;
#27 = Utf8 callerSpecial
#28 = InterfaceMethodref #20.#15 //
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#29 = Utf8
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#30 = Utf8 java/lang/Object
#31 = Utf8 java/lang/invoke/LambdaMetafactory
#32 = Utf8 Code
{
public Interf callerDynamic(Interf);
descriptor: (LInterf;)LInterf;
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokedynamic #2, 0 // InvokeDynamic
#0:bar:(LInterf;LInterf;)LInterf;
7: areturn
public Interf callerSpecial(Interf);
descriptor: (LInterf;)LInterf;
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokespecial #1 // Method
foo:(LInterf;)Ljava/lang/Object;
5: areturn
public abstract java.lang.Object bar();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "Interf.jasm"
RuntimeVisibleAnnotations:
0: #21()
BootstrapMethods:
0: #9 invokestatic
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#24 ()Ljava/lang/Object;
#12 invokespecial Interf.foo:(LInterf;)Ljava/lang/Object;
#24 ()Ljava/lang/Object;
------- Main.java ------
public class Main implements Interf {
public static void main(String[] var0) {
Main x = new Main();
try {
System.out.println("Dynamic");
x.callerDynamic(x);
System.out.println("OK");
} catch (Throwable e) {
e.printStackTrace(System.out);
}
try {
System.out.println("Special");
x.callerSpecial(x);
System.out.println("OK");
} catch (Throwable e) {
e.printStackTrace(System.out);
}
}
public Object bar() {
return null;
}
}
---------------------------------
1) 0-th boostrap method references LambdaMetafactory.metafactory() as
InterfaceMethodRef #9 but the declaring class is not an interface.
unning this sample on JDK-13 gives the output:
------ stdout -------
Dynamic
java.lang.IncompatibleClassChangeError: Inconsistent constant pool
data in classfile for class java/lang/invoke/LambdaMetafactory. Method
'java.lang.invoke.CallSite
metafactory(java.lang.invoke.MethodHandles$Lookup, java.lang.String,
java.lang.invoke.MethodType, java.lang.invoke.MethodType,
java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)' at index
9 is CONSTANT_InterfaceMethodRef and should be CONSTANT_MethodRef
at Interf.callerDynamic(Interf.jasm)
at Main.main(Main.java:6)
There are some problems with generation of CP entries for
invokedynamic of non-interface metafactory method
Minimal example:
------- Interf.jasm -------
@+java/lang/FunctionalInterface { }
public interface Interf
version 52:0
{
public Method callerDynamic:"(LInterf;)LInterf;"
stack 2 locals 2
{
aload_0;
aload_1;
invokedynamic InvokeDynamic
REF_invokeStatic:java/lang/invoke/LambdaMetafactory.metafactory:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;":bar:"(LInterf;LInterf;)LInterf;"
MethodType "()Ljava/lang/Object;", MethodHandle
REF_invokeSpecial:Interf.foo:"(LInterf;)Ljava/lang/Object;",
MethodType "()Ljava/lang/Object;";
areturn;
}
public Method callerSpecial:"(LInterf;)LInterf;"
stack 2 locals 2
{
aload_0;
aload_1;
invokespecial Interf.foo:"(LInterf;)Ljava/lang/Object;";
areturn;
}
private synthetic Method foo:"(LInterf;)Ljava/lang/Object;"
stack 1 locals 2
{
aconst_null;
areturn;
}
public abstract Method bar:"()Ljava/lang/Object;";
}
--------------------------
The resulting class Interf looks like the following after compilation
with the latest asmtools (changeset 41):
---------- Interf.javap --------------
Classfile /tmp/asmtools-bugs/Interf.class
Last modified Mar 30, 2020; size 768 bytes
MD5 checksum 95fb63d2b77ed98e4fd1a478666a7965
Compiled from "Interf.jasm"
public interface Interf
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Methodref #4.#11 //
Interf.foo:(LInterf;)Ljava/lang/Object;
#2 = InvokeDynamic #0:#8 // #0:bar:(LInterf;LInterf;)LInterf;
#3 = Utf8 (LInterf;)Ljava/lang/Object;
#4 = Class #18 // Interf
#5 = Utf8 (LInterf;)LInterf;
#6 = Utf8 bar
#7 = Utf8 Interf.jasm
#8 = NameAndType #6:#14 // bar:(LInterf;LInterf;)LInterf;
#9 = MethodHandle #6:#28 // invokestatic
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#10 = Utf8 SourceFile
#11 = NameAndType #13:#3 // foo:(LInterf;)Ljava/lang/Object;
#12 = MethodHandle #7:#23 // invokespecial
Interf.foo:(LInterf;)Ljava/lang/Object;
#13 = Utf8 foo
#14 = Utf8 (LInterf;LInterf;)LInterf;
#15 = NameAndType #16:#29 //
metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#16 = Utf8 metafactory
#17 = Utf8 callerDynamic
#18 = Utf8 Interf
#19 = Class #30 // java/lang/Object
#20 = Class #31 // java/lang/invoke/LambdaMetafactory
#21 = Utf8 Ljava/lang/FunctionalInterface;
#22 = Utf8 RuntimeVisibleAnnotations
#23 = InterfaceMethodref #4.#11 //
Interf.foo:(LInterf;)Ljava/lang/Object;
#24 = MethodType #26 // ()Ljava/lang/Object;
#25 = Utf8 BootstrapMethods
#26 = Utf8 ()Ljava/lang/Object;
#27 = Utf8 callerSpecial
#28 = InterfaceMethodref #20.#15 //
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#29 = Utf8
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#30 = Utf8 java/lang/Object
#31 = Utf8 java/lang/invoke/LambdaMetafactory
#32 = Utf8 Code
{
public Interf callerDynamic(Interf);
descriptor: (LInterf;)LInterf;
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokedynamic #2, 0 // InvokeDynamic
#0:bar:(LInterf;LInterf;)LInterf;
7: areturn
public Interf callerSpecial(Interf);
descriptor: (LInterf;)LInterf;
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokespecial #1 // Method
foo:(LInterf;)Ljava/lang/Object;
5: areturn
public abstract java.lang.Object bar();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "Interf.jasm"
RuntimeVisibleAnnotations:
0: #21()
BootstrapMethods:
0: #9 invokestatic
java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#24 ()Ljava/lang/Object;
#12 invokespecial Interf.foo:(LInterf;)Ljava/lang/Object;
#24 ()Ljava/lang/Object;
------- Main.java ------
public class Main implements Interf {
public static void main(String[] var0) {
Main x = new Main();
try {
System.out.println("Dynamic");
x.callerDynamic(x);
System.out.println("OK");
} catch (Throwable e) {
e.printStackTrace(System.out);
}
try {
System.out.println("Special");
x.callerSpecial(x);
System.out.println("OK");
} catch (Throwable e) {
e.printStackTrace(System.out);
}
}
public Object bar() {
return null;
}
}
---------------------------------
1) 0-th boostrap method references LambdaMetafactory.metafactory() as
InterfaceMethodRef #9 but the declaring class is not an interface.
unning this sample on JDK-13 gives the output:
------ stdout -------
Dynamic
java.lang.IncompatibleClassChangeError: Inconsistent constant pool
data in classfile for class java/lang/invoke/LambdaMetafactory. Method
'java.lang.invoke.CallSite
metafactory(java.lang.invoke.MethodHandles$Lookup, java.lang.String,
java.lang.invoke.MethodType, java.lang.invoke.MethodType,
java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)' at index
9 is CONSTANT_InterfaceMethodRef and should be CONSTANT_MethodRef
at Interf.callerDynamic(Interf.jasm)
at Main.main(Main.java:6)
- relates to
-
CODETOOLS-7902333 jasm produces inconsistent constant pool data for bootstrap methods of interfaces if cfv >= 52
-
- Resolved
-
-
CODETOOLS-7902660 jdis includes unnecessary Field references in MethodHandle parameters while printing static params of a bsm and skips the method tag in ldc# instructions
-
- Resolved
-