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 
  27 package jdk.incubator.foreign;
  28 
  29 import java.nio.ByteBuffer;
  30 
  31 import jdk.internal.foreign.Utils;
  32 
  33 import java.io.IOException;
  34 import java.nio.channels.FileChannel;
  35 import java.nio.file.Path;
  36 
  37 /**
  38  * A memory segment models a contiguous region of memory. A memory segment is associated with both spatial
  39  * and temporal bounds. Spatial bounds ensure that memory access operations on a memory segment cannot affect a memory location
  40  * which falls <em>outside</em> the boundaries of the memory segment being accessed. Temporal checks ensure that memory access
  41  * operations on a segment cannot occur after a memory segment has been closed (see {@link MemorySegment#close()}).
  42  * <p>
  43  * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
  44  * use of identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or synchronization) on
  45  * instances of {@code MemorySegment} may have unpredictable results and should be avoided. The {@code equals} method should
  46  * be used for comparisons.
  47  * <p>
  48  * Non-platform classes should not implement {@linkplain MemorySegment} directly.
  49  *
  50  * <h2>Constructing memory segments from different sources</h2>
  51  *
  52  * There are multiple ways to obtain a memory segment. First, memory segments backed by off-heap memory can
  53  * be allocated using one of the many factory methods provided (see {@link MemorySegment#allocateNative(MemoryLayout)},
  54  * {@link MemorySegment#allocateNative(long)} and {@link MemorySegment#allocateNative(long, long)}). Memory segments obtained
  55  * in this way are called <em>native memory segments</em>.
  56  * <p>
  57  * It is also possible to obtain a memory segment backed by an existing heap-allocated Java array,
  58  * using one of the provided factory methods (e.g. {@link MemorySegment#ofArray(int[])}). Memory segments obtained
  59  * in this way are called <em>array memory segments</em>.
  60  * <p>
  61  * It is possible to obtain a memory segment backed by an existing Java byte buffer (see {@link ByteBuffer}),
  62  * using the factory method {@link MemorySegment#ofByteBuffer(ByteBuffer)}.
  63  * Memory segments obtained in this way are called <em>buffer memory segments</em>. Note that buffer memory segments might
  64  * be backed by native memory (as in the case of native memory segments) or heap memory (as in the case of array memory segments),
  65  * depending on the characteristics of the byte buffer instance the segment is associated with. For instance, a buffer memory
  66  * segment obtained from a byte buffer created with the {@link ByteBuffer#allocateDirect(int)} method will be backed
  67  * by native memory.
  68  * <p>
  69  * Finally, it is also possible to obtain a memory segment backed by a memory-mapped file using the factory method
  70  * {@link MemorySegment#mapFromPath(Path, long, FileChannel.MapMode)}. Such memory segments are called <em>mapped memory segments</em>.
  71  *
  72  * <h2>Closing a memory segment</h2>
  73  *
  74  * Memory segments are closed explicitly (see {@link MemorySegment#close()}). In general when a segment is closed, all off-heap
  75  * resources associated with it are released; this has different meanings depending on the kind of memory segment being
  76  * considered:
  77  * <ul>
  78  *     <li>closing a native memory segment results in <em>freeing</em> the native memory associated with it</li>
  79  *     <li>closing a mapped memory segment results in the backing memory-mapped file to be unmapped</li>
  80  *     <li>closing an acquired memory segment <b>does not</b> result in the release of resources
  81  *     (see the section on <a href="#thread-confinement">thread confinement</a> for more details)</li>
  82  *     <li>closing a buffer, or a heap segment does not have any side-effect, other than making the marking the segment
  83  *     as <em>not alive</em> (see {@link MemorySegment#isAlive()}). Also, since the buffer and heap segments might keep
  84  *     strong references to the original buffer or array instance, it is the responsibility of clients to ensure that
  85  *     these segments are discarded in a timely manner, so as not to prevent garbage collection to reclaim the underlying
  86  *     objects.</li>
  87  * </ul>
  88  *
  89  * <h2><a id = "thread-confinement">Thread confinement</a></h2>
  90  *
  91  * Memory segments support strong thread-confinement guarantees. Upon creation, they are assigned an <em>owner thread</em>,
  92  * typically the thread which initiated the creation operation. After creation, only the owner thread will be allowed
  93  * to directly manipulate the memory segment (e.g. close the memory segment) or access the underlying memory associated with
  94  * the segment using a memory access var handle. Any attempt to perform such operations from a thread other than the
  95  * owner thread will result in a runtime failure.
  96  * <p>
  97  * If a memory segment S owned by thread A needs to be used by thread B, B needs to explicitly <em>acquire</em> S,
  98  * which will create a so called <em>acquired</em> memory segment owned by B (see {@link #acquire()}) backed by the same resources
  99  * as S. A memory segment can be acquired multiple times by one or more threads; in that case, a memory segment S cannot
 100  * be closed until all the acquired memory segments derived from S have been closed. Furthermore, closing an acquired
 101  * memory segment does <em>not</em> trigger any deallocation action. It is therefore important that clients remember to
 102  * explicitly close the original segment from which the acquired memory segments have been obtained in order to truly
 103  * ensure that off-heap resources associated with the memory segment are released.
 104  *
 105  * <h2>Memory segment views</h2>
 106  *
 107  * Memory segments support <em>views</em>. It is possible to create an <em>immutable</em> view of a memory segment
 108  * (see {@link MemorySegment#asReadOnly()}) which does not support write operations. It is also possible to create views
 109  * whose spatial bounds are stricter than the ones of the original segment (see {@link MemorySegment#asSlice(long, long)}).
 110  * <p>
 111  * Temporal bounds of the original segment are inherited by the view; that is, closing a segment view, such as a sliced
 112  * view, will cause the original segment to be closed; as such special care must be taken when sharing views
 113  * between multiple clients. If a client want to protect itself against early closure of a segment by
 114  * another actor, it is the responsibility of that client to take protective measures, such as calling
 115  * {@link MemorySegment#acquire()} before sharing the view with another client.
 116  * <p>
 117  * To allow for interoperability with existing code, a byte buffer view can be obtained from a memory segment
 118  * (see {@link #asByteBuffer()}). This can be useful, for instance, for those clients that want to keep using the
 119  * {@link ByteBuffer} API, but need to operate on large memory segments. Byte buffers obtained in such a way support
 120  * the same spatial and temporal access restrictions associated to the memory address from which they originated.
 121  *
 122  * @apiNote In the future, if the Java language permits, {@link MemorySegment}
 123  * may become a {@code sealed} interface, which would prohibit subclassing except by
 124  * explicitly permitted types.
 125  *
 126  * @implSpec
 127  * Implementations of this interface are immutable and thread-safe.
 128  */
 129 public interface MemorySegment extends AutoCloseable {
 130 
 131     /**
 132      * The base memory address associated with this memory segment.
 133      * @return The base memory address.
 134      */
 135     MemoryAddress baseAddress();
 136 
 137     /**
 138      * Obtains an <a href="#thread-confinement">acquired</a> memory segment which can be used to access memory associated
 139      * with this segment from the current thread. As a side-effect, this segment cannot be closed until the acquired
 140      * view has been closed too (see {@link #close()}).
 141      * @return an <a href="#thread-confinement">acquired</a> memory segment which can be used to access memory associated
 142      * with this segment from the current thread.
 143      * @throws IllegalStateException if this segment has been closed.
 144      */
 145     MemorySegment acquire();
 146 
 147     /**
 148      * Is this segment accessible from the current thread?
 149      * @return true, if this segment is accessible from the current thread.
 150      */
 151     boolean isAccessible();
 152 
 153     /**
 154      * The size (in bytes) of this memory segment.
 155      * @return The size (in bytes) of this memory segment.
 156      */
 157     long byteSize();
 158 
 159     /**
 160      * Obtains a read-only view of this segment. An attempt to write memory associated with a read-only memory segment
 161      * will fail with {@link UnsupportedOperationException}.
 162      * @return a read-only view of this segment.
 163      * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
 164      * thread owning this segment.
 165      */
 166     MemorySegment asReadOnly();
 167 
 168     /**
 169      * Obtains a new memory segment view whose base address is the same as the base address of this segment plus a given offset,
 170      * and whose new size is specified by the given argument.
 171      * @param offset The new segment base offset (relative to the current segment base address), specified in bytes.
 172      * @param newSize The new segment size, specified in bytes.
 173      * @return a new memory segment view with updated base/limit addresses.
 174      * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
 175      * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
 176      * thread owning this segment.
 177      */
 178     MemorySegment asSlice(long offset, long newSize);
 179 
 180     /**
 181      * Is this segment alive?
 182      * @return true, if the segment is alive.
 183      * @see MemorySegment#close()
 184      */
 185     boolean isAlive();
 186 
 187     /**
 188      * Is this segment read-only?
 189      * @return true, if the segment is read-only.
 190      * @see MemorySegment#asReadOnly()
 191      */
 192     boolean isReadOnly();
 193 
 194     /**
 195      * Closes this memory segment. Once a memory segment has been closed, any attempt to use the memory segment,
 196      * or to access the memory associated with the segment will fail with {@link IllegalStateException}. Depending on
 197      * the kind of memory segment being closed, calling this method further trigger deallocation of all the resources
 198      * associated with the memory segment.
 199      * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
 200      * thread owning this segment, or if existing acquired views of this segment are still in use (see {@link MemorySegment#acquire()}).
 201      */
 202     void close();
 203 
 204     /**
 205      * Wraps this segment in a {@link ByteBuffer}. Some of the properties of the returned buffer are linked to
 206      * the properties of this segment. For instance, if this segment is <em>immutable</em>
 207      * (see {@link MemorySegment#asReadOnly()}, then the resulting buffer is <em>read-only</em>
 208      * (see {@link ByteBuffer#isReadOnly()}. Additionally, if this is a native memory segment, the resulting buffer is
 209      * <em>direct</em> (see {@link ByteBuffer#isDirect()}).
 210      * <p>
 211      * The life-cycle of the returned buffer will be tied to that of this segment. That means that if the this segment
 212      * is closed (see {@link MemorySegment#close()}, accessing the returned
 213      * buffer will throw an {@link IllegalStateException}.
 214      * <p>
 215      * The resulting buffer's byte order is {@link java.nio.ByteOrder#BIG_ENDIAN}; this can be changed using
 216      * {@link ByteBuffer#order(java.nio.ByteOrder)}.
 217      *
 218      * @return a {@link ByteBuffer} view of this memory segment.
 219      * @throws UnsupportedOperationException if this segment cannot be mapped onto a {@link ByteBuffer} instance,
 220      * e.g. because it models an heap-based segment that is not based on a {@code byte[]}), or if its size is greater
 221      * than {@link Integer#MAX_VALUE}.
 222      * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
 223      * thread owning this segment.
 224      */
 225     ByteBuffer asByteBuffer();
 226 
 227     /**
 228      * Copy the contents of this memory segment into a fresh byte array.
 229      * @return a fresh byte array copy of this memory segment.
 230      * @throws UnsupportedOperationException if this segment's contents cannot be copied into a {@link byte[]} instance,
 231      * e.g. its size is greater than {@link Integer#MAX_VALUE}.
 232      * @throws IllegalStateException if this segment has been closed, or if access occurs from a thread other than the
 233      * thread owning this segment.
 234      */
 235     byte[] toByteArray();
 236 
 237     /**
 238      * Creates a new buffer memory segment that models the memory associated with the given byte
 239      * buffer. The segment starts relative to the buffer's position (inclusive)
 240      * and ends relative to the buffer's limit (exclusive).
 241      * <p>
 242      * The resulting memory segment keeps a reference to the backing buffer, to ensure it remains <em>reachable</em>
 243      * for the life-time of the segment.
 244      *
 245      * @param bb the byte buffer backing the buffer memory segment.
 246      * @return a new buffer memory segment.
 247      */
 248     static MemorySegment ofByteBuffer(ByteBuffer bb) {
 249         return Utils.makeBufferSegment(bb);
 250     }
 251 
 252     /**
 253      * Creates a new array memory segment that models the memory associated with a given heap-allocated byte array.
 254      * <p>
 255      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 256      * for the life-time of the segment.
 257      *
 258      * @param arr the primitive array backing the array memory segment.
 259      * @return a new array memory segment.
 260      */
 261     static MemorySegment ofArray(byte[] arr) {
 262         return Utils.makeArraySegment(arr);
 263     }
 264 
 265     /**
 266      * Creates a new array memory segment that models the memory associated with a given heap-allocated char array.
 267      * <p>
 268      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 269      * for the life-time of the segment.
 270      *
 271      * @param arr the primitive array backing the array memory segment.
 272      * @return a new array memory segment.
 273      */
 274     static MemorySegment ofArray(char[] arr) {
 275         return Utils.makeArraySegment(arr);
 276     }
 277 
 278     /**
 279      * Creates a new array memory segment that models the memory associated with a given heap-allocated short array.
 280      * <p>
 281      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 282      * for the life-time of the segment.
 283      *
 284      * @param arr the primitive array backing the array memory segment.
 285      * @return a new array memory segment.
 286      */
 287     static MemorySegment ofArray(short[] arr) {
 288         return Utils.makeArraySegment(arr);
 289     }
 290 
 291     /**
 292      * Creates a new array memory segment that models the memory associated with a given heap-allocated int array.
 293      * <p>
 294      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 295      * for the life-time of the segment.
 296      *
 297      * @param arr the primitive array backing the array memory segment.
 298      * @return a new array memory segment.
 299      */
 300     static MemorySegment ofArray(int[] arr) {
 301         return Utils.makeArraySegment(arr);
 302     }
 303 
 304     /**
 305      * Creates a new array memory segment that models the memory associated with a given heap-allocated float array.
 306      * <p>
 307      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 308      * for the life-time of the segment.
 309      *
 310      * @param arr the primitive array backing the array memory segment.
 311      * @return a new array memory segment.
 312      */
 313     static MemorySegment ofArray(float[] arr) {
 314         return Utils.makeArraySegment(arr);
 315     }
 316 
 317     /**
 318      * Creates a new array memory segment that models the memory associated with a given heap-allocated long array.
 319      * <p>
 320      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 321      * for the life-time of the segment.
 322      *
 323      * @param arr the primitive array backing the array memory segment.
 324      * @return a new array memory segment.
 325      */
 326     static MemorySegment ofArray(long[] arr) {
 327         return Utils.makeArraySegment(arr);
 328     }
 329 
 330     /**
 331      * Creates a new array memory segment that models the memory associated with a given heap-allocated double array.
 332      * <p>
 333      * The resulting memory segment keeps a reference to the backing array, to ensure it remains <em>reachable</em>
 334      * for the life-time of the segment.
 335      *
 336      * @param arr the primitive array backing the array memory segment.
 337      * @return a new array memory segment.
 338      */
 339     static MemorySegment ofArray(double[] arr) {
 340         return Utils.makeArraySegment(arr);
 341     }
 342 
 343     /**
 344      * Creates a new native memory segment that models a newly allocated block of off-heap memory with given layout.
 345      * <p>
 346      * This is equivalent to the following code:
 347      * <blockquote><pre>{@code
 348     allocateNative(layout.bytesSize(), layout.bytesAlignment());
 349      * }</pre></blockquote>
 350      *
 351      * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
 352      * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
 353      * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
 354      * will result in off-heap memory leaks.
 355      *
 356      * @param layout the layout of the off-heap memory block backing the native memory segment.
 357      * @return a new native memory segment.
 358      * @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint.
 359      */
 360     static MemorySegment allocateNative(MemoryLayout layout) {
 361         return allocateNative(layout.byteSize(), layout.byteAlignment());
 362     }
 363 
 364     /**
 365      * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size (in bytes).
 366      * <p>
 367      * This is equivalent to the following code:
 368      * <blockquote><pre>{@code
 369     allocateNative(bytesSize, 1);
 370      * }</pre></blockquote>
 371      *
 372      * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
 373      * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
 374      * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
 375      * will result in off-heap memory leaks.
 376      *
 377      * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment.
 378      * @return a new native memory segment.
 379      * @throws IllegalArgumentException if {@code bytesSize < 0}.
 380      */
 381     static MemorySegment allocateNative(long bytesSize) {
 382         return allocateNative(bytesSize, 1);
 383     }
 384 
 385     /**
 386      * Creates a new mapped memory segment that models a memory-mapped region of a file from a given path.
 387      *
 388      * @implNote When obtaining a mapped segment from a newly created file, the initialization state of the contents of the block
 389      * of mapped memory associated with the returned mapped memory segment is unspecified and should not be relied upon.
 390      *
 391      * @param path the path to the file to memory map.
 392      * @param bytesSize the size (in bytes) of the mapped memory backing the memory segment.
 393      * @param mapMode a file mapping mode, see {@link FileChannel#map(FileChannel.MapMode, long, long)}.
 394      * @return a new mapped memory segment.
 395      * @throws IllegalArgumentException if {@code bytesSize < 0}.
 396      * @throws UnsupportedOperationException if an unsupported map mode is specified.
 397      * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs.
 398      */
 399     static MemorySegment mapFromPath(Path path, long bytesSize, FileChannel.MapMode mapMode) throws IOException {
 400         return Utils.makeMappedSegment(path, bytesSize, mapMode);
 401     }
 402 
 403     /**
 404      * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size and
 405      * alignment constraint (in bytes).
 406      *
 407      * @implNote The initialization state of the contents of the block of off-heap memory associated with the returned native memory
 408      * segment is unspecified and should not be relied upon. Moreover, a client is responsible to call the {@link MemorySegment#close()}
 409      * on a native memory segment, to make sure the backing off-heap memory block is deallocated accordingly. Failure to do so
 410      * will result in off-heap memory leaks.
 411      *
 412      * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment.
 413      * @param alignmentBytes the alignment constraint (in bytes) of the off-heap memory block backing the native memory segment.
 414      * @return a new native memory segment.
 415      * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes < 0}, or if {@code alignmentBytes}
 416      * is not a power of 2.
 417      */
 418     static MemorySegment allocateNative(long bytesSize, long alignmentBytes) {
 419         if (bytesSize <= 0) {
 420             throw new IllegalArgumentException("Invalid allocation size : " + bytesSize);
 421         }
 422 
 423         if (alignmentBytes < 0 ||
 424                 ((alignmentBytes & (alignmentBytes - 1)) != 0L)) {
 425             throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes);
 426         }
 427 
 428         return Utils.makeNativeSegment(bytesSize, alignmentBytes);
 429     }
 430 }