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.MethodType; 31 import java.lang.invoke.VarHandle; 32 import java.util.EnumSet; 33 import java.util.Objects; 34 import java.util.Optional; 35 import java.util.Set; 36 import java.util.function.Function; 37 import java.util.stream.Stream; 38 39 import jdk.internal.foreign.LayoutPath; 40 import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind; 41 import jdk.internal.foreign.Utils; 42 import jdk.internal.foreign.layout.MemoryLayoutUtil; 43 import jdk.internal.foreign.layout.PaddingLayoutImpl; 44 import jdk.internal.foreign.layout.SequenceLayoutImpl; 45 import jdk.internal.foreign.layout.StructLayoutImpl; 46 import jdk.internal.foreign.layout.UnionLayoutImpl; 47 import jdk.internal.vm.annotation.ForceInline; 48 49 /** 50 * A memory layout describes the contents of a memory segment. 51 * <p> 52 * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind 53 * and {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to represent a portion of a memory 54 * segment whose contents should be ignored, and which are primarily present for alignment reasons. 55 * Some common value layout constants, such as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED} 56 * are defined in the {@link ValueLayout} class. A special kind of value layout, namely an {@linkplain AddressLayout address layout}, 57 * is used to model values that denote the address of a region of memory. 58 * <p> 59 * More complex layouts can be derived from simpler ones: a {@linkplain SequenceLayout sequence layout} denotes a 60 * homogeneous repetition of zero or more occurrences of an element layout; a {@linkplain GroupLayout group layout} 61 * denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two 62 * flavors: {@linkplain StructLayout struct layouts}, where member layouts are laid out one after the other, and 63 * {@linkplain UnionLayout union layouts} where member layouts are laid out at the same starting offset. 64 * <p> 65 * Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when 66 * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. 67 * <p> 68 * Consider the following struct declaration in C: 69 * 70 * {@snippet lang=c : 71 * typedef struct { 72 * char kind; 73 * int value; 74 * } TaggedValues[5]; 75 * } 76 * 77 * The above declaration can be modelled using a layout object, as follows: 78 * 79 * {@snippet lang=java : 80 * SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5, 81 * MemoryLayout.structLayout( 82 * ValueLayout.JAVA_BYTE.withName("kind"), 83 * MemoryLayout.paddingLayout(3), 84 * ValueLayout.JAVA_INT.withName("value") 85 * ) 86 * ).withName("TaggedValues"); 87 * } 88 * 89 * <h2 id="layout-align">Characteristics of memory layouts</h2> 90 * 91 * All layouts have a <em>size</em> (expressed in bytes), which is defined as follows: 92 * <ul> 93 * <li>The size of a value layout is determined by the {@linkplain ValueLayout#carrier()} 94 * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} has carrier {@code int}, and 95 * size of 4 bytes;</li> 96 * <li>The size of an address layout is platform-dependent. That is, the constant {@link ValueLayout#ADDRESS} 97 * has size of 8 bytes on a 64-bit platform;</li> 98 * <li>The size of a padding layout is always provided explicitly, on {@linkplain MemoryLayout#paddingLayout(long) construction};</li> 99 * <li>The size of a sequence layout whose element layout is <em>E</em> and element count is <em>L</em>, 100 * is the size of <em>E</em>, multiplied by <em>L</em>;</li> 101 * <li>The size of a struct layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are 102 * <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>S1 + S2 + ... + Sn</em>;</li> 103 * <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 104 * <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>max(S1, S2, ... Sn).</em></li> 105 * </ul> 106 * <p> 107 * Furthermore, all layouts have a <em>natural alignment</em> (expressed in bytes) which is defined as follows: 108 * <ul> 109 * <li>The natural alignment of a padding layout is 1;</li> 110 * <li>The natural alignment of a value layout whose size is <em>N</em> is <em>N</em>;</li> 111 * <li>The natural alignment of a sequence layout whose element layout is <em>E</em> is the alignment of <em>E</em>;</li> 112 * <li>The natural alignment of a group layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose 113 * alignments are <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, is <em>max(A1, A2 ... An)</em>.</li> 114 * </ul> 115 * A layout's alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe 116 * layouts with weaker or stronger alignment constraints. 117 * 118 * <h2 id="layout-paths">Layout paths</h2> 119 * 120 * A <em>layout path</em> is used to unambiguously select a layout that is nested in some other layout. 121 * Layout paths are typically expressed as a sequence of one or more {@linkplain PathElement path elements}. 122 * (A more formal definition of layout paths is provided <a href="#well-formedness">below</a>). 123 * <p> 124 * Layout paths can be used to: 125 * <ul> 126 * <li>obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of arbitrarily nested layouts;</li> 127 * <li>obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used to access the value corresponding 128 * to the selected layout;</li> 129 * <li>{@linkplain #select(PathElement...) select} an arbitrarily nested layout.</li> 130 * </ul> 131 * <p> 132 * For instance, given the {@code taggedValues} sequence layout constructed above, we can obtain the offset, 133 * in bytes, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows: 134 * {@snippet lang=java : 135 * long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0), 136 * PathElement.groupElement("value")); // yields 4 137 * } 138 * 139 * Similarly, we can select the member layout named {@code value}, as follows: 140 * {@snippet lang=java : 141 * MemoryLayout value = taggedValues.select(PathElement.sequenceElement(), 142 * PathElement.groupElement("value")); 143 * } 144 * 145 * <h3 id="open-path-elements">Open path elements</h3> 146 * 147 * Some layout path elements, said <em>open path elements</em>, can select multiple layouts at once. For instance, 148 * the open path elements {@link PathElement#sequenceElement()}, {@link PathElement#sequenceElement(long, long)} select 149 * an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more 150 * open path element features additional coordinates of type {@code long}, which can be used by clients to <em>bind</em> 151 * the open elements in the path: 152 * 153 * {@snippet lang=java : 154 * VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(), 155 * PathElement.groupElement("value")); 156 * MemorySegment valuesSegment = ... 157 * int val = (int) valueHandle.get(valuesSegment, 2); // reads the "value" field of the third struct in the array 158 * } 159 * 160 * <p> 161 * Open path elements also affects the creation of 162 * {@linkplain #byteOffsetHandle(PathElement...) offset-computing method handles}. Each open path element becomes 163 * an additional {@code long} parameter in the obtained method handle. This parameter can be used to specify the index 164 * of the sequence element whose offset is to be computed: 165 * 166 * {@snippet lang=java : 167 * MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(), 168 * PathElement.groupElement("kind")); 169 * long offset1 = (long) offsetHandle.invokeExact(1L); // 8 170 * long offset2 = (long) offsetHandle.invokeExact(2L); // 16 171 * } 172 * 173 * <h3 id="deref-path-elements">Dereference path elements</h3> 174 * 175 * A special kind of path element, called <em>dereference path element</em>, allows var handles obtained from 176 * memory layouts to follow pointers. Consider the following layout: 177 * 178 * {@snippet lang=java : 179 * StructLayout RECTANGLE = MemoryLayout.structLayout( 180 * ValueLayout.ADDRESS.withTargetLayout( 181 * MemoryLayout.sequenceLayout(4, 182 * MemoryLayout.structLayout( 183 * ValueLayout.JAVA_INT.withName("x"), 184 * ValueLayout.JAVA_INT.withName("y") 185 * ).withName("point") 186 * ) 187 * ).withName("points") 188 * ); 189 * } 190 * 191 * This layout is a struct layout which describe a rectangle. It contains a single field, namely {@code points}, 192 * an address layout whose {@linkplain AddressLayout#targetLayout() target layout} is a sequence layout of four 193 * struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or 194 * {@link ValueLayout#JAVA_INT} coordinates, with names {@code x} and {@code y}, respectively. 195 * <p> 196 * With dereference path elements, we can obtain a var handle which accesses the {@code y} coordinate of one of the 197 * point in the rectangle, as follows: 198 * 199 * {@snippet lang=java : 200 * VarHandle rectPointYs = RECTANGLE.varHandle( 201 * PathElement.groupElement("points"), 202 * PathElement.dereferenceElement(), 203 * PathElement.sequenceElement(), 204 * PathElement.groupElement("y") 205 * ); 206 * 207 * MemorySegment rect = ... 208 * int rect_y_4 = (int) rectPointYs.get(rect, 2); // rect.points[2]->y 209 * } 210 * 211 * <h3 id="well-formedness">Layout path well-formedness</h3> 212 * 213 * A layout path is applied to a layout {@code C_0}, also called the <em>initial layout</em>. Each path element in a 214 * layout path can be thought of as a function which updates the current layout {@code C_i-1} to some other layout 215 * {@code C_i}. That is, for each path element {@code E1, E2, ... En}, in a layout path {@code P}, we compute 216 * {@code C_i = f_i(C_i-1)}, where {@code f_i} is the selection function associated with the path element under consideration, 217 * denoted as {@code E_i}. The final layout {@code C_i} is also called the <em>selected layout</em>. 218 * <p> 219 * A layout path {@code P} is considered well-formed for an initial layout {@code C_0} if all its path elements 220 * {@code E1, E2, ... En} are well-formed for their corresponding input layouts {@code C_0, C_1, ... C_n-1}. 221 * A path element {@code E} is considered well-formed for a layout {@code L} if any of the following is true: 222 * <ul> 223 * <li>{@code L} is a sequence layout and {@code E} is a sequence path element (one of {@link PathElement#sequenceElement(long)}, 224 * {@link PathElement#sequenceElement(long, long)} or {@link PathElement#sequenceElement()}). Moreover, if {@code E} 225 * contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;</li> 226 * <li>{@code L} is a group layout and {@code E} is a group path element (one of {@link PathElement#groupElement(String)} 227 * or {@link PathElement#groupElement(long)}). Moreover, the group path element must refer to a valid member layout in 228 * {@code L}, either by name, or index;</li> 229 * <li>{@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() dereference path element}. 230 * Moreover, {@code L} must define some {@linkplain AddressLayout#targetLayout() target layout}.</li> 231 * </ul> 232 * Any attempt to provide a layout path {@code P} that is not well-formed for an initial layout {@code C_0} will result 233 * in an {@link IllegalArgumentException}. 234 * 235 * <h2 id="access-mode-restrictions">Access mode restrictions</h2> 236 * 237 * A var handle returned by {@link #varHandle(PathElement...)} or {@link ValueLayout#varHandle()} features certain 238 * access characteristics, which are derived from the selected layout {@code L}: 239 * <ul> 240 * <li>A carrier type {@code T}, derived from {@code L.carrier()}</li> 241 * <li>An alignment constraint {@code A}, derived from {@code L.byteAlignment()}</li> 242 * <li>An access size {@code S}, derived from {@code L.byteSize()}</li> 243 * </ul> 244 * Depending on the above characteristics, the returned var handle might feature certain <i>access mode restrictions</i>. 245 * We say that a var handle is <em>aligned</em> if its alignment constraint {@code A} is compatible with the access size 246 * {@code S}, that is if {@code A >= S}. An aligned var handle is guaranteed to support the following access modes: 247 * <ul> 248 * <li>read write access modes for all {@code T}. On 32-bit platforms, access modes 249 * {@code get} and {@code set} for {@code long}, {@code double} and {@code MemorySegment} 250 * are supported but might lead to word tearing, as described in Section {@jls 17.7}. 251 * of <cite>The Java Language Specification</cite>. 252 * <li>atomic update access modes for {@code int}, {@code long}, 253 * {@code float}, {@code double} and {@link MemorySegment}. 254 * (Future major platform releases of the JDK may support additional 255 * types for certain currently unsupported access modes.) 256 * <li>numeric atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}. 257 * (Future major platform releases of the JDK may support additional 258 * numeric types for certain currently unsupported access modes.) 259 * <li>bitwise atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}. 260 * (Future major platform releases of the JDK may support additional 261 * numeric types for certain currently unsupported access modes.) 262 * </ul> 263 * If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic update access modes compare 264 * values using their bitwise representation (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits} 265 * and {@link MemorySegment#address()}, respectively). 266 * <p> 267 * Alternatively, a var handle is <em>unaligned</em> if its alignment constraint {@code A} is incompatible with the 268 * access size {@code S}, that is, if {@code A < S}. An unaligned var handle only supports the {@code get} and {@code set} 269 * access modes. All other access modes will result in {@link UnsupportedOperationException} being thrown. Moreover, 270 * while supported, access modes {@code get} and {@code set} might lead to word tearing. 271 * 272 * @implSpec 273 * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. 274 * 275 * @sealedGraph 276 * @since 22 277 */ 278 public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout { 279 280 /** 281 * {@return the layout size, in bytes} 282 */ 283 long byteSize(); 284 285 /** 286 * {@return the name (if any) associated with this layout} 287 * @see MemoryLayout#withName(String) 288 */ 289 Optional<String> name(); 290 291 /** 292 * {@return a memory layout with the same characteristics as this layout, but with the given name} 293 * 294 * @param name the layout name. 295 * @see MemoryLayout#name() 296 */ 297 MemoryLayout withName(String name); 298 299 /** 300 * {@return a memory layout with the same characteristics as this layout, but with no name} 301 * 302 * @apiNote This can be useful to compare two layouts that have different names, but are otherwise equal. 303 * @see MemoryLayout#name() 304 */ 305 MemoryLayout withoutName(); 306 307 /** 308 * {@return the alignment constraint associated with this layout, expressed in bytes} Layout alignment defines a power 309 * 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 310 * for any pointer that correctly points to this layout. Thus: 311 * 312 * <ul> 313 * <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li> 314 * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li> 315 * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li> 316 * </ul> 317 * 318 * If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}), 319 * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout. 320 */ 321 long byteAlignment(); 322 323 /** 324 * {@return a memory layout with the same characteristics as this layout, but with the given 325 * alignment constraint (in bytes)} 326 * 327 * @param byteAlignment the layout alignment constraint, expressed in bytes. 328 * @throws IllegalArgumentException if {@code byteAlignment} is not a power of two. 329 */ 330 MemoryLayout withByteAlignment(long byteAlignment); 331 332 /** 333 * {@return {@code offset + (byteSize() * index)}} 334 * 335 * @param offset the base offset 336 * @param index the index to be scaled by the byte size of this layout 337 * @throws IllegalArgumentException if {@code offset} or {@code index} is negative 338 * @throws ArithmeticException if either the addition or multiplication overflows 339 */ 340 @ForceInline 341 default long scale(long offset, long index) { 342 if (offset < 0) { 343 throw new IllegalArgumentException("Negative offset: " + offset); 344 } 345 if (index < 0) { 346 throw new IllegalArgumentException("Negative index: " + index); 347 } 348 349 return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); 350 } 351 352 /** 353 *{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout} 354 */ 355 default MethodHandle scaleHandle() { 356 class Holder { 357 static final MethodHandle MH_SCALE; 358 static { 359 try { 360 MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale", 361 MethodType.methodType(long.class, long.class, long.class)); 362 } catch (ReflectiveOperationException e) { 363 throw new ExceptionInInitializerError(e); 364 } 365 } 366 } 367 return Holder.MH_SCALE.bindTo(this); 368 } 369 370 /** 371 * Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the 372 * path is this layout. 373 * 374 * @param elements the layout path elements. 375 * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}. 376 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 377 * @throws IllegalArgumentException if the layout path contains one or more <a href=#open-path-elements>open path elements</a>. 378 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 379 */ 380 default long byteOffset(PathElement... elements) { 381 return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset, 382 EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); 383 } 384 385 /** 386 * Creates a method handle that computes the offset, in bytes, of the layout selected 387 * by the given layout path, where the initial layout in the path is this layout. 388 * <p> 389 * The returned method handle has the following characteristics: 390 * <ul> 391 * <li>its return type is {@code long};</li> 392 * <li>it has one leading {@code long} parameter representing the base offset;</li> 393 * <li>it has as zero or more trailing parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a> 394 * in the provided layout path. The order of these parameters corresponds to the order in which the open path 395 * elements occur in the provided layout path. 396 * </ul> 397 * <p> 398 * The final offset returned by the method handle is computed as follows: 399 * 400 * <blockquote><pre>{@code 401 * offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n) 402 * }</pre></blockquote> 403 * 404 * where {@code b} represents the base offset provided as a <em>dynamic</em> {@code long} argument, {@code x_1}, {@code x_2}, 405 * ... {@code x_n} represent indices into sequences provided as <em>dynamic</em> {@code long} arguments, whereas 406 * {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants derived from the size of the element 407 * layout of a sequence, and {@code c_1}, {@code c_2}, ... {@code c_m} are other <em>static</em> offset constants 408 * (such as field offsets) which are derived from the layout path. 409 * 410 * @apiNote The returned method handle can be used to compute a layout offset, similarly to {@link #byteOffset(PathElement...)}, 411 * but more flexibly, as some indices can be specified when invoking the method handle. 412 * 413 * @param elements the layout path elements. 414 * @return a method handle that computes the offset, in bytes, of the layout selected by the given layout path. 415 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 416 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 417 */ 418 default MethodHandle byteOffsetHandle(PathElement... elements) { 419 return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle, 420 EnumSet.of(PathKind.DEREF_ELEMENT), elements); 421 } 422 423 /** 424 * Creates a var handle that accesses a memory segment at the offset selected by the given layout path, 425 * where the initial layout in the path is this layout. 426 * <p> 427 * The returned var handle has the following characteristics: 428 * <ul> 429 * <li>its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the 430 * selected value layout;</li> 431 * <li>it has a leading parameter of type {@code MemorySegment} representing the accessed segment</li> 432 * <li>a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};</li> 433 * <li>it has zero or more trailing access coordinates of type {@code long}, one for each 434 * <a href=#open-path-elements>open path element</a> in the provided layout path, denoted as 435 * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order 436 * in which the open path elements occur in the provided layout path. 437 * </ul> 438 * <p> 439 * If the provided layout path {@code P} contains no dereference elements, then the offset of the access operation is 440 * computed as follows: 441 * 442 * {@snippet lang = "java": 443 * offset = this.offsetHandle(P).invokeExact(B, I1, I2, ... In); 444 * } 445 * <p> 446 * Accessing a memory segment using the var handle returned by this method is subject to the following checks: 447 * <ul> 448 * <li>The physical address of the accessed memory segment must be <a href="MemorySegment.html#segment-alignment">aligned</a> 449 * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or 450 * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout 451 * can be more strict (but not less) than the alignment constraint of the selected value layout.</li> 452 * <li>The offset of the access operation (computed as above) must fall inside the spatial bounds of the 453 * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S}, 454 * where {@code O} is the accessed offset (computed as above), {@code A} is the size of the selected layout and {@code S} 455 * is the size of the accessed memory segment.</li> 456 * <li>The accessed memory segment must be {@link MemorySegment#isAccessibleBy(Thread) accessible} from the 457 * thread performing the access operation, or a {@link WrongThreadException} is thrown.</li> 458 * <li>The {@linkplain MemorySegment#scope() scope} associated with the accessed segment must be 459 * {@linkplain MemorySegment.Scope#isAlive() alive}, or an {@link IllegalStateException} is thrown.</li> 460 * </ul> 461 * <p> 462 * If the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#get(Object...)} 463 * on the returned var handle will return a new memory segment. The segment is associated with a scope that is 464 * always alive. Moreover, the size of the segment depends on whether the address layout has a 465 * {@linkplain AddressLayout#targetLayout() target layout}. More specifically: 466 * <ul> 467 * <li>If the address layout has a target layout {@code T}, then the size of the returned segment 468 * is {@code T.byteSize()};</li> 469 * <li>Otherwise, the address layout has no target layout, and the size of the returned segment 470 * is <a href="MemorySegment.html#wrapping-addresses">zero</a>.</li> 471 * </ul> 472 * Moreover, if the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#set(Object...)} 473 * can throw {@link IllegalArgumentException} if the memory segment representing the address to be written is not a 474 * {@linkplain MemorySegment#isNative() native} memory segment. 475 * <p> 476 * If the provided layout path has size {@code m} and contains a dereference path element in position {@code k} 477 * (where {@code k <= m}) then two layout paths {@code P} and {@code P'} are derived, where P contains all the path 478 * elements from 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} to 479 * {@code m} (if any). Then, the returned var handle is computed as follows: 480 * 481 * {@snippet lang = "java": 482 * VarHandle baseHandle = this.varHandle(P); 483 * MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); 484 * VarHandle targetHandle = target.varHandle(P'); 485 * targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 486 * targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, 487 * baseHandle.toMethodHandle(VarHandle.AccessMode.GET)); 488 * } 489 * 490 * (The above can be trivially generalized to cases where the provided layout path contains more than one dereference 491 * path elements). 492 * <p> 493 * As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows: 494 * {@snippet lang = "java": 495 * GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout( 496 * MemoryLayout.paddingLayout(4), 497 * ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") 498 * ); 499 * } 500 * To access the member layout named {@code value}, we can construct a var handle as follows: 501 * {@snippet lang = "java": 502 * VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int 503 * } 504 * 505 * @apiNote The resulting var handle features certain <a href="#access-mode-restrictions"><em>access mode restrictions</em></a>, 506 * which are common to all var handles derived from memory layouts. 507 * 508 * @param elements the layout path elements. 509 * @return a var handle that accesses a memory segment at the offset selected by the given layout path. 510 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 511 * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}. 512 */ 513 default VarHandle varHandle(PathElement... elements) { 514 Objects.requireNonNull(elements); 515 if (this instanceof ValueLayout vl && elements.length == 0) { 516 return vl.varHandle(); // fast path 517 } 518 return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle, 519 Set.of(), elements); 520 } 521 522 /** 523 * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice} 524 * corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout. 525 * <p> 526 * The returned method handle has the following characteristics: 527 * <ul> 528 * <li>its return type is {@code MemorySegment};</li> 529 * <li>it has a leading parameter of type {@code MemorySegment} corresponding to the memory segment to be sliced</li> 530 * <li>a following {@code long} parameter, corresponding to the base offset</li> 531 * <li>it has as zero or more trailing parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a> 532 * in the provided layout path. The order of these parameters corresponds to the order in which the open path 533 * elements occur in the provided layout path. 534 * </ul> 535 * <p> 536 * The offset of the returned segment is computed as if by a call to a 537 * {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed using the given path elements. 538 * <p> 539 * Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks: 540 * <ul> 541 * <li>The physical address of the accessed memory segment must be <a href="MemorySegment.html#segment-alignment">aligned</a> 542 * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or 543 * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout 544 * can be more strict (but not less) than the alignment constraint of the selected layout.</li> 545 * <li>The start offset of the slicing operation (computed as above) must fall fall inside the spatial bounds of the 546 * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S}, 547 * where {@code O} is the start offset of the slicing operation (computed as above), {@code A} is the size of the 548 * selected layout and {@code S} is the size of the accessed memory segment.</li> 549 * </ul> 550 * 551 * @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)}, 552 * but more flexibly, as some indices can be specified when invoking the method handle. 553 * 554 * @param elements the layout path elements. 555 * @return a method handle which is used to slice a memory segment at the offset selected by the given layout path. 556 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 557 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 558 */ 559 default MethodHandle sliceHandle(PathElement... elements) { 560 return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle, 561 Set.of(PathKind.DEREF_ELEMENT), elements); 562 } 563 564 /** 565 * Returns the layout selected from the provided path, where the initial layout in the path is this layout. 566 * 567 * @param elements the layout path elements. 568 * @return the layout selected by the layout path in {@code elements}. 569 * @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout. 570 * @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>. 571 * @throws IllegalArgumentException if the layout path contains one or more path elements that select one or more 572 * sequence element indices, such as {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}). 573 */ 574 default MemoryLayout select(PathElement... elements) { 575 return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout, 576 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); 577 } 578 579 private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer, 580 Set<PathKind> badKinds, PathElement... elements) { 581 Objects.requireNonNull(elements); 582 for (PathElement e : elements) { 583 LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e); 584 if (badKinds.contains(pathElem.kind())) { 585 throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description())); 586 } 587 path = pathElem.apply(path); 588 } 589 return finalizer.apply(path); 590 } 591 592 /** 593 * An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There 594 * are three kinds of path elements: 595 * <ul> 596 * <li><em>group path elements</em>, used to select a member layout within a {@link GroupLayout}, either by name or by index;</li> 597 * <li><em>sequence path elements</em>, used to select one or more sequence element layouts within a {@link SequenceLayout}; and</li> 598 * <li><em>dereference path elements</em>, used to <a href="MemoryLayout.html#deref-path-elements">dereference</a> 599 * an address layout as its target layout.</li> 600 * </ul> 601 * Sequence path elements selecting more than one sequence element layout are called 602 * <a href="MemoryLayout.html#open-path-elements">open path elements</a>. 603 * 604 * @implSpec 605 * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. 606 * 607 * @since 22 608 */ 609 sealed interface PathElement permits LayoutPath.PathElementImpl { 610 611 /** 612 * Returns a path element which selects a member layout with the given name in a group layout. 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 the lowest offset from current path is selected. 616 * In such cases, using {@link #groupElement(long)} might be preferable. 617 * 618 * @param name the name of the member layout to be selected. 619 * @return a path element which selects the group member layout with the given name. 620 */ 621 static PathElement groupElement(String name) { 622 Objects.requireNonNull(name); 623 return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT, 624 path -> path.groupElement(name)); 625 } 626 627 /** 628 * Returns a path element which selects a member layout with the given index in a group layout. 629 * 630 * @param index the index of the member layout element to be selected. 631 * @return a path element which selects the group member layout with the given index. 632 * @throws IllegalArgumentException if {@code index < 0}. 633 */ 634 static PathElement groupElement(long index) { 635 if (index < 0) { 636 throw new IllegalArgumentException("Index < 0"); 637 } 638 return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT, 639 path -> path.groupElement(index)); 640 } 641 642 /** 643 * Returns a path element which selects the element layout at the specified position in a sequence layout. 644 * 645 * @param index the index of the sequence element to be selected. 646 * @return a path element which selects the sequence element layout with the given index. 647 * @throws IllegalArgumentException if {@code index < 0}. 648 */ 649 static PathElement sequenceElement(long index) { 650 if (index < 0) { 651 throw new IllegalArgumentException("Index must be positive: " + index); 652 } 653 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT_INDEX, 654 path -> path.sequenceElement(index)); 655 } 656 657 /** 658 * Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects the element 659 * layout in a <em>range</em> of positions in a sequence layout. The range is expressed as a pair of starting 660 * index (inclusive) {@code S} and step factor (which can also be negative) {@code F}. 661 * <p> 662 * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the 663 * sequence element count, it follows that {@code 0 <= I < B}, where {@code B} is computed as follows: 664 * <ul> 665 * <li>if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}</li> 666 * <li>if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}</li> 667 * </ul> 668 * 669 * @param start the index of the first sequence element to be selected. 670 * @param step the step factor at which subsequence sequence elements are to be selected. 671 * @return a path element which selects the sequence element layout with the given index. 672 * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}. 673 */ 674 static PathElement sequenceElement(long start, long step) { 675 if (start < 0) { 676 throw new IllegalArgumentException("Start index must be positive: " + start); 677 } 678 if (step == 0) { 679 throw new IllegalArgumentException("Step must be != 0: " + step); 680 } 681 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_RANGE, 682 path -> path.sequenceElement(start, step)); 683 } 684 685 /** 686 * Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects an unspecified 687 * element layout in a sequence layout. 688 * <p> 689 * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the 690 * sequence element count, it follows that {@code 0 <= I < C}. 691 * 692 * @return a path element which selects an unspecified sequence element layout. 693 */ 694 static PathElement sequenceElement() { 695 return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT, 696 LayoutPath::sequenceElement); 697 } 698 699 /** 700 * Returns a path element which dereferences an address layout as its 701 * {@linkplain AddressLayout#targetLayout() target layout} (where set). 702 * 703 * @return a path element which dereferences an address layout. 704 */ 705 static PathElement dereferenceElement() { 706 return new LayoutPath.PathElementImpl(PathKind.DEREF_ELEMENT, 707 LayoutPath::derefElement); 708 } 709 } 710 711 /** 712 * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified 713 * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of 714 * the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional 715 * conditions must be satisfied: 716 * <ul> 717 * <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order}, 718 * and {@linkplain ValueLayout#carrier() carrier}. Additionally, two address layouts are considered equal if they 719 * also have the same {@linkplain AddressLayout#targetLayout() target layout};</li> 720 * <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and 721 * if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal;</li> 722 * <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout}, 723 * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal.</li> 724 * </ul> 725 * 726 * @param other the object to be compared for equality with this layout. 727 * @return {@code true} if the specified object is equal to this layout. 728 */ 729 boolean equals(Object other); 730 731 /** 732 * {@return the hash code value for this layout} 733 */ 734 int hashCode(); 735 736 /** 737 * {@return the string representation of this layout} 738 */ 739 @Override 740 String toString(); 741 742 /** 743 * Creates a padding layout with the given byte size. The alignment constraint of the returned layout 744 * is 1. As such, regardless of its size, in the absence of an {@linkplain #withByteAlignment(long) explicit} 745 * alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout 746 * it is nested into. 747 * 748 * @param byteSize the padding size (expressed in bytes). 749 * @return the new selector layout. 750 * @throws IllegalArgumentException if {@code byteSize <= 0}. 751 */ 752 static PaddingLayout paddingLayout(long byteSize) { 753 return PaddingLayoutImpl.of(MemoryLayoutUtil.requireByteSizeValid(byteSize, false)); 754 } 755 756 /** 757 * Creates a sequence layout with the given element layout and element count. 758 * 759 * @param elementCount the sequence element count. 760 * @param elementLayout the sequence element layout. 761 * @return the new sequence layout with the given element layout and size. 762 * @throws IllegalArgumentException if {@code elementCount} is negative. 763 * @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount} overflows. 764 * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}. 765 */ 766 static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { 767 MemoryLayoutUtil.requireNonNegative(elementCount); 768 Objects.requireNonNull(elementLayout); 769 Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); 770 return Utils.wrapOverflow(() -> 771 SequenceLayoutImpl.of(elementCount, elementLayout)); 772 } 773 774 /** 775 * Creates a struct layout with the given member layouts. 776 * 777 * @param elements The member layouts of the struct layout. 778 * @return a struct layout with the given member layouts. 779 * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member layouts 780 * overflows. 781 * @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset (relative to the start 782 * of the struct layout) which is not compatible with its alignment constraint. 783 * 784 * @apiNote This factory does not automatically align element layouts, by inserting additional {@linkplain PaddingLayout 785 * padding layout} elements. As such, the following struct layout creation will fail with an exception: 786 * 787 * {@snippet lang = java: 788 * structLayout(JAVA_SHORT, JAVA_INT); 789 * } 790 * 791 * To avoid the exception, clients can either insert additional padding layout elements: 792 * 793 * {@snippet lang = java: 794 * structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT); 795 * } 796 * 797 * Or, alternatively, they can use a member layout which features a smaller alignment constraint. This will result 798 * in a <em>packed</em> struct layout: 799 * 800 * {@snippet lang = java: 801 * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2)); 802 * } 803 */ 804 static StructLayout structLayout(MemoryLayout... elements) { 805 Objects.requireNonNull(elements); 806 return Utils.wrapOverflow(() -> 807 StructLayoutImpl.of(Stream.of(elements) 808 .map(Objects::requireNonNull) 809 .toList())); 810 } 811 812 /** 813 * Creates a union layout with the given member layouts. 814 * 815 * @param elements The member layouts of the union layout. 816 * @return a union layout with the given member layouts. 817 */ 818 static UnionLayout unionLayout(MemoryLayout... elements) { 819 Objects.requireNonNull(elements); 820 return UnionLayoutImpl.of(Stream.of(elements) 821 .map(Objects::requireNonNull) 822 .toList()); 823 } 824 }