-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
minimal
-
Since these are new APIs, and the default behavior of VarHandles is not changed (as witnessed by the test suite), there is minimal compatibility risk.
-
Java API
-
SE
Summary
Add a withInvokeExactBehavior() method to VarHandle, that can be used to create an exact VarHandle, which will, upon invocation of one of its signature polymorphic methods, check that the type of the invocation matches its expected type exactly, and throw an exception in case of a mismatch.
Problem
Var handles have what are called signature-polymorphic methods, whereby the type of the method is derived almost completely from the call site of the method, rather than its declaration. This for example helps with avoiding the overhead of boxing primitives, while still providing a generic interface which can be used for many different memory access use-cases.
The default mode (and only mode prior to this CSR) for a VarHandle is, if the type of the call site of a signature-polymorphic method does not match the expected type of the invocation exactly, then the type of the VarHandle is adapted on the fly. Care was taken to ensure adaption is efficient, however in certain cases, such as unintended primitive conversions, it can result in a performance penalty. Sometimes it is a developers intention to only use only exact invocations, whereby the call site of a signature-polymorphic method matches the expected type exactly (to avoid the mentioned performance penalty), but they inadvertently end up with an inexact invocation, which can be hard to spot in source code.
Solution
The closely related MethodHandle API, has the invokeExact method, which can help catch these kinds of cases, by doing a check that the type of the MethodHandle matches the type of the call site exactly. If a mismatch is found, a WrongMethodTypeExaception will be thrown to alert the developer.
However, VarHandle has numerous signature-polymorphic methods, and providing an exact version of each would nearly double the methods in VarHandle. Instead, we can provide a way to create an exact VarHandle instance, that will do the required type checking. We can also provide a way to go back from an exact VarHandle to an inexact one, as well as a predicate that can be used to check whether a VarHandle is exact or inexact.
Specification
Here is the diff of the specification parts of the patch
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java
@@ -282,8 +282,8 @@
* match fails, it means that the access mode method which the caller is
* invoking is not present on the individual VarHandle being invoked.
*
- * <p>
- * Invocation of an access mode method behaves as if an invocation of
+ * <p id="invoke-behavior">
+ * Invocation of an access mode method behaves, by default, as if an invocation of
* {@link MethodHandle#invoke}, where the receiving method handle accepts the
* VarHandle instance as the leading argument. More specifically, the
* following, where {@code {access-mode}} corresponds to the access mode method
@@ -318,7 +318,7 @@
* widen primitive values, as if by {@link MethodHandle#asType asType} (see also
* {@link MethodHandles#varHandleInvoker}).
*
- * More concisely, such behaviour is equivalent to:
+ * More concisely, such behavior is equivalent to:
* <pre> {@code
* VarHandle vh = ..
* VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
@@ -328,6 +328,37 @@
* }</pre>
* Where, in this case, the method handle is bound to the VarHandle instance.
*
+ * <p id="invoke-exact-behavior">
+ * A VarHandle's invocation behavior can be adjusted (see {@link #withInvokeExactBehavior}) such that invocation of
+ * an access mode method behaves as if invocation of {@link MethodHandle#invokeExact},
+ * where the receiving method handle accepts the VarHandle instance as the leading argument.
+ * More specifically, the following, where {@code {access-mode}} corresponds to the access mode method
+ * name:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * R r = (R) vh.{access-mode}(p1, p2, ..., pN);
+ * }</pre>
+ * behaves as if:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = MethodHandles.varHandleExactInvoker(
+ * am,
+ * vh.accessModeType(am));
+ *
+ * R r = (R) mh.invokeExact(vh, p1, p2, ..., pN)
+ * }</pre>
+ * (modulo access mode methods do not declare throwing of {@code Throwable}).
+ *
+ * More concisely, such behavior is equivalent to:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = vh.toMethodHandle(am);
+ *
+ * R r = (R) mh.invokeExact(p1, p2, ..., pN)
+ * }</pre>
+ * Where, in this case, the method handle is bound to the VarHandle instance.
*
* <h2>Invocation checking</h2>
* In typical programs, VarHandle access mode type matching will usually
@@ -425,7 +456,7 @@
* {@link java.lang.invoke.MethodHandles#varHandleInvoker}. The
* {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* API is also able to return a method handle to call an access mode method for
- * any specified access mode type and is equivalent in behaviour to
+ * any specified access mode type and is equivalent in behavior to
* {@link java.lang.invoke.MethodHandles#varHandleInvoker}.
*
* <h2>Interoperation between VarHandles and Java generics</h2>
@@ -465,6 +502,18 @@ VarHandle asDirect() {
VarHandle target() { return null; }
+ /**
+ * Returns {@code true} if this VarHandle has <a href="#invoke-exact-behavior"><em>invoke-exact behavior</em></a>.
+ *
+ * @see #withInvokeExactBehavior()
+ * @see #withInvokeBehavior()
+ * @return {@code true} if this VarHandle has <a href="#invoke-exact-behavior"><em>invoke-exact behavior</em></a>.
+ * @since 16
+ */
+ public boolean hasInvokeExactBehavior() {
+ return exact;
+ }
+
// Plain accessors
/**
@@ -1541,6 +1590,37 @@ VarHandle asDirect() {
@IntrinsicCandidate
Object getAndBitwiseXorRelease(Object... args);
+ /**
+ * Returns a VarHandle, with access to the same variable(s) as this VarHandle, but whose
+ * invocation behavior of access mode methods is adjusted to
+ * <a href="#invoke-exact-behavior"><em>invoke-exact behavior</em></a>.
+ * <p>
+ * If this VarHandle already has invoke-exact behavior this VarHandle is returned.
+ * <p>
+ * Invoking {@link #hasInvokeExactBehavior()} on the returned var handle
+ * is guaranteed to return {@code true}.
+ *
+ * @apiNote
+ * Invoke-exact behavior guarantees that upon invocation of an access mode method
+ * the types and arity of the arguments must match the {@link #accessModeType(AccessMode) access mode type},
+ * otherwise a {@link WrongMethodTypeException} is thrown.
+ *
+ * @see #withInvokeBehavior()
+ * @see #hasInvokeExactBehavior()
+ * @return a VarHandle with invoke-exact behavior
+ * @since 16
+ */
+ public abstract VarHandle withInvokeExactBehavior();
+
+ /**
+ * Returns a VarHandle, with access to the same variable(s) as this VarHandle, but whose
+ * invocation behavior of access mode methods is adjusted to
+ * <a href="#invoke-behavior"><em>invoke behavior</em></a>.
+ * <p>
+ * If this VarHandle already has invoke behavior this VarHandle is returned.
+ * <p>
+ * Invoking {@link #hasInvokeExactBehavior()} on the returned var handle
+ * is guaranteed to return {@code false}.
+ *
+ * @see #withInvokeExactBehavior()
+ * @see #hasInvokeExactBehavior()
+ * @return a VarHandle with invoke behavior
+ * @since 16
+ */
+ public abstract VarHandle withInvokeBehavior();
enum AccessType {
GET(Object.class),
- csr of
-
JDK-8254354 Add a withInvokeExactBehavior() VarHandle combinator
-
- Resolved
-