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.lang.invoke.VarHandle;
29 import java.lang.reflect.Array;
30 import java.nio.ByteOrder;
31 import java.nio.charset.StandardCharsets;
32 import java.util.Objects;
33 import java.util.function.Function;
34 import jdk.internal.foreign.AbstractMemorySegmentImpl;
35 import jdk.internal.foreign.SlicingAllocator;
36 import jdk.internal.foreign.Utils;
37 import jdk.internal.javac.PreviewFeature;
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 19
74 */
75 @FunctionalInterface
76 @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
77 public interface SegmentAllocator {
78
79 /**
80 * {@return a new memory segment with a Java string converted into a UTF-8 encoded, null-terminated C string}
81 * <p>
82 * This method always replaces malformed-input and unmappable-character
83 * sequences with this charset's default replacement byte array. The
84 * {@link java.nio.charset.CharsetEncoder} class should be used when more
85 * control over the encoding process is required.
86 * <p>
87 * If the given string contains any {@code '\0'} characters, they will be
88 * copied as well. This means that, depending on the method used to read
89 * the string, such as {@link MemorySegment#getUtf8String(long)}, the string
90 * will appear truncated when read again.
91 *
92 * @implSpec The default implementation for this method copies the contents of the provided Java string
93 * into a new memory segment obtained by calling {@code this.allocate(str.length() + 1)}.
94 * @param str the Java string to be converted into a C string.
95 */
96 default MemorySegment allocateUtf8String(String str) {
97 Objects.requireNonNull(str);
98 return Utils.toCString(str.getBytes(StandardCharsets.UTF_8), this);
99 }
100
101 /**
102 * {@return a new memory segment initialized with the provided {@code byte} {@code value} as
103 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
104 *
105 * @implSpec The default implementation is equivalent to:
106 * {@snippet lang=java :
107 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
108 * seg.set(layout, 0, value);
109 * return seg;
110 * }
111 *
112 * @param layout the layout of the block of memory to be allocated.
113 * @param value the value to be set in the newly allocated memory segment.
114 */
115 default MemorySegment allocate(ValueLayout.OfByte layout, byte value) {
116 Objects.requireNonNull(layout);
117 VarHandle handle = layout.varHandle();
118 MemorySegment seg = allocate(layout);
119 handle.set(seg, value);
120 return seg;
121 }
122
123 /**
124 * {@return a new memory segment initialized with the provided {@code char} {@code value} as
125 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
126 *
127 * @implSpec The default implementation is equivalent to:
128 * {@snippet lang=java :
129 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
130 * seg.set(layout, 0, value);
131 * return seg;
132 * }
133 *
134 * @param layout the layout of the block of memory to be allocated.
135 * @param value the value to be set in the newly allocated memory segment.
136 */
137 default MemorySegment allocate(ValueLayout.OfChar layout, char value) {
138 Objects.requireNonNull(layout);
139 VarHandle handle = layout.varHandle();
140 MemorySegment seg = allocate(layout);
141 handle.set(seg, value);
142 return seg;
143 }
144
145 /**
146 * {@return a new memory segment initialized with the provided {@code short} {@code value} as
147 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
148 *
149 * @implSpec The default implementation is equivalent to:
150 * {@snippet lang=java :
151 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
152 * seg.set(layout, 0, value);
153 * return seg;
154 * }
155 *
156 * @param layout the layout of the block of memory to be allocated.
157 * @param value the value to be set in the newly allocated memory segment.
158 */
159 default MemorySegment allocate(ValueLayout.OfShort layout, short value) {
160 Objects.requireNonNull(layout);
161 VarHandle handle = layout.varHandle();
162 MemorySegment seg = allocate(layout);
163 handle.set(seg, value);
164 return seg;
165 }
166
167 /**
168 * {@return a new memory segment initialized with the provided {@code int} {@code value} as
169 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
170 *
171 * @implSpec The default implementation is equivalent to:
172 * {@snippet lang=java :
173 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
174 * seg.set(layout, 0, value);
175 * return seg;
176 * }
177 *
178 * @param layout the layout of the block of memory to be allocated.
179 * @param value the value to be set in the newly allocated memory segment.
180 */
181 default MemorySegment allocate(ValueLayout.OfInt layout, int value) {
182 Objects.requireNonNull(layout);
183 VarHandle handle = layout.varHandle();
184 MemorySegment seg = allocate(layout);
185 handle.set(seg, value);
186 return seg;
187 }
188
189 /**
190 * {@return a new memory segment initialized with the provided {@code float} {@code value} as
191 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
192 *
193 * @implSpec The default implementation is equivalent to:
194 * {@snippet lang=java :
195 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
196 * seg.set(layout, 0, value);
197 * return seg;
198 * }
199 *
200 * @param layout the layout of the block of memory to be allocated.
201 * @param value the value to be set in the newly allocated memory segment.
202 */
203 default MemorySegment allocate(ValueLayout.OfFloat layout, float value) {
204 Objects.requireNonNull(layout);
205 VarHandle handle = layout.varHandle();
206 MemorySegment seg = allocate(layout);
207 handle.set(seg, value);
208 return seg;
209 }
210
211 /**
212 * {@return a new memory segment initialized with the provided {@code long} {@code value} as
213 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
214 *
215 * @implSpec The default implementation is equivalent to:
216 * {@snippet lang=java :
217 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
218 * seg.set(layout, 0, value);
219 * return seg;
220 * }
221 *
222 * @param layout the layout of the block of memory to be allocated.
223 * @param value the value to be set in the newly allocated memory segment.
224 */
225 default MemorySegment allocate(ValueLayout.OfLong layout, long value) {
226 Objects.requireNonNull(layout);
227 VarHandle handle = layout.varHandle();
228 MemorySegment seg = allocate(layout);
229 handle.set(seg, value);
230 return seg;
231 }
232
233 /**
234 * {@return a new memory segment initialized with the provided {@code double} {@code value} as
235 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
236 *
237 * @implSpec The default implementation is equivalent to:
238 * {@snippet lang=java :
239 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
240 * seg.set(layout, 0, value);
241 * return seg;
242 * }
243 *
244 * @param layout the layout of the block of memory to be allocated.
245 * @param value the value to be set in the newly allocated memory segment.
246 */
247 default MemorySegment allocate(ValueLayout.OfDouble layout, double value) {
248 Objects.requireNonNull(layout);
249 VarHandle handle = layout.varHandle();
250 MemorySegment seg = allocate(layout);
251 handle.set(seg, value);
252 return seg;
253 }
254
255 /**
256 * {@return a new memory segment initialized with the address of the provided {@code value} as
257 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
258 * <p>
259 * The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}).
260 *
261 * @implSpec The default implementation is equivalent to:
262 * {@snippet lang=java :
263 * Objects.requireNonNull(value);
264 * MemorySegment seg = allocate(Objects.requireNonNull(layout));
265 * seg.set(layout, 0, value);
266 * return seg;
267 * }
268 *
269 * @param layout the layout of the block of memory to be allocated.
270 * @param value the value to be set in the newly allocated memory segment.
271 */
272 default MemorySegment allocate(AddressLayout layout, MemorySegment value) {
273 Objects.requireNonNull(value);
274 Objects.requireNonNull(layout);
275 MemorySegment seg = allocate(layout);
276 layout.varHandle().set(seg, value);
277 return seg;
278 }
279
280 /**
281 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
282 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code byte} {@code elements} as
283 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
284 *
285 * @implSpec The default implementation is equivalent to:
286 * {@snippet lang=java :
287 * int size = Objects.requireNonNull(elements).length;
288 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
289 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
290 * return seg;
291 * }
292 *
293 * @param elementLayout the element layout of the array to be allocated.
294 * @param elements the short elements to be copied to the newly allocated memory block.
295 */
296 default MemorySegment allocateArray(ValueLayout.OfByte elementLayout, byte... elements) {
297 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
298 }
299
300 /**
301 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
302 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code short} {@code elements} as
303 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
304 *
305 * @implSpec The default implementation is equivalent to:
306 * {@snippet lang=java :
307 * int size = Objects.requireNonNull(elements).length;
308 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
309 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
310 * return seg;
311 * }
312 *
313 * @param elementLayout the element layout of the array to be allocated.
314 * @param elements the short elements to be copied to the newly allocated memory block.
315 */
316 default MemorySegment allocateArray(ValueLayout.OfShort elementLayout, short... elements) {
317 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
318 }
319
320 /**
321 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
322 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code char} {@code elements} as
323 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
324 *
325 * @implSpec The default implementation is equivalent to:
326 * {@snippet lang=java :
327 * int size = Objects.requireNonNull(elements).length;
328 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
329 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
330 * return seg;
331 * }
332 *
333 * @param elementLayout the element layout of the array to be allocated.
334 * @param elements the short elements to be copied to the newly allocated memory block.
335 */
336 default MemorySegment allocateArray(ValueLayout.OfChar elementLayout, char... elements) {
337 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
338 }
339
340 /**
341 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
342 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code int} {@code elements} as
343 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
344 *
345 * @implSpec The default implementation is equivalent to:
346 * {@snippet lang=java :
347 * int size = Objects.requireNonNull(elements).length;
348 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
349 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
350 * return seg;
351 * }
352 *
353 * @param elementLayout the element layout of the array to be allocated.
354 * @param elements the short elements to be copied to the newly allocated memory block.
355 */
356 default MemorySegment allocateArray(ValueLayout.OfInt elementLayout, int... elements) {
357 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
358 }
359
360 /**
361 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
362 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code float} {@code elements} as
363 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
364 *
365 * @implSpec The default implementation is equivalent to:
366 * {@snippet lang=java :
367 * int size = Objects.requireNonNull(elements).length;
368 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
369 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
370 * return seg;
371 * }
372 *
373 * @param elementLayout the element layout of the array to be allocated.
374 * @param elements the short elements to be copied to the newly allocated memory block.
375 */
376 default MemorySegment allocateArray(ValueLayout.OfFloat elementLayout, float... elements) {
377 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
378 }
379
380 /**
381 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
382 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code long} {@code elements} as
383 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
384 *
385 * @implSpec The default implementation is equivalent to:
386 * {@snippet lang=java :
387 * int size = Objects.requireNonNull(elements).length;
388 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
389 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
390 * return seg;
391 * }
392 *
393 * @param elementLayout the element layout of the array to be allocated.
394 * @param elements the short elements to be copied to the newly allocated memory block.
395 */
396 default MemorySegment allocateArray(ValueLayout.OfLong elementLayout, long... elements) {
397 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
398 }
399
400 /**
401 * {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
402 * {@code E*layout.byteSize()} initialized with the provided {@code E} {@code double} {@code elements} as
403 * specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
404 *
405 * @implSpec The default implementation is equivalent to:
406 * {@snippet lang=java :
407 * int size = Objects.requireNonNull(elements).length;
408 * MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
409 * MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
410 * return seg;
411 * }
412 *
413 * @param elementLayout the element layout of the array to be allocated.
414 * @param elements the short elements to be copied to the newly allocated memory block.
415 */
416 default MemorySegment allocateArray(ValueLayout.OfDouble elementLayout, double... elements) {
417 return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
418 }
419
420 private <Z> MemorySegment copyArrayWithSwapIfNeeded(Z array, ValueLayout elementLayout,
421 Function<Z, MemorySegment> heapSegmentFactory) {
422 int size = Array.getLength(Objects.requireNonNull(array));
423 MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
424 if (size > 0) {
425 MemorySegment.copy(heapSegmentFactory.apply(array), elementLayout, 0,
426 seg, elementLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
427 }
428 return seg;
429 }
430
431 /**
432 * {@return a new memory segment with the given layout}
433 *
434 * @implSpec The default implementation for this method calls
435 * {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
436 *
437 * @param layout the layout of the block of memory to be allocated.
438 */
439 default MemorySegment allocate(MemoryLayout layout) {
440 Objects.requireNonNull(layout);
441 return allocate(layout.byteSize(), layout.byteAlignment());
442 }
443
444 /**
445 * {@return a new memory segment with the given {@code elementLayout} and {@code count}}
446 *
447 * @implSpec The default implementation for this method calls
448 * {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
449 *
450 * @param elementLayout the array element layout.
451 * @param count the array element count.
452 * @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows.
453 * @throws IllegalArgumentException if {@code count < 0}.
454 */
455 default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
456 Objects.requireNonNull(elementLayout);
457 if (count < 0) {
458 throw new IllegalArgumentException("Negative array size");
459 }
460 return allocate(MemoryLayout.sequenceLayout(count, elementLayout));
461 }
462
463 /**
464 * {@return a new memory segment with the given {@code byteSize}}
465 *
466 * @implSpec The default implementation for this method calls
467 * {@code this.allocate(byteSize, 1)}.
468 *
469 * @param byteSize the size (in bytes) of the block of memory to be allocated.
470 * @throws IllegalArgumentException if {@code byteSize < 0}
471 */
472 default MemorySegment allocate(long byteSize) {
473 return allocate(byteSize, 1);
474 }
475
508 * Equivalent to (but likely more efficient than) the following code:
509 * {@snippet lang=java :
510 * MemorySegment segment = ...
511 * SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align);
512 * }
513 * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
514 * segment with the requested size and alignment cannot be found.
515 *
516 * @apiNote A prefix allocator can be useful to limit allocation requests in case a client
517 * knows that they have fully processed the contents of the allocated segment before the subsequent allocation request
518 * takes place.
519 * @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on the same recycling
520 * allocator might cause a thread to overwrite contents written to the underlying segment by a different thread.
521 *
522 * @param segment the memory segment to be recycled by the returned allocator.
523 * @return an allocator which recycles an existing segment upon each new allocation request.
524 */
525 static SegmentAllocator prefixAllocator(MemorySegment segment) {
526 return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment);
527 }
528 }
|
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
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 }
|