1 /* 2 * Copyright (c) 2021, 2023, 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 java.lang.foreign; 27 28 import java.nio.ByteOrder; 29 import java.nio.charset.Charset; 30 import java.nio.charset.StandardCharsets; 31 import java.util.Objects; 32 33 import jdk.internal.foreign.AbstractMemorySegmentImpl; 34 import jdk.internal.foreign.ArenaImpl; 35 import jdk.internal.foreign.SlicingAllocator; 36 import jdk.internal.foreign.StringSupport; 37 import jdk.internal.vm.annotation.ForceInline; 38 39 /** 40 * An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface 41 * must implement the {@link #allocate(long, long)} method. A segment allocator defines several methods 42 * which can be useful to create segments from several kinds of Java values such as primitives and arrays. 43 * <p> 44 * {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. Clients can easily obtain a new 45 * segment allocator by using either a lambda expression or a method reference: 46 * 47 * {@snippet lang=java : 48 * SegmentAllocator autoAllocator = (byteSize, byteAlignment) -> Arena.ofAuto().allocate(byteSize, byteAlignment); 49 * } 50 * <p> 51 * This interface defines factories for commonly used allocators: 52 * <ul> 53 * <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory 54 * is allocated by repeatedly slicing the provided memory segment;</li> 55 * <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment 56 * and recycles its content upon each new allocation request.</li> 57 * </ul> 58 * <p> 59 * Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em> 60 * the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance, 61 * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional 62 * {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively, 63 * the allocator parameter tells the linker where to store the return value of the foreign function. 64 * 65 * @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is not thread-safe. 66 * Furthermore, memory segments allocated by a segment allocator can be associated with different 67 * lifetimes, and can even be backed by overlapping regions of memory. For these reasons, clients should generally 68 * only interact with a segment allocator they own. 69 * <p> 70 * Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety, 71 * lifetime and non-overlapping guarantees. 72 * 73 * @since 22 74 */ 75 @FunctionalInterface 76 public interface SegmentAllocator { 77 78 /** 79 * Converts a Java string into a null-terminated C string using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset, 80 * storing the result into a memory segment. 81 * <p> 82 * Calling this method is equivalent to the following code: 83 * {@snippet lang = java: 84 * allocateFrom(str, StandardCharsets.UTF_8); 85 *} 86 * 87 * @param str the Java string to be converted into a C string. 88 * @return a new native segment containing the converted C string. 89 */ 90 @ForceInline 91 default MemorySegment allocateFrom(String str) { 92 Objects.requireNonNull(str); 93 return allocateFrom(str, StandardCharsets.UTF_8); 94 } 95 96 /** 97 * Converts a Java string into a null-terminated C string using the provided charset, 98 * and storing the result into a memory segment. 99 * <p> 100 * This method always replaces malformed-input and unmappable-character 101 * sequences with this charset's default replacement byte array. The 102 * {@link java.nio.charset.CharsetEncoder} class should be used when more 103 * control over the encoding process is required. 104 * <p> 105 * If the given string contains any {@code '\0'} characters, they will be 106 * copied as well. This means that, depending on the method used to read 107 * the string, such as {@link MemorySegment#getString(long)}, the string 108 * will appear truncated when read again. 109 * 110 * @param str the Java string to be converted into a C string. 111 * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes. 112 * @return a new native segment containing the converted C string. 113 * @throws UnsupportedOperationException if {@code charset} is not a {@linkplain StandardCharsets standard charset}. 114 * @implSpec The default implementation for this method copies the contents of the provided Java string 115 * into a new memory segment obtained by calling {@code this.allocate(B + N)}, where: 116 * <ul> 117 * <li>{@code B} is the size, in bytes, of the string encoded using the provided charset 118 * (e.g. {@code str.getBytes(charset).length});</li> 119 * <li>{@code N} is the size (in bytes) of the terminator char according to the provided charset. For instance, 120 * this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.</li> 121 * </ul> 122 */ 123 @ForceInline 124 default MemorySegment allocateFrom(String str, Charset charset) { 125 Objects.requireNonNull(charset); 126 Objects.requireNonNull(str); 127 int termCharSize = StringSupport.CharsetKind.of(charset).terminatorCharSize(); 128 byte[] bytes = str.getBytes(charset); 129 MemorySegment segment = allocateNoInit(bytes.length + termCharSize); 130 MemorySegment.copy(bytes, 0, segment, ValueLayout.JAVA_BYTE, 0, bytes.length); 131 for (int i = 0 ; i < termCharSize ; i++) { 132 segment.set(ValueLayout.JAVA_BYTE, bytes.length + i, (byte)0); 133 } 134 return segment; 135 } 136 137 /** 138 * {@return a new memory segment initialized with the provided {@code byte} {@code value} as 139 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 140 * 141 * @implSpec The default implementation is equivalent to: 142 * {@snippet lang=java : 143 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 144 * seg.set(layout, 0, value); 145 * return seg; 146 * } 147 * 148 * @param layout the layout of the block of memory to be allocated. 149 * @param value the value to be set in the newly allocated memory segment. 150 */ 151 default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) { 152 Objects.requireNonNull(layout); 153 MemorySegment seg = allocateNoInit(layout); 154 seg.set(layout, 0, value); 155 return seg; 156 } 157 158 /** 159 * {@return a new memory segment initialized with the provided {@code char} {@code value} as 160 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 161 * 162 * @implSpec The default implementation is equivalent to: 163 * {@snippet lang=java : 164 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 165 * seg.set(layout, 0, value); 166 * return seg; 167 * } 168 * 169 * @param layout the layout of the block of memory to be allocated. 170 * @param value the value to be set in the newly allocated memory segment. 171 */ 172 default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) { 173 Objects.requireNonNull(layout); 174 MemorySegment seg = allocateNoInit(layout); 175 seg.set(layout, 0, value); 176 return seg; 177 } 178 179 /** 180 * {@return a new memory segment initialized with the provided {@code short} {@code value} as 181 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 182 * 183 * @implSpec The default implementation is equivalent to: 184 * {@snippet lang=java : 185 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 186 * seg.set(layout, 0, value); 187 * return seg; 188 * } 189 * 190 * @param layout the layout of the block of memory to be allocated. 191 * @param value the value to be set in the newly allocated memory segment. 192 */ 193 default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) { 194 Objects.requireNonNull(layout); 195 MemorySegment seg = allocateNoInit(layout); 196 seg.set(layout, 0, value); 197 return seg; 198 } 199 200 /** 201 * {@return a new memory segment initialized with the provided {@code int} {@code value} as 202 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 203 * 204 * @implSpec The default implementation is equivalent to: 205 * {@snippet lang=java : 206 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 207 * seg.set(layout, 0, value); 208 * return seg; 209 * } 210 * 211 * @param layout the layout of the block of memory to be allocated. 212 * @param value the value to be set in the newly allocated memory segment. 213 */ 214 default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) { 215 Objects.requireNonNull(layout); 216 MemorySegment seg = allocateNoInit(layout); 217 seg.set(layout, 0, value); 218 return seg; 219 } 220 221 /** 222 * {@return a new memory segment initialized with the provided {@code float} {@code value} as 223 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 224 * 225 * @implSpec The default implementation is equivalent to: 226 * {@snippet lang=java : 227 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 228 * seg.set(layout, 0, value); 229 * return seg; 230 * } 231 * 232 * @param layout the layout of the block of memory to be allocated. 233 * @param value the value to be set in the newly allocated memory segment. 234 */ 235 default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) { 236 Objects.requireNonNull(layout); 237 MemorySegment seg = allocateNoInit(layout); 238 seg.set(layout, 0, value); 239 return seg; 240 } 241 242 /** 243 * {@return a new memory segment initialized with the provided {@code long} {@code value} as 244 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 245 * 246 * @implSpec The default implementation is equivalent to: 247 * {@snippet lang=java : 248 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 249 * seg.set(layout, 0, value); 250 * return seg; 251 * } 252 * 253 * @param layout the layout of the block of memory to be allocated. 254 * @param value the value to be set in the newly allocated memory segment. 255 */ 256 default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) { 257 Objects.requireNonNull(layout); 258 MemorySegment seg = allocateNoInit(layout); 259 seg.set(layout, 0, value); 260 return seg; 261 } 262 263 /** 264 * {@return a new memory segment initialized with the provided {@code double} {@code value} as 265 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 266 * 267 * @implSpec The default implementation is equivalent to: 268 * {@snippet lang=java : 269 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 270 * seg.set(layout, 0, value); 271 * return seg; 272 * } 273 * 274 * @param layout the layout of the block of memory to be allocated. 275 * @param value the value to be set in the newly allocated memory segment. 276 */ 277 default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) { 278 Objects.requireNonNull(layout); 279 MemorySegment seg = allocateNoInit(layout); 280 seg.set(layout, 0, value); 281 return seg; 282 } 283 284 /** 285 * {@return a new memory segment initialized with the address of the provided {@code value} as 286 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 287 * <p> 288 * The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}). 289 * 290 * @implSpec The default implementation is equivalent to: 291 * {@snippet lang=java : 292 * Objects.requireNonNull(value); 293 * MemorySegment seg = allocate(Objects.requireNonNull(layout)); 294 * seg.set(layout, 0, value); 295 * return seg; 296 * } 297 * 298 * @param layout the layout of the block of memory to be allocated. 299 * @param value the value to be set in the newly allocated memory segment. 300 */ 301 default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { 302 Objects.requireNonNull(value); 303 Objects.requireNonNull(layout); 304 MemorySegment segment = allocateNoInit(layout); 305 segment.set(layout, 0, value); 306 return segment; 307 } 308 309 /** 310 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 311 * {@code elementCount*elementLayout.byteSize()} initialized with the contents of the provided {@code source} segment 312 * as specified by the provided {@code elementLayout} (i.e. byte ordering, alignment and size)} 313 * 314 * @implSpec the default implementation for this method is equivalent to the following code: 315 * {@snippet lang = java: 316 * MemorySegment dest = this.allocate(elementLayout, elementCount); 317 * MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount); 318 * return dest; 319 * } 320 * @param elementLayout the element layout of the allocated array. 321 * @param source the source segment. 322 * @param sourceElementLayout the element layout of the source segment. 323 * @param sourceOffset the starting offset, in bytes, of the source segment. 324 * @param elementCount the number of elements in the source segment to be copied. 325 * @throws IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()}. 326 * @throws IllegalArgumentException if the source segment/offset are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> 327 * in the source element layout. 328 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 329 * @throws IllegalArgumentException if {@code sourceElementLayout.byteAlignment() > sourceElementLayout.byteSize()}. 330 * @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated with {@code source} is not 331 * {@linkplain MemorySegment.Scope#isAlive() alive}. 332 * @throws WrongThreadException if this method is called from a thread {@code T}, 333 * such that {@code source.isAccessibleBy(T) == false}. 334 * @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows. 335 * @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}. 336 * @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0}. 337 */ 338 @ForceInline 339 default MemorySegment allocateFrom(ValueLayout elementLayout, MemorySegment source, 340 ValueLayout sourceElementLayout, long sourceOffset, long elementCount) { 341 Objects.requireNonNull(source); 342 Objects.requireNonNull(sourceElementLayout); 343 Objects.requireNonNull(elementLayout); 344 MemorySegment dest = allocateNoInit(elementLayout, elementCount); 345 MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount); 346 return dest; 347 } 348 349 /** 350 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 351 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code byte} {@code elements} as 352 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 353 * 354 * @implSpec the default implementation for this method is equivalent to the following code: 355 * {@snippet lang = java: 356 * this.allocateFrom(layout, MemorySegment.ofArray(array), 357 * ValueLayout.JAVA_BYTE, 0, array.length) 358 *} 359 * @param elementLayout the element layout of the array to be allocated. 360 * @param elements the byte elements to be copied to the newly allocated memory block. 361 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 362 */ 363 @ForceInline 364 default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... elements) { 365 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 366 ValueLayout.JAVA_BYTE, 0, elements.length); 367 } 368 369 /** 370 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 371 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code short} {@code elements} as 372 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 373 * 374 * @implSpec the default implementation for this method is equivalent to the following code: 375 * {@snippet lang = java: 376 * this.allocateFrom(layout, MemorySegment.ofArray(array), 377 * ValueLayout.JAVA_SHORT, 0, array.length) 378 *} 379 * @param elementLayout the element layout of the array to be allocated. 380 * @param elements the short elements to be copied to the newly allocated memory block. 381 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 382 */ 383 @ForceInline 384 default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... elements) { 385 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 386 ValueLayout.JAVA_SHORT, 0, elements.length); 387 } 388 389 /** 390 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 391 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code char} {@code elements} as 392 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 393 * 394 * @implSpec the default implementation for this method is equivalent to the following code: 395 * {@snippet lang = java: 396 * this.allocateFrom(layout, MemorySegment.ofArray(array), 397 * ValueLayout.JAVA_CHAR, 0, array.length) 398 *} 399 * @param elementLayout the element layout of the array to be allocated. 400 * @param elements the char elements to be copied to the newly allocated memory block. 401 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 402 */ 403 @ForceInline 404 default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... elements) { 405 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 406 ValueLayout.JAVA_CHAR, 0, elements.length); 407 } 408 409 /** 410 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 411 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code int} {@code elements} as 412 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 413 * 414 * @implSpec the default implementation for this method is equivalent to the following code: 415 * {@snippet lang = java: 416 * this.allocateFrom(layout, MemorySegment.ofArray(array), 417 * ValueLayout.JAVA_INT, 0, array.length) 418 *} 419 * @param elementLayout the element layout of the array to be allocated. 420 * @param elements the int elements to be copied to the newly allocated memory block. 421 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 422 */ 423 @ForceInline 424 default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... elements) { 425 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 426 ValueLayout.JAVA_INT, 0, elements.length); 427 } 428 429 /** 430 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 431 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code float} {@code elements} as 432 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 433 * 434 * @implSpec the default implementation for this method is equivalent to the following code: 435 * {@snippet lang = java: 436 * this.allocateFrom(layout, MemorySegment.ofArray(array), 437 * ValueLayout.JAVA_FLOAT, 0, array.length) 438 *} 439 * @param elementLayout the element layout of the array to be allocated. 440 * @param elements the float elements to be copied to the newly allocated memory block. 441 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 442 */ 443 @ForceInline 444 default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... elements) { 445 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 446 ValueLayout.JAVA_FLOAT, 0, elements.length); 447 } 448 449 /** 450 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 451 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code long} {@code elements} as 452 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 453 * 454 * @implSpec the default implementation for this method is equivalent to the following code: 455 * {@snippet lang = java: 456 * this.allocateFrom(layout, MemorySegment.ofArray(array), 457 * ValueLayout.JAVA_LONG, 0, array.length) 458 *} 459 * @param elementLayout the element layout of the array to be allocated. 460 * @param elements the long elements to be copied to the newly allocated memory block. 461 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 462 */ 463 @ForceInline 464 default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... elements) { 465 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 466 ValueLayout.JAVA_LONG, 0, elements.length); 467 } 468 469 /** 470 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of 471 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code double} {@code elements} as 472 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)} 473 * 474 * @implSpec the default implementation for this method is equivalent to the following code: 475 * {@snippet lang = java: 476 * this.allocateFrom(layout, MemorySegment.ofArray(array), 477 * ValueLayout.JAVA_DOUBLE, 0, array.length) 478 *} 479 * @param elementLayout the element layout of the array to be allocated. 480 * @param elements the double elements to be copied to the newly allocated memory block. 481 * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}. 482 */ 483 @ForceInline 484 default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... elements) { 485 return allocateFrom(elementLayout, MemorySegment.ofArray(elements), 486 ValueLayout.JAVA_DOUBLE, 0, elements.length); 487 } 488 489 /** 490 * {@return a new memory segment with the given layout} 491 * 492 * @implSpec The default implementation for this method calls 493 * {@code this.allocate(layout.byteSize(), layout.byteAlignment())}. 494 * 495 * @param layout the layout of the block of memory to be allocated. 496 */ 497 default MemorySegment allocate(MemoryLayout layout) { 498 Objects.requireNonNull(layout); 499 return allocate(layout.byteSize(), layout.byteAlignment()); 500 } 501 502 /** 503 * {@return a new memory segment with the given {@code elementLayout} and {@code count}} 504 * 505 * @implSpec The default implementation for this method calls 506 * {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}. 507 * 508 * @param elementLayout the array element layout. 509 * @param count the array element count. 510 * @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows. 511 * @throws IllegalArgumentException if {@code count < 0}. 512 */ 513 default MemorySegment allocate(MemoryLayout elementLayout, long count) { 514 Objects.requireNonNull(elementLayout); 515 if (count < 0) { 516 throw new IllegalArgumentException("Negative array size"); 517 } 518 return allocate(MemoryLayout.sequenceLayout(count, elementLayout)); 519 } 520 521 /** 522 * {@return a new memory segment with the given {@code byteSize}} 523 * 524 * @implSpec The default implementation for this method calls 525 * {@code this.allocate(byteSize, 1)}. 526 * 527 * @param byteSize the size (in bytes) of the block of memory to be allocated. 528 * @throws IllegalArgumentException if {@code byteSize < 0} 529 */ 530 default MemorySegment allocate(long byteSize) { 531 return allocate(byteSize, 1); 532 } 533 534 /** 535 * {@return a new memory segment with the given {@code byteSize} and {@code byteAlignment}} 536 * 537 * @param byteSize the size (in bytes) of the block of memory to be allocated. 538 * @param byteAlignment the alignment (in bytes) of the block of memory to be allocated. 539 * @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0}, 540 * or if {@code byteAlignment} is not a power of 2. 541 */ 542 MemorySegment allocate(long byteSize, long byteAlignment); 543 544 /** 545 * Returns a segment allocator which responds to allocation requests by returning consecutive slices 546 * obtained from the provided segment. Each new allocation request will return a new slice starting at the 547 * current offset (modulo additional padding to satisfy alignment constraint), with given size. 548 * <p> 549 * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided 550 * segment with the requested size and alignment cannot be found. 551 * 552 * @implNote A slicing allocator is not <em>thread-safe</em>. 553 * 554 * @param segment the segment which the returned allocator should slice from. 555 * @return a new slicing allocator 556 */ 557 static SegmentAllocator slicingAllocator(MemorySegment segment) { 558 Objects.requireNonNull(segment); 559 return new SlicingAllocator(segment); 560 } 561 562 /** 563 * Returns a segment allocator which responds to allocation requests by recycling a single segment. Each 564 * new allocation request will return a new slice starting at the segment offset {@code 0}, hence the name 565 * <em>prefix allocator</em>. 566 * Equivalent to (but likely more efficient than) the following code: 567 * {@snippet lang=java : 568 * MemorySegment segment = ... 569 * SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align); 570 * } 571 * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided 572 * segment with the requested size and alignment cannot be found. 573 * 574 * @apiNote A prefix allocator can be useful to limit allocation requests in case a client 575 * knows that they have fully processed the contents of the allocated segment before the subsequent allocation request 576 * takes place. 577 * @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on the same recycling 578 * allocator might cause a thread to overwrite contents written to the underlying segment by a different thread. 579 * 580 * @param segment the memory segment to be recycled by the returned allocator. 581 * @return an allocator which recycles an existing segment upon each new allocation request. 582 */ 583 static SegmentAllocator prefixAllocator(MemorySegment segment) { 584 return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment); 585 } 586 587 @ForceInline 588 private MemorySegment allocateNoInit(long byteSize) { 589 return this instanceof ArenaImpl arenaImpl ? 590 arenaImpl.allocateNoInit(byteSize, 1) : 591 allocate(byteSize); 592 } 593 594 @ForceInline 595 private MemorySegment allocateNoInit(MemoryLayout layout) { 596 return this instanceof ArenaImpl arenaImpl ? 597 arenaImpl.allocateNoInit(layout.byteSize(), layout.byteAlignment()) : 598 allocate(layout); 599 } 600 601 @ForceInline 602 private MemorySegment allocateNoInit(MemoryLayout layout, long size) { 603 return this instanceof ArenaImpl arenaImpl ? 604 arenaImpl.allocateNoInit(layout.byteSize() * size, layout.byteAlignment()) : 605 allocate(layout, size); 606 } 607 }