< prev index next >

src/java.base/share/classes/java/lang/invoke/VarHandle.java

Print this page
rev 52865 : [mq]: 8210031


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import jdk.internal.HotSpotIntrinsicCandidate;
  29 import jdk.internal.util.Preconditions;
  30 import jdk.internal.vm.annotation.ForceInline;
  31 import jdk.internal.vm.annotation.Stable;
  32 

  33 import java.util.HashMap;
  34 import java.util.List;
  35 import java.util.Map;


  36 import java.util.function.BiFunction;
  37 import java.util.function.Function;
  38 





  39 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
  40 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  41 
  42 /**
  43  * A VarHandle is a dynamically strongly typed reference to a variable, or to a
  44  * parametrically-defined family of variables, including static fields,
  45  * non-static fields, array elements, or components of an off-heap data
  46  * structure.  Access to such variables is supported under various
  47  * <em>access modes</em>, including plain read/write access, volatile
  48  * read/write access, and compare-and-set.
  49  *
  50  * <p>VarHandles are immutable and have no visible state.  VarHandles cannot be
  51  * subclassed by the user.
  52  *
  53  * <p>A VarHandle has:
  54  * <ul>
  55  * <li>a {@link #varType variable type} T, the type of every variable referenced
  56  * by this VarHandle; and
  57  * <li>a list of {@link #coordinateTypes coordinate types}
  58  * {@code CT1, CT2, ..., CTn}, the types of <em>coordinate expressions</em> that
  59  * jointly locate a variable referenced by this VarHandle.
  60  * </ul>


 420  * API is also able to return a method handle to call an access mode method for
 421  * any specified access mode type and is equivalent in behaviour to
 422  * {@link java.lang.invoke.MethodHandles#varHandleInvoker}.
 423  *
 424  * <h1>Interoperation between VarHandles and Java generics</h1>
 425  * A VarHandle can be obtained for a variable, such as a field, which is
 426  * declared with Java generic types.  As with the Core Reflection API, the
 427  * VarHandle's variable type will be constructed from the erasure of the
 428  * source-level type.  When a VarHandle access mode method is invoked, the
 429  * types
 430  * of its arguments or the return value cast type may be generic types or type
 431  * instances.  If this occurs, the compiler will replace those types by their
 432  * erasures when it constructs the symbolic type descriptor for the
 433  * {@code invokevirtual} instruction.
 434  *
 435  * @see MethodHandle
 436  * @see MethodHandles
 437  * @see MethodType
 438  * @since 9
 439  */
 440 public abstract class VarHandle {
 441     final VarForm vform;
 442 
 443     VarHandle(VarForm vform) {
 444         this.vform = vform;
 445     }
 446 
 447     RuntimeException unsupported() {
 448         return new UnsupportedOperationException();
 449     }
 450 
 451     // Plain accessors
 452 
 453     /**
 454      * Returns the value of a variable, with memory semantics of reading as
 455      * if the variable was declared non-{@code volatile}.  Commonly referred to
 456      * as plain read access.
 457      *
 458      * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
 459      *
 460      * <p>The symbolic type descriptor at the call site of {@code get}


1840             return vform.memberName_table[ordinal];
1841         }
1842     }
1843 
1844     static final class AccessDescriptor {
1845         final MethodType symbolicMethodTypeErased;
1846         final MethodType symbolicMethodTypeInvoker;
1847         final Class<?> returnType;
1848         final int type;
1849         final int mode;
1850 
1851         public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
1852             this.symbolicMethodTypeErased = symbolicMethodType.erase();
1853             this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class);
1854             this.returnType = symbolicMethodType.returnType();
1855             this.type = type;
1856             this.mode = mode;
1857         }
1858     }
1859 


























1860     /**
1861      * Returns the variable type of variables referenced by this VarHandle.
1862      *
1863      * @return the variable type of variables referenced by this VarHandle
1864      */
1865     public final Class<?> varType() {
1866         MethodType typeSet = accessModeType(AccessMode.SET);
1867         return typeSet.parameterType(typeSet.parameterCount() - 1);
1868     }
1869 
1870     /**
1871      * Returns the coordinate types for this VarHandle.
1872      *
1873      * @return the coordinate types for this VarHandle. The returned
1874      * list is unmodifiable
1875      */
1876     public final List<Class<?>> coordinateTypes() {
1877         MethodType typeGet = accessModeType(AccessMode.GET);
1878         return typeGet.parameterList();
1879     }


1934      * MethodHandle bmh = mh.bindTo(vh);
1935      * }</pre>
1936      *
1937      * @param accessMode the access mode, corresponding to the
1938      * signature-polymorphic method of the same name
1939      * @return a method handle bound to this VarHandle and the given access mode
1940      */
1941     public final MethodHandle toMethodHandle(AccessMode accessMode) {
1942         MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
1943         if (mn != null) {
1944             MethodHandle mh = getMethodHandle(accessMode.ordinal());
1945             return mh.bindTo(this);
1946         }
1947         else {
1948             // Ensure an UnsupportedOperationException is thrown
1949             return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
1950                     bindTo(this);
1951         }
1952     }
1953 














1954     @Stable
1955     TypesAndInvokers typesAndInvokers;
1956 
1957     static class TypesAndInvokers {
1958         final @Stable
1959         MethodType[] methodType_table =
1960                 new MethodType[VarHandle.AccessType.values().length];
1961 
1962         final @Stable
1963         MethodHandle[] methodHandle_table =
1964                 new MethodHandle[AccessMode.values().length];
1965     }
1966 
1967     @ForceInline
1968     private final TypesAndInvokers getTypesAndInvokers() {
1969         TypesAndInvokers tis = typesAndInvokers;
1970         if (tis == null) {
1971             tis = typesAndInvokers = new TypesAndInvokers();
1972         }
1973         return tis;


2065         UNSAFE.storeFence();
2066     }
2067 
2068     /**
2069      * Ensures that loads before the fence will not be reordered with
2070      * loads after the fence.
2071      */
2072     @ForceInline
2073     public static void loadLoadFence() {
2074         UNSAFE.loadLoadFence();
2075     }
2076 
2077     /**
2078      * Ensures that stores before the fence will not be reordered with
2079      * stores after the fence.
2080      */
2081     @ForceInline
2082     public static void storeStoreFence() {
2083         UNSAFE.storeStoreFence();
2084     }































































































































































2085 }


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.constant.ClassDesc;
  29 import java.lang.constant.Constable;
  30 import java.lang.constant.ConstantDesc;
  31 import java.lang.constant.ConstantDescs;
  32 import java.lang.constant.DirectMethodHandleDesc;
  33 import java.lang.constant.DynamicConstantDesc;
  34 import java.util.HashMap;
  35 import java.util.List;
  36 import java.util.Map;
  37 import java.util.Objects;
  38 import java.util.Optional;
  39 import java.util.function.BiFunction;
  40 import java.util.function.Function;
  41 
  42 import jdk.internal.HotSpotIntrinsicCandidate;
  43 import jdk.internal.util.Preconditions;
  44 import jdk.internal.vm.annotation.ForceInline;
  45 import jdk.internal.vm.annotation.Stable;
  46 
  47 import static java.lang.invoke.MethodHandleStatics.UNSAFE;

  48 
  49 /**
  50  * A VarHandle is a dynamically strongly typed reference to a variable, or to a
  51  * parametrically-defined family of variables, including static fields,
  52  * non-static fields, array elements, or components of an off-heap data
  53  * structure.  Access to such variables is supported under various
  54  * <em>access modes</em>, including plain read/write access, volatile
  55  * read/write access, and compare-and-set.
  56  *
  57  * <p>VarHandles are immutable and have no visible state.  VarHandles cannot be
  58  * subclassed by the user.
  59  *
  60  * <p>A VarHandle has:
  61  * <ul>
  62  * <li>a {@link #varType variable type} T, the type of every variable referenced
  63  * by this VarHandle; and
  64  * <li>a list of {@link #coordinateTypes coordinate types}
  65  * {@code CT1, CT2, ..., CTn}, the types of <em>coordinate expressions</em> that
  66  * jointly locate a variable referenced by this VarHandle.
  67  * </ul>


 427  * API is also able to return a method handle to call an access mode method for
 428  * any specified access mode type and is equivalent in behaviour to
 429  * {@link java.lang.invoke.MethodHandles#varHandleInvoker}.
 430  *
 431  * <h1>Interoperation between VarHandles and Java generics</h1>
 432  * A VarHandle can be obtained for a variable, such as a field, which is
 433  * declared with Java generic types.  As with the Core Reflection API, the
 434  * VarHandle's variable type will be constructed from the erasure of the
 435  * source-level type.  When a VarHandle access mode method is invoked, the
 436  * types
 437  * of its arguments or the return value cast type may be generic types or type
 438  * instances.  If this occurs, the compiler will replace those types by their
 439  * erasures when it constructs the symbolic type descriptor for the
 440  * {@code invokevirtual} instruction.
 441  *
 442  * @see MethodHandle
 443  * @see MethodHandles
 444  * @see MethodType
 445  * @since 9
 446  */
 447 public abstract class VarHandle implements Constable {
 448     final VarForm vform;
 449 
 450     VarHandle(VarForm vform) {
 451         this.vform = vform;
 452     }
 453 
 454     RuntimeException unsupported() {
 455         return new UnsupportedOperationException();
 456     }
 457 
 458     // Plain accessors
 459 
 460     /**
 461      * Returns the value of a variable, with memory semantics of reading as
 462      * if the variable was declared non-{@code volatile}.  Commonly referred to
 463      * as plain read access.
 464      *
 465      * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
 466      *
 467      * <p>The symbolic type descriptor at the call site of {@code get}


1847             return vform.memberName_table[ordinal];
1848         }
1849     }
1850 
1851     static final class AccessDescriptor {
1852         final MethodType symbolicMethodTypeErased;
1853         final MethodType symbolicMethodTypeInvoker;
1854         final Class<?> returnType;
1855         final int type;
1856         final int mode;
1857 
1858         public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
1859             this.symbolicMethodTypeErased = symbolicMethodType.erase();
1860             this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class);
1861             this.returnType = symbolicMethodType.returnType();
1862             this.type = type;
1863             this.mode = mode;
1864         }
1865     }
1866 
1867     @Override
1868     public final boolean equals(Object o) {
1869         if (this == o) return true;
1870         if (o == null || getClass() != o.getClass()) return false;
1871 
1872         VarHandle that = (VarHandle) o;
1873         return accessModeType(AccessMode.GET).equals(that.accessModeType(AccessMode.GET)) &&
1874                internalEquals(that);
1875     }
1876 
1877     abstract boolean internalEquals(VarHandle vh);
1878 
1879     @Override
1880     public final int hashCode() {
1881         return 31 * accessModeType(AccessMode.GET).hashCode() + internalHashCode();
1882     }
1883 
1884     abstract int internalHashCode();
1885 
1886     @Override
1887     public final String toString() {
1888         return String.format("VarHandle[varType=%s, coord=%s]",
1889                              varType().getName(),
1890                              coordinateTypes());
1891     }
1892 
1893     /**
1894      * Returns the variable type of variables referenced by this VarHandle.
1895      *
1896      * @return the variable type of variables referenced by this VarHandle
1897      */
1898     public final Class<?> varType() {
1899         MethodType typeSet = accessModeType(AccessMode.SET);
1900         return typeSet.parameterType(typeSet.parameterCount() - 1);
1901     }
1902 
1903     /**
1904      * Returns the coordinate types for this VarHandle.
1905      *
1906      * @return the coordinate types for this VarHandle. The returned
1907      * list is unmodifiable
1908      */
1909     public final List<Class<?>> coordinateTypes() {
1910         MethodType typeGet = accessModeType(AccessMode.GET);
1911         return typeGet.parameterList();
1912     }


1967      * MethodHandle bmh = mh.bindTo(vh);
1968      * }</pre>
1969      *
1970      * @param accessMode the access mode, corresponding to the
1971      * signature-polymorphic method of the same name
1972      * @return a method handle bound to this VarHandle and the given access mode
1973      */
1974     public final MethodHandle toMethodHandle(AccessMode accessMode) {
1975         MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
1976         if (mn != null) {
1977             MethodHandle mh = getMethodHandle(accessMode.ordinal());
1978             return mh.bindTo(this);
1979         }
1980         else {
1981             // Ensure an UnsupportedOperationException is thrown
1982             return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
1983                     bindTo(this);
1984         }
1985     }
1986 
1987     /**
1988      * Return a nominal descriptor for this instance, if one can be
1989      * constructed, or an empty {@link Optional} if one cannot be.
1990      *
1991      * @return An {@link Optional} containing the resulting nominal descriptor,
1992      * or an empty {@link Optional} if one cannot be constructed.
1993      * @since 12
1994      */
1995     @Override
1996     public Optional<VarHandleDesc> describeConstable() {
1997         // partial function for field and array only
1998         return Optional.empty();
1999     }
2000 
2001     @Stable
2002     TypesAndInvokers typesAndInvokers;
2003 
2004     static class TypesAndInvokers {
2005         final @Stable
2006         MethodType[] methodType_table =
2007                 new MethodType[VarHandle.AccessType.values().length];
2008 
2009         final @Stable
2010         MethodHandle[] methodHandle_table =
2011                 new MethodHandle[AccessMode.values().length];
2012     }
2013 
2014     @ForceInline
2015     private final TypesAndInvokers getTypesAndInvokers() {
2016         TypesAndInvokers tis = typesAndInvokers;
2017         if (tis == null) {
2018             tis = typesAndInvokers = new TypesAndInvokers();
2019         }
2020         return tis;


2112         UNSAFE.storeFence();
2113     }
2114 
2115     /**
2116      * Ensures that loads before the fence will not be reordered with
2117      * loads after the fence.
2118      */
2119     @ForceInline
2120     public static void loadLoadFence() {
2121         UNSAFE.loadLoadFence();
2122     }
2123 
2124     /**
2125      * Ensures that stores before the fence will not be reordered with
2126      * stores after the fence.
2127      */
2128     @ForceInline
2129     public static void storeStoreFence() {
2130         UNSAFE.storeStoreFence();
2131     }
2132 
2133     /**
2134      * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
2135      * {@link VarHandle} constant.
2136      *
2137      * @since 12
2138      */
2139     public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
2140 
2141         /**
2142          * Kinds of variable handle descs
2143          */
2144         private enum Kind {
2145             FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
2146             STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
2147             ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
2148 
2149             final DirectMethodHandleDesc bootstrapMethod;
2150 
2151             Kind(DirectMethodHandleDesc bootstrapMethod) {
2152                 this.bootstrapMethod = bootstrapMethod;
2153             }
2154 
2155             ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
2156                 switch (this) {
2157                     case FIELD:
2158                     case STATIC_FIELD:
2159                         return new ConstantDesc[] {declaringClass, varType };
2160                     case ARRAY:
2161                         return new ConstantDesc[] {declaringClass };
2162                     default:
2163                         throw new InternalError("Cannot reach here");
2164                 }
2165             }
2166         }
2167 
2168         private final Kind kind;
2169         private final ClassDesc declaringClass;
2170         private final ClassDesc varType;
2171 
2172         /**
2173          * Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
2174          * class.
2175          *
2176          * @param kind the kind of of the var handle
2177          * @param name the unqualified name of the field, for field var handles; otherwise ignored
2178          * @param declaringClass a {@link ClassDesc} describing the declaring class,
2179          *                       for field var handles
2180          * @param varType a {@link ClassDesc} describing the type of the variable
2181          * @throws NullPointerException if any required argument is null
2182          * @jvms 4.2.2 Unqualified Names
2183          */
2184         private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
2185             super(kind.bootstrapMethod, name,
2186                   ConstantDescs.CD_VarHandle,
2187                   kind.toBSMArgs(declaringClass, varType));
2188             this.kind = kind;
2189             this.declaringClass = declaringClass;
2190             this.varType = varType;
2191         }
2192 
2193         /**
2194          * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
2195          * for an instance field.
2196          *
2197          * @param name the unqualifed name of the field
2198          * @param declaringClass a {@link ClassDesc} describing the declaring class,
2199          *                       for field var handles
2200          * @param fieldType a {@link ClassDesc} describing the type of the field
2201          * @return the {@linkplain VarHandleDesc}
2202          * @throws NullPointerException if any of the arguments are null
2203          * @jvms 4.2.2 Unqualified Names
2204          */
2205         public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
2206             Objects.requireNonNull(declaringClass);
2207             Objects.requireNonNull(name);
2208             Objects.requireNonNull(fieldType);
2209             return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
2210         }
2211 
2212         /**
2213          * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
2214          * for a static field.
2215          *
2216          * @param name the unqualified name of the field
2217          * @param declaringClass a {@link ClassDesc} describing the declaring class,
2218          *                       for field var handles
2219          * @param fieldType a {@link ClassDesc} describing the type of the field
2220          * @return the {@linkplain VarHandleDesc}
2221          * @throws NullPointerException if any of the arguments are null
2222          * @jvms 4.2.2 Unqualified Names
2223          */
2224         public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
2225             Objects.requireNonNull(declaringClass);
2226             Objects.requireNonNull(name);
2227             Objects.requireNonNull(fieldType);
2228             return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
2229         }
2230 
2231         /**
2232          * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
2233          * for for an array type.
2234          *
2235          * @param arrayClass a {@link ClassDesc} describing the type of the array
2236          * @return the {@linkplain VarHandleDesc}
2237          * @throws NullPointerException if any of the arguments are null
2238          */
2239         public static VarHandleDesc ofArray(ClassDesc arrayClass) {
2240             Objects.requireNonNull(arrayClass);
2241             if (!arrayClass.isArray())
2242                 throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
2243             return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
2244         }
2245 
2246         /**
2247          * Returns a {@link ClassDesc} describing the type of the variable described
2248          * by this descriptor.
2249          *
2250          * @return the variable type
2251          */
2252         public ClassDesc varType() {
2253             return varType;
2254         }
2255 
2256         @Override
2257         public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
2258                 throws ReflectiveOperationException {
2259             switch (kind) {
2260                 case FIELD:
2261                     return lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
2262                                                 constantName(),
2263                                                 (Class<?>) varType.resolveConstantDesc(lookup));
2264                 case STATIC_FIELD:
2265                     return lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
2266                                                       constantName(),
2267                                                       (Class<?>) varType.resolveConstantDesc(lookup));
2268                 case ARRAY:
2269                     return MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
2270                 default:
2271                     throw new InternalError("Cannot reach here");
2272             }
2273         }
2274 
2275         @Override
2276         public String toString() {
2277             switch (kind) {
2278                 case FIELD:
2279                 case STATIC_FIELD:
2280                     return String.format("VarHandleDesc[%s%s.%s:%s]",
2281                                          (kind == Kind.STATIC_FIELD) ? "static " : "",
2282                                          declaringClass.displayName(), constantName(), varType.displayName());
2283                 case ARRAY:
2284                     return String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
2285                 default:
2286                     throw new InternalError("Cannot reach here");
2287             }
2288         }
2289     }
2290 
2291 }
< prev index next >