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 }