< prev index next >

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

Print this page

 29 import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
 30 import jdk.internal.foreign.Utils;
 31 
 32 import java.lang.constant.Constable;
 33 import java.lang.constant.DynamicConstantDesc;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.VarHandle;
 37 import java.nio.ByteOrder;
 38 import java.util.EnumSet;
 39 import java.util.Objects;
 40 import java.util.Optional;
 41 import java.util.OptionalLong;
 42 import java.util.Set;
 43 import java.util.function.Function;
 44 import java.util.function.UnaryOperator;
 45 import java.util.stream.Collectors;
 46 import java.util.stream.Stream;
 47 
 48 /**
 49  * A memory layout can be used to describe the contents of a memory segment in a <em>language neutral</em> fashion.
 50  * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
 51  * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
 52  * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#paddingLayout(long)}).
 53  * Some common value layout constants are defined in the {@link MemoryLayouts} class.
 54  * <p>
 55  * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
 56  * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
 57  * member layouts (see {@link GroupLayout}).
 58  * <p>
 59  * For instance, consider the following struct declaration in C:
 60  *
 61  * <blockquote><pre>{@code
 62  typedef struct {
 63      char kind;
 64      int value;
 65  } TaggedValues[5];
 66  * }</pre></blockquote>
 67  *
 68  * The above declaration can be modelled using a layout object, as follows:
 69  *
 70  * <blockquote><pre>{@code
 71 SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
 72     MemoryLayout.structLayout(
 73         MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
 74         MemoryLayout.paddingLayout(24),
 75         MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("value")
 76     )
 77 ).withName("TaggedValues");
 78  * }</pre></blockquote>
 79  * <p>
 80  * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
 81  * programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
 82  * use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
 83  * synchronization may fail. The {@code equals} method should be used for comparisons.
 84  * <p>
 85  * Non-platform classes should not implement {@linkplain MemoryLayout} directly.
 86  *
 87  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 88  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 89  *
 90  * <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
 91  *
 92  * All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
 93  * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
 94  * as follows:
 95  * <ul>

105  * <ul>
106  *     <li>for a padding layout <em>L</em>, the natural alignment is 1, regardless of its size; that is, in the absence
107  *     of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group
108  *     layout it is nested into</li>
109  *     <li>for a value layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
110  *     <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
111  *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
112  *     <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
113  * </ul>
114  * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
115  * hyper-aligned layouts.
116  * <p>
117  * All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
118  *
119  * <h2><a id = "layout-paths">Layout paths</a></h2>
120  *
121  * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
122  * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
123  * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
124  * <p>
125  * Layout paths are for example useful in order to obtain offsets of arbitrarily nested layouts inside another layout
126  * (see {@link MemoryLayout#bitOffset(PathElement...)}), to quickly obtain a memory access handle corresponding to the selected
127  * layout (see {@link MemoryLayout#varHandle(Class, PathElement...)}), to select an arbitrarily nested layout inside
128  * another layout (see {@link MemoryLayout#select(PathElement...)}, or to transform a nested layout element inside
129  * another layout (see {@link MemoryLayout#map(UnaryOperator, PathElement...)}).
130  * <p>
131  * Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
132  * For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
133  * in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
134  * <blockquote><pre>{@code
135 long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
136                                           PathElement.groupElement("value")); // yields 32
137  * }</pre></blockquote>
138  *
139  * Similarly, we can select the member layout named {@code value}, as follows:
140  * <blockquote><pre>{@code
141 MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
142                                          PathElement.groupElement("value"));
143  * }</pre></blockquote>
144  *
145  * And, we can also replace the layout named {@code value} with another layout, as follows:
146  * <blockquote><pre>{@code
147 MemoryLayout taggedValuesWithHole = taggedValues.map(l -> MemoryLayout.paddingLayout(32),
148                                             PathElement.sequenceElement(), PathElement.groupElement("value"));
149  * }</pre></blockquote>
150  *
151  * That is, the above declaration is identical to the following, more verbose one:
152  * <blockquote><pre>{@code
153 MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
154     MemoryLayout.structLayout(
155         MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
156         MemoryLayout.paddingLayout(32),
157         MemoryLayout.paddingLayout(32)
158 ));
159  * }</pre></blockquote>
160  *
161  * Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
162  * an unspecified sequence element (that is, where one of the path component was obtained with the
163  * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
164  * This is important when obtaining memory access var handle from layouts, as in the following code:
165  *
166  * <blockquote><pre>{@code
167 VarHandle valueHandle = taggedValues.varHandle(int.class,
168                                                PathElement.sequenceElement(),
169                                                PathElement.groupElement("value"));
170  * }</pre></blockquote>
171  *
172  * Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
173  * <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
174  * it follows that the memory access var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
175  * access coordinate.
176  *
177  * <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
178  * {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
179  * translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
180  * offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
181  * For instance:
182  *
183  * <blockquote><pre>{@code
184 MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
185                                                           PathElement.groupElement("kind"));
186 long offset1 = (long) offsetHandle.invokeExact(1L); // 8
187 long offset2 = (long) offsetHandle.invokeExact(2L); // 16
188  * }</pre></blockquote>
189  *
190  * <h2>Layout attributes</h2>
191  *
192  * Layouts can be optionally associated with one or more <em>attributes</em>. A layout attribute forms a <em>name/value</em>
193  * pair, where the name is a {@link String} and the value is a {@link Constable}. The most common form of layout attribute
194  * 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
195  * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
196  *
197  * @implSpec
198  * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
199  */
200 public sealed interface MemoryLayout extends Constable permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
201 
202     /**
203      * Returns an {@link Optional} containing the nominal descriptor for this
204      * layout, if one can be constructed, or an empty {@link Optional}
205      * if one cannot be constructed.
206      *
207      * @return An {@link Optional} containing the resulting nominal descriptor,
208      * or an empty {@link Optional} if one cannot be constructed.
209      */
210     @Override
211     Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable();
212 
213     /**
214      * Does this layout have a specified size? A layout does not have a specified size if it is (or contains) a sequence layout whose

219      *
220      * @return {@code true}, if this layout has a specified size.
221      */
222     boolean hasSize();
223 
224     /**
225      * Computes the layout size, in bits.
226      *
227      * @return the layout size, in bits.
228      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}).
229      */
230     long bitSize();
231 
232     /**
233      * Computes the layout size, in bytes.
234      *
235      * @return the layout size, in bytes.
236      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
237      * or if {@code bitSize()} is not a multiple of 8.
238      */
239     default long byteSize() {
240         return Utils.bitsToBytesOrThrow(bitSize(),
241                 () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
242     }
243 
244     /**
245      * Return the <em>name</em> (if any) associated with this layout.
246      * <p>
247      * This is equivalent to the following code:
248      * <blockquote><pre>{@code
249     attribute(LAYOUT_NAME).map(String.class::cast);
250      * }</pre></blockquote>
251      *
252      * @return the layout <em>name</em> (if any).
253      * @see MemoryLayout#withName(String)
254      */
255     Optional<String> name();
256 
257     /**
258      * Creates a new layout which features the desired layout <em>name</em>.
259      * <p>
260      * This is equivalent to the following code:
261      * <blockquote><pre>{@code
262     withAttribute(LAYOUT_NAME, name);
263      * }</pre></blockquote>
264      *
265      * @param name the layout name.
266      * @return a new layout which is the same as this layout, except for the <em>name</em> associated with it.
267      * @see MemoryLayout#name()
268      */
269     MemoryLayout withName(String name);
270 
271     /**
272      * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
273      * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
274      * bytes that must be aligned for any pointer that correctly points to this layout. Thus:
275      *
276      * <ul>
277      * <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
278      * <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
279      * <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
280      * </ul>
281      *
282      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
283      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bits) associated with this layout.

296      * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li>
297      * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
298      * </ul>
299      *
300      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
301      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
302      *
303      * @return the layout alignment constraint, in bytes.
304      * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
305      */
306     default long byteAlignment() {
307         return Utils.bitsToBytesOrThrow(bitAlignment(),
308                 () -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
309     }
310 
311     /**
312      * Creates a new layout which features the desired alignment constraint.
313      *
314      * @param bitAlignment the layout alignment constraint, expressed in bits.
315      * @return a new layout which is the same as this layout, except for the alignment constraint associated with it.
316      * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than than 8.
317      */
318     MemoryLayout withBitAlignment(long bitAlignment);
319 
320     /**
321      * Returns the attribute with the given name (if it exists).
322      *
323      * @param name the attribute name
324      * @return the attribute with the given name (if it exists).
325      */
326     Optional<Constable> attribute(String name);
327 
328     /**
329      * Returns a new memory layout which features the same attributes as this layout, plus the newly specified attribute.
330      * If this layout already contains an attribute with the same name, the existing attribute value is overwritten in the returned
331      * layout.
332      *
333      * @param name the attribute name.
334      * @param value the attribute value.
335      * @return a new memory layout which features the same attributes as this layout, plus the newly specified attribute.
336      */
337     MemoryLayout withAttribute(String name, Constable value);
338 
339     /**
340      * Returns a stream of the attribute names associated with this layout.
341      *
342      * @return a stream of the attribute names associated with this layout.
343      */
344     Stream<String> attributes();
345 
346     /**
347      * Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
348      * layout.
349      *
350      * @param elements the layout path elements.
351      * @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
352      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
353      * layout path contains one or more path elements that select multiple sequence element indices
354      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
355      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
356      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
357      * in {@code elements} is {@code null}.
358      */
359     default long bitOffset(PathElement... elements) {
360         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offset,
361                 EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE), elements);
362     }
363 
364     /**
365      * Creates a method handle that can be used to compute the offset, in bits, of the layout selected
366      * by a given layout path, where the path is considered rooted in this layout.
367      *
368      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
369      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
370      * where the order of the parameters corresponds to the order of the path elements.
371      * The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
372      * but where some sequence indices are specified only when invoking the method handle.
373      *
374      * <p>The final offset returned by the method handle is computed as follows:
375      *
376      * <blockquote><pre>{@code
377     offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
378      * }</pre></blockquote>
379      *
380      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
381      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
382      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
383      * the layout path.
384      *
385      * @param elements the layout path elements.
386      * @return a method handle that can be used to compute the bit offset of the layout element
387      * specified by the given layout path elements, when supplied with the missing sequence element indices.
388      * @throws IllegalArgumentException if the layout path contains one or more path elements that select
389      * multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).

400      *
401      * @param elements the layout path elements.
402      * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}.
403      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
404      * layout path contains one or more path elements that select multiple sequence element indices
405      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
406      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size,
407      * or if {@code bitOffset(elements)} is not a multiple of 8.
408      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
409      * in {@code elements} is {@code null}.
410      */
411     default long byteOffset(PathElement... elements) {
412         return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.bitsToBytesThrowOffset);
413     }
414 
415     /**
416      * Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
417      * by a given layout path, where the path is considered rooted in this layout.
418      *
419      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
420      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
421      * where the order of the parameters corresponds to the order of the path elements.
422      * The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
423      * but where some sequence indices are specified only when invoking the method handle.
424      *
425      * <p>The final offset returned by the method handle is computed as follows:
426      *
427      * <blockquote><pre>{@code
428     bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
429     offset = bitOffset / 8
430      * }</pre></blockquote>
431      *
432      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
433      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
434      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
435      * the layout path.
436      *
437      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
438      * offset in bits is not a multiple of 8.
439      *
440      * @param elements the layout path elements.

460     address = base + offset
461      * }</pre></blockquote>
462      *
463      * where {@code base} denotes the base address expressed by the {@link MemorySegment} access coordinate
464      * (see {@link MemorySegment#address()} and {@link MemoryAddress#toRawLongValue()}) and {@code offset}
465      * can be expressed in the following form:
466      *
467      * <blockquote><pre>{@code
468     offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
469      * }</pre></blockquote>
470      *
471      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
472      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
473      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
474      * the layout path.
475      *
476      * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
477      * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
478      * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
479      *
480      * @param carrier the var handle carrier type.
481      * @param elements the layout path elements.
482      * @return a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in {@code elements}.
483      * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints,
484      * or if one of the layouts traversed by the layout path has unspecified size.
485      * @throws IllegalArgumentException if the carrier does not represent a primitive type, if the carrier is {@code void},
486      * {@code boolean}, or if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}),
487      * or if the selected value layout has a size that that does not match that of the specified carrier type.
488      */
489     default VarHandle varHandle(Class<?> carrier, PathElement... elements) {
490         Objects.requireNonNull(carrier);
491         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), path -> path.dereferenceHandle(carrier),
492                 Set.of(), elements);
493     }
494 
495     /**
496      * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
497      * corresponding to the layout selected by a given layout path, where the path is considered rooted in this layout.
498      *
499      * <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
500      * parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
501      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()},
502      * where the order of the parameters corresponds to the order of the path elements.
503      * The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
504      * but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
505      *
506      * <p>The offset of the returned segment is computed as follows:
507      *
508      * <blockquote><pre>{@code
509     bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
510     offset = bitOffset / 8
511      * }</pre></blockquote>
512      *
513      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
514      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
515      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
516      * the layout path.
517      *
518      * <p>After the offset is computed, the returned segment is create as if by calling:
519      * <blockquote><pre>{@code
520     segment.asSlice(offset, layout.byteSize());
521      * }</pre></blockquote>
522      *
523      * where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
524      * layout path, as per {@link MemoryLayout#select(PathElement...)}.
525      *
526      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
527      * offset in bits is not a multiple of 8.
528      *
529      * @param elements the layout path elements.
530      * @return a method handle which can be used to create a slice of the selected layout element, given a segment.
531      * @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
532      */
533     default MethodHandle sliceHandle(PathElement... elements) {
534         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::sliceHandle,
535                 Set.of(), elements);
536     }
537 
538 

565     default MemoryLayout map(UnaryOperator<MemoryLayout> op, PathElement... elements) {
566         Objects.requireNonNull(op);
567         return computePathOp(LayoutPath.rootPath(this, l -> 0L), path -> path.map(op),
568                 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
569     }
570 
571     private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
572                                        Set<LayoutPath.PathElementImpl.PathKind> badKinds, PathElement... elements) {
573         Objects.requireNonNull(elements);
574         for (PathElement e : elements) {
575             LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
576             if (badKinds.contains(pathElem.kind())) {
577                 throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
578             }
579             path = pathElem.apply(path);
580         }
581         return finalizer.apply(path);
582     }
583 
584     /**
585      * Is this a padding layout (e.g. a layout created from {@link #paddingLayout(long)}) ?
586      * @return true, if this layout is a padding layout.
587      */
588     boolean isPadding();
589 
590     /**
591      * Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There
592      * are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
593      * path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence
594      * path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
595      * of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
596      * <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
597      * sequence path elements, it acquires additional <em>free dimensions</em>.
598      * <p>
599      * Non-platform classes should not implement {@linkplain PathElement} directly.
600      *
601      * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
602      * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
603      *
604      * @implSpec
605      * Implementations of this interface are immutable and thread-safe.
606      */
607     sealed interface PathElement permits LayoutPath.PathElementImpl {
608 
609         /**
610          * Returns a path element which selects a member layout with given name from a given group layout.
611          * The path element returned by this method does not alter the number of free dimensions of any path
612          * that is combined with such element.
613          *
614          * @implSpec in case multiple group elements with a matching name exist, the path element returned by this
615          * method will select the first one; that is, the group element with lowest offset from current path is selected.
616          *
617          * @param name the name of the group element to be selected.
618          * @return a path element which selects the group element with given name.
619          */
620         static PathElement groupElement(String name) {
621             Objects.requireNonNull(name);
622             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.GROUP_ELEMENT,
623                                                   path -> path.groupElement(name));
624         }
625 
626         /**
627          * Returns a path element which selects the element layout at the specified position in a given the sequence layout.
628          * The path element returned by this method does not alter the number of free dimensions of any path
629          * that is combined with such element.
630          *
631          * @param index the index of the sequence element to be selected.
632          * @return a path element which selects the sequence element layout with given index.
633          * @throws IllegalArgumentException if {@code index < 0}.
634          */
635         static PathElement sequenceElement(long index) {

711      * Returns a string representation of this layout.
712      *
713      * @return a string representation of this layout.
714      */
715     @Override
716     String toString();
717 
718     /**
719      * Create a new padding layout with given size.
720      *
721      * @param size the padding size in bits.
722      * @return the new selector layout.
723      * @throws IllegalArgumentException if {@code size <= 0}.
724      */
725     static MemoryLayout paddingLayout(long size) {
726         AbstractLayout.checkSize(size);
727         return new PaddingLayout(size);
728     }
729 
730     /**
731      * Create a value layout of given byte order and size.
732      *
733      * @param size the value layout size.











734      * @param order the value layout's byte order.
735      * @return a new value layout.
736      * @throws IllegalArgumentException if {@code size <= 0}.
737      */
738     static ValueLayout valueLayout(long size, ByteOrder order) {

739         Objects.requireNonNull(order);
740         AbstractLayout.checkSize(size);
741         return new ValueLayout(order, size);



















742     }
743 
744     /**
745      * Create a new sequence layout with given element layout and element count.
746      *
747      * @param elementCount the sequence element count.
748      * @param elementLayout the sequence element layout.
749      * @return the new sequence layout with given element layout and size.
750      * @throws IllegalArgumentException if {@code elementCount < 0}.
751      */
752     static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
753         AbstractLayout.checkSize(elementCount, true);
754         OptionalLong size = OptionalLong.of(elementCount);
755         return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
756     }
757 
758     /**
759      * Create a new sequence layout, with unbounded element count and given element layout.
760      *
761      * @param elementLayout the element layout of the sequence layout.

775         Objects.requireNonNull(elements);
776         return new GroupLayout(GroupLayout.Kind.STRUCT,
777                 Stream.of(elements)
778                         .map(Objects::requireNonNull)
779                         .collect(Collectors.toList()));
780     }
781 
782     /**
783      * Create a new <em>union</em> group layout with given member layouts.
784      *
785      * @param elements The member layouts of the <em>union</em> layout.
786      * @return a new <em>union</em> group layout with given member layouts.
787      */
788     static GroupLayout unionLayout(MemoryLayout... elements) {
789         Objects.requireNonNull(elements);
790         return new GroupLayout(GroupLayout.Kind.UNION,
791                 Stream.of(elements)
792                         .map(Objects::requireNonNull)
793                         .collect(Collectors.toList()));
794     }
795 
796     /**
797      * Attribute name used to specify the <em>name</em> property of a memory layout (see {@link #name()} and {@link #withName(String)}).
798      */
799     String LAYOUT_NAME = "layout/name";
800 }

 29 import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
 30 import jdk.internal.foreign.Utils;
 31 
 32 import java.lang.constant.Constable;
 33 import java.lang.constant.DynamicConstantDesc;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.VarHandle;
 37 import java.nio.ByteOrder;
 38 import java.util.EnumSet;
 39 import java.util.Objects;
 40 import java.util.Optional;
 41 import java.util.OptionalLong;
 42 import java.util.Set;
 43 import java.util.function.Function;
 44 import java.util.function.UnaryOperator;
 45 import java.util.stream.Collectors;
 46 import java.util.stream.Stream;
 47 
 48 /**
 49  * A memory layout can be used to describe the contents of a memory segment.
 50  * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
 51  * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
 52  * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#paddingLayout(long)}).
 53  * Some common value layout constants are defined in the {@link ValueLayout} class.
 54  * <p>
 55  * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
 56  * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
 57  * member layouts (see {@link GroupLayout}).
 58  * <p>
 59  * For instance, consider the following struct declaration in C:
 60  *
 61  * <blockquote><pre>{@code
 62  typedef struct {
 63      char kind;
 64      int value;
 65  } TaggedValues[5];
 66  * }</pre></blockquote>
 67  *
 68  * The above declaration can be modelled using a layout object, as follows:
 69  *
 70  * <blockquote><pre>{@code
 71 SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
 72     MemoryLayout.structLayout(
 73         ValueLayout.JAVA_BYTE.withName("kind"),
 74         MemoryLayout.paddingLayout(24),
 75         ValueLayout.JAVA_INT.withName("value")
 76     )
 77 ).withName("TaggedValues");
 78  * }</pre></blockquote>
 79  * <p>
 80  * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
 81  * programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
 82  * use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
 83  * synchronization may fail. The {@code equals} method should be used for comparisons.
 84  * <p>
 85  * Non-platform classes should not implement {@linkplain MemoryLayout} directly.
 86  *
 87  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 88  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 89  *
 90  * <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
 91  *
 92  * All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
 93  * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
 94  * as follows:
 95  * <ul>

105  * <ul>
106  *     <li>for a padding layout <em>L</em>, the natural alignment is 1, regardless of its size; that is, in the absence
107  *     of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group
108  *     layout it is nested into</li>
109  *     <li>for a value layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
110  *     <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
111  *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
112  *     <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
113  * </ul>
114  * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
115  * hyper-aligned layouts.
116  * <p>
117  * All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
118  *
119  * <h2><a id = "layout-paths">Layout paths</a></h2>
120  *
121  * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
122  * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
123  * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
124  * <p>
125  * Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
126  * arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
127  * corresponding to the selected layout, to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
128  * another layout, or to {@link #map(UnaryOperator, PathElement...) transform} a nested layout element inside
129  * another layout.
130  * <p>
131  * Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
132  * For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
133  * in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
134  * <blockquote><pre>{@code
135 long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
136                                           PathElement.groupElement("value")); // yields 32
137  * }</pre></blockquote>
138  *
139  * Similarly, we can select the member layout named {@code value}, as follows:
140  * <blockquote><pre>{@code
141 MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
142                                          PathElement.groupElement("value"));
143  * }</pre></blockquote>
144  *
145  * And, we can also replace the layout named {@code value} with another layout, as follows:
146  * <blockquote><pre>{@code
147 MemoryLayout taggedValuesWithHole = taggedValues.map(l -> MemoryLayout.paddingLayout(32),
148                                             PathElement.sequenceElement(), PathElement.groupElement("value"));
149  * }</pre></blockquote>
150  *
151  * That is, the above declaration is identical to the following, more verbose one:
152  * <blockquote><pre>{@code
153 MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
154     MemoryLayout.structLayout(
155         ValueLayout.JAVA_BYTE.withName("kind"),
156         MemoryLayout.paddingLayout(32),
157         MemoryLayout.paddingLayout(32)
158 ));
159  * }</pre></blockquote>
160  *
161  * Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
162  * an unspecified sequence element (that is, where one of the path component was obtained with the
163  * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
164  * This is important when obtaining memory access var handle from layouts, as in the following code:
165  *
166  * <blockquote><pre>{@code
167 VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),

168                                                PathElement.groupElement("value"));
169  * }</pre></blockquote>
170  *
171  * Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
172  * <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
173  * it follows that the memory access var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
174  * access coordinate.
175  *
176  * <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
177  * {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
178  * translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
179  * offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
180  * For instance:
181  *
182  * <blockquote><pre>{@code
183 MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
184                                                           PathElement.groupElement("kind"));
185 long offset1 = (long) offsetHandle.invokeExact(1L); // 8
186 long offset2 = (long) offsetHandle.invokeExact(2L); // 16
187  * }</pre></blockquote>
188  *
189  * <h2>Layout attributes</h2>
190  *
191  * Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when


192  * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
193  *
194  * @implSpec
195  * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
196  */
197 public sealed interface MemoryLayout extends Constable permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
198 
199     /**
200      * Returns an {@link Optional} containing the nominal descriptor for this
201      * layout, if one can be constructed, or an empty {@link Optional}
202      * if one cannot be constructed.
203      *
204      * @return An {@link Optional} containing the resulting nominal descriptor,
205      * or an empty {@link Optional} if one cannot be constructed.
206      */
207     @Override
208     Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable();
209 
210     /**
211      * Does this layout have a specified size? A layout does not have a specified size if it is (or contains) a sequence layout whose

216      *
217      * @return {@code true}, if this layout has a specified size.
218      */
219     boolean hasSize();
220 
221     /**
222      * Computes the layout size, in bits.
223      *
224      * @return the layout size, in bits.
225      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}).
226      */
227     long bitSize();
228 
229     /**
230      * Computes the layout size, in bytes.
231      *
232      * @return the layout size, in bytes.
233      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
234      * or if {@code bitSize()} is not a multiple of 8.
235      */
236     long byteSize();



237 
238     /**
239      * Return the <em>name</em> (if any) associated with this layout.





240      *
241      * @return the layout <em>name</em> (if any).
242      * @see MemoryLayout#withName(String)
243      */
244     Optional<String> name();
245 
246     /**
247      * Creates a new layout which features the desired layout <em>name</em>.





248      *
249      * @param name the layout name.
250      * @return a new layout which is the same as this layout, except for the <em>name</em> associated with it.
251      * @see MemoryLayout#name()
252      */
253     MemoryLayout withName(String name);
254 
255     /**
256      * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
257      * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
258      * bytes that must be aligned for any pointer that correctly points to this layout. Thus:
259      *
260      * <ul>
261      * <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
262      * <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
263      * <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
264      * </ul>
265      *
266      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
267      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bits) associated with this layout.

280      * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li>
281      * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
282      * </ul>
283      *
284      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
285      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
286      *
287      * @return the layout alignment constraint, in bytes.
288      * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
289      */
290     default long byteAlignment() {
291         return Utils.bitsToBytesOrThrow(bitAlignment(),
292                 () -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
293     }
294 
295     /**
296      * Creates a new layout which features the desired alignment constraint.
297      *
298      * @param bitAlignment the layout alignment constraint, expressed in bits.
299      * @return a new layout which is the same as this layout, except for the alignment constraint associated with it.
300      * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
301      */
302     MemoryLayout withBitAlignment(long bitAlignment);
303 


























304     /**
305      * Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
306      * layout.
307      *
308      * @param elements the layout path elements.
309      * @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
310      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
311      * layout path contains one or more path elements that select multiple sequence element indices
312      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
313      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
314      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
315      * in {@code elements} is {@code null}.
316      */
317     default long bitOffset(PathElement... elements) {
318         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offset,
319                 EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE), elements);
320     }
321 
322     /**
323      * Creates a method handle that can be used to compute the offset, in bits, of the layout selected
324      * by a given layout path, where the path is considered rooted in this layout.
325      *
326      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
327      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
328      * where the order of the parameters corresponds to the order of the path elements.
329      * The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
330      * but where some sequence indices are specified only when invoking the method handle.
331      *
332      * <p>The final offset returned by the method handle is computed as follows:
333      *
334      * <blockquote><pre>{@code
335     offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
336      * }</pre></blockquote>
337      *
338      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
339      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
340      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
341      * the layout path.
342      *
343      * @param elements the layout path elements.
344      * @return a method handle that can be used to compute the bit offset of the layout element
345      * specified by the given layout path elements, when supplied with the missing sequence element indices.
346      * @throws IllegalArgumentException if the layout path contains one or more path elements that select
347      * multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).

358      *
359      * @param elements the layout path elements.
360      * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}.
361      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
362      * layout path contains one or more path elements that select multiple sequence element indices
363      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
364      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size,
365      * or if {@code bitOffset(elements)} is not a multiple of 8.
366      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
367      * in {@code elements} is {@code null}.
368      */
369     default long byteOffset(PathElement... elements) {
370         return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.bitsToBytesThrowOffset);
371     }
372 
373     /**
374      * Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
375      * by a given layout path, where the path is considered rooted in this layout.
376      *
377      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
378      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
379      * where the order of the parameters corresponds to the order of the path elements.
380      * The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
381      * but where some sequence indices are specified only when invoking the method handle.
382      *
383      * <p>The final offset returned by the method handle is computed as follows:
384      *
385      * <blockquote><pre>{@code
386     bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
387     offset = bitOffset / 8
388      * }</pre></blockquote>
389      *
390      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
391      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
392      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
393      * the layout path.
394      *
395      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
396      * offset in bits is not a multiple of 8.
397      *
398      * @param elements the layout path elements.

418     address = base + offset
419      * }</pre></blockquote>
420      *
421      * where {@code base} denotes the base address expressed by the {@link MemorySegment} access coordinate
422      * (see {@link MemorySegment#address()} and {@link MemoryAddress#toRawLongValue()}) and {@code offset}
423      * can be expressed in the following form:
424      *
425      * <blockquote><pre>{@code
426     offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
427      * }</pre></blockquote>
428      *
429      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
430      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
431      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
432      * the layout path.
433      *
434      * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
435      * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
436      * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
437      *

438      * @param elements the layout path elements.
439      * @return a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in {@code elements}.
440      * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints,
441      * or if one of the layouts traversed by the layout path has unspecified size.
442      * @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).


443      */
444     default VarHandle varHandle(PathElement... elements) {
445         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::dereferenceHandle,

446                 Set.of(), elements);
447     }
448 
449     /**
450      * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
451      * corresponding to the layout selected by a given layout path, where the path is considered rooted in this layout.
452      *
453      * <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
454      * parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
455      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
456      * where the order of the parameters corresponds to the order of the path elements.
457      * The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
458      * but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
459      *
460      * <p>The offset of the returned segment is computed as follows:
461      *
462      * <blockquote><pre>{@code
463     bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
464     offset = bitOffset / 8
465      * }</pre></blockquote>
466      *
467      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
468      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
469      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
470      * the layout path.
471      *
472      * <p>After the offset is computed, the returned segment is created as if by calling:
473      * <blockquote><pre>{@code
474     segment.asSlice(offset, layout.byteSize());
475      * }</pre></blockquote>
476      *
477      * where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
478      * layout path, as per {@link MemoryLayout#select(PathElement...)}.
479      *
480      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
481      * offset in bits is not a multiple of 8.
482      *
483      * @param elements the layout path elements.
484      * @return a method handle which can be used to create a slice of the selected layout element, given a segment.
485      * @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
486      */
487     default MethodHandle sliceHandle(PathElement... elements) {
488         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::sliceHandle,
489                 Set.of(), elements);
490     }
491 
492 

519     default MemoryLayout map(UnaryOperator<MemoryLayout> op, PathElement... elements) {
520         Objects.requireNonNull(op);
521         return computePathOp(LayoutPath.rootPath(this, l -> 0L), path -> path.map(op),
522                 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
523     }
524 
525     private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
526                                        Set<LayoutPath.PathElementImpl.PathKind> badKinds, PathElement... elements) {
527         Objects.requireNonNull(elements);
528         for (PathElement e : elements) {
529             LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
530             if (badKinds.contains(pathElem.kind())) {
531                 throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
532             }
533             path = pathElem.apply(path);
534         }
535         return finalizer.apply(path);
536     }
537 
538     /**
539      * Is this a {@linkplain #paddingLayout(long) padding layout} ?
540      * @return true, if this layout is a padding layout.
541      */
542     boolean isPadding();
543 
544     /**
545      * Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There
546      * are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
547      * path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence
548      * path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
549      * of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
550      * <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
551      * sequence path elements, it acquires additional <em>free dimensions</em>.
552      * <p>
553      * Non-platform classes should not implement {@linkplain PathElement} directly.
554      *
555      * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
556      * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
557      *
558      * @implSpec
559      * Implementations of this interface are immutable and thread-safe.
560      */
561     sealed interface PathElement permits LayoutPath.PathElementImpl {
562 
563         /**
564          * Returns a path element which selects a member layout with given name from a given group layout.
565          * The path element returned by this method does not alter the number of free dimensions of any path
566          * that is combined with such element.
567          *
568          * @implSpec in case multiple group elements with a matching name exist, the path element returned by this
569          * method will select the first one; that is, the group element with the lowest offset from current path is selected.
570          *
571          * @param name the name of the group element to be selected.
572          * @return a path element which selects the group element with given name.
573          */
574         static PathElement groupElement(String name) {
575             Objects.requireNonNull(name);
576             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.GROUP_ELEMENT,
577                                                   path -> path.groupElement(name));
578         }
579 
580         /**
581          * Returns a path element which selects the element layout at the specified position in a given the sequence layout.
582          * The path element returned by this method does not alter the number of free dimensions of any path
583          * that is combined with such element.
584          *
585          * @param index the index of the sequence element to be selected.
586          * @return a path element which selects the sequence element layout with given index.
587          * @throws IllegalArgumentException if {@code index < 0}.
588          */
589         static PathElement sequenceElement(long index) {

665      * Returns a string representation of this layout.
666      *
667      * @return a string representation of this layout.
668      */
669     @Override
670     String toString();
671 
672     /**
673      * Create a new padding layout with given size.
674      *
675      * @param size the padding size in bits.
676      * @return the new selector layout.
677      * @throws IllegalArgumentException if {@code size <= 0}.
678      */
679     static MemoryLayout paddingLayout(long size) {
680         AbstractLayout.checkSize(size);
681         return new PaddingLayout(size);
682     }
683 
684     /**
685      * Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined
686      * by the carrier provided:
687      * <ul>
688      *     <li>{@link ValueLayout.OfBoolean}, for {@code boolean.class}</li>
689      *     <li>{@link ValueLayout.OfByte}, for {@code byte.class}</li>
690      *     <li>{@link ValueLayout.OfShort}, for {@code short.class}</li>
691      *     <li>{@link ValueLayout.OfChar}, for {@code char.class}</li>
692      *     <li>{@link ValueLayout.OfInt}, for {@code int.class}</li>
693      *     <li>{@link ValueLayout.OfFloat}, for {@code float.class}</li>
694      *     <li>{@link ValueLayout.OfLong}, for {@code long.class}</li>
695      *     <li>{@link ValueLayout.OfDouble}, for {@code double.class}</li>
696      *     <li>{@link ValueLayout.OfAddress}, for {@code MemoryAddress.class}</li>
697      * </ul>
698      * @param carrier the value layout carrier.
699      * @param order the value layout's byte order.
700      * @return a new value layout.
701      * @throws IllegalArgumentException if the carrier type is not supported.
702      */
703     static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
704         Objects.requireNonNull(carrier);
705         Objects.requireNonNull(order);
706         if (carrier == boolean.class) {
707             return new ValueLayout.OfBoolean(order);
708         } else if (carrier == char.class) {
709             return new ValueLayout.OfChar(order);
710         } else if (carrier == byte.class) {
711             return new ValueLayout.OfByte(order);
712         } else if (carrier == short.class) {
713             return new ValueLayout.OfShort(order);
714         } else if (carrier == int.class) {
715             return new ValueLayout.OfInt(order);
716         } else if (carrier == float.class) {
717             return new ValueLayout.OfFloat(order);
718         } else if (carrier == long.class) {
719             return new ValueLayout.OfLong(order);
720         } else if (carrier == double.class) {
721             return new ValueLayout.OfDouble(order);
722         } else if (carrier == MemoryAddress.class) {
723             return new ValueLayout.OfAddress(order);
724         } else {
725             throw new IllegalArgumentException("Unsupported carrier: " + carrier.getName());
726         }
727     }
728 
729     /**
730      * Create a new sequence layout with given element layout and element count.
731      *
732      * @param elementCount the sequence element count.
733      * @param elementLayout the sequence element layout.
734      * @return the new sequence layout with given element layout and size.
735      * @throws IllegalArgumentException if {@code elementCount < 0}.
736      */
737     static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
738         AbstractLayout.checkSize(elementCount, true);
739         OptionalLong size = OptionalLong.of(elementCount);
740         return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
741     }
742 
743     /**
744      * Create a new sequence layout, with unbounded element count and given element layout.
745      *
746      * @param elementLayout the element layout of the sequence layout.

760         Objects.requireNonNull(elements);
761         return new GroupLayout(GroupLayout.Kind.STRUCT,
762                 Stream.of(elements)
763                         .map(Objects::requireNonNull)
764                         .collect(Collectors.toList()));
765     }
766 
767     /**
768      * Create a new <em>union</em> group layout with given member layouts.
769      *
770      * @param elements The member layouts of the <em>union</em> layout.
771      * @return a new <em>union</em> group layout with given member layouts.
772      */
773     static GroupLayout unionLayout(MemoryLayout... elements) {
774         Objects.requireNonNull(elements);
775         return new GroupLayout(GroupLayout.Kind.UNION,
776                 Stream.of(elements)
777                         .map(Objects::requireNonNull)
778                         .collect(Collectors.toList()));
779     }





780 }
< prev index next >