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 A which is the bitwise alignment of the layout. If A&gt;=8 then A/8 is the number of bytes that must be aligned
 175      * for any pointer that correctly points to this layout. Thus:
 176      *
 177      * <ul>
 178      * <li>A=8 means unaligned (in the usual sense), which is common in packets.</li>
 179      * <li>A=64 means word aligned (on LP64), A=32 int aligned, A=16 short aligned, etc.</li>
 180      * <li>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 A which is the bytewise alignment of the layout, where 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>A=1 means unaligned (in the usual sense), which is common in packets.</li>
 194      * <li>A=8 means word aligned (on LP64), A=4 int aligned, A=2 short aligned, etc.</li>
 195      * <li>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 }