< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  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.misc.CDS;


 29 import sun.invoke.util.Wrapper;
 30 
 31 import java.lang.foreign.MemoryLayout;
 32 import java.lang.reflect.Constructor;
 33 import java.lang.reflect.Field;
 34 import java.lang.reflect.Method;
 35 import java.lang.reflect.Modifier;
 36 import java.nio.ByteOrder;
 37 import java.util.ArrayList;
 38 import java.util.List;
 39 import java.util.Objects;
 40 import java.util.stream.Stream;
 41 
 42 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 43 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_SEGMENT_FORCE_EXACT;
 44 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT;
 45 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
 46 
 47 final class VarHandles {
 48 
 49     static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean isWriteAllowedOnFinalFields) {


 50         if (!f.isStatic()) {
 51             long foffset = MethodHandleNatives.objectFieldOffset(f);
 52             Class<?> type = f.getFieldType();
 53             if (!type.isPrimitive()) {
 54                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 55                        ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type)
 56                        : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type));



























 57             }
 58             else if (type == boolean.class) {
 59                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 60                        ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset)
 61                        : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset));
 62             }
 63             else if (type == byte.class) {
 64                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 65                        ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset)
 66                        : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset));
 67             }
 68             else if (type == short.class) {
 69                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 70                        ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset)
 71                        : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset));
 72             }
 73             else if (type == char.class) {
 74                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 75                        ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset)
 76                        : new VarHandleChars.FieldInstanceReadWrite(refc, foffset));
 77             }
 78             else if (type == int.class) {
 79                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 80                        ? new VarHandleInts.FieldInstanceReadOnly(refc, foffset)
 81                        : new VarHandleInts.FieldInstanceReadWrite(refc, foffset));
 82             }
 83             else if (type == long.class) {
 84                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 85                        ? new VarHandleLongs.FieldInstanceReadOnly(refc, foffset)
 86                        : new VarHandleLongs.FieldInstanceReadWrite(refc, foffset));
 87             }
 88             else if (type == float.class) {
 89                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 90                        ? new VarHandleFloats.FieldInstanceReadOnly(refc, foffset)
 91                        : new VarHandleFloats.FieldInstanceReadWrite(refc, foffset));
 92             }
 93             else if (type == double.class) {
 94                 return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
 95                        ? new VarHandleDoubles.FieldInstanceReadOnly(refc, foffset)
 96                        : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset));
 97             }
 98             else {
 99                 throw new UnsupportedOperationException();
100             }
101         }
102         else {
103             Class<?> decl = f.getDeclaringClass();
104             var vh = makeStaticFieldVarHandle(decl, f, isWriteAllowedOnFinalFields);
105             return maybeAdapt((UNSAFE.shouldBeInitialized(decl) || CDS.needsClassInitBarrier(decl))
106                     ? new LazyInitializingVarHandle(vh, decl)
107                     : vh);
108         }
109     }
110 
111     static VarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean isWriteAllowedOnFinalFields) {































112         Object base = MethodHandleNatives.staticFieldBase(f);
113         long foffset = MethodHandleNatives.staticFieldOffset(f);
114         Class<?> type = f.getFieldType();
115         if (!type.isPrimitive()) {
116             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
117                     ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type)
118                     : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type));













119         }
120         else if (type == boolean.class) {
121             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
122                     ? new VarHandleBooleans.FieldStaticReadOnly(decl, base, foffset)
123                     : new VarHandleBooleans.FieldStaticReadWrite(decl, base, foffset));
124         }
125         else if (type == byte.class) {
126             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
127                     ? new VarHandleBytes.FieldStaticReadOnly(decl, base, foffset)
128                     : new VarHandleBytes.FieldStaticReadWrite(decl, base, foffset));
129         }
130         else if (type == short.class) {
131             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
132                     ? new VarHandleShorts.FieldStaticReadOnly(decl, base, foffset)
133                     : new VarHandleShorts.FieldStaticReadWrite(decl, base, foffset));
134         }
135         else if (type == char.class) {
136             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
137                     ? new VarHandleChars.FieldStaticReadOnly(decl, base, foffset)
138                     : new VarHandleChars.FieldStaticReadWrite(decl, base, foffset));
139         }
140         else if (type == int.class) {
141             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
142                     ? new VarHandleInts.FieldStaticReadOnly(decl, base, foffset)
143                     : new VarHandleInts.FieldStaticReadWrite(decl, base, foffset));
144         }
145         else if (type == long.class) {
146             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
147                     ? new VarHandleLongs.FieldStaticReadOnly(decl, base, foffset)
148                     : new VarHandleLongs.FieldStaticReadWrite(decl, base, foffset));
149         }
150         else if (type == float.class) {
151             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
152                     ? new VarHandleFloats.FieldStaticReadOnly(decl, base, foffset)
153                     : new VarHandleFloats.FieldStaticReadWrite(decl, base, foffset));
154         }
155         else if (type == double.class) {
156             return maybeAdapt(f.isFinal() && !isWriteAllowedOnFinalFields
157                     ? new VarHandleDoubles.FieldStaticReadOnly(decl, base, foffset)
158                     : new VarHandleDoubles.FieldStaticReadWrite(decl, base, foffset));
159         }
160         else {
161             throw new UnsupportedOperationException();
162         }
163     }
164 















165     // Required by instance field handles
166     static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
167                                                long offset,
168                                                Class<?> fieldType) {
169         // The receiver may be a referenced class different from the declaring class
170         for (var declaringClass = receiverType; declaringClass != null; declaringClass = declaringClass.getSuperclass()) {
171             for (Field f : declaringClass.getDeclaredFields()) {
172                 if (Modifier.isStatic(f.getModifiers())) continue;
173 
174                 if (offset == UNSAFE.objectFieldOffset(f)) {
175                     assert f.getType() == fieldType;
176                     return f;
177                 }
178             }
179         }
180         throw new InternalError("Field not found at offset");
181     }
182 
183     // Required by instance static field handles
184     static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
185                                                  long offset,
186                                                  Class<?> fieldType) {
187         for (Field f : declaringClass.getDeclaredFields()) {
188             if (!Modifier.isStatic(f.getModifiers())) continue;
189 
190             if (offset == UNSAFE.staticFieldOffset(f)) {
191                 assert f.getType() == fieldType;
192                 return f;
193             }
194         }
195         throw new InternalError("Static field not found at offset");
196     }
197 







198     static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
199         if (!arrayClass.isArray())
200             throw new IllegalArgumentException("not an array: " + arrayClass);
201 
202         Class<?> componentType = arrayClass.getComponentType();
203 
204         int aoffset = (int) UNSAFE.arrayBaseOffset(arrayClass);
205         int ascale = UNSAFE.arrayIndexScale(arrayClass);
206         int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
207 
208         if (!componentType.isPrimitive()) {
209             return maybeAdapt(new VarHandleReferences.Array(aoffset, ashift, arrayClass));




210         }
211         else if (componentType == boolean.class) {
212             return maybeAdapt(new VarHandleBooleans.Array(aoffset, ashift));
213         }
214         else if (componentType == byte.class) {
215             return maybeAdapt(new VarHandleBytes.Array(aoffset, ashift));
216         }
217         else if (componentType == short.class) {
218             return maybeAdapt(new VarHandleShorts.Array(aoffset, ashift));
219         }
220         else if (componentType == char.class) {
221             return maybeAdapt(new VarHandleChars.Array(aoffset, ashift));
222         }
223         else if (componentType == int.class) {
224             return maybeAdapt(new VarHandleInts.Array(aoffset, ashift));
225         }
226         else if (componentType == long.class) {
227             return maybeAdapt(new VarHandleLongs.Array(aoffset, ashift));
228         }
229         else if (componentType == float.class) {
230             return maybeAdapt(new VarHandleFloats.Array(aoffset, ashift));
231         }
232         else if (componentType == double.class) {
233             return maybeAdapt(new VarHandleDoubles.Array(aoffset, ashift));
234         }
235         else {
236             throw new UnsupportedOperationException();
237         }
238     }
239 
240     static VarHandle byteArrayViewHandle(Class<?> viewArrayClass,
241                                          boolean be) {
242         if (!viewArrayClass.isArray())
243             throw new IllegalArgumentException("not an array: " + viewArrayClass);
244 
245         Class<?> viewComponentType = viewArrayClass.getComponentType();
246 
247         if (viewComponentType == long.class) {
248             return maybeAdapt(new VarHandleByteArrayAsLongs.ArrayHandle(be));
249         }
250         else if (viewComponentType == int.class) {
251             return maybeAdapt(new VarHandleByteArrayAsInts.ArrayHandle(be));
252         }
253         else if (viewComponentType == short.class) {

  1 /*
  2  * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  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.misc.CDS;
 29 import jdk.internal.value.ValueClass;
 30 import jdk.internal.vm.annotation.LooselyConsistentValue;
 31 import sun.invoke.util.Wrapper;
 32 
 33 import java.lang.foreign.MemoryLayout;
 34 import java.lang.reflect.Constructor;
 35 import java.lang.reflect.Field;
 36 import java.lang.reflect.Method;
 37 import java.lang.reflect.Modifier;
 38 import java.nio.ByteOrder;
 39 import java.util.ArrayList;
 40 import java.util.List;
 41 import java.util.Objects;
 42 import java.util.stream.Stream;
 43 
 44 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 45 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_SEGMENT_FORCE_EXACT;
 46 import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT;
 47 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
 48 
 49 final class VarHandles {
 50 
 51     static VarHandle makeFieldHandle(MemberName f, Class<?> refc, boolean trustedLookup) {
 52         // No strict final or trusted final writes: we don't know the lifecycle of such a field.
 53         boolean noWriting = f.isFinal() && (!trustedLookup || f.isStrictInit() || f.isTrustedFinalField());
 54         if (!f.isStatic()) {
 55             long foffset = MethodHandleNatives.objectFieldOffset(f);
 56             Class<?> type = f.getFieldType();
 57             if (!type.isPrimitive()) {
 58                 if (ValueClass.isConcreteValueClass(type)) {
 59                     int layout = f.getLayout();
 60                     boolean isAtomic = isAtomicFlat(f);
 61                     boolean isFlat = f.isFlat();
 62                     if (isFlat) {
 63                         if (isAtomic) {
 64                             return maybeAdapt(noWriting
 65                                     ? new VarHandleFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
 66                                     : new VarHandleFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
 67                         } else {
 68                             return maybeAdapt(noWriting
 69                                     ? new VarHandleNonAtomicFlatValues.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted(), layout)
 70                                     : new VarHandleNonAtomicFlatValues.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted(), layout));
 71                         }
 72                     } else {
 73                         if (isAtomic) {
 74                             return maybeAdapt(noWriting
 75                                     ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
 76                                     : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
 77                         } else {
 78                             return maybeAdapt(noWriting
 79                                     ? new VarHandleNonAtomicReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
 80                                     : new VarHandleNonAtomicReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
 81                         }
 82                     }
 83                 } else {
 84                     return maybeAdapt(noWriting
 85                        ? new VarHandleReferences.FieldInstanceReadOnly(refc, foffset, type, f.isNullRestricted())
 86                        : new VarHandleReferences.FieldInstanceReadWrite(refc, foffset, type, f.isNullRestricted()));
 87                 }
 88             }
 89             else if (type == boolean.class) {
 90                 return maybeAdapt(noWriting
 91                        ? new VarHandleBooleans.FieldInstanceReadOnly(refc, foffset)
 92                        : new VarHandleBooleans.FieldInstanceReadWrite(refc, foffset));
 93             }
 94             else if (type == byte.class) {
 95                 return maybeAdapt(noWriting
 96                        ? new VarHandleBytes.FieldInstanceReadOnly(refc, foffset)
 97                        : new VarHandleBytes.FieldInstanceReadWrite(refc, foffset));
 98             }
 99             else if (type == short.class) {
100                 return maybeAdapt(noWriting
101                        ? new VarHandleShorts.FieldInstanceReadOnly(refc, foffset)
102                        : new VarHandleShorts.FieldInstanceReadWrite(refc, foffset));
103             }
104             else if (type == char.class) {
105                 return maybeAdapt(noWriting
106                        ? new VarHandleChars.FieldInstanceReadOnly(refc, foffset)
107                        : new VarHandleChars.FieldInstanceReadWrite(refc, foffset));
108             }
109             else if (type == int.class) {
110                 return maybeAdapt(noWriting
111                        ? new VarHandleInts.FieldInstanceReadOnly(refc, foffset)
112                        : new VarHandleInts.FieldInstanceReadWrite(refc, foffset));
113             }
114             else if (type == long.class) {
115                 return maybeAdapt(noWriting
116                        ? new VarHandleLongs.FieldInstanceReadOnly(refc, foffset)
117                        : new VarHandleLongs.FieldInstanceReadWrite(refc, foffset));
118             }
119             else if (type == float.class) {
120                 return maybeAdapt(noWriting
121                        ? new VarHandleFloats.FieldInstanceReadOnly(refc, foffset)
122                        : new VarHandleFloats.FieldInstanceReadWrite(refc, foffset));
123             }
124             else if (type == double.class) {
125                 return maybeAdapt(noWriting
126                        ? new VarHandleDoubles.FieldInstanceReadOnly(refc, foffset)
127                        : new VarHandleDoubles.FieldInstanceReadWrite(refc, foffset));
128             }
129             else {
130                 throw new UnsupportedOperationException();
131             }
132         }
133         else {
134             Class<?> decl = f.getDeclaringClass();
135             var vh = makeStaticFieldVarHandle(decl, f, noWriting);
136             return maybeAdapt((UNSAFE.shouldBeInitialized(decl) || CDS.needsClassInitBarrier(decl))
137                     ? new LazyInitializingVarHandle(vh, f.isStrictInit())
138                     : vh);
139         }
140     }
141 
142     /// A root class for static field var handles. Allows [LazyInitializingVarHandle]
143     /// to access the declaring class and field offsets.
144     sealed static abstract class StaticFieldVarHandle extends VarHandle permits
145             VarHandleBooleans.FieldStaticReadOnly,
146             VarHandleBytes.FieldStaticReadOnly,
147             VarHandleChars.FieldStaticReadOnly,
148             VarHandleShorts.FieldStaticReadOnly,
149             VarHandleInts.FieldStaticReadOnly,
150             VarHandleLongs.FieldStaticReadOnly,
151             VarHandleFloats.FieldStaticReadOnly,
152             VarHandleDoubles.FieldStaticReadOnly,
153             VarHandleReferences.FieldStaticReadOnly,
154             VarHandleNonAtomicReferences.FieldStaticReadOnly {
155         final Class<?> declaringClass;
156         final Object base;
157         final long fieldOffset;
158 
159         StaticFieldVarHandle(VarForm vform, boolean exact, Class<?> declaringClass, Object base, long fieldOffset) {
160             this.declaringClass = declaringClass;
161             this.base = base;
162             this.fieldOffset = fieldOffset;
163             super(vform, exact);
164         }
165 
166         @Override
167         public abstract StaticFieldVarHandle withInvokeBehavior();
168 
169         @Override
170         public abstract StaticFieldVarHandle withInvokeExactBehavior();
171     }
172 
173     static StaticFieldVarHandle makeStaticFieldVarHandle(Class<?> decl, MemberName f, boolean noWriting) {
174         Object base = MethodHandleNatives.staticFieldBase(f);
175         long foffset = MethodHandleNatives.staticFieldOffset(f);
176         Class<?> type = f.getFieldType();
177         if (!type.isPrimitive()) {
178             assert !f.isFlat() : ("static field is flat in " + decl + "." + f.getName());
179             if (ValueClass.isConcreteValueClass(type)) {
180                 if (isAtomicFlat(f)) {
181                     return noWriting
182                             ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
183                             : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
184                 } else {
185                     return noWriting
186                             ? new VarHandleNonAtomicReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
187                             : new VarHandleNonAtomicReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
188                 }
189             } else {
190                 return noWriting
191                         ? new VarHandleReferences.FieldStaticReadOnly(decl, base, foffset, type, f.isNullRestricted())
192                         : new VarHandleReferences.FieldStaticReadWrite(decl, base, foffset, type, f.isNullRestricted());
193             }
194         }
195         else if (type == boolean.class) {
196             return noWriting
197                     ? new VarHandleBooleans.FieldStaticReadOnly(decl, base, foffset)
198                     : new VarHandleBooleans.FieldStaticReadWrite(decl, base, foffset);
199         }
200         else if (type == byte.class) {
201             return noWriting
202                     ? new VarHandleBytes.FieldStaticReadOnly(decl, base, foffset)
203                     : new VarHandleBytes.FieldStaticReadWrite(decl, base, foffset);
204         }
205         else if (type == short.class) {
206             return noWriting
207                     ? new VarHandleShorts.FieldStaticReadOnly(decl, base, foffset)
208                     : new VarHandleShorts.FieldStaticReadWrite(decl, base, foffset);
209         }
210         else if (type == char.class) {
211             return noWriting
212                     ? new VarHandleChars.FieldStaticReadOnly(decl, base, foffset)
213                     : new VarHandleChars.FieldStaticReadWrite(decl, base, foffset);
214         }
215         else if (type == int.class) {
216             return noWriting
217                     ? new VarHandleInts.FieldStaticReadOnly(decl, base, foffset)
218                     : new VarHandleInts.FieldStaticReadWrite(decl, base, foffset);
219         }
220         else if (type == long.class) {
221             return noWriting
222                     ? new VarHandleLongs.FieldStaticReadOnly(decl, base, foffset)
223                     : new VarHandleLongs.FieldStaticReadWrite(decl, base, foffset);
224         }
225         else if (type == float.class) {
226             return noWriting
227                     ? new VarHandleFloats.FieldStaticReadOnly(decl, base, foffset)
228                     : new VarHandleFloats.FieldStaticReadWrite(decl, base, foffset);
229         }
230         else if (type == double.class) {
231             return noWriting
232                     ? new VarHandleDoubles.FieldStaticReadOnly(decl, base, foffset)
233                     : new VarHandleDoubles.FieldStaticReadWrite(decl, base, foffset);
234         }
235         else {
236             throw new UnsupportedOperationException();
237         }
238     }
239 
240     static boolean isAtomicFlat(MemberName field) {
241         boolean hasAtomicAccess = (field.getModifiers() & Modifier.VOLATILE) != 0 ||
242                 !(field.isNullRestricted()) ||
243                 !field.getFieldType().isAnnotationPresent(LooselyConsistentValue.class);
244         return hasAtomicAccess && ValueClass.hasBinaryPayload(field.getFieldType());
245     }
246 
247     static boolean isAtomicFlat(Object[] array) {
248         Class<?> componentType = array.getClass().componentType();
249         boolean hasAtomicAccess = ValueClass.isAtomicArray(array) ||
250                 !ValueClass.isNullRestrictedArray(array) ||
251                 !componentType.isAnnotationPresent(LooselyConsistentValue.class);
252         return hasAtomicAccess && ValueClass.hasBinaryPayload(componentType);
253     }
254 
255     // Required by instance field handles
256     static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
257                                                long offset,
258                                                Class<?> fieldType) {
259         // The receiver may be a referenced class different from the declaring class
260         for (var declaringClass = receiverType; declaringClass != null; declaringClass = declaringClass.getSuperclass()) {
261             for (Field f : declaringClass.getDeclaredFields()) {
262                 if (Modifier.isStatic(f.getModifiers())) continue;
263 
264                 if (offset == UNSAFE.objectFieldOffset(f)) {
265                     assert f.getType() == fieldType;
266                     return f;
267                 }
268             }
269         }
270         throw new InternalError("Field not found at offset");
271     }
272 
273     // Required by instance static field handles
274     static Field getStaticFieldFromBaseAndOffset(Class<?> declaringClass,
275                                                  long offset,
276                                                  Class<?> fieldType) {
277         for (Field f : declaringClass.getDeclaredFields()) {
278             if (!Modifier.isStatic(f.getModifiers())) continue;
279 
280             if (offset == UNSAFE.staticFieldOffset(f)) {
281                 assert f.getType() == fieldType;
282                 return f;
283             }
284         }
285         throw new InternalError("Static field not found at offset");
286     }
287 
288     // This is invoked by non-flat array var handle code when attempting to access a flat array
289     public static void checkAtomicFlatArray(Object[] array) {
290         if (!isAtomicFlat(array)) {
291             throw new IllegalArgumentException("Attempt to perform a non-plain access on a non-atomic array");
292         }
293     }
294 
295     static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
296         if (!arrayClass.isArray())
297             throw new IllegalArgumentException("not an array: " + arrayClass);
298 
299         Class<?> componentType = arrayClass.getComponentType();





300         if (!componentType.isPrimitive()) {
301             // Here we always return a reference array element var handle. This is because
302             // the access semantics is determined at runtime, when an actual array object is passed
303             // to the var handle. The var handle implementation will switch to use flat access
304             // primitives if it sees a flat array.
305             return maybeAdapt(new ArrayVarHandle(arrayClass));
306         }
307         else if (componentType == boolean.class) {
308             return maybeAdapt(VarHandleBooleans.Array.NON_EXACT_INSTANCE);
309         }
310         else if (componentType == byte.class) {
311             return maybeAdapt(VarHandleBytes.Array.NON_EXACT_INSTANCE);
312         }
313         else if (componentType == short.class) {
314             return maybeAdapt(VarHandleShorts.Array.NON_EXACT_INSTANCE);
315         }
316         else if (componentType == char.class) {
317             return maybeAdapt(VarHandleChars.Array.NON_EXACT_INSTANCE);
318         }
319         else if (componentType == int.class) {
320             return maybeAdapt(VarHandleInts.Array.NON_EXACT_INSTANCE);
321         }
322         else if (componentType == long.class) {
323             return maybeAdapt(VarHandleLongs.Array.NON_EXACT_INSTANCE);
324         }
325         else if (componentType == float.class) {
326             return maybeAdapt(VarHandleFloats.Array.NON_EXACT_INSTANCE);
327         }
328         else if (componentType == double.class) {
329             return maybeAdapt(VarHandleDoubles.Array.NON_EXACT_INSTANCE);
330         }
331         else {
332             throw new UnsupportedOperationException();
333         }
334     }
335 
336     static VarHandle byteArrayViewHandle(Class<?> viewArrayClass,
337                                          boolean be) {
338         if (!viewArrayClass.isArray())
339             throw new IllegalArgumentException("not an array: " + viewArrayClass);
340 
341         Class<?> viewComponentType = viewArrayClass.getComponentType();
342 
343         if (viewComponentType == long.class) {
344             return maybeAdapt(new VarHandleByteArrayAsLongs.ArrayHandle(be));
345         }
346         else if (viewComponentType == int.class) {
347             return maybeAdapt(new VarHandleByteArrayAsInts.ArrayHandle(be));
348         }
349         else if (viewComponentType == short.class) {
< prev index next >