1 /* 2 * Copyright (c) 2019, 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 jdk.incubator.foreign; 27 28 import jdk.internal.foreign.LayoutPath; 29 import jdk.internal.foreign.Utils; 30 31 import java.lang.constant.Constable; 32 import java.lang.constant.DynamicConstantDesc; 33 import java.lang.invoke.VarHandle; 34 import java.nio.ByteOrder; 35 import java.util.List; 36 import java.util.Objects; 37 import java.util.Optional; 38 import java.util.OptionalLong; 39 40 /** 41 * A memory layout can be used to describe the contents of a memory segment in a <em>language neutral</em> fashion. 42 * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see 43 * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory 44 * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#ofPaddingBits(long)}). 45 * Some common value layout constants are defined in the {@link MemoryLayouts} class. 46 * <p> 47 * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more 48 * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous 49 * member layouts (see {@link GroupLayout}). 50 * <p> 51 * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>; 52 * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on 53 * instances of {@code MemoryLayout} may have unpredictable results and should be avoided. The {@code equals} method should 54 * be used for comparisons. 55 * <p> 56 * Non-platform classes should not implement {@linkplain MemoryLayout} directly. 57 * 58 * <h2>Size, alignment and byte order</h2> 59 * 60 * All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description 61 * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed 62 * as follows: 63 * <ul> 64 * <li>for a <em>finite</em> sequence layout <em>S</em> whose element layout is <em>E</em> and size is L, 65 * the size of <em>S</em> is that of <em>E, multiplied by L</em></li> 66 * <li>the size of an <em>unbounded</em> sequence layout is <em>unknown</em></li> 67 * <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are 68 * <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or 69 * <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li> 70 * </ul> 71 * <p> 72 * Furthermore, all layouts feature a <em>natural alignment</em> which can be inferred as follows: 73 * <ul> 74 * <li>for value and padding layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li> 75 * <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> 76 * <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are 77 * <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> 78 * </ul> 79 * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe 80 * hyper-aligned layouts. 81 * <p> 82 * All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created. 83 * 84 * <h2><a id = "layout-paths">Layout paths</a></h2> 85 * 86 * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates 87 * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path. 88 * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances. 89 * <p> 90 * Layout paths are useful in order to e.g. to obtain offset of leaf elements inside arbitrarily nested layouts 91 * (see {@link MemoryLayout#offset(PathElement...)}), or to quickly obtain a memory access handle corresponding to the selected 92 * layout (see {@link MemoryLayout#varHandle(Class, PathElement...)}). 93 * <p> 94 * Such <em>layout paths</em> can be constructed programmatically using the methods in this class. 95 * For instance, given a layout constructed as follows: 96 * <blockquote><pre>{@code 97 SequenceLayout seq = MemoryLayout.ofSequence(5, 98 MemoryLayout.ofStruct( 99 MemoryLayout.ofPaddingBits(32), 100 MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value") 101 )); 102 * }</pre></blockquote> 103 * 104 * We can obtain the offset of the member layout named <code>value</code> from <code>seq</code>, as follows: 105 * <blockquote><pre>{@code 106 long valueOffset = seq.offset(PathElement.sequenceElement(), PathElement.groupElement("value")); 107 * }</pre></blockquote> 108 * 109 * Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing 110 * an unspecified sequence element (that is, where one of the path component was obtained with the 111 * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime; 112 * that is, the memory access var handle associated with such a layout path expression will feature an extra {@code long} 113 * access coordinate. The layout path constructed in the above example features exactly one free dimension. 114 * 115 * @apiNote In the future, if the Java language permits, {@link MemoryLayout} 116 * may become a {@code sealed} interface, which would prohibit subclassing except by 117 * explicitly permitted types. 118 * 119 * @implSpec 120 * Implementations of this class are immutable and thread-safe. 121 */ 122 public interface MemoryLayout extends Constable { 123 124 /** 125 * Returns an {@link Optional} containing the nominal descriptor for this 126 * layout, if one can be constructed, or an empty {@link Optional} 127 * if one cannot be constructed. 128 * 129 * @return An {@link Optional} containing the resulting nominal descriptor, 130 * or an empty {@link Optional} if one cannot be constructed. 131 */ 132 @Override 133 Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable(); 134 135 /** 136 * Computes the layout size, in bits. 137 * 138 * @return the layout size, in bits. 139 * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}). 140 */ 141 long bitSize(); 142 143 /** 144 * Computes the layout size, in bytes. 145 * 146 * @return the layout size, in bytes. 147 * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}), 148 * or if {@code bitSize()} is not a multiple of 8. 149 */ 150 default long byteSize() { 151 return Utils.bitsToBytesOrThrow(bitSize(), 152 () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8")); 153 } 154 155 /** 156 * Return the <em>name</em> (if any) associated with this layout. 157 * 158 * @return the layout <em>name</em> (if any). 159 * @see MemoryLayout#withName(String) 160 */ 161 Optional<String> name(); 162 163 /** 164 * Attach a <em>name</em> to this layout. 165 * 166 * @param name the layout name. 167 * @return a new layout which is the same as this layout, except for the <em>name</em> associated to it. 168 * @see MemoryLayout#name() 169 */ 170 MemoryLayout withName(String name); 171 172 /** 173 * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power 174 * 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 175 * bytes that must be aligned for any pointer that correctly points to this layout. Thus: 176 * 177 * <ul> 178 * <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li> 179 * <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li> 180 * <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li> 181 * </ul> 182 * 183 * @return the layout alignment constraint, in bits. 184 */ 185 long bitAlignment(); 186 187 /** 188 * Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power 189 * 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 190 * for any pointer that correctly points to this layout. Thus: 191 * 192 * <ul> 193 * <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li> 194 * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li> 195 * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li> 196 * </ul> 197 * 198 * @return the layout alignment constraint, in bytes. 199 * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8. 200 */ 201 default long byteAlignment() { 202 return Utils.bitsToBytesOrThrow(bitAlignment(), 203 () -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8")); 204 } 205 206 /** 207 * Creates a new layout which features the desired alignment constraint. 208 * 209 * @param bitAlignment the layout alignment constraint, expressed in bits. 210 * @return a new layout which is the same as this layout, except for the alignment constraint associated to it. 211 * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than than 8. 212 */ 213 MemoryLayout withBitAlignment(long bitAlignment); 214 215 /** 216 * Computes the offset of the layout selected by a given layout path, where the path is considered rooted in this 217 * layout. 218 * 219 * @apiNote if the layout path has one (or more) free dimensions, 220 * the offset is computed as if all the indices corresponding to such dimensions were set to {@code 0}. 221 * 222 * @param elements the layout path elements. 223 * @return The offset of layout selected by a the layout path obtained by concatenating the path elements in {@code elements}. 224 * @throws IllegalArgumentException if the layout path obtained by concatenating the path elements in {@code elements} 225 * does not select a valid layout element. 226 */ 227 default long offset(PathElement... elements) { 228 LayoutPath path = LayoutPath.rootPath(this); 229 for (PathElement e : elements) { 230 path = ((LayoutPath.PathElementImpl)e).apply(path); 231 } 232 return path.offset(); 233 } 234 235 /** 236 * Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path, 237 * where the path is considered rooted in this layout. 238 * 239 * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every 240 * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle 241 * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles. 242 * 243 * @param carrier the var handle carrier type. 244 * @param elements the layout path elements. 245 * @return a var handle which can be used to dereference memory at the layout denoted by given layout path. 246 * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints. 247 * @throws IllegalArgumentException if the carrier does not represent a primitive type, if the carrier is {@code void}, 248 * {@code boolean}, or if the layout path obtained by concatenating the path elements in {@code elements} 249 * does not select a value layout (see {@link ValueLayout}), or if the selected value layout has a size that 250 * that does not match that of the specified carrier type. 251 */ 252 default VarHandle varHandle(Class<?> carrier, PathElement... elements) { 253 LayoutPath path = LayoutPath.rootPath(this); 254 for (PathElement e : elements) { 255 path = ((LayoutPath.PathElementImpl)e).apply(path); 256 } 257 return path.dereferenceHandle(carrier); 258 } 259 260 /** 261 * Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There 262 * are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group 263 * path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence 264 * path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection 265 * of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or 266 * <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit 267 * sequence path elements, it acquires additional <em>free dimensions</em>. 268 * <p> 269 * Non-platform classes should not implement {@linkplain PathElement} directly. 270 * 271 * @apiNote In the future, if the Java language permits, {@link PathElement} 272 * may become a {@code sealed} interface, which would prohibit subclassing except by 273 * explicitly permitted types. 274 * 275 * @implSpec 276 * Implementations of this interface are immutable and thread-safe. 277 */ 278 interface PathElement { 279 280 /** 281 * Returns a path element which selects a member layout with given name from a given group layout. 282 * The path element returned by this method does not alter the number of free dimensions of any path 283 * that is combined with such element. 284 * 285 * @implSpec in case multiple group elements with a matching name exist, the path element returned by this 286 * method will select the first one; that is, the group element with lowest offset from current path is selected. 287 * 288 * @param name the name of the group element to be selected. 289 * @return a path element which selects the group element with given name. 290 * @throws NullPointerException if the specified group element name is {@code null}. 291 */ 292 static PathElement groupElement(String name) { 293 Objects.requireNonNull(name); 294 return new LayoutPath.PathElementImpl(path -> path.groupElement(name)); 295 } 296 297 /** 298 * Returns a path element which selects the element layout at the specified position in a given the sequence layout. 299 * The path element returned by this method does not alter the number of free dimensions of any path 300 * that is combined with such element. 301 * 302 * @param index the index of the sequence element to be selected. 303 * @return a path element which selects the sequence element layout with given index. 304 * @throws IllegalArgumentException if {@code index < 0}. 305 */ 306 static PathElement sequenceElement(long index) { 307 if (index < 0) { 308 throw new IllegalArgumentException("Index must be positive: " + index); 309 } 310 return new LayoutPath.PathElementImpl(path -> path.sequenceElement(index)); 311 } 312 313 /** 314 * Returns a path element which selects the element layout in a <em>range</em> of positions in a given the sequence layout, 315 * where the range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative) 316 * {@code F}. 317 * If a path with free dimensions {@code n} is combined with the path element returned by this method, 318 * the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated 319 * with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following 320 * formula: 321 * <blockquote><pre>{@code 322 E * (S + I * F) 323 * }</pre></blockquote> 324 * where {@code E} is the size (in bytes) of the sequence element layout. 325 * 326 * @param start the index of the first sequence element to be selected. 327 * @param step the step factor at which subsequence sequence elements are to be selected. 328 * @return a path element which selects the sequence element layout with given index. 329 * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}. 330 */ 331 static PathElement sequenceElement(long start, long step) { 332 if (start < 0) { 333 throw new IllegalArgumentException("Start index must be positive: " + start); 334 } 335 if (step == 0) { 336 throw new IllegalArgumentException("Step must be != 0: " + step); 337 } 338 return new LayoutPath.PathElementImpl(path -> path.sequenceElement(start, step)); 339 } 340 341 /** 342 * Returns a path element which selects an unspecified element layout from a given sequence layout. 343 * If a path with free dimensions {@code n} is combined with the path element returned by this method, 344 * the number of free dimensions of the resulting path will be {@code 1 + n}. 345 * 346 * @return a path element which selects an unspecified sequence element layout. 347 */ 348 static PathElement sequenceElement() { 349 return new LayoutPath.PathElementImpl(LayoutPath::sequenceElement); 350 } 351 } 352 353 /** 354 * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified 355 * object is also a layout, and it is equal to this layout. 356 * 357 * @param that the object to be compared for equality with this layout. 358 * @return {@code true} if the specified object is equal to this layout. 359 */ 360 boolean equals(Object that); 361 362 /** 363 * Returns the hash code value for this layout. 364 * 365 * @return the hash code value for this layout. 366 */ 367 int hashCode(); 368 369 /** 370 * Returns a string representation of this layout. 371 * 372 * @return a string representation of this layout. 373 */ 374 @Override 375 String toString(); 376 377 /** 378 * Create a new padding layout with given size. 379 * 380 * @param size the padding size in bits. 381 * @return the new selector layout. 382 * @throws IllegalArgumentException if {@code size <= 0}. 383 */ 384 static MemoryLayout ofPaddingBits(long size) { 385 AbstractLayout.checkSize(size); 386 return new PaddingLayout(size); 387 } 388 389 /** 390 * Create a value layout of given byte order and size. 391 * 392 * @param size the value layout size. 393 * @param order the value layout's byte order. 394 * @return a new value layout. 395 * @throws IllegalArgumentException if {@code size <= 0}. 396 */ 397 static ValueLayout ofValueBits(long size, ByteOrder order) { 398 AbstractLayout.checkSize(size); 399 return new ValueLayout(order, size); 400 } 401 402 /** 403 * Create a new sequence layout with given element layout and element count. 404 * 405 * @param elementCount the sequence element count. 406 * @param elementLayout the sequence element layout. 407 * @return the new sequence layout with given element layout and size. 408 * @throws IllegalArgumentException if {@code elementCount < 0}. 409 */ 410 static SequenceLayout ofSequence(long elementCount, MemoryLayout elementLayout) { 411 AbstractLayout.checkSize(elementCount, true); 412 OptionalLong size = OptionalLong.of(elementCount); 413 return new SequenceLayout(size, elementLayout); 414 } 415 416 /** 417 * Create a new sequence layout, with unbounded element count and given element layout. 418 * 419 * @param elementLayout the element layout of the sequence layout. 420 * @return the new sequence layout with given element layout. 421 */ 422 static SequenceLayout ofSequence(MemoryLayout elementLayout) { 423 return new SequenceLayout(OptionalLong.empty(), elementLayout); 424 } 425 426 /** 427 * Create a new <em>struct</em> group layout with given member layouts. 428 * 429 * @param elements The member layouts of the <em>struct</em> group layout. 430 * @return a new <em>struct</em> group layout with given member layouts. 431 */ 432 static GroupLayout ofStruct(MemoryLayout... elements) { 433 return new GroupLayout(GroupLayout.Kind.STRUCT, List.of(elements)); 434 } 435 436 /** 437 * Create a new <em>union</em> group layout with given member layouts. 438 * 439 * @param elements The member layouts of the <em>union</em> layout. 440 * @return a new <em>union</em> group layout with given member layouts. 441 */ 442 static GroupLayout ofUnion(MemoryLayout... elements) { 443 return new GroupLayout(GroupLayout.Kind.UNION, List.of(elements)); 444 } 445 } --- EOF ---