/* * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang.invoke; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.vm.annotation.ForceInline; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; import static java.lang.invoke.MethodHandleStatics.UNSAFE; import static java.lang.invoke.MethodHandleStatics.newInternalError; /** * A VarHandle is a dynamically typed reference to a variable, or to a * parametrically-defined family of variables, including static fields, * non-static fields, array elements, or components of an off-heap data * structure. Access to such variables is supported under various * access modes, including plain read/write access, volatile * read/write access, and compare-and-swap. * *
VarHandles are immutable and have no visible state. VarHandles cannot be * subclassed by the user. * *
A VarHandle has: *
Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup * lookup} VarHandle instances document the supported variable type, coordinate * types, and shape. * * For example, a VarHandle referencing a non-static field will declare a shape * of {@code (R : T)}, where {@code R} is the receiver type and * {@code T} is the field type, and where the VarHandle and an instance of the * receiver type can be utilized to access the field variable. * A VarHandle referencing array elements will declare a shape of * {@code (T[], int : T)}, where {@code T[]} is the array type and {@code T} * its component type, and where the VarHandle, an instance of the array type, * and an {@code int} index can be utilized to access an array element variable. * *
Each access mode is associated with a * signature polymorphic method of the * same name, where the VarHandle shape and access mode uniquely determine the * canonical {@link #accessModeType(AccessMode) access mode type}, * which in turn determines the matching constraints on a valid symbolic * type descriptor at the call site of an access mode's method * invocation. * * As such, VarHandles are dynamically and strongly typed. Their arity, * argument types, and return type of an access mode method invocation are not * statically checked. If they, and associated values, do not match the arity * and types of the access mode's type, an exception will be thrown. * * The parameter types of an access mode method type will consist of those that * are the VarHandles's coordinate types (in order), followed by access mode * parameter types specific to the access mode. * *
An access mode's method documents the form of its method signature, which * is derived from the access mode parameter types. The form is declared with * the notation {@code (CT, P1 p1, P2 p2, ..., PN pn)R}, where {@code CT} is the * coordinate types (as documented by a VarHandle factory method), {@code P1}, * {@code P2} and {@code PN} are the first, second and the n'th access mode * parameters named {@code p1}, {@code p2} and {@code pn} respectively, and * {@code R} is the return type. * * For example, for the generic shape of {@code (CT : T)} the * {@link #compareAndSet} access mode method documents that its method * signature is of the form {@code (CT, T expectedValue, T newValue)boolean}, * where the parameter types named {@code extendedValue} and {@code newValue} * are the access mode parameter types. If the VarHandle accesses array * elements with a shape of say {@code (T[], int : T)} then the access mode * method type is {@code (T[], int, T, T)boolean}. * *
Access modes are grouped into the following categories: *
Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup * lookup} VarHandle instances document the set of access modes that are * supported, which may also include documenting restrictions based on the * variable type and whether a variable is read-only. If an access mode is not * supported then the corresponding signature-polymorphic method will on * invocation throw an {@code UnsupportedOperationException}. * The {@link #get get} access mode is supported for all * VarHandle instances and the corresponding method never throws * {@code UnsupportedOperationException}. * If a VarHandle references a read-only variable (for example a {@code final} * field) then write, atomic update and numeric atomic update access modes are * not supported and corresponding methods throw * {@code UnsupportedOperationException}. * Read/write access modes (if supported), with the exception of * {@code get} and {@code set}, provide atomic access for * reference types and all primitive types. * Unless stated otherwise in the documentation of a factory method, the access * modes {@code get} and {@code set} (if supported) provide atomic access for * reference types and all primitives types, with the exception of {@code long} * and {@code double} on 32-bit platforms * *
Access modes will override any memory ordering effects specified at * the declaration site of a variable. For example, a VarHandle accessing a * a field using the {@code get} access mode will access the field as * specified by its access mode even if that field is declared * {@code volatile}. When mixed access is performed extreme care should be * taken since the Java Memory Model may permit surprising results. * *
In addition to supporting access to variables under various access modes, * a set of static methods, referred to as memory fence methods, is also * provided for fine-grained control of memory ordering. * * The Java Language Specification permits other threads to observe operations * as if they were executed in orders different than are apparent in program * source code, subject to constraints arising, for example, from the use of * locks, {@code volatile} fields or VarHandles. The static methods, * {@link #fullFence fullFence}, {@link #acquireFence acquireFence}, * {@link #releaseFence releaseFence}, {@link #loadLoadFence loadLoadFence} and * {@link #storeStoreFence storeStoreFence}, can also be used to impose * constraints. Their specifications, as is the case for certain access modes, * are phrased in terms of the lack of "reorderings" -- observable ordering * effects that might otherwise occur if the fence was not present. More * precise phrasing of the specification of access mode methods and memory fence * methods may accompany future updates of the Java Language Specification. * *
* As is usual with virtual methods, source-level calls to access mode methods * compile to an {@code invokevirtual} instruction. More unusually, the * compiler must record the actual argument types, and may not perform method * invocation conversions on the arguments. Instead, it must generate * instructions to push them on the stack according to their own unconverted * types. The VarHandle object itself will be pushed on the stack before the * arguments. The compiler then generates an {@code invokevirtual} instruction * that invokes the access mode method with a symbolic type descriptor which * describes the argument and return types. *
* To issue a complete symbolic type descriptor, the compiler must also * determine the return type (if polymorphic). This is based on a cast on the * method invocation expression, if there is one, or else {@code Object} if the * invocation is an expression, or else {@code void} if the invocation is a * statement. The cast may be to a primitive type (but not {@code void}). *
* As a corner case, an uncasted {@code null} argument is given a symbolic type * descriptor of {@code java.lang.Void}. The ambiguity with the type * {@code Void} is harmless, since there are no references of type {@code Void} * except the null reference. * * *
* When the {@code invokevirtual} is executed after linking, the receiving * VarHandle's access mode type is first checked by the JVM to ensure that it * matches the symbolic type descriptor. If the type * match fails, it means that the access mode method which the caller is * invoking is not present on the individual VarHandle being invoked. * *
* Invocation of an access mode's signature-polymorphic method behaves as if an * invocation of {@link MethodHandle#invoke}, where the receiving method handle * is bound to a VarHandle instance and the access mode. More specifically, the * following: *
{@code * VarHandle vh = .. * R r = (R) vh.{access-mode}(p1, p2, ..., pN); * }* behaves as if (modulo the access mode methods do not declare throwing of * {@code Throwable}): *
{@code * VarHandle vh = .. * MethodHandle mh = MethodHandles.varHandleExactInvoker( * VarHandle.AccessMode.{access-mode}, * vh.accessModeType(VarHandle.AccessMode.{access-mode})); * * mh = mh.bindTo(vh); * R r = (R) mh.invoke(p1, p2, ..., pN) * }* or, more concisely, behaves as if: *
{@code * VarHandle vh = .. * MethodHandle mh = vh.toMethodHandle(VarHandle.AccessMode.{access-mode}); * * R r = (R) mh.invoke(p1, p2, ..., pN) * }* In terms of equivalent {@code invokevirtual} bytecode behaviour an access * mode method invocation is equivalent to: *
{@code * MethodHandle mh = MethodHandles.lookup().findVirtual( * VarHandle.class, * VarHandle.AccessMode.{access-mode}.name(), * MethodType.methodType(R, p1, p2, ..., pN)); * * R r = (R) mh.invokeExact(vh, p1, p2, ..., pN) * }* where the desired method type is the symbolic type descriptor and a * {@link MethodHandle#invokeExact} is performed, since before invocation of the * target, the handle will apply reference casts as necessary and box, unbox, or * widen primitive values, as if by {@link MethodHandle#asType asType} (see also * {@link MethodHandles#varHandleInvoker}). * *
* Thus, an access mode type mismatch which might show up as a linkage error * in a statically typed program can show up as a dynamic * {@code WrongMethodTypeException} in a program which uses VarHandles. *
* Because access mode types contain "live" {@code Class} objects, method type * matching takes into account both type names and class loaders. * Thus, even if a VarHandle {@code VH} is created in one class loader * {@code L1} and used in another {@code L2}, VarHandle access mode method * calls are type-safe, because the caller's symbolic type descriptor, as * resolved in {@code L2}, is matched against the original callee method's * symbolic type descriptor, as resolved in {@code L1}. The resolution in * {@code L1} happens when {@code VH} is created and its access mode types are * assigned, while the resolution in {@code L2} happens when the * {@code invokevirtual} instruction is linked. *
* Apart from type descriptor checks, a VarHandles's capability to * access it's variables is unrestricted. * If a VarHandle is formed on a non-public variable by a class that has access * to that variable, the resulting VarHandle can be used in any place by any * caller who receives a reference to it. *
* Unlike with the Core Reflection API, where access is checked every time a * reflective method is invoked, VarHandle access checking is performed * when the VarHandle is * created. * Thus, VarHandles to non-public variables, or to variables in non-public * classes, should generally be kept secret. They should not be passed to * untrusted code unless their use from the untrusted code would be harmless. * * *
* Access to protected field members is restricted to receivers only of the * accessing class, or one of its subclasses, and the accessing class must in * turn be a subclass (or package sibling) of the protected member's defining * class. If a VarHandle refers to a protected non-static field of a declaring * class outside the current package, the receiver argument will be narrowed to * the type of the accessing class. * *
* As a special case, when the Core Reflection API is used to view the * signature polymorphic access mode methods in this class, they appear as * ordinary non-polymorphic methods. Their reflective appearance, as viewed by * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod}, * is unaffected by their special status in this API. * For example, {@link java.lang.reflect.Method#getModifiers * Method.getModifiers} * will report exactly those modifier bits required for any similarly * declared method, including in this case {@code native} and {@code varargs} * bits. *
* As with any reflected method, these methods (when reflected) may be invoked * directly via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, * via JNI, or indirectly via * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}. * However, such reflective calls do not result in access mode method * invocations. Such a call, if passed the required argument (a single one, of * type {@code Object[]}), will ignore the argument and will throw an * {@code UnsupportedOperationException}. *
* Since {@code invokevirtual} instructions can natively invoke VarHandle * access mode methods under any symbolic type descriptor, this reflective view * conflicts with the normal presentation of these methods via bytecodes. * Thus, these native methods, when reflectively viewed by * {@code Class.getDeclaredMethod}, may be regarded as placeholders only. *
* In order to obtain an invoker method for a particular access mode type, * use {@link java.lang.invoke.MethodHandles#varHandleExactInvoker} or * {@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 * {@link java.lang.invoke.MethodHandles#varHandleInvoker}. * *
The method signature is of the form {@code (CT)T}. * *
The symbolic type descriptor at the call site of {@code get} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.get)} on this VarHandle. * *
This access mode is supported by all VarHandle instances and never * throws {@code UnsupportedOperationException}. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} * , statically represented using varargs. * @return the signature-polymorphic result that is the value of the * variable * , statically represented using {@code Object}. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object get(Object... args); /** * Sets the value of a variable to the {@code newValue}, with memory * semantics of setting as if the variable was declared non-{@code volatile} * and non-{@code final}. Commonly referred to as plain write access. * *
The method signature is of the form {@code (CT, T newValue)void} * *
The symbolic type descriptor at the call site of {@code set} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.set)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} * , statically represented using varargs. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate void set(Object... args); // Volatile accessors /** * Returns the value of a variable, with memory semantics of reading as if * the variable was declared {@code volatile}. * *
The method signature is of the form {@code (CT)T}. * *
The symbolic type descriptor at the call site of {@code getVolatile} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.getVolatile)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} * , statically represented using varargs. * @return the signature-polymorphic result that is the value of the * variable * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object getVolatile(Object... args); /** * Sets the value of a variable to the {@code newValue}, with memory * semantics of setting as if the variable was declared {@code volatile}. * *
The method signature is of the form {@code (CT, T newValue)void}. * *
The symbolic type descriptor at the call site of {@code setVolatile} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.setVolatile)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} * , statically represented using varargs. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @apiNote Ignoring the many semantic differences from C and C++, this * method has memory ordering effects compatible with * {@code memory_order_seq_cst}. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate void setVolatile(Object... args); /** * Returns the value of a variable, accessed in program order, but with no * assurance of memory ordering effects with respect to other threads. * *
The method signature is of the form {@code (CT)T}. * *
The symbolic type descriptor at the call site of {@code getOpaque} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.getOpaque)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} * , statically represented using varargs. * @return the signature-polymorphic result that is the value of the * variable * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object getOpaque(Object... args); /** * Sets the value of a variable to the {@code newValue}, in program order, * but with no assurance of memory ordering effects with respect to other * threads. * *
The method signature is of the form {@code (CT, T newValue)void}. * *
The symbolic type descriptor at the call site of {@code setOpaque} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.setOpaque)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} * , statically represented using varargs. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate void setOpaque(Object... args); // Lazy accessors /** * Returns the value of a variable, and ensures that subsequent loads and * stores are not reordered before this access. * *
The method signature is of the form {@code (CT)T}. * *
The symbolic type descriptor at the call site of {@code getAcquire} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.getAcquire)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT)} * , statically represented using varargs. * @return the signature-polymorphic result that is the value of the * variable * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @apiNote Ignoring the many semantic differences from C and C++, this * method has memory ordering effects compatible with * {@code memory_order_acquire} ordering. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object getAcquire(Object... args); /** * Sets the value of a variable to the {@code newValue}, and ensures that * prior loads and stores are not reordered after this access. * *
The method signature is of the form {@code (CT, T newValue)void}. * *
The symbolic type descriptor at the call site of {@code setRelease} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.setRelease)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} * , statically represented using varargs. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @apiNote Ignoring the many semantic differences from C and C++, this * method has memory ordering effects compatible with * {@code memory_order_release} ordering. */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate void setRelease(Object... args); // Compare and set accessors /** * Atomically sets the value of a variable to the {@code newValue} with the * memory semantics of {@link #setVolatile} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #getVolatile}. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *
The symbolic type descriptor at the call site of {@code * compareAndSet} must match the access mode type that is the result of * calling {@code accessModeType(VarHandle.AccessMode.compareAndSet)} on * this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return {@code true} if successful, otherwise {@code false} if the * witness value was not the same as the {@code expectedValue}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setVolatile(Object...) * @see #getVolatile(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate boolean compareAndSet(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the * memory semantics of {@link #setVolatile} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #getVolatile}. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)T}. * *
The symbolic type descriptor at the call site of {@code * compareAndExchangeVolatile} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeVolatile)} * on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return the signature-polymorphic result that is the witness value, which * will be the same as the {@code expectedValue} if successful * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setVolatile(Object...) * @see #getVolatile(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object compareAndExchangeVolatile(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the * memory semantics of {@link #set} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #getAcquire}. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)T}. * *
The symbolic type descriptor at the call site of {@code * compareAndExchangeAcquire} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeAcquire)} on * this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return the signature-polymorphic result that is the witness value, which * will be the same as the {@code expectedValue} if successful * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #set(Object...) * @see #getAcquire(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object compareAndExchangeAcquire(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the * memory semantics of {@link #setRelease} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #get}. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)T}. * *
The symbolic type descriptor at the call site of {@code * compareAndExchangeRelease} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeRelease)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return the signature-polymorphic result that is the witness value, which * will be the same as the {@code expectedValue} if successful * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setRelease(Object...) * @see #get(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object compareAndExchangeRelease(Object... args); // Weak (spurious failures allowed) /** * Possibly atomically sets the value of a variable to the {@code newValue} * with the semantics of {@link #set} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #get}. * *
This operation may fail spuriously (typically, due to memory * contention) even if the current value does match the expected value. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *
The symbolic type descriptor at the call site of {@code * weakCompareAndSet} must match the access mode type that is the result of * calling {@code accessModeType(VarHandle.AccessMode.weakCompareAndSet)} on * this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return {@code true} if successful, otherwise {@code false} if the * witness value was not the same as the {@code expectedValue} or if this * operation spuriously failed. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #set(Object...) * @see #get(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate boolean weakCompareAndSet(Object... args); /** * Possibly atomically sets the value of a variable to the {@code newValue} * with the semantics of {@link #set} if the variable's current value, * referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #getAcquire}. * *
This operation may fail spuriously (typically, due to memory * contention) even if the current value does match the expected value. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *
The symbolic type descriptor at the call site of {@code * weakCompareAndSetAcquire} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetAcquire)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return {@code true} if successful, otherwise {@code false} if the * witness value was not the same as the {@code expectedValue} or if this * operation spuriously failed. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #set(Object...) * @see #getAcquire(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate boolean weakCompareAndSetAcquire(Object... args); /** * Possibly atomically sets the value of a variable to the {@code newValue} * with the semantics of {@link #setRelease} if the variable's current * value, referred to as the witness value, {@code ==} the * {@code expectedValue}, as accessed with the memory semantics of * {@link #get}. * *
This operation may fail spuriously (typically, due to memory * contention) even if the current value does match the expected value. * *
The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}. * *
The symbolic type descriptor at the call site of {@code * weakCompareAndSetRelease} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetRelease)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T expectedValue, T newValue)} * , statically represented using varargs. * @return {@code true} if successful, otherwise {@code false} if the * witness value was not the same as the {@code expectedValue} or if this * operation spuriously failed. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setRelease(Object...) * @see #get(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate boolean weakCompareAndSetRelease(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the * memory semantics of {@link #setVolatile} and returns the variable's * previous value, as accessed with the memory semantics of * {@link #getVolatile}. * *
The method signature is of the form {@code (CT, T newValue)T}. * *
The symbolic type descriptor at the call site of {@code getAndSet} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.getAndSet)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T newValue)} * , statically represented using varargs. * @return the signature-polymorphic result that is the previous value of * the variable * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setVolatile(Object...) * @see #getVolatile(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object getAndSet(Object... args); // Primitive adders // Throw UnsupportedOperationException for refs /** * Atomically adds the {@code value} to the current value of a variable with * the memory semantics of {@link #setVolatile}, and returns the variable's * previous value, as accessed with the memory semantics of * {@link #getVolatile}. * *
The method signature is of the form {@code (CT, T value)T}. * *
The symbolic type descriptor at the call site of {@code getAndAdd} * must match the access mode type that is the result of calling * {@code accessModeType(VarHandle.AccessMode.getAndAdd)} on this VarHandle. * * @param args the signature-polymorphic parameter list of the form * {@code (CT, T value)} * , statically represented using varargs. * @return the signature-polymorphic result that is the previous value of * the variable * , statically represented using {@code Object}. * @throws UnsupportedOperationException if the access mode is unsupported * for this VarHandle. * @throws WrongMethodTypeException if the access mode type is not * compatible with the caller's symbolic type descriptor. * @see #setVolatile(Object...) * @see #getVolatile(Object...) */ public final native @MethodHandle.PolymorphicSignature @HotSpotIntrinsicCandidate Object getAndAdd(Object... args); /** * Atomically adds the {@code value} to the current value of a variable with * the memory semantics of {@link #setVolatile}, and returns the variable's * current (updated) value, as accessed with the memory semantics of * {@link #getVolatile}. * *
The method signature is of the form {@code (CT, T value)T}. * *
The symbolic type descriptor at the call site of {@code addAndGet}
* must match the access mode type that is the result of calling
* {@code accessModeType(VarHandle.AccessMode.addAndGet)} on this VarHandle.
*
* @param args the signature-polymorphic parameter list of the form
* {@code (CT, T value)}
* , statically represented using varargs.
* @return the signature-polymorphic result that is the current value of
* the variable
* , statically represented using {@code Object}.
* @throws UnsupportedOperationException if the access mode is unsupported
* for this VarHandle.
* @throws WrongMethodTypeException if the access mode type is not
* compatible with the caller's symbolic type descriptor.
* @see #setVolatile(Object...)
* @see #getVolatile(Object...)
*/
public final native
@MethodHandle.PolymorphicSignature
@HotSpotIntrinsicCandidate
Object addAndGet(Object... args);
enum AccessType {
get, // 0
set, // 1
compareAndSwap, // 2
compareAndExchange, // 3
getAndUpdate; // 4
MethodType getMethodType(VarHandle vh) {
return getMethodType(this.ordinal(), vh);
}
@ForceInline
static MethodType getMethodType(int ordinal, VarHandle vh) {
if (ordinal == 0) {
return vh.typeGet;
}
else if (ordinal == 1) {
return vh.typeSet;
}
else if (ordinal == 2) {
return vh.typeCompareSwap;
}
else if (ordinal == 3) {
return vh.typeCompareExchange;
}
else if (ordinal == 4) {
return vh.typeGetAndUpdate;
}
else {
throw new IllegalStateException("Illegal access type: " + ordinal);
}
}
}
/**
* The set of access modes that specify how a variable, referenced by a
* VarHandle, is accessed.
*/
public enum AccessMode {
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#get VarHandle.get}
*/
get(AccessType.get, Object.class), // 0
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#set VarHandle.set}
*/
set(AccessType.set, void.class), // 1
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#getVolatile VarHandle.getVolatile}
*/
getVolatile(AccessType.get, Object.class), // 2
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#setVolatile VarHandle.setVolatile}
*/
setVolatile(AccessType.set, void.class), // 3
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#getAcquire VarHandle.getAcquire}
*/
getAcquire(AccessType.get, Object.class), // 4
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#setRelease VarHandle.setRelease}
*/
setRelease(AccessType.set, void.class), // 5
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#getOpaque VarHandle.getOpaque}
*/
getOpaque(AccessType.get, Object.class), // 6
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#setOpaque VarHandle.setOpaque}
*/
setOpaque(AccessType.set, void.class), // 7
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#compareAndSet VarHandle.compareAndSet}
*/
compareAndSet(AccessType.compareAndSwap, boolean.class), // 8
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#compareAndExchangeVolatile VarHandle.compareAndExchangeVolatile}
*/
compareAndExchangeVolatile(AccessType.compareAndExchange, Object.class), // 9
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire}
*/
compareAndExchangeAcquire(AccessType.compareAndExchange, Object.class), // 10
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease}
*/
compareAndExchangeRelease(AccessType.compareAndExchange, Object.class), // 11
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet}
*/
weakCompareAndSet(AccessType.compareAndSwap, boolean.class), // 12
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire}
*/
weakCompareAndSetAcquire(AccessType.compareAndSwap, boolean.class), // 13
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease}
*/
weakCompareAndSetRelease(AccessType.compareAndSwap, boolean.class), // 14
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#getAndSet VarHandle.getAndSet}
*/
getAndSet(AccessType.getAndUpdate, Object.class), // 15
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#getAndAdd VarHandle.getAndAdd}
*/
getAndAdd(AccessType.getAndUpdate, Object.class), // 16
/**
* The access mode whose access is specified by the corresponding
* method
* {@link VarHandle#addAndGet VarHandle.addAndGet}
*/
addAndGet(AccessType.getAndUpdate, Object.class), // 17
;
final AccessType at;
final boolean isPolyMorphicInReturnType;
final Class> returnType;
AccessMode(AccessType at, Class> returnType) {
this.at = at;
// Assert that return type is correct
// Otherwise, when disabled avoid using reflection
assert returnType == getReturnType(name());
this.returnType = returnType;
isPolyMorphicInReturnType = returnType != Object.class;
}
private static Class> getReturnType(String name) {
try {
Method m = VarHandle.class.getMethod(name, Object[].class);
return m.getReturnType();
}
catch (Exception e) {
throw newInternalError(e);
}
}
@ForceInline
static MemberName getMemberName(int ordinal, VarForm vform) {
return vform.table[ordinal];
}
}
static final class AccessDescriptor {
final MethodType symbolicMethodType;
final int type;
final int mode;
public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
this.symbolicMethodType = symbolicMethodType;
this.type = type;
this.mode = mode;
}
}
/**
* Returns the variable type of variables referenced by this VarHandle.
*
* @return the variable type of variables referenced by this VarHandle
*/
public final Class> varType() {
return typeSet.parameterType(typeSet.parameterCount() - 1);
}
/**
* Returns the coordinate types for this VarHandle.
*
* @return the coordinate types for this VarHandle. The returned
* list is unmodifiable
*/
public final List The access mode type's parameter types will consist of a prefix that
* is the coordinate types of this VarHandle followed by further
* types as defined by the access mode's method.
* The access mode type's return type is defined by the return type of the
* access mode's method.
*
* @param accessMode the access mode, corresponding to the
* signature-polymorphic method of the same name
* @return the access mode type for the given access mode
*/
public final MethodType accessModeType(AccessMode accessMode) {
return accessMode.at.getMethodType(this);
}
/**
* Returns {@code true} if the given access mode is supported, otherwise
* {@code false}.
*
* The return of a {@code false} value for a given access mode indicates
* that an {@code UnsupportedOperationException} is thrown on invocation
* of the corresponding access mode's signature-polymorphic method.
*
* @param accessMode the access mode, corresponding to the
* signature-polymorphic method of the same name
* @return {@code true} if the given access mode is supported, otherwise
* {@code false}.
*/
public final boolean isAccessModeSupported(AccessMode accessMode) {
return AccessMode.getMemberName(accessMode.ordinal(), vform) != null;
}
/**
* Obtains a method handle bound to this VarHandle and the given access
* mode.
*
* @apiNote This method, for a VarHandle {@code vh} and access mode
* {@code {access-mode}}, returns a method handle that is equivalent to
* method handle {@code bhm} in the following code (though it may be more
* efficient):
* {@code
* MethodHandle mh = MethodHandles.varHandleExactInvoker(
* vh.accessModeType(VarHandle.AccessMode.{access-mode}));
*
* MethodHandle bmh = mh.bindTo(vh);
* }
*
* @param accessMode the access mode, corresponding to the
* signature-polymorphic method of the same name
* @return a method handle bound to this VarHandle and the given access mode
*/
public final MethodHandle toMethodHandle(AccessMode accessMode) {
MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
if (mn != null) {
return DirectMethodHandle.make(mn).
bindTo(this).
asType(accessMode.at.getMethodType(this));
}
else {
// Ensure an UnsupportedOperationException is thrown
return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
bindTo(this);
}
}
/*non-public*/
final void updateVarForm(VarForm newVForm) {
if (vform == newVForm) return;
UNSAFE.putObject(this, VFORM_OFFSET, newVForm);
UNSAFE.fullFence();
}
static final BiFunction