1 /* 2 * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.foreign; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.VarHandle; 31 import java.util.EnumSet; 32 import java.util.Objects; 33 import java.util.Optional; 34 import java.util.Set; 35 import java.util.function.Function; 36 import java.util.stream.Stream; 37 38 import jdk.internal.foreign.LayoutPath; 39 import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind; 40 import jdk.internal.foreign.Utils; 41 import jdk.internal.foreign.layout.MemoryLayoutUtil; 42 import jdk.internal.foreign.layout.PaddingLayoutImpl; 43 import jdk.internal.foreign.layout.SequenceLayoutImpl; 44 import jdk.internal.foreign.layout.StructLayoutImpl; 45 import jdk.internal.foreign.layout.UnionLayoutImpl; 46 import jdk.internal.javac.PreviewFeature; 47 48 /** 49 * A memory layout describes the contents of a memory segment. 50 * <p> 51 * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind (see 52 * and {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to represent a portion of a memory 53 * segment whose contents should be ignored, and which are primarily present for alignment reasons. 54 * Some common value layout constants, such as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED} 55 * are defined in the {@link ValueLayout} class. A special kind of value layout, namely an {@linkplain AddressLayout address layout}, 56 * is used to model values that denote the address of a region of memory. 57 * <p> 58 * More complex layouts can be derived from simpler ones: a {@linkplain SequenceLayout sequence layout} denotes a 59 * homogeneous repetition of zero or more occurrences of an element layout; a {@linkplain GroupLayout group layout} 60 * denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two 61 * flavors: {@linkplain StructLayout struct layouts}, where member layouts are laid out one after the other, and 62 * {@linkplain UnionLayout union layouts} where member layouts are laid out at the same starting offset. 63 * <p> 64 * Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when 65 * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. 66 * <p> 67 * Consider the following struct declaration in C: 68 * 69 * {@snippet lang=c : 70 * typedef struct { 71 * char kind; 72 * int value; 73 * } TaggedValues[5]; 74 * } 75 * 76 * The above declaration can be modelled using a layout object, as follows: 77 * 78 * {@snippet lang=java : 79 * SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5, 80 * MemoryLayout.structLayout( 81 * ValueLayout.JAVA_BYTE.withName("kind"), 82 * MemoryLayout.paddingLayout(3), 83 * ValueLayout.JAVA_INT.withName("value") 84 * ) 85 * ).withName("TaggedValues"); 86 * } 87 * 88 * <h2 id="layout-align">Characteristics of memory layouts</h2> 89 * 90 * All layouts have a <em>size</em> (expressed in bytes), which is defined as follows: 91 * <ul> 92 * <li>The size of a value layout is determined by the {@linkplain ValueLayout#carrier()} 93 * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} has carrier {@code int}, and 94 * size of 4 bytes;</li> 95 * <li>The size of an address layout is platform-dependent. That is, the constant {@link ValueLayout#ADDRESS} 96 * has size of 8 bytes on a 64-bit platform;</li> 97 * <li>The size of a padding layout is always provided explicitly, on {@linkplain MemoryLayout#paddingLayout(long) construction};</li> 98 * <li>The size of a sequence layout whose element layout is <em>E</em> and element count is <em>L</em>, 99 * is the size of <em>E</em>, multiplied by <em>L</em>;</li> 100 * <li>The size of a struct layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are 101 * <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>S1 + S2 + ... + Sn</em>;</li> 102 * <li>The size of a union layout <em>U</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are 103 * <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>max(S1, S2, ... Sn).</em></li> 104 * </ul> 105 * <p> 106 * Furthermore, all layouts have a <em>natural alignment</em> (expressed in bytes) which is defined as follows: 107 * <ul> 108 * <li>The natural alignment of a padding layout is 1;</li> 109 * <li>The natural alignment of a value layout whose size is <em>N</em> is <em>N</em>;</li> 110 * <li>The natural alignment of a sequence layout whose element layout is <em>E</em> is the alignment of <em>E</em>;</li> 111 * <li>The natural alignment of a group layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose 112 * alignments are <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, is <em>max(A1, A2 ... An)</em>.</li> 113 * </ul> 114 * A layout's alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe 115 * layouts with weaker or stronger alignment constraints. 116 * 117 * <h2 id="layout-paths">Layout paths</h2> 118 * 119 * A <em>layout path</em> is used to unambiguously select a layout that is nested in some other layout. 120 * Layout paths are typically expressed as a sequence of one or more {@linkplain PathElement path elements}. 121 * (A more formal definition of layout paths is provided <a href="#well-formedness">below</a>). 122 * <p> 123 * Layout paths can be used to: 124 * <ul> 125 * <li>obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of arbitrarily nested layouts;</li> 126 * <li>obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used to access the value corresponding 127 * to the selected layout;</li> 128 * <li>{@linkplain #select(PathElement...) select} an arbitrarily nested layout.</li> 129 * </ul> 130 * <p> 131 * For instance, given the {@code taggedValues} sequence layout constructed above, we can obtain the offset, 132 * in bytes, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows: 133 * {@snippet lang=java : 134 * long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0), 135 * PathElement.groupElement("value")); // yields 4 136 * } 137 * 138 * Similarly, we can select the member layout named {@code value}, as follows: 139 * {@snippet lang=java : 140 * MemoryLayout value = taggedValues.select(PathElement.sequenceElement(), 141 * PathElement.groupElement("value")); 142 * } 143 * 144 * <h3 id="open-path-elements">Open path elements</h3> 145 * 146 * Some layout path elements, said <em>open path elements</em>, can select multiple layouts at once. For instance, 147 * the open path elements {@link PathElement#sequenceElement()}, {@link PathElement#sequenceElement(long, long)} select 148 * an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more 149 * open path element features additional coordinates of type {@code long}, which can be used by clients to <em>bind</em> 150 * the open elements in the path: 151 * 152 * {@snippet lang=java : 153 * VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(), 154 * PathElement.groupElement("value")); 155 * MemorySegment valuesSegment = ... 156 * int val = (int) valueHandle.get(valuesSegment, 2); // reads the "value" field of the third struct in the array 157 * } 158 * 159 * <p> 160 * Open path elements also affects the creation of 161 * {@linkplain #byteOffsetHandle(PathElement...) offset-computing method handles}. Each open path element becomes 162 * an additional {@code long} parameter in the obtained method handle. This parameter can be used to specify the index 163 * of the sequence element whose offset is to be computed: 164 * 165 * {@snippet lang=java : 166 * MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(), 167 * PathElement.groupElement("kind")); 168 * long offset1 = (long) offsetHandle.invokeExact(1L); // 8 169 * long offset2 = (long) offsetHandle.invokeExact(2L); // 16 170 * } 171 * 172 * <h3 id="deref-path-elements">Dereference path elements</h3> 173 * 174 * A special kind of path element, called <em>dereference path element</em>, allows var handles obtained from 175 * memory layouts to follow pointers. Consider the following layout: 176 * 177 * {@snippet lang=java : 178 * StructLayout RECTANGLE = MemoryLayout.structLayout( 179 * ValueLayout.ADDRESS.withTargetLayout( 180 * MemoryLayout.sequenceLayout(4, 181 * MemoryLayout.structLayout( 182 * ValueLayout.JAVA_INT.withName("x"), 183 * ValueLayout.JAVA_INT.withName("y") 184 * ).withName("point") 185 * ) 186 * ).withName("points") 187 * ); 188 * } 189 * 190 * This layout is a struct layout which describe a rectangle. It contains a single field, namely {@code points}, 191 * an address layout whose {@linkplain AddressLayout#targetLayout() target layout} is a sequence layout of four 192 * struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or 193 * {@link ValueLayout#JAVA_INT} coordinates, with names {@code x} and {@code y}, respectively. 194 * <p> 195 * With dereference path elements, we can obtain a var handle which accesses the {@code y} coordinate of one of the 196 * point in the rectangle, as follows: 197 * 198 * {@snippet lang=java : 199 * VarHandle rectPointYs = RECTANGLE.varHandle( 200 * PathElement.groupElement("points"), 201 * PathElement.dereferenceElement(), 202 * PathElement.sequenceElement(), 203 * PathElement.groupElement("y") 204 * ); 205 * 206 * MemorySegment rect = ... 207 * int rect_y_4 = (int) rectPointYs.get(rect, 2); // rect.points[2]->y 208 * } 209 * 210 * <h3 id="well-formedness">Layout path well-formedness</h3> 211 * 212 * A layout path is applied to a layout {@code C_0}, also called the <em>initial layout</em>. Each path element in a 213 * layout path can be thought of as a function which updates the current layout {@code C_i-1} to some other layout 214 * {@code C_i}. That is, for each path element {@code E1, E2, ... En}, in a layout path {@code P}, we compute 215 * {@code C_i = f_i(C_i-1)}, where {@code f_i} is the selection function associated with the path element under consideration, 216 * denoted as {@code E_i}. The final layout {@code C_i} is also called the <em>selected layout</em>. 217 * <p> 218 * A layout path {@code P} is considered well-formed for an initial layout {@code C_0} if all its path elements 219 * {@code E1, E2, ... En} are well-formed for their corresponding input layouts {@code C_0, C_1, ... C_n-1}. 220 * A path element {@code E} is considered well-formed for a layout {@code L} if any of the following is true: 221 * <ul> 222 * <li>{@code L} is a sequence layout and {@code E} is a sequence path element (one of {@link PathElement#sequenceElement(long)}, 223 * {@link PathElement#sequenceElement(long, long)} or {@link PathElement#sequenceElement()}). Moreover, if {@code E} 224 * contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;</li> 225 * <li>{@code L} is a group layout and {@code E} is a group path element (one of {@link PathElement#groupElement(String)} 226 * or {@link PathElement#groupElement(long)}). Moreover, the group path element must refer to a valid member layout in 227 * {@code L}, either by name, or index;</li> 228 * <li>{@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() dereference path element}. 229 * Moreover, {@code L} must define some {@linkplain AddressLayout#targetLayout() target layout}.</li> 230 * </ul> 231 * Any attempt to provide a layout path {@code P} that is not well-formed for an initial layout {@code C_0} will result 232 * in an {@link IllegalArgumentException}. 233 * 234 * @implSpec 235 * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. 236 * 237 * @sealedGraph 238 * @since 19 239 */ 240 @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN) 241 public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout { 242 243 /** 244 * {@return the layout size, in bytes} 245 */ 246 long byteSize(); 247 248 /** 249 * {@return the name (if any) associated with this layout} 250 * @see MemoryLayout#withName(String) 251 */ 252 Optional<String> name(); 253 254 /** 255 * {@return a memory layout with the same characteristics as this layout, but with the given name} 256 * 257 * @param name the layout name. 258 * @see MemoryLayout#name() 259 */ 260 MemoryLayout withName(String name); 261 262 /** 263 * {@return a memory layout with the same characteristics as this layout, but with no name} 264 * 265 * @apiNote This can be useful to compare two layouts that have different names, but are otherwise equal. 266 * @see MemoryLayout#name() 267 */ 268 MemoryLayout withoutName(); 269 270 /** 271 * {@return the alignment constraint associated with this layout, expressed in bytes} Layout alignment defines a power 272 * of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned 273 * for any pointer that correctly points to this layout. Thus: 274 * 275 * <ul> 276 * <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li> 277 * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li> 278 * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li> 279 * </ul> 280 * 281 * If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}), 282 * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout. 283 */ 284 long byteAlignment(); 285 286 /** 287 * {@return a memory layout with the same characteristics as this layout, but with the given 288 * alignment constraint (in bytes)} 289 * 290 * @param byteAlignment the layout alignment constraint, expressed in bytes. 291 * @throws IllegalArgumentException if {@code byteAlignment} is not a power of two. 292 */ 293 MemoryLayout withByteAlignment(long byteAlignment); 294 295 /** 296 * Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the 297 * path is this layout. 298 * 299 * @param elements the layout path elements. 300 * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}. 301 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 302 * @throws IllegalArgumentException if the layout path contains one or more <a href=#open-path-elements>open path elements</a>. 303 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 304 */ 305 default long byteOffset(PathElement... elements) { 306 return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset, 307 EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); 308 } 309 310 /** 311 * Creates a method handle that computes the offset, in bytes, of the layout selected 312 * by the given layout path, where the initial layout in the path is this layout. 313 * <p> 314 * The returned method handle has the following characteristics: 315 * <ul> 316 * <li>its return type is {@code long};</li> 317 * <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a> 318 * in the provided layout path. The order of these parameters corresponds to the order in which the open path 319 * elements occur in the provided layout path. 320 * </ul> 321 * <p> 322 * The final offset returned by the method handle is computed as follows: 323 * 324 * <blockquote><pre>{@code 325 * offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n) 326 * }</pre></blockquote> 327 * 328 * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long} 329 * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants 330 * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from 331 * the layout path. 332 * 333 * @apiNote The returned method handle can be used to compute a layout offset, similarly to {@link #byteOffset(PathElement...)}, 334 * but more flexibly, as some indices can be specified when invoking the method handle. 335 * 336 * @param elements the layout path elements. 337 * @return a method handle that computes the offset, in bytes, of the layout selected by the given layout path. 338 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 339 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 340 */ 341 default MethodHandle byteOffsetHandle(PathElement... elements) { 342 return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle, 343 EnumSet.of(PathKind.DEREF_ELEMENT), elements); 344 } 345 346 /** 347 * Creates a var handle that accesses a memory segment at the offset selected by the given layout path, 348 * where the initial layout in the path is this layout. 349 * <p> 350 * The returned var handle has the following characteristics: 351 * <ul> 352 * <li>its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the 353 * selected value layout;</li> 354 * <li>it has as zero or more access coordinates of type {@code long}, one for each 355 * <a href=#open-path-elements>open path element</a> in the provided layout path. The order of these access 356 * coordinates corresponds to the order in which the open path elements occur in the provided 357 * layout path. 358 * </ul> 359 * <p> 360 * The final address accessed by the returned var handle can be computed as follows: 361 * 362 * <blockquote><pre>{@code 363 * address = base(segment) + offset 364 * }</pre></blockquote> 365 * 366 * Where {@code base(segment)} denotes a function that returns the physical base address of the accessed 367 * memory segment. For native segments, this function just returns the native segment's 368 * {@linkplain MemorySegment#address() address}. For heap segments, this function is more complex, as the address 369 * of heap segments is virtualized. The {@code offset} value can be expressed in the following form: 370 * 371 * <blockquote><pre>{@code 372 * offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n) 373 * }</pre></blockquote> 374 * 375 * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long} 376 * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants 377 * and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from 378 * the layout path. 379 * <p> 380 * Additionally, the provided dynamic values must conform to bounds which are derived from the layout path, that is, 381 * {@code 0 <= x_i < b_i}, where {@code 1 <= i <= n}, or {@link IndexOutOfBoundsException} is thrown. 382 * <p> 383 * The base address must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the {@linkplain 384 * #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more strict 385 * (but not less) than the alignment constraint of the selected value layout. 386 * <p> 387 * Multiple paths can be chained, with <a href=#deref-path-elements>dereference path elements</a>. 388 * A dereference path element constructs a fresh native memory segment whose base address is the address value 389 * read obtained by accessing a memory segment at the offset determined by the layout path elements immediately preceding 390 * the dereference path element. In other words, if a layout path contains one or more dereference path elements, 391 * the final address accessed by the returned var handle can be computed as follows: 392 * 393 * <blockquote><pre>{@code 394 * address_1 = base(segment) + offset_1 395 * address_2 = base(segment_1) + offset_2 396 * ... 397 * address_k = base(segment_k-1) + offset_k 398 * }</pre></blockquote> 399 * 400 * where {@code k} is the number of dereference path elements in a layout path, {@code segment} is the input segment, 401 * {@code segment_1}, ... {@code segment_k-1} are the segments obtained by dereferencing the address associated with 402 * a given dereference path element (e.g. {@code segment_1} is a native segment whose base address is {@code address_1}), 403 * and {@code offset_1}, {@code offset_2}, ... {@code offset_k} are the offsets computed by evaluating 404 * the path elements after a given dereference operation (these offsets are obtained using the computation described 405 * above). In these more complex access operations, all memory accesses immediately preceding a dereference operation 406 * (e.g. those at addresses {@code address_1}, {@code address_2}, ..., {@code address_k-1} are performed using the 407 * {@link VarHandle.AccessMode#GET} access mode. 408 * 409 * @apiNote The resulting var handle features certain <em>access mode restrictions</em>, which are common to all 410 * {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view handles}. 411 * 412 * @param elements the layout path elements. 413 * @return a var handle that accesses a memory segment at the offset selected by the given layout path. 414 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 415 * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}. 416 * @see MethodHandles#memorySegmentViewVarHandle(ValueLayout) 417 */ 418 default VarHandle varHandle(PathElement... elements) { 419 return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle, 420 Set.of(), elements); 421 } 422 423 /** 424 * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice} 425 * corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout. 426 * <p> 427 * The returned method handle has the following characteristics: 428 * <ul> 429 * <li>its return type is {@code MemorySegment};</li> 430 * <li>it has a leading parameter of type {@code MemorySegment}, corresponding to the memory segment 431 * to be sliced;</li> 432 * <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a> 433 * in the provided layout path. The order of these parameters corresponds to the order in which the open path 434 * elements occur in the provided layout path. 435 * </ul> 436 * <p> 437 * The offset of the returned segment is computed as follows: 438 * {@snippet lang=java : 439 * long offset = byteOffset(elements); 440 * long size = select(elements).byteSize(); 441 * MemorySegment slice = segment.asSlice(offset, size); 442 * } 443 * <p> 444 * The segment to be sliced must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the 445 * {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more 446 * strict (but not less) than the alignment constraint of the selected value layout. 447 * 448 * @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)}, 449 * but more flexibly, as some indices can be specified when invoking the method handle. 450 * 451 * @param elements the layout path elements. 452 * @return a method handle which is used to slice a memory segment at the offset selected by the given layout path. 453 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 454 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 455 */ 456 default MethodHandle sliceHandle(PathElement... elements) { 457 return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle, 458 Set.of(PathKind.DEREF_ELEMENT), elements); 459 } 460 461 /** 462 * Returns the layout selected from the provided path, where the initial layout in the path is this layout. 463 * 464 * @param elements the layout path elements. 465 * @return the layout selected by the layout path in {@code elements}. 466 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 467 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 468 * @throws IllegalArgumentException if the layout path contains one or more path elements that select one or more 469 * sequence element indices, such as {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}). 470 */ 471 default MemoryLayout select(PathElement... elements) { 472 return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout, 473 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); 474 } 475 476 private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer, 477 Set<PathKind> badKinds, PathElement... elements) { 478 Objects.requireNonNull(elements); 479 for (PathElement e : elements) { 480 LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e); 481 if (badKinds.contains(pathElem.kind())) { 482 throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description())); 483 } 484 path = pathElem.apply(path); 485 } 486 return finalizer.apply(path); 487 } 488 489 /** 490 * An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There 491 * are three kinds of path elements: 492 * <ul> 493 * <li><em>group path elements</em>, used to select a member layout within a {@link GroupLayout}, either by name or by index;</li> 494 * <li><em>sequence path elements</em>, used to select one or more sequence element layouts within a {@link SequenceLayout}; and</li> 495 * <li><em>dereference path elements</em>, used to <a href="MemoryLayout.html#deref-path-elements">dereference</a> 496 * an address layout as its target layout.</li> 497 * </ul> 498 * Sequence path elements selecting more than one sequence element layout are called 499 * <a href="MemoryLayout.html#open-path-elements">open path elements</a>. 500 * 501 * @implSpec 502 * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. 503 * 504 * @since 19 505 */ 506 @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN) 507 sealed interface PathElement permits LayoutPath.PathElementImpl { 508 509 /** 510 * Returns a path element which selects a member layout with the given name in a group layout. 511 * 512 * @implSpec in case multiple group elements with a matching name exist, the path element returned by this 513 * method will select the first one; that is, the group element with the lowest offset from current path is selected. 514 * In such cases, using {@link #groupElement(long)} might be preferable. 515 * 516 * @param name the name of the member layout to be selected. 517 * @return a path element which selects the group member layout with the given name. 518 */ 519 static PathElement groupElement(String name) { 520 Objects.requireNonNull(name); 521 return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT, 522 path -> path.groupElement(name)); 523 } 524 525 /** 526 * Returns a path element which selects a member layout with the given index in a group layout. 527 * 528 * @param index the index of the member layout element to be selected. 529 * @return a path element which selects the group member layout with the given index. 530 * @throws IllegalArgumentException if {@code index < 0}. 531 */ 532 static PathElement groupElement(long index) { 533 if (index < 0) { 534 throw new IllegalArgumentException("Index < 0"); 535 } 536 return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT, 537 path -> path.groupElement(index)); 538 } 539 540 /** 541 * Returns a path element which selects the element layout at the specified position in a sequence layout. 542 * 543 * @param index the index of the sequence element to be selected. 544 * @return a path element which selects the sequence element layout with the given index. 545 * @throws IllegalArgumentException if {@code index < 0}. 546 */ 547 static PathElement sequenceElement(long index) { 548 if (index < 0) { 549 throw new IllegalArgumentException("Index must be positive: " + index); 550 } 551 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT_INDEX, 552 path -> path.sequenceElement(index)); 553 } 554 555 /** 556 * Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects the element 557 * layout in a <em>range</em> of positions in a sequence layout. The range is expressed as a pair of starting 558 * index (inclusive) {@code S} and step factor (which can also be negative) {@code F}. 559 * <p> 560 * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the 561 * sequence element count, it follows that {@code 0 <= I < B}, where {@code B} is computed as follows: 562 * <ul> 563 * <li>if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}</li> 564 * <li>if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}</li> 565 * </ul> 566 * 567 * @param start the index of the first sequence element to be selected. 568 * @param step the step factor at which subsequence sequence elements are to be selected. 569 * @return a path element which selects the sequence element layout with the given index. 570 * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}. 571 */ 572 static PathElement sequenceElement(long start, long step) { 573 if (start < 0) { 574 throw new IllegalArgumentException("Start index must be positive: " + start); 575 } 576 if (step == 0) { 577 throw new IllegalArgumentException("Step must be != 0: " + step); 578 } 579 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_RANGE, 580 path -> path.sequenceElement(start, step)); 581 } 582 583 /** 584 * Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects an unspecified 585 * element layout in a sequence layout. 586 * <p> 587 * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the 588 * sequence element count, it follows that {@code 0 <= I < C}. 589 * 590 * @return a path element which selects an unspecified sequence element layout. 591 */ 592 static PathElement sequenceElement() { 593 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT, 594 LayoutPath::sequenceElement); 595 } 596 597 /** 598 * Returns a path element which dereferences an address layout as its 599 * {@linkplain AddressLayout#targetLayout() target layout} (where set). 600 * 601 * @return a path element which dereferences an address layout. 602 */ 603 static PathElement dereferenceElement() { 604 return new LayoutPath.PathElementImpl(PathKind.DEREF_ELEMENT, 605 LayoutPath::derefElement); 606 } 607 } 608 609 /** 610 * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified 611 * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of 612 * the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional 613 * conditions must be satisfied: 614 * <ul> 615 * <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order}, 616 * and {@linkplain ValueLayout#carrier() carrier}. Additionally, two address layouts are considered equal if they 617 * also have the same {@linkplain AddressLayout#targetLayout() target layout};</li> 618 * <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and 619 * if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal;</li> 620 * <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout}, 621 * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal.</li> 622 * </ul> 623 * 624 * @param other the object to be compared for equality with this layout. 625 * @return {@code true} if the specified object is equal to this layout. 626 */ 627 boolean equals(Object other); 628 629 /** 630 * {@return the hash code value for this layout} 631 */ 632 int hashCode(); 633 634 /** 635 * {@return the string representation of this layout} 636 */ 637 @Override 638 String toString(); 639 640 /** 641 * Creates a padding layout with the given byte size. The alignment constraint of the returned layout 642 * is 1. As such, regardless of its size, in the absence of an {@linkplain #withByteAlignment(long) explicit} 643 * alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout 644 * it is nested into. 645 * 646 * @param byteSize the padding size (expressed in bytes). 647 * @return the new selector layout. 648 * @throws IllegalArgumentException if {@code byteSize <= 0}. 649 */ 650 static PaddingLayout paddingLayout(long byteSize) { 651 return PaddingLayoutImpl.of(MemoryLayoutUtil.requireByteSizeValid(byteSize, false)); 652 } 653 654 /** 655 * Creates a sequence layout with the given element layout and element count. 656 * 657 * @param elementCount the sequence element count. 658 * @param elementLayout the sequence element layout. 659 * @return the new sequence layout with the given element layout and size. 660 * @throws IllegalArgumentException if {@code elementCount} is negative. 661 * @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount} overflows. 662 * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}. 663 */ 664 static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { 665 MemoryLayoutUtil.requireNonNegative(elementCount); 666 Objects.requireNonNull(elementLayout); 667 Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); 668 return Utils.wrapOverflow(() -> 669 SequenceLayoutImpl.of(elementCount, elementLayout)); 670 } 671 672 /** 673 * Creates a sequence layout with the given element layout and the maximum element 674 * count such that it does not overflow a {@code long}. 675 * 676 * This is equivalent to the following code: 677 * {@snippet lang = java: 678 * sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout); 679 * } 680 * 681 * @param elementLayout the sequence element layout. 682 * @return a new sequence layout with the given element layout and maximum element count. 683 * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}. 684 */ 685 static SequenceLayout sequenceLayout(MemoryLayout elementLayout) { 686 Objects.requireNonNull(elementLayout); 687 return sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout); 688 } 689 690 /** 691 * Creates a struct layout with the given member layouts. 692 * 693 * @param elements The member layouts of the struct layout. 694 * @return a struct layout with the given member layouts. 695 * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member layouts 696 * overflows. 697 * @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset (relative to the start 698 * of the struct layout) which is not compatible with its alignment constraint. 699 * 700 * @apiNote This factory does not automatically align element layouts, by inserting additional {@linkplain PaddingLayout 701 * padding layout} elements. As such, the following struct layout creation will fail with an exception: 702 * 703 * {@snippet lang = java: 704 * structLayout(JAVA_SHORT, JAVA_INT); 705 * } 706 * 707 * To avoid the exception, clients can either insert additional padding layout elements: 708 * 709 * {@snippet lang = java: 710 * structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT); 711 * } 712 * 713 * Or, alternatively, they can use a member layout which features a smaller alignment constraint. This will result 714 * in a <em>packed</em> struct layout: 715 * 716 * {@snippet lang = java: 717 * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2)); 718 * } 719 */ 720 static StructLayout structLayout(MemoryLayout... elements) { 721 Objects.requireNonNull(elements); 722 return Utils.wrapOverflow(() -> 723 StructLayoutImpl.of(Stream.of(elements) 724 .map(Objects::requireNonNull) 725 .toList())); 726 } 727 728 /** 729 * Creates a union layout with the given member layouts. 730 * 731 * @param elements The member layouts of the union layout. 732 * @return a union layout with the given member layouts. 733 */ 734 static UnionLayout unionLayout(MemoryLayout... elements) { 735 Objects.requireNonNull(elements); 736 return UnionLayoutImpl.of(Stream.of(elements) 737 .map(Objects::requireNonNull) 738 .toList()); 739 } 740 }