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