< prev index next >

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

Print this page
@@ -44,15 +44,15 @@
  import java.util.function.UnaryOperator;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
  
  /**
-  * A memory layout can be used to describe the contents of a memory segment in a <em>language neutral</em> fashion.
+  * A memory layout can be used to describe the contents of a memory segment.
   * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
   * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
   * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#paddingLayout(long)}).
-  * Some common value layout constants are defined in the {@link MemoryLayouts} class.
+  * Some common value layout constants are defined in the {@link ValueLayout} class.
   * <p>
   * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
   * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
   * member layouts (see {@link GroupLayout}).
   * <p>

@@ -68,13 +68,13 @@
   * The above declaration can be modelled using a layout object, as follows:
   *
   * <blockquote><pre>{@code
  SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
      MemoryLayout.structLayout(
-         MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
+         ValueLayout.JAVA_BYTE.withName("kind"),
          MemoryLayout.paddingLayout(24),
-         MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("value")
+         ValueLayout.JAVA_INT.withName("value")
      )
  ).withName("TaggedValues");
   * }</pre></blockquote>
   * <p>
   * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;

@@ -120,15 +120,15 @@
   *
   * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
   * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
   * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
   * <p>
-  * Layout paths are for example useful in order to obtain offsets of arbitrarily nested layouts inside another layout
-  * (see {@link MemoryLayout#bitOffset(PathElement...)}), to quickly obtain a memory access handle corresponding to the selected
-  * layout (see {@link MemoryLayout#varHandle(Class, PathElement...)}), to select an arbitrarily nested layout inside
-  * another layout (see {@link MemoryLayout#select(PathElement...)}, or to transform a nested layout element inside
-  * another layout (see {@link MemoryLayout#map(UnaryOperator, PathElement...)}).
+  * Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
+  * arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
+  * corresponding to the selected layout, to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
+  * another layout, or to {@link #map(UnaryOperator, PathElement...) transform} a nested layout element inside
+  * another layout.
   * <p>
   * Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
   * For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
   * in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
   * <blockquote><pre>{@code

@@ -150,11 +150,11 @@
   *
   * That is, the above declaration is identical to the following, more verbose one:
   * <blockquote><pre>{@code
  MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
      MemoryLayout.structLayout(
-         MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
+         ValueLayout.JAVA_BYTE.withName("kind"),
          MemoryLayout.paddingLayout(32),
          MemoryLayout.paddingLayout(32)
  ));
   * }</pre></blockquote>
   *

@@ -162,12 +162,11 @@
   * an unspecified sequence element (that is, where one of the path component was obtained with the
   * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
   * This is important when obtaining memory access var handle from layouts, as in the following code:
   *
   * <blockquote><pre>{@code
- VarHandle valueHandle = taggedValues.varHandle(int.class,
-                                                PathElement.sequenceElement(),
+ VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
                                                 PathElement.groupElement("value"));
   * }</pre></blockquote>
   *
   * Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
   * <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),

@@ -187,13 +186,11 @@
  long offset2 = (long) offsetHandle.invokeExact(2L); // 16
   * }</pre></blockquote>
   *
   * <h2>Layout attributes</h2>
   *
-  * Layouts can be optionally associated with one or more <em>attributes</em>. A layout attribute forms a <em>name/value</em>
-  * pair, where the name is a {@link String} and the value is a {@link Constable}. The most common form of layout attribute
-  * is the <em>layout name</em> (see {@link #LAYOUT_NAME}), a custom name that can be associated with memory layouts and that can be referred to when
+  * Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
   * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
   *
   * @implSpec
   * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
   */

@@ -234,35 +231,22 @@
       *
       * @return the layout size, in bytes.
       * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
       * or if {@code bitSize()} is not a multiple of 8.
       */
-     default long byteSize() {
-         return Utils.bitsToBytesOrThrow(bitSize(),
-                 () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
-     }
+     long byteSize();
  
      /**
       * Return the <em>name</em> (if any) associated with this layout.
-      * <p>
-      * This is equivalent to the following code:
-      * <blockquote><pre>{@code
-     attribute(LAYOUT_NAME).map(String.class::cast);
-      * }</pre></blockquote>
       *
       * @return the layout <em>name</em> (if any).
       * @see MemoryLayout#withName(String)
       */
      Optional<String> name();
  
      /**
       * Creates a new layout which features the desired layout <em>name</em>.
-      * <p>
-      * This is equivalent to the following code:
-      * <blockquote><pre>{@code
-     withAttribute(LAYOUT_NAME, name);
-      * }</pre></blockquote>
       *
       * @param name the layout name.
       * @return a new layout which is the same as this layout, except for the <em>name</em> associated with it.
       * @see MemoryLayout#name()
       */

@@ -311,40 +295,14 @@
      /**
       * Creates a new layout which features the desired alignment constraint.
       *
       * @param bitAlignment the layout alignment constraint, expressed in bits.
       * @return a new layout which is the same as this layout, except for the alignment constraint associated with it.
-      * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than than 8.
+      * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
       */
      MemoryLayout withBitAlignment(long bitAlignment);
  
-     /**
-      * Returns the attribute with the given name (if it exists).
-      *
-      * @param name the attribute name
-      * @return the attribute with the given name (if it exists).
-      */
-     Optional<Constable> attribute(String name);
- 
-     /**
-      * Returns a new memory layout which features the same attributes as this layout, plus the newly specified attribute.
-      * If this layout already contains an attribute with the same name, the existing attribute value is overwritten in the returned
-      * layout.
-      *
-      * @param name the attribute name.
-      * @param value the attribute value.
-      * @return a new memory layout which features the same attributes as this layout, plus the newly specified attribute.
-      */
-     MemoryLayout withAttribute(String name, Constable value);
- 
-     /**
-      * Returns a stream of the attribute names associated with this layout.
-      *
-      * @return a stream of the attribute names associated with this layout.
-      */
-     Stream<String> attributes();
- 
      /**
       * Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
       * layout.
       *
       * @param elements the layout path elements.

@@ -364,11 +322,11 @@
      /**
       * Creates a method handle that can be used to compute the offset, in bits, of the layout selected
       * by a given layout path, where the path is considered rooted in this layout.
       *
       * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
-      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
+      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
       * where the order of the parameters corresponds to the order of the path elements.
       * The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
       * but where some sequence indices are specified only when invoking the method handle.
       *
       * <p>The final offset returned by the method handle is computed as follows:

@@ -415,11 +373,11 @@
      /**
       * Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
       * by a given layout path, where the path is considered rooted in this layout.
       *
       * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
-      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
+      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
       * where the order of the parameters corresponds to the order of the path elements.
       * The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
       * but where some sequence indices are specified only when invoking the method handle.
       *
       * <p>The final offset returned by the method handle is computed as follows:

@@ -475,32 +433,28 @@
       *
       * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
       * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
       * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
       *
-      * @param carrier the var handle carrier type.
       * @param elements the layout path elements.
       * @return a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in {@code elements}.
       * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints,
       * or if one of the layouts traversed by the layout path has unspecified size.
-      * @throws IllegalArgumentException if the carrier does not represent a primitive type, if the carrier is {@code void},
-      * {@code boolean}, or if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}),
-      * or if the selected value layout has a size that that does not match that of the specified carrier type.
+      * @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
       */
-     default VarHandle varHandle(Class<?> carrier, PathElement... elements) {
-         Objects.requireNonNull(carrier);
-         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), path -> path.dereferenceHandle(carrier),
+     default VarHandle varHandle(PathElement... elements) {
+         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::dereferenceHandle,
                  Set.of(), elements);
      }
  
      /**
       * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
       * corresponding to the layout selected by a given layout path, where the path is considered rooted in this layout.
       *
       * <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
       * parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
-      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
+      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
       * where the order of the parameters corresponds to the order of the path elements.
       * The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
       * but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
       *
       * <p>The offset of the returned segment is computed as follows:

@@ -513,11 +467,11 @@
       * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
       * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
       * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
       * the layout path.
       *
-      * <p>After the offset is computed, the returned segment is create as if by calling:
+      * <p>After the offset is computed, the returned segment is created as if by calling:
       * <blockquote><pre>{@code
      segment.asSlice(offset, layout.byteSize());
       * }</pre></blockquote>
       *
       * where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given

@@ -580,11 +534,11 @@
          }
          return finalizer.apply(path);
      }
  
      /**
-      * Is this a padding layout (e.g. a layout created from {@link #paddingLayout(long)}) ?
+      * Is this a {@linkplain #paddingLayout(long) padding layout} ?
       * @return true, if this layout is a padding layout.
       */
      boolean isPadding();
  
      /**

@@ -610,11 +564,11 @@
           * Returns a path element which selects a member layout with given name from a given group layout.
           * The path element returned by this method does not alter the number of free dimensions of any path
           * that is combined with such element.
           *
           * @implSpec in case multiple group elements with a matching name exist, the path element returned by this
-          * method will select the first one; that is, the group element with lowest offset from current path is selected.
+          * method will select the first one; that is, the group element with the lowest offset from current path is selected.
           *
           * @param name the name of the group element to be selected.
           * @return a path element which selects the group element with given name.
           */
          static PathElement groupElement(String name) {

@@ -726,21 +680,52 @@
          AbstractLayout.checkSize(size);
          return new PaddingLayout(size);
      }
  
      /**
-      * Create a value layout of given byte order and size.
-      *
-      * @param size the value layout size.
+      * Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined
+      * by the carrier provided:
+      * <ul>
+      *     <li>{@link ValueLayout.OfBoolean}, for {@code boolean.class}</li>
+      *     <li>{@link ValueLayout.OfByte}, for {@code byte.class}</li>
+      *     <li>{@link ValueLayout.OfShort}, for {@code short.class}</li>
+      *     <li>{@link ValueLayout.OfChar}, for {@code char.class}</li>
+      *     <li>{@link ValueLayout.OfInt}, for {@code int.class}</li>
+      *     <li>{@link ValueLayout.OfFloat}, for {@code float.class}</li>
+      *     <li>{@link ValueLayout.OfLong}, for {@code long.class}</li>
+      *     <li>{@link ValueLayout.OfDouble}, for {@code double.class}</li>
+      *     <li>{@link ValueLayout.OfAddress}, for {@code MemoryAddress.class}</li>
+      * </ul>
+      * @param carrier the value layout carrier.
       * @param order the value layout's byte order.
       * @return a new value layout.
-      * @throws IllegalArgumentException if {@code size <= 0}.
+      * @throws IllegalArgumentException if the carrier type is not supported.
       */
-     static ValueLayout valueLayout(long size, ByteOrder order) {
+     static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
+         Objects.requireNonNull(carrier);
          Objects.requireNonNull(order);
-         AbstractLayout.checkSize(size);
-         return new ValueLayout(order, size);
+         if (carrier == boolean.class) {
+             return new ValueLayout.OfBoolean(order);
+         } else if (carrier == char.class) {
+             return new ValueLayout.OfChar(order);
+         } else if (carrier == byte.class) {
+             return new ValueLayout.OfByte(order);
+         } else if (carrier == short.class) {
+             return new ValueLayout.OfShort(order);
+         } else if (carrier == int.class) {
+             return new ValueLayout.OfInt(order);
+         } else if (carrier == float.class) {
+             return new ValueLayout.OfFloat(order);
+         } else if (carrier == long.class) {
+             return new ValueLayout.OfLong(order);
+         } else if (carrier == double.class) {
+             return new ValueLayout.OfDouble(order);
+         } else if (carrier == MemoryAddress.class) {
+             return new ValueLayout.OfAddress(order);
+         } else {
+             throw new IllegalArgumentException("Unsupported carrier: " + carrier.getName());
+         }
      }
  
      /**
       * Create a new sequence layout with given element layout and element count.
       *

@@ -790,11 +775,6 @@
          return new GroupLayout(GroupLayout.Kind.UNION,
                  Stream.of(elements)
                          .map(Objects::requireNonNull)
                          .collect(Collectors.toList()));
      }
- 
-     /**
-      * Attribute name used to specify the <em>name</em> property of a memory layout (see {@link #name()} and {@link #withName(String)}).
-      */
-     String LAYOUT_NAME = "layout/name";
  }
< prev index next >