--- /dev/null 2019-12-04 18:44:18.020007537 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java 2019-12-09 18:15:29.956000302 +0000 @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.incubator.foreign; + +import jdk.internal.foreign.LayoutPath; +import jdk.internal.foreign.Utils; + +import java.lang.constant.Constable; +import java.lang.constant.DynamicConstantDesc; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalLong; + +/** + * A memory layout can be used to describe the contents of a memory segment in a language neutral fashion. + * There are two leaves in the layout hierarchy, value layouts, which are used to represent values of given size and kind (see + * {@link ValueLayout}) and padding layouts which are used, as the name suggests, to represent a portion of a memory + * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#ofPaddingBits(long)}). + * Some common value layout constants are defined in the {@link MemoryLayouts} class. + *
+ * More complex layouts can be derived from simpler ones: a sequence layout denotes a repetition of one or more + * element layout (see {@link SequenceLayout}); a group layout denotes an aggregation of (typically) heterogeneous + * member layouts (see {@link GroupLayout}). + *
+ * All implementations of this interface must be value-based; + * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on + * instances of {@code MemoryLayout} may have unpredictable results and should be avoided. The {@code equals} method should + * be used for comparisons. + *
+ * Non-platform classes should not implement {@linkplain MemoryLayout} directly. + * + *
+ * Furthermore, all layouts feature a natural alignment which can be inferred as follows: + *
+ * All value layouts have an explicit byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created. + * + *
+ * Layout paths are useful in order to e.g. to obtain offset of leaf elements inside arbitrarily nested layouts + * (see {@link MemoryLayout#offset(PathElement...)}), or to quickly obtain a memory access handle corresponding to the selected + * layout (see {@link MemoryLayout#varHandle(Class, PathElement...)}). + *
+ * Such layout paths can be constructed programmatically using the methods in this class. + * For instance, given a layout constructed as follows: + *
+ * + * We can obtain the offset of the member layout named{@code +SequenceLayout seq = MemoryLayout.ofSequence(5, + MemoryLayout.ofStruct( + MemoryLayout.ofPaddingBits(32), + MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value") +)); + * }
value
from seq
, as follows:
+ * + * + * Layout paths can feature one or more free dimensions. For instance, a layout path traversing + * an unspecified sequence element (that is, where one of the path component was obtained with the + * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime; + * that is, the memory access var handle associated with such a layout path expression will feature an extra {@code long} + * access coordinate. The layout path constructed in the above example features exactly one free dimension. + * + * @apiNote In the future, if the Java language permits, {@link MemoryLayout} + * may become a {@code sealed} interface, which would prohibit subclassing except by + * explicitly permitted types. + * + * @implSpec + * Implementations of this class are immutable and thread-safe. + */ +public interface MemoryLayout extends Constable { + + /** + * Returns an {@link Optional} containing the nominal descriptor for this + * layout, if one can be constructed, or an empty {@link Optional} + * if one cannot be constructed. + * + * @return An {@link Optional} containing the resulting nominal descriptor, + * or an empty {@link Optional} if one cannot be constructed. + */ + @Override + Optional extends DynamicConstantDesc extends MemoryLayout>> describeConstable(); + + /** + * Computes the layout size, in bits. + * + * @return the layout size, in bits. + * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}). + */ + long bitSize(); + + /** + * Computes the layout size, in bytes. + * + * @return the layout size, in bytes. + * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}), + * or if {@code bitSize()} is not a multiple of 8. + */ + default long byteSize() { + return Utils.bitsToBytesOrThrow(bitSize(), + () -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8")); + } + + /** + * Return the name (if any) associated with this layout. + * + * @return the layout name (if any). + * @see MemoryLayout#withName(String) + */ + Optional{@code +long valueOffset = seq.offset(PathElement.sequenceElement(), PathElement.groupElement("value")); + * }
+ * Non-platform classes should not implement {@linkplain PathElement} directly. + * + * @apiNote In the future, if the Java language permits, {@link PathElement} + * may become a {@code sealed} interface, which would prohibit subclassing except by + * explicitly permitted types. + * + * @implSpec + * Implementations of this interface are immutable and thread-safe. + */ + interface PathElement { + + /** + * Returns a path element which selects a member layout with given name from a given group layout. + * The path element returned by this method does not alter the number of free dimensions of any path + * that is combined with such element. + * + * @implSpec in case multiple group elements with a matching name exist, the path element returned by this + * method will select the first one; that is, the group element with lowest offset from current path is selected. + * + * @param name the name of the group element to be selected. + * @return a path element which selects the group element with given name. + * @throws NullPointerException if the specified group element name is {@code null}. + */ + static PathElement groupElement(String name) { + Objects.requireNonNull(name); + return new LayoutPath.PathElementImpl(path -> path.groupElement(name)); + } + + /** + * Returns a path element which selects the element layout at the specified position in a given the sequence layout. + * The path element returned by this method does not alter the number of free dimensions of any path + * that is combined with such element. + * + * @param index the index of the sequence element to be selected. + * @return a path element which selects the sequence element layout with given index. + * @throws IllegalArgumentException if {@code index < 0}. + */ + static PathElement sequenceElement(long index) { + if (index < 0) { + throw new IllegalArgumentException("Index must be positive: " + index); + } + return new LayoutPath.PathElementImpl(path -> path.sequenceElement(index)); + } + + /** + * Returns a path element which selects the element layout in a range of positions in a given the sequence layout, + * where the range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative) + * {@code F}. + * If a path with free dimensions {@code n} is combined with the path element returned by this method, + * the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated + * with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following + * formula: + *
+ * where {@code E} is the size (in bytes) of the sequence element layout. + * + * @param start the index of the first sequence element to be selected. + * @param step the step factor at which subsequence sequence elements are to be selected. + * @return a path element which selects the sequence element layout with given index. + * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}. + */ + static PathElement sequenceElement(long start, long step) { + if (start < 0) { + throw new IllegalArgumentException("Start index must be positive: " + start); + } + if (step == 0) { + throw new IllegalArgumentException("Step must be != 0: " + step); + } + return new LayoutPath.PathElementImpl(path -> path.sequenceElement(start, step)); + } + + /** + * Returns a path element which selects an unspecified element layout from a given sequence layout. + * If a path with free dimensions {@code n} is combined with the path element returned by this method, + * the number of free dimensions of the resulting path will be {@code 1 + n}. + * + * @return a path element which selects an unspecified sequence element layout. + */ + static PathElement sequenceElement() { + return new LayoutPath.PathElementImpl(LayoutPath::sequenceElement); + } + } + + /** + * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified + * object is also a layout, and it is equal to this layout. + * + * @param that the object to be compared for equality with this layout. + * @return {@code true} if the specified object is equal to this layout. + */ + boolean equals(Object that); + + /** + * Returns the hash code value for this layout. + * + * @return the hash code value for this layout. + */ + int hashCode(); + + /** + * Returns a string representation of this layout. + * + * @return a string representation of this layout. + */ + @Override + String toString(); + + /** + * Create a new padding layout with given size. + * + * @param size the padding size in bits. + * @return the new selector layout. + * @throws IllegalArgumentException if {@code size <= 0}. + */ + static MemoryLayout ofPaddingBits(long size) { + AbstractLayout.checkSize(size); + return new PaddingLayout(size); + } + + /** + * Create a value layout of given byte order and size. + * + * @param size the value layout size. + * @param order the value layout's byte order. + * @return a new value layout. + * @throws IllegalArgumentException if {@code size <= 0}. + */ + static ValueLayout ofValueBits(long size, ByteOrder order) { + AbstractLayout.checkSize(size); + return new ValueLayout(order, size); + } + + /** + * Create a new sequence layout with given element layout and element count. + * + * @param elementCount the sequence element count. + * @param elementLayout the sequence element layout. + * @return the new sequence layout with given element layout and size. + * @throws IllegalArgumentException if {@code elementCount < 0}. + */ + static SequenceLayout ofSequence(long elementCount, MemoryLayout elementLayout) { + AbstractLayout.checkSize(elementCount, true); + OptionalLong size = OptionalLong.of(elementCount); + return new SequenceLayout(size, elementLayout); + } + + /** + * Create a new sequence layout, with unbounded element count and given element layout. + * + * @param elementLayout the element layout of the sequence layout. + * @return the new sequence layout with given element layout. + */ + static SequenceLayout ofSequence(MemoryLayout elementLayout) { + return new SequenceLayout(OptionalLong.empty(), elementLayout); + } + + /** + * Create a new struct group layout with given member layouts. + * + * @param elements The member layouts of the struct group layout. + * @return a new struct group layout with given member layouts. + */ + static GroupLayout ofStruct(MemoryLayout... elements) { + return new GroupLayout(GroupLayout.Kind.STRUCT, List.of(elements)); + } + + /** + * Create a new union group layout with given member layouts. + * + * @param elements The member layouts of the union layout. + * @return a new union group layout with given member layouts. + */ + static GroupLayout ofUnion(MemoryLayout... elements) { + return new GroupLayout(GroupLayout.Kind.UNION, List.of(elements)); + } +}{@code +E * (S + I * F) + * }