< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java

Print this page




  64  * The final memory location accessed by a memory access var handle can be computed as follows:
  65  *
  66  * <blockquote><pre>{@code
  67 address = base + offset
  68  * }</pre></blockquote>
  69  *
  70  * where {@code base} denotes the address expressed by the {@link MemoryAddress} access coordinate, and {@code offset}
  71  * can be expressed in the following form:
  72  *
  73  * <blockquote><pre>{@code
  74 offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
  75  * }</pre></blockquote>
  76  *
  77  * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as optional {@code long}
  78  * access coordinates, whereas {@code c_1}, {@code c_2}, ... {@code c_m} and {@code s_0}, {@code s_1}, ... {@code s_n} are
  79  * <em>static</em> constants which are can be acquired through the {@link MemoryHandles#withOffset(VarHandle, long)}
  80  * and the {@link MemoryHandles#withStride(VarHandle, long)} combinators, respectively.
  81  *
  82  * <h2><a id="memaccess-mode"></a>Alignment and access modes</h2>
  83  *
  84  * Memory access may be <em>aligned</em> or <em>misaligned</em> for the given carrier {@code T},
  85  * with respect to the underlying memory address, {@code A} say, which is the final address (computed by the formula described above)
  86  * at which the memory dereference operation occurs.
  87  *
  88  * If access is misaligned then access for anything other than the {@code get} and {@code set} access modes will result
  89  * in an {@code IllegalStateException}. In such cases atomic access is only guaranteed with respect to the largest power
  90  * of two that divides the GCD of {@code A} and the size (in bytes) of {@code T}.
  91  * If access is aligned then following access modes are supported and are
  92  * guaranteed to support atomic access:
  93  * <ul>
  94  * <li>read write access modes for all {@code T}, with the exception of
  95  *     access modes {@code get} and {@code set} for {@code long} and
  96  *     {@code double} on 32-bit platforms.
  97  * <li>atomic update access modes for {@code int}, {@code long},
  98  *     {@code float} or {@code double}.
  99  *     (Future major platform releases of the JDK may support additional
 100  *     types for certain currently unsupported access modes.)
 101  * <li>numeric atomic update access modes for {@code int} and {@code long}.
 102  *     (Future major platform releases of the JDK may support additional
 103  *     numeric types for certain currently unsupported access modes.)
 104  * <li>bitwise atomic update access modes for {@code int} and {@code long}.
 105  *     (Future major platform releases of the JDK may support additional
 106  *     numeric types for certain currently unsupported access modes.)
 107  * </ul>
 108  * <p>
 109  * If {@code T} is {@code float} or {@code double} then atomic
 110  * update access modes compare values using their bitwise representation
 111  * (see {@link Float#floatToRawIntBits} and
 112  * {@link Double#doubleToRawLongBits}, respectively).








 113  */
 114 public final class MemoryHandles {
 115 
 116     private final static JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
 117 
 118     private MemoryHandles() {
 119         //sorry, just the one!
 120     }
 121 
 122     /**
 123      * Creates a memory access var handle with the given carrier type and byte order.
 124      *
 125      * The resulting memory access var handle features a single {@link MemoryAddress} access coordinate,
 126      * and its variable type is set by the given carrier type.
 127      *
 128      * The alignment constraint for the resulting memory access var handle is the same as the in memory size of the
 129      * carrier type, and the accessed offset is set at zero.
 130      *
 131      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 132      * which are common to all memory access var handles.


 153      * The accessed offset is zero.
 154      *
 155      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 156      * which are common to all memory access var handles.
 157      *
 158      * @param carrier the carrier type. Valid carriers are {@code byte}, {@code short}, {@code char}, {@code int},
 159      * {@code float}, {@code long}, and {@code double}.
 160      * @param alignmentBytes the alignment constraint (in bytes). Must be a power of two.
 161      * @param byteOrder the required byte order.
 162      * @return the new memory access var handle.
 163      * @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
 164      */
 165     public static VarHandle varHandle(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder) {
 166         checkCarrier(carrier);
 167 
 168         if (alignmentBytes <= 0
 169                 || (alignmentBytes & (alignmentBytes - 1)) != 0) { // is power of 2?
 170             throw new IllegalArgumentException("Bad alignment: " + alignmentBytes);
 171         }
 172 
 173         return JLI.memoryAddressViewVarHandle(carrier, alignmentBytes, byteOrder, 0, new long[]{});
 174     }
 175 
 176     /**
 177      * Creates a memory access var handle with a fixed offset added to the accessed offset. That is,
 178      * if the target memory access var handle accesses a memory location at offset <em>O</em>, the new memory access var
 179      * handle will access a memory location at offset <em>O' + O</em>.
 180      *
 181      * The resulting memory access var handle will feature the same access coordinates as the ones in the target memory access var handle.
 182      *
 183      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 184      * which are common to all memory access var handles.
 185      *
 186      * @param target the target memory access handle to access after the offset adjustment.
 187      * @param bytesOffset the offset, in bytes. Must be positive or zero.
 188      * @return the new memory access var handle.
 189      * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
 190      * or when {@code bytesOffset < 0}, or otherwise incompatible with the alignment constraint.
 191      */
 192     public static VarHandle withOffset(VarHandle target, long bytesOffset) {
 193         if (bytesOffset < 0) {
 194             throw new IllegalArgumentException("Illegal offset: " + bytesOffset);
 195         }
 196 
 197         long align = JLI.memoryAddressAlignment(target);
 198 
 199         if (bytesOffset % align != 0) {
 200             throw new IllegalArgumentException("Offset " + bytesOffset + " does not conform to alignment " + align);
 201         }
 202 
 203         return JLI.memoryAddressViewVarHandle(
 204                 JLI.memoryAddressCarrier(target),
 205                 align,
 206                 JLI.memoryAddressByteOrder(target),
 207                 JLI.memoryAddressOffset(target) + bytesOffset,
 208                 JLI.memoryAddressStrides(target));
 209     }
 210 
 211     /**
 212      * Creates a memory access var handle with a <em>variable</em> offset added to the accessed offset.
 213      * That is, if the target memory access var handle accesses a memory location at offset <em>O</em>,
 214      * the new memory access var handle will access a memory location at offset <em>(S * X) + O</em>, where <em>S</em>
 215      * is a constant <em>stride</em>, whereas <em>X</em> is a dynamic value that will be provided as an additional access
 216      * coordinate (of type {@code long}). The new access coordinate will be <em>prepended</em> to the ones available
 217      * in the target memory access var handles (if any).
 218      *
 219      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 220      * which are common to all memory access var handles.
 221      *
 222      * @param target the target memory access handle to access after the scale adjustment.
 223      * @param bytesStride the stride, in bytes, by which to multiply the coordinate value. Must be greater than zero.
 224      * @return the new memory access var handle.
 225      * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
 226      * or if {@code bytesStride <= 0}, or otherwise incompatible with the alignment constraint.
 227      */
 228     public static VarHandle withStride(VarHandle target, long bytesStride) {
 229         if (bytesStride == 0) {
 230             throw new IllegalArgumentException("Stride must be positive: " + bytesStride);
 231         }
 232 
 233         long align = JLI.memoryAddressAlignment(target);
 234 
 235         if (bytesStride % align != 0) {
 236             throw new IllegalArgumentException("Stride " + bytesStride + " does not conform to alignment " + align);
 237         }
 238 
 239         long offset = JLI.memoryAddressOffset(target);
 240         Class<?> carrier = JLI.memoryAddressCarrier(target);
 241 
 242         long[] strides = JLI.memoryAddressStrides(target);
 243         long[] newStrides = new long[strides.length + 1];
 244         System.arraycopy(strides, 0, newStrides, 1, strides.length);
 245         newStrides[0] = bytesStride;
 246 
 247         return JLI.memoryAddressViewVarHandle(
 248                 JLI.memoryAddressCarrier(target),
 249                 align,
 250                 JLI.memoryAddressByteOrder(target),
 251                 offset,
 252                 newStrides);
 253     }
 254 
 255     private static void checkCarrier(Class<?> carrier) {
 256         if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
 257             throw new IllegalArgumentException("Illegal carrier: " + carrier.getSimpleName());
 258         }
 259     }
 260 
 261     private static long carrierSize(Class<?> carrier) {
 262         long bitsAlignment = Math.max(8, Wrapper.forPrimitiveType(carrier).bitWidth());
 263         return Utils.bitsToBytesOrThrow(bitsAlignment, IllegalStateException::new);
 264     }
 265 }


  64  * The final memory location accessed by a memory access var handle can be computed as follows:
  65  *
  66  * <blockquote><pre>{@code
  67 address = base + offset
  68  * }</pre></blockquote>
  69  *
  70  * where {@code base} denotes the address expressed by the {@link MemoryAddress} access coordinate, and {@code offset}
  71  * can be expressed in the following form:
  72  *
  73  * <blockquote><pre>{@code
  74 offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
  75  * }</pre></blockquote>
  76  *
  77  * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as optional {@code long}
  78  * access coordinates, whereas {@code c_1}, {@code c_2}, ... {@code c_m} and {@code s_0}, {@code s_1}, ... {@code s_n} are
  79  * <em>static</em> constants which are can be acquired through the {@link MemoryHandles#withOffset(VarHandle, long)}
  80  * and the {@link MemoryHandles#withStride(VarHandle, long)} combinators, respectively.
  81  *
  82  * <h2><a id="memaccess-mode"></a>Alignment and access modes</h2>
  83  *
  84  * A memory access var handle is associated with an access size {@code S} and an alignment constraint {@code B}
  85  * (both expressed in bytes). We say that a memory access operation is <em>fully aligned</em> if it occurs
  86  * at a memory address {@code A} which is compatible with both alignment constraints {@code S} and {@code B}.
  87  * If access is fully aligned then following access modes are supported and are




  88  * guaranteed to support atomic access:
  89  * <ul>
  90  * <li>read write access modes for all {@code T}, with the exception of
  91  *     access modes {@code get} and {@code set} for {@code long} and
  92  *     {@code double} on 32-bit platforms.
  93  * <li>atomic update access modes for {@code int}, {@code long},
  94  *     {@code float} or {@code double}.
  95  *     (Future major platform releases of the JDK may support additional
  96  *     types for certain currently unsupported access modes.)
  97  * <li>numeric atomic update access modes for {@code int} and {@code long}.
  98  *     (Future major platform releases of the JDK may support additional
  99  *     numeric types for certain currently unsupported access modes.)
 100  * <li>bitwise atomic update access modes for {@code int} and {@code long}.
 101  *     (Future major platform releases of the JDK may support additional
 102  *     numeric types for certain currently unsupported access modes.)
 103  * </ul>
 104  *
 105  * If {@code T} is {@code float} or {@code double} then atomic
 106  * update access modes compare values using their bitwise representation
 107  * (see {@link Float#floatToRawIntBits} and
 108  * {@link Double#doubleToRawLongBits}, respectively).
 109  * <p>
 110  * Alternatively, a memory access operation is <em>partially aligned</em> if it occurs at a memory address {@code A}
 111  * which is only compatible with the alignment constraint {@code B}; in such cases, access for anything other than the
 112  * {@code get} and {@code set} access modes will result in an {@code IllegalStateException}. If access is partially aligned,
 113  * atomic access is only guaranteed with respect to the largest power of two that divides the GCD of {@code A} and {@code S}.
 114  * <p>
 115  * Finally, in all other cases, we say that a memory access operation is <em>misaligned</em>; in such cases an
 116  * {@code IllegalStateException} is thrown, irrespective of the access mode being used.
 117  */
 118 public final class MemoryHandles {
 119 
 120     private final static JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
 121 
 122     private MemoryHandles() {
 123         //sorry, just the one!
 124     }
 125 
 126     /**
 127      * Creates a memory access var handle with the given carrier type and byte order.
 128      *
 129      * The resulting memory access var handle features a single {@link MemoryAddress} access coordinate,
 130      * and its variable type is set by the given carrier type.
 131      *
 132      * The alignment constraint for the resulting memory access var handle is the same as the in memory size of the
 133      * carrier type, and the accessed offset is set at zero.
 134      *
 135      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 136      * which are common to all memory access var handles.


 157      * The accessed offset is zero.
 158      *
 159      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 160      * which are common to all memory access var handles.
 161      *
 162      * @param carrier the carrier type. Valid carriers are {@code byte}, {@code short}, {@code char}, {@code int},
 163      * {@code float}, {@code long}, and {@code double}.
 164      * @param alignmentBytes the alignment constraint (in bytes). Must be a power of two.
 165      * @param byteOrder the required byte order.
 166      * @return the new memory access var handle.
 167      * @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
 168      */
 169     public static VarHandle varHandle(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder) {
 170         checkCarrier(carrier);
 171 
 172         if (alignmentBytes <= 0
 173                 || (alignmentBytes & (alignmentBytes - 1)) != 0) { // is power of 2?
 174             throw new IllegalArgumentException("Bad alignment: " + alignmentBytes);
 175         }
 176 
 177         return JLI.memoryAddressViewVarHandle(carrier, alignmentBytes - 1, byteOrder, 0, new long[]{});
 178     }
 179 
 180     /**
 181      * Creates a memory access var handle with a fixed offset added to the accessed offset. That is,
 182      * if the target memory access var handle accesses a memory location at offset <em>O</em>, the new memory access var
 183      * handle will access a memory location at offset <em>O' + O</em>.
 184      *
 185      * The resulting memory access var handle will feature the same access coordinates as the ones in the target memory access var handle.
 186      *
 187      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 188      * which are common to all memory access var handles.
 189      *
 190      * @param target the target memory access handle to access after the offset adjustment.
 191      * @param bytesOffset the offset, in bytes. Must be positive or zero.
 192      * @return the new memory access var handle.
 193      * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
 194      * or when {@code bytesOffset < 0}, or otherwise incompatible with the alignment constraint.
 195      */
 196     public static VarHandle withOffset(VarHandle target, long bytesOffset) {
 197         if (bytesOffset < 0) {
 198             throw new IllegalArgumentException("Illegal offset: " + bytesOffset);
 199         }
 200 
 201         long alignMask = JLI.memoryAddressAlignmentMask(target);
 202 
 203         if ((bytesOffset & alignMask) != 0) {
 204             throw new IllegalArgumentException("Offset " + bytesOffset + " does not conform to alignment " + (alignMask + 1));
 205         }
 206 
 207         return JLI.memoryAddressViewVarHandle(
 208                 JLI.memoryAddressCarrier(target),
 209                 alignMask,
 210                 JLI.memoryAddressByteOrder(target),
 211                 JLI.memoryAddressOffset(target) + bytesOffset,
 212                 JLI.memoryAddressStrides(target));
 213     }
 214 
 215     /**
 216      * Creates a memory access var handle with a <em>variable</em> offset added to the accessed offset.
 217      * That is, if the target memory access var handle accesses a memory location at offset <em>O</em>,
 218      * the new memory access var handle will access a memory location at offset <em>(S * X) + O</em>, where <em>S</em>
 219      * is a constant <em>stride</em>, whereas <em>X</em> is a dynamic value that will be provided as an additional access
 220      * coordinate (of type {@code long}). The new access coordinate will be <em>prepended</em> to the ones available
 221      * in the target memory access var handles (if any).
 222      *
 223      * @apiNote the resulting var handle features certain <a href="#memaccess-mode">access mode restrictions</a>,
 224      * which are common to all memory access var handles.
 225      *
 226      * @param target the target memory access handle to access after the scale adjustment.
 227      * @param bytesStride the stride, in bytes, by which to multiply the coordinate value. Must be greater than zero.
 228      * @return the new memory access var handle.
 229      * @throws IllegalArgumentException when the target var handle is not a memory access var handle,
 230      * or if {@code bytesStride <= 0}, or otherwise incompatible with the alignment constraint.
 231      */
 232     public static VarHandle withStride(VarHandle target, long bytesStride) {
 233         if (bytesStride == 0) {
 234             throw new IllegalArgumentException("Stride must be positive: " + bytesStride);
 235         }
 236 
 237         long alignMask = JLI.memoryAddressAlignmentMask(target);
 238 
 239         if ((bytesStride & alignMask) != 0) {
 240             throw new IllegalArgumentException("Stride " + bytesStride + " does not conform to alignment " + (alignMask + 1));
 241         }
 242 
 243         long offset = JLI.memoryAddressOffset(target);

 244 
 245         long[] strides = JLI.memoryAddressStrides(target);
 246         long[] newStrides = new long[strides.length + 1];
 247         System.arraycopy(strides, 0, newStrides, 1, strides.length);
 248         newStrides[0] = bytesStride;
 249 
 250         return JLI.memoryAddressViewVarHandle(
 251                 JLI.memoryAddressCarrier(target),
 252                 alignMask,
 253                 JLI.memoryAddressByteOrder(target),
 254                 offset,
 255                 newStrides);
 256     }
 257 
 258     private static void checkCarrier(Class<?> carrier) {
 259         if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
 260             throw new IllegalArgumentException("Illegal carrier: " + carrier.getSimpleName());
 261         }
 262     }
 263 
 264     private static long carrierSize(Class<?> carrier) {
 265         long bitsAlignment = Math.max(8, Wrapper.forPrimitiveType(carrier).bitWidth());
 266         return Utils.bitsToBytesOrThrow(bitsAlignment, IllegalStateException::new);
 267     }
 268 }
< prev index next >