Resolution/translation of VarHandle.compareAndSet seems to conflict with JVMS/javadoc.

Jorn Vernee jbvernee at xs4all.nl
Sat Jan 5 19:56:24 UTC 2019


Hi,

I'm bringing this up based on a question asked on Stack Overflow [1].

For the following code:

public class Main {
     public int publicTestVariable = 10;

     public static void main(String[] args) throws Throwable {
	Main e = new Main();
	e.update();
     }

     public void update() throws Throwable {
	VarHandle publicIntHandle = MethodHandles.lookup()
	    .findVarHandle(Main.class, "publicTestVariable", int.class);
	publicIntHandle.compareAndSet(this, 10, 100);
     }
}

javac derives the descriptor for the call to `compareAndSet` [2] as 
`(Lmain/Main;II)Z`, but eclipsec derives the descriptor as 
`(Lmain/Main;II)V`. Note that `compareAndSet` is signature polymorphic.

Each compiler generates a different return type. The one generated by 
eclipsec seems to be correct since the call site has no indication that 
the call should return a boolean. According to the javadoc for Signature 
polymorphism [3] "The unusual part is that the symbolic type descriptor 
is derived from the actual argument and return types, not from the 
method declaration.", and the code generated by javac definitely seems 
to depend on the method declaration, and not just the call site.

When running the eclipsec generated code on jdk/jdk tip this throws a 
NSME:

     Exception in thread "main" java.lang.NoSuchMethodError: 
VarHandle.compareAndSet(Main,int,int)void
         at 
java.base/java.lang.invoke.MethodHandleNatives.newNoSuchMethodErrorOnVarHandle(MethodHandleNatives.java:576)
         at 
java.base/java.lang.invoke.MethodHandleNatives.varHandleOperationLinkerMethod(MethodHandleNatives.java:529)
         at 
java.base/java.lang.invoke.MethodHandleNatives.linkMethodImpl(MethodHandleNatives.java:462)
         at 
java.base/java.lang.invoke.MethodHandleNatives.linkMethod(MethodHandleNatives.java:450)
         at main.Main.update(Main.java:18)
         at main.Main.main(Main.java:12)

While the code generated by javac runs without an error.

Regardless of the question whether discarding the returned value is a 
good idea or not, the exception being thrown seems to conflict with 
JVMS-5.4.3.3 [4] which states:

"If C declares exactly one method with the name specified by the method 
reference, and the declaration is a signature polymorphic method 
(§2.9.3), then method lookup succeeds. All the class names mentioned in 
the descriptor are resolved (§5.4.3.1). The resolved method is the 
signature polymorphic method declaration. It is not necessary for C to 
declare a method with the descriptor specified by the method reference."

The javadoc [3] also says that: "When the JVM processes bytecode 
containing signature polymorphic calls, it will successfully link any 
such call, regardless of its symbolic type descriptor".

So the VM should not be throwing an NSME here AFAICT. But, it looks like 
this case is being checked explicitly and an error is being thrown [5]:

     if (ak.at.isMonomorphicInReturnType) {
         if (ak.at.returnType != mtype.returnType()) {
             // The caller contains a different return type than that
             // defined by the method
             throw newNoSuchMethodErrorOnVarHandle(name, mtype);
         }
         // Adjust the return type of the signature method type
         guardReturnType = ak.at.returnType;
     }

I guess this is being done because the return type of compareAndSet is 
monomorphic, but imho the call should still succeed with `void` as a 
return type (discarding the value). For other types, it would be more 
consistent with the spec/doc if the return type was dynamically cast to 
that of the descriptor, with possible CCE, but linking still succeeded.

Any thoughts on this?

Cheers,
Jorn

[1] : https://stackoverflow.com/q/52962939
[2] : 
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/VarHandle.html#compareAndSet(java.lang.Object...)
[3] : 
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandle.html#sigpoly
[4] : 
https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.3.3
[5] : 
http://hg.openjdk.java.net/jdk/jdk/file/22baf8054a40/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java#l526


More information about the jdk-dev mailing list