--- /dev/null 2019-12-04 18:44:18.020007537 +0000 +++ new/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java 2019-12-09 18:15:31.864034752 +0000 @@ -0,0 +1,430 @@ +/* + * 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 java.nio.ByteBuffer; + +import jdk.internal.foreign.Utils; + +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.Path; + +/** + * A memory segment models a contiguous region of memory. A memory segment is associated with both spatial + * and temporal bounds. Spatial bounds ensure that memory access operations on a memory segment cannot affect a memory location + * which falls outside the boundaries of the memory segment being accessed. Temporal checks ensure that memory access + * operations on a segment cannot occur after a memory segment has been closed (see {@link MemorySegment#close()}). + *
+ * 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 MemorySegment} may have unpredictable results and should be avoided. The {@code equals} method should + * be used for comparisons. + *
+ * Non-platform classes should not implement {@linkplain MemorySegment} directly. + * + *
+ * It is also possible to obtain a memory segment backed by an existing heap-allocated Java array, + * using one of the provided factory methods (e.g. {@link MemorySegment#ofArray(int[])}). Memory segments obtained + * in this way are called array memory segments. + *
+ * It is possible to obtain a memory segment backed by an existing Java byte buffer (see {@link ByteBuffer}), + * using the factory method {@link MemorySegment#ofByteBuffer(ByteBuffer)}. + * Memory segments obtained in this way are called buffer memory segments. Note that buffer memory segments might + * be backed by native memory (as in the case of native memory segments) or heap memory (as in the case of array memory segments), + * depending on the characteristics of the byte buffer instance the segment is associated with. For instance, a buffer memory + * segment obtained from a byte buffer created with the {@link ByteBuffer#allocateDirect(int)} method will be backed + * by native memory. + *
+ * Finally, it is also possible to obtain a memory segment backed by a memory-mapped file using the factory method + * {@link MemorySegment#mapFromPath(Path, long, FileChannel.MapMode)}. Such memory segments are called mapped memory segments. + * + *
+ * If a memory segment S owned by thread A needs to be used by thread B, B needs to explicitly acquire S, + * which will create a so called acquired memory segment owned by B (see {@link #acquire()}) backed by the same resources + * as S. A memory segment can be acquired multiple times by one or more threads; in that case, a memory segment S cannot + * be closed until all the acquired memory segments derived from S have been closed. Furthermore, closing an acquired + * memory segment does not trigger any deallocation action. It is therefore important that clients remember to + * explicitly close the original segment from which the acquired memory segments have been obtained in order to truly + * ensure that off-heap resources associated with the memory segment are released. + * + *
+ * Temporal bounds of the original segment are inherited by the view; that is, closing a segment view, such as a sliced + * view, will cause the original segment to be closed; as such special care must be taken when sharing views + * between multiple clients. If a client want to protect itself against early closure of a segment by + * another actor, it is the responsibility of that client to take protective measures, such as calling + * {@link MemorySegment#acquire()} before sharing the view with another client. + *
+ * To allow for interoperability with existing code, a byte buffer view can be obtained from a memory segment + * (see {@link #asByteBuffer()}). This can be useful, for instance, for those clients that want to keep using the + * {@link ByteBuffer} API, but need to operate on large memory segments. Byte buffers obtained in such a way support + * the same spatial and temporal access restrictions associated to the memory address from which they originated. + * + * @apiNote In the future, if the Java language permits, {@link MemorySegment} + * 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. + */ +public interface MemorySegment extends AutoCloseable { + + /** + * The base memory address associated with this memory segment. + * @return The base memory address. + */ + MemoryAddress baseAddress(); + + /** + * Obtains an acquired memory segment which can be used to access memory associated + * with this segment from the current thread. As a side-effect, this segment cannot be closed until the acquired + * view has been closed too (see {@link #close()}). + * @return an acquired memory segment which can be used to access memory associated + * with this segment from the current thread. + * @throws IllegalStateException if this segment has been closed. + */ + MemorySegment acquire(); + + /** + * Is this segment accessible from the current thread? + * @return true, if this segment is accessible from the current thread. + */ + boolean isAccessible(); + + /** + * The size (in bytes) of this memory segment. + * @return The size (in bytes) of this memory segment. + */ + long byteSize(); + + /** + * Obtains a read-only view of this segment. An attempt to write memory associated with a read-only memory segment + * will fail with {@link UnsupportedOperationException}. + * @return a read-only view of this segment. + * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the + * thread owning this segment. + */ + MemorySegment asReadOnly(); + + /** + * Obtains a new memory segment view whose base address is the same as the base address of this segment plus a given offset, + * and whose new size is specified by the given argument. + * @param offset The new segment base offset (relative to the current segment base address), specified in bytes. + * @param newSize The new segment size, specified in bytes. + * @return a new memory segment view with updated base/limit addresses. + * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset} + * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the + * thread owning this segment. + */ + MemorySegment asSlice(long offset, long newSize); + + /** + * Is this segment alive? + * @return true, if the segment is alive. + * @see MemorySegment#close() + */ + boolean isAlive(); + + /** + * Is this segment read-only? + * @return true, if the segment is read-only. + * @see MemorySegment#asReadOnly() + */ + boolean isReadOnly(); + + /** + * Closes this memory segment. Once a memory segment has been closed, any attempt to use the memory segment, + * or to access the memory associated with the segment will fail with {@link IllegalStateException}. Depending on + * the kind of memory segment being closed, calling this method further trigger deallocation of all the resources + * associated with the memory segment. + * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the + * thread owning this segment, or if existing acquired views of this segment are still in use (see {@link MemorySegment#acquire()}). + */ + void close(); + + /** + * Wraps this segment in a {@link ByteBuffer}. Some of the properties of the returned buffer are linked to + * the properties of this segment. For instance, if this segment is immutable + * (see {@link MemorySegment#asReadOnly()}, then the resulting buffer is read-only + * (see {@link ByteBuffer#isReadOnly()}. Additionally, if this is a native memory segment, the resulting buffer is + * direct (see {@link ByteBuffer#isDirect()}). + *
+ * The life-cycle of the returned buffer will be tied to that of this segment. That means that if the this segment + * is closed (see {@link MemorySegment#close()}, accessing the returned + * buffer will throw an {@link IllegalStateException}. + *
+ * The resulting buffer's byte order is {@link java.nio.ByteOrder#BIG_ENDIAN}; this can be changed using + * {@link ByteBuffer#order(java.nio.ByteOrder)}. + * + * @return a {@link ByteBuffer} view of this memory segment. + * @throws UnsupportedOperationException if this segment cannot be mapped onto a {@link ByteBuffer} instance, + * e.g. because it models an heap-based segment that is not based on a {@code byte[]}), or if its size is greater + * than {@link Integer#MAX_VALUE}. + * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the + * thread owning this segment. + */ + ByteBuffer asByteBuffer(); + + /** + * Copy the contents of this memory segment into a fresh byte array. + * @return a fresh byte array copy of this memory segment. + * @throws UnsupportedOperationException if this segment's contents cannot be copied into a {@link byte[]} instance, + * e.g. its size is greater than {@link Integer#MAX_VALUE}. + * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the + * thread owning this segment. + */ + byte[] toByteArray(); + + /** + * Creates a new buffer memory segment that models the memory associated with the given byte + * buffer. The segment starts relative to the buffer's position (inclusive) + * and ends relative to the buffer's limit (exclusive). + *
+ * The resulting memory segment keeps a reference to the backing buffer, to ensure it remains reachable + * for the life-time of the segment. + * + * @param bb the byte buffer backing the buffer memory segment. + * @return a new buffer memory segment. + */ + static MemorySegment ofByteBuffer(ByteBuffer bb) { + return Utils.makeBufferSegment(bb); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated byte array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(byte[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated char array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(char[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated short array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(short[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated int array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(int[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated float array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(float[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated long array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(long[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new array memory segment that models the memory associated with a given heap-allocated double array. + *
+ * The resulting memory segment keeps a reference to the backing array, to ensure it remains reachable + * for the life-time of the segment. + * + * @param arr the primitive array backing the array memory segment. + * @return a new array memory segment. + */ + static MemorySegment ofArray(double[] arr) { + return Utils.makeArraySegment(arr); + } + + /** + * Creates a new native memory segment that models a newly allocated block of off-heap memory with given layout. + *
+ * This is equivalent to the following code: + *
+ * + * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory + * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()} + * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so + * will result in off-heap memory leaks. + * + * @param layout the layout of the off-heap memory block backing the native memory segment. + * @return a new native memory segment. + * @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint. + */ + static MemorySegment allocateNative(MemoryLayout layout) { + return allocateNative(layout.byteSize(), layout.byteAlignment()); + } + + /** + * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size (in bytes). + *{@code + allocateNative(layout.bytesSize(), layout.bytesAlignment()); + * }
+ * This is equivalent to the following code: + *
+ * + * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory + * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()} + * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so + * will result in off-heap memory leaks. + * + * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment. + * @return a new native memory segment. + * @throws IllegalArgumentException if {@code bytesSize < 0}. + */ + static MemorySegment allocateNative(long bytesSize) { + return allocateNative(bytesSize, 1); + } + + /** + * Creates a new mapped memory segment that models a memory-mapped region of a file from a given path. + * + * @implNote When obtaining a mapped segment from a newly created file, the initialization state of the contents of the block + * of mapped memory associated with the returned mapped memory segment is unspecified and should not be relied upon. + * + * @param path the path to the file to memory map. + * @param bytesSize the size (in bytes) of the mapped memory backing the memory segment. + * @param mapMode a file mapping mode, see {@link FileChannel#map(FileChannel.MapMode, long, long)}. + * @return a new mapped memory segment. + * @throws IllegalArgumentException if {@code bytesSize < 0}. + * @throws UnsupportedOperationException if an unsupported map mode is specified. + * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs. + */ + static MemorySegment mapFromPath(Path path, long bytesSize, FileChannel.MapMode mapMode) throws IOException { + return Utils.makeMappedSegment(path, bytesSize, mapMode); + } + + /** + * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size and + * alignment constraint (in bytes). + * + * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory + * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()} + * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so + * will result in off-heap memory leaks. + * + * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment. + * @param alignmentBytes the alignment constraint (in bytes) of the off-heap memory block backing the native memory segment. + * @return a new native memory segment. + * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes < 0}, or if {@code alignmentBytes} + * is not a power of 2. + */ + static MemorySegment allocateNative(long bytesSize, long alignmentBytes) { + if (bytesSize <= 0) { + throw new IllegalArgumentException("Invalid allocation size : " + bytesSize); + } + + if (alignmentBytes < 0 || + ((alignmentBytes & (alignmentBytes - 1)) != 0L)) { + throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes); + } + + return Utils.makeNativeSegment(bytesSize, alignmentBytes); + } +}{@code + allocateNative(bytesSize, 1); + * }