1 /*
  2  * Copyright (c) 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 package java.lang.invoke;
 26 
 27 import java.util.Optional;
 28 
 29 import jdk.internal.misc.Unsafe;
 30 import jdk.internal.util.Preconditions;
 31 import jdk.internal.value.ValueClass;
 32 import jdk.internal.vm.annotation.ForceInline;
 33 
 34 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
 35 
 36 /// The var handle for polymorphic arrays.
 37 final class ArrayVarHandle extends VarHandle {
 38     static final int REFERENCE_BASE = Math.toIntExact(Unsafe.ARRAY_OBJECT_BASE_OFFSET);
 39     static final int REFERENCE_SHIFT = Integer.numberOfTrailingZeros(Unsafe.ARRAY_OBJECT_INDEX_SCALE);
 40     final Class<?> arrayType;
 41     final Class<?> componentType;
 42 
 43     ArrayVarHandle(Class<?> arrayType) {
 44         this(arrayType, false);
 45     }
 46 
 47     private ArrayVarHandle(Class<?> arrayType, boolean exact) {
 48         super(ArrayVarHandle.FORM, exact);
 49         this.arrayType = arrayType;
 50         this.componentType = arrayType.getComponentType();
 51     }
 52 
 53     @Override
 54     public ArrayVarHandle withInvokeExactBehavior() {
 55         return hasInvokeExactBehavior()
 56                 ? this
 57                 : new ArrayVarHandle(arrayType, true);
 58     }
 59 
 60     @Override
 61     public ArrayVarHandle withInvokeBehavior() {
 62         return !hasInvokeExactBehavior()
 63                 ? this
 64                 : new ArrayVarHandle(arrayType, false);
 65     }
 66 
 67     @Override
 68     public Optional<VarHandleDesc> describeConstable() {
 69         var arrayTypeRef = arrayType.describeConstable();
 70         if (arrayTypeRef.isEmpty())
 71             return Optional.empty();
 72 
 73         return Optional.of(VarHandleDesc.ofArray(arrayTypeRef.get()));
 74     }
 75 
 76     @Override
 77     final MethodType accessModeTypeUncached(AccessType at) {
 78         return at.accessModeType(arrayType, componentType, int.class);
 79     }
 80 
 81     @ForceInline
 82     static Object storeCheck(ArrayVarHandle handle, Object[] oarray, Object value) {
 83         if (value == null && ValueClass.isNullRestrictedArray(oarray)) {
 84             throw new NullPointerException("null not allowed for null-restricted array " + oarray.getClass().toGenericString());
 85         }
 86         if (handle.arrayType == oarray.getClass()) {
 87             // Fast path: static array type same as argument array type
 88             return handle.componentType.cast(value);
 89         } else {
 90             // Slow path: check value against argument array component type
 91             return reflectiveTypeCheck(oarray, value);
 92         }
 93     }
 94 
 95     @ForceInline
 96     static Object reflectiveTypeCheck(Object[] oarray, Object value) {
 97         try {
 98             return oarray.getClass().getComponentType().cast(value);
 99         } catch (ClassCastException e) {
100             throw new ArrayStoreException();
101         }
102     }
103 
104     @ForceInline
105     static Object get(VarHandle ob, Object oarray, int index) {
106         ArrayVarHandle handle = (ArrayVarHandle) ob;
107         Object[] array = (Object[]) handle.arrayType.cast(oarray);
108         return array[index];
109     }
110 
111     @ForceInline
112     static void set(VarHandle ob, Object oarray, int index, Object value) {
113         ArrayVarHandle handle = (ArrayVarHandle) ob;
114         Object[] array = (Object[]) handle.arrayType.cast(oarray);
115         array[index] = storeCheck(handle, array, value);
116     }
117 
118     @ForceInline
119     static Object getVolatile(VarHandle ob, Object oarray, int index) {
120         ArrayVarHandle handle = (ArrayVarHandle) ob;
121         Object[] array = (Object[]) handle.arrayType.cast(oarray);
122         Class<?> arrayType = oarray.getClass();
123         if (ValueClass.isFlatArray(oarray)) {
124             // delegate to flat access primitives
125             VarHandles.checkAtomicFlatArray(array);
126             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
127             int ascale = UNSAFE.arrayIndexScale(array);
128             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
129             int layout = UNSAFE.arrayLayout(array);
130             return UNSAFE.getFlatValueVolatile(array,
131                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType());
132         }
133         return UNSAFE.getReferenceVolatile(array,
134                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE);
135     }
136 
137     @ForceInline
138     static void setVolatile(VarHandle ob, Object oarray, int index, Object value) {
139         ArrayVarHandle handle = (ArrayVarHandle) ob;
140         Object[] array = (Object[]) handle.arrayType.cast(oarray);
141         Class<?> arrayType = oarray.getClass();
142         if (ValueClass.isFlatArray(oarray)) {
143             // delegate to flat access primitives
144             VarHandles.checkAtomicFlatArray(array);
145             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
146             int ascale = UNSAFE.arrayIndexScale(array);
147             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
148             int layout = UNSAFE.arrayLayout(array);
149             UNSAFE.putFlatValueVolatile(array,
150                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
151                     storeCheck(handle, array, value));
152             return;
153         }
154         UNSAFE.putReferenceVolatile(array,
155                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
156                 storeCheck(handle, array, value));
157     }
158 
159     @ForceInline
160     static Object getOpaque(VarHandle ob, Object oarray, int index) {
161         ArrayVarHandle handle = (ArrayVarHandle) ob;
162         Object[] array = (Object[]) handle.arrayType.cast(oarray);
163         Class<?> arrayType = oarray.getClass();
164         if (ValueClass.isFlatArray(oarray)) {
165             // delegate to flat access primitives
166             VarHandles.checkAtomicFlatArray(array);
167             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
168             int ascale = UNSAFE.arrayIndexScale(array);
169             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
170             int layout = UNSAFE.arrayLayout(array);
171             return UNSAFE.getFlatValueOpaque(array,
172                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType());
173         }
174         return UNSAFE.getReferenceOpaque(array,
175                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE);
176     }
177 
178     @ForceInline
179     static void setOpaque(VarHandle ob, Object oarray, int index, Object value) {
180         ArrayVarHandle handle = (ArrayVarHandle) ob;
181         Object[] array = (Object[]) handle.arrayType.cast(oarray);
182         Class<?> arrayType = oarray.getClass();
183         if (ValueClass.isFlatArray(oarray)) {
184             // delegate to flat access primitives
185             VarHandles.checkAtomicFlatArray(array);
186             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
187             int ascale = UNSAFE.arrayIndexScale(array);
188             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
189             int layout = UNSAFE.arrayLayout(array);
190             UNSAFE.putFlatValueOpaque(array,
191                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
192                     storeCheck(handle, array, value));
193             return;
194         }
195         UNSAFE.putReferenceOpaque(array,
196                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
197                 storeCheck(handle, array, value));
198     }
199 
200     @ForceInline
201     static Object getAcquire(VarHandle ob, Object oarray, int index) {
202         ArrayVarHandle handle = (ArrayVarHandle) ob;
203         Object[] array = (Object[]) handle.arrayType.cast(oarray);
204         Class<?> arrayType = oarray.getClass();
205         if (ValueClass.isFlatArray(oarray)) {
206             // delegate to flat access primitives
207             VarHandles.checkAtomicFlatArray(array);
208             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
209             int ascale = UNSAFE.arrayIndexScale(array);
210             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
211             int layout = UNSAFE.arrayLayout(array);
212             return UNSAFE.getFlatValueAcquire(array,
213                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType());
214         }
215         return UNSAFE.getReferenceAcquire(array,
216                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE);
217     }
218 
219     @ForceInline
220     static void setRelease(VarHandle ob, Object oarray, int index, Object value) {
221         ArrayVarHandle handle = (ArrayVarHandle) ob;
222         Object[] array = (Object[]) handle.arrayType.cast(oarray);
223         Class<?> arrayType = oarray.getClass();
224         if (ValueClass.isFlatArray(oarray)) {
225             // delegate to flat access primitives
226             VarHandles.checkAtomicFlatArray(array);
227             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
228             int ascale = UNSAFE.arrayIndexScale(array);
229             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
230             int layout = UNSAFE.arrayLayout(array);
231             UNSAFE.putFlatValueRelease(array,
232                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
233                     storeCheck(handle, array, value));
234             return;
235         }
236         UNSAFE.putReferenceRelease(array,
237                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
238                 storeCheck(handle, array, value));
239     }
240 
241     @ForceInline
242     static boolean compareAndSet(VarHandle ob, Object oarray, int index, Object expected, Object value) {
243         ArrayVarHandle handle = (ArrayVarHandle) ob;
244         Object[] array = (Object[]) handle.arrayType.cast(oarray);
245         Class<?> arrayType = oarray.getClass();
246         if (ValueClass.isFlatArray(oarray)) {
247             // delegate to flat access primitives
248             VarHandles.checkAtomicFlatArray(array);
249             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
250             int ascale = UNSAFE.arrayIndexScale(array);
251             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
252             int layout = UNSAFE.arrayLayout(array);
253             return UNSAFE.compareAndSetFlatValue(array,
254                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
255                     arrayType.componentType().cast(expected),
256                     storeCheck(handle, array, value));
257         }
258         return UNSAFE.compareAndSetReference(array,
259                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
260                 handle.componentType.cast(expected),
261                 storeCheck(handle, array, value));
262     }
263 
264     @ForceInline
265     static Object compareAndExchange(VarHandle ob, Object oarray, int index, Object expected, Object value) {
266         ArrayVarHandle handle = (ArrayVarHandle) ob;
267         Object[] array = (Object[]) handle.arrayType.cast(oarray);
268         Class<?> arrayType = oarray.getClass();
269         if (ValueClass.isFlatArray(oarray)) {
270             // delegate to flat access primitives
271             VarHandles.checkAtomicFlatArray(array);
272             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
273             int ascale = UNSAFE.arrayIndexScale(array);
274             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
275             int layout = UNSAFE.arrayLayout(array);
276             return UNSAFE.compareAndExchangeFlatValue(array,
277                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
278                     arrayType.componentType().cast(expected),
279                     storeCheck(handle, array, value));
280         }
281         return UNSAFE.compareAndExchangeReference(array,
282                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
283                 handle.componentType.cast(expected),
284                 storeCheck(handle, array, value));
285     }
286 
287     @ForceInline
288     static Object compareAndExchangeAcquire(VarHandle ob, Object oarray, int index, Object expected, Object value) {
289         ArrayVarHandle handle = (ArrayVarHandle) ob;
290         Object[] array = (Object[]) handle.arrayType.cast(oarray);
291         Class<?> arrayType = oarray.getClass();
292         if (ValueClass.isFlatArray(oarray)) {
293             // delegate to flat access primitives
294             VarHandles.checkAtomicFlatArray(array);
295             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
296             int ascale = UNSAFE.arrayIndexScale(array);
297             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
298             int layout = UNSAFE.arrayLayout(array);
299             return UNSAFE.compareAndExchangeFlatValueAcquire(array,
300                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
301                     arrayType.componentType().cast(expected),
302                     storeCheck(handle, array, value));
303         }
304         return UNSAFE.compareAndExchangeReferenceAcquire(array,
305                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
306                 handle.componentType.cast(expected),
307                 storeCheck(handle, array, value));
308     }
309 
310     @ForceInline
311     static Object compareAndExchangeRelease(VarHandle ob, Object oarray, int index, Object expected, Object value) {
312         ArrayVarHandle handle = (ArrayVarHandle) ob;
313         Object[] array = (Object[]) handle.arrayType.cast(oarray);
314         Class<?> arrayType = oarray.getClass();
315         if (ValueClass.isFlatArray(oarray)) {
316             // delegate to flat access primitives
317             VarHandles.checkAtomicFlatArray(array);
318             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
319             int ascale = UNSAFE.arrayIndexScale(array);
320             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
321             int layout = UNSAFE.arrayLayout(array);
322             return UNSAFE.compareAndExchangeFlatValueRelease(array,
323                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
324                     arrayType.componentType().cast(expected),
325                     storeCheck(handle, array, value));
326         }
327         return UNSAFE.compareAndExchangeReferenceRelease(array,
328                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
329                 handle.componentType.cast(expected),
330                 storeCheck(handle, array, value));
331     }
332 
333     @ForceInline
334     static boolean weakCompareAndSetPlain(VarHandle ob, Object oarray, int index, Object expected, Object value) {
335         ArrayVarHandle handle = (ArrayVarHandle) ob;
336         Object[] array = (Object[]) handle.arrayType.cast(oarray);
337         Class<?> arrayType = oarray.getClass();
338         if (ValueClass.isFlatArray(oarray)) {
339             // delegate to flat access primitives
340             VarHandles.checkAtomicFlatArray(array);
341             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
342             int ascale = UNSAFE.arrayIndexScale(array);
343             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
344             int layout = UNSAFE.arrayLayout(array);
345             return UNSAFE.weakCompareAndSetFlatValuePlain(array,
346                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
347                     arrayType.componentType().cast(expected),
348                     storeCheck(handle, array, value));
349         }
350         return UNSAFE.weakCompareAndSetReferencePlain(array,
351                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
352                 handle.componentType.cast(expected),
353                 storeCheck(handle, array, value));
354     }
355 
356     @ForceInline
357     static boolean weakCompareAndSet(VarHandle ob, Object oarray, int index, Object expected, Object value) {
358         ArrayVarHandle handle = (ArrayVarHandle) ob;
359         Object[] array = (Object[]) handle.arrayType.cast(oarray);
360         Class<?> arrayType = oarray.getClass();
361         if (ValueClass.isFlatArray(oarray)) {
362             // delegate to flat access primitives
363             VarHandles.checkAtomicFlatArray(array);
364             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
365             int ascale = UNSAFE.arrayIndexScale(array);
366             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
367             int layout = UNSAFE.arrayLayout(array);
368             return UNSAFE.weakCompareAndSetFlatValue(array,
369                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
370                     arrayType.componentType().cast(expected),
371                     storeCheck(handle, array, value));
372         }
373         return UNSAFE.weakCompareAndSetReference(array,
374                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
375                 handle.componentType.cast(expected),
376                 storeCheck(handle, array, value));
377     }
378 
379     @ForceInline
380     static boolean weakCompareAndSetAcquire(VarHandle ob, Object oarray, int index, Object expected, Object value) {
381         ArrayVarHandle handle = (ArrayVarHandle) ob;
382         Object[] array = (Object[]) handle.arrayType.cast(oarray);
383         Class<?> arrayType = oarray.getClass();
384         if (ValueClass.isFlatArray(oarray)) {
385             // delegate to flat access primitives
386             VarHandles.checkAtomicFlatArray(array);
387             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
388             int ascale = UNSAFE.arrayIndexScale(array);
389             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
390             int layout = UNSAFE.arrayLayout(array);
391             return UNSAFE.weakCompareAndSetFlatValueAcquire(array,
392                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
393                     arrayType.componentType().cast(expected),
394                     storeCheck(handle, array, value));
395         }
396         return UNSAFE.weakCompareAndSetReferenceAcquire(array,
397                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
398                 handle.componentType.cast(expected),
399                 storeCheck(handle, array, value));
400     }
401 
402     @ForceInline
403     static boolean weakCompareAndSetRelease(VarHandle ob, Object oarray, int index, Object expected, Object value) {
404         ArrayVarHandle handle = (ArrayVarHandle) ob;
405         Object[] array = (Object[]) handle.arrayType.cast(oarray);
406         Class<?> arrayType = oarray.getClass();
407         if (ValueClass.isFlatArray(oarray)) {
408             // delegate to flat access primitives
409             VarHandles.checkAtomicFlatArray(array);
410             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
411             int ascale = UNSAFE.arrayIndexScale(array);
412             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
413             int layout = UNSAFE.arrayLayout(array);
414             return UNSAFE.weakCompareAndSetFlatValueRelease(array,
415                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
416                     arrayType.componentType().cast(expected),
417                     storeCheck(handle, array, value));
418         }
419         return UNSAFE.weakCompareAndSetReferenceRelease(array,
420                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE, handle.componentType,
421                 handle.componentType.cast(expected),
422                 storeCheck(handle, array, value));
423     }
424 
425     @ForceInline
426     static Object getAndSet(VarHandle ob, Object oarray, int index, Object value) {
427         ArrayVarHandle handle = (ArrayVarHandle) ob;
428         Object[] array = (Object[]) handle.arrayType.cast(oarray);
429         Class<?> arrayType = oarray.getClass();
430         if (ValueClass.isFlatArray(oarray)) {
431             // delegate to flat access primitives
432             VarHandles.checkAtomicFlatArray(array);
433             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
434             int ascale = UNSAFE.arrayIndexScale(array);
435             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
436             int layout = UNSAFE.arrayLayout(array);
437             return UNSAFE.getAndSetFlatValue(array,
438                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
439                     storeCheck(handle, array, value));
440         }
441         return UNSAFE.getAndSetReference(array,
442                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
443                 handle.componentType, storeCheck(handle, array, value));
444     }
445 
446     @ForceInline
447     static Object getAndSetAcquire(VarHandle ob, Object oarray, int index, Object value) {
448         ArrayVarHandle handle = (ArrayVarHandle) ob;
449         Object[] array = (Object[]) handle.arrayType.cast(oarray);
450         Class<?> arrayType = oarray.getClass();
451         if (ValueClass.isFlatArray(oarray)) {
452             // delegate to flat access primitives
453             VarHandles.checkAtomicFlatArray(array);
454             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
455             int ascale = UNSAFE.arrayIndexScale(array);
456             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
457             int layout = UNSAFE.arrayLayout(array);
458             return UNSAFE.getAndSetFlatValueAcquire(array,
459                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
460                     storeCheck(handle, array, value));
461         }
462         return UNSAFE.getAndSetReferenceAcquire(array,
463                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
464                 handle.componentType, storeCheck(handle, array, value));
465     }
466 
467     @ForceInline
468     static Object getAndSetRelease(VarHandle ob, Object oarray, int index, Object value) {
469         ArrayVarHandle handle = (ArrayVarHandle) ob;
470         Object[] array = (Object[]) handle.arrayType.cast(oarray);
471         Class<?> arrayType = oarray.getClass();
472         if (ValueClass.isFlatArray(oarray)) {
473             // delegate to flat access primitives
474             VarHandles.checkAtomicFlatArray(array);
475             int aoffset = (int) UNSAFE.arrayBaseOffset(array);
476             int ascale = UNSAFE.arrayIndexScale(array);
477             int ashift = 31 - Integer.numberOfLeadingZeros(ascale);
478             int layout = UNSAFE.arrayLayout(array);
479             return UNSAFE.getAndSetFlatValueRelease(array,
480                     (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << ashift) + aoffset, layout, arrayType.componentType(),
481                     storeCheck(handle, array, value));
482         }
483         return UNSAFE.getAndSetReferenceRelease(array,
484                 (((long) Preconditions.checkIndex(index, array.length, Preconditions.AIOOBE_FORMATTER)) << REFERENCE_SHIFT) + REFERENCE_BASE,
485                 handle.componentType, storeCheck(handle, array, value));
486     }
487 
488     static final VarForm FORM = new VarForm(ArrayVarHandle.class, Object[].class, Object.class, int.class);
489 }