Skip to content

Commit 54ec366

Browse files
author
duke
committedSep 24, 2021
Automatic merge of foreign-memaccess+abi into foreign-jextract
2 parents b3cfaca + 5ce4e30 commit 54ec366

File tree

12 files changed

+92
-39
lines changed

12 files changed

+92
-39
lines changed
 

‎src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ResourceScope.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
* Moreover, closing a resource scope might trigger the releasing of the underlying memory resources associated with said scope; for instance:
5353
* <ul>
5454
* <li>closing the scope associated with a native memory segment results in <em>freeing</em> the native memory associated with it
55-
* (see {@link MemorySegment#allocateNative(long, ResourceScope)}, or {@link SegmentAllocator#arenaAllocator(ResourceScope)})</li>
55+
* (see {@link MemorySegment#allocateNative(long, ResourceScope)}, or {@link SegmentAllocator#arenaUnbounded(ResourceScope)})</li>
5656
* <li>closing the scope associated with a mapped memory segment results in the backing memory-mapped file to be unmapped
5757
* (see {@link MemorySegment#mapFile(Path, long, long, FileChannel.MapMode, ResourceScope)})</li>
5858
* <li>closing the scope associated with an upcall stub results in releasing the stub

‎src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SegmentAllocator.java

+59-16
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
* (e.g. {@link MemorySegment#allocateNative(long, long, ResourceScope)}); since {@link SegmentAllocator} is a <em>functional interface</em>,
4444
* clients can easily obtain a native allocator by using either a lambda expression or a method reference.
4545
* <p>
46-
* This interface also defines factories for commonly used allocators; for instance {@link #arenaAllocator(ResourceScope)}
47-
* and {@link #arenaAllocator(long, ResourceScope)} are arena-style native allocators. Finally {@link #prefixAllocator(MemorySegment)}
46+
* This interface also defines factories for commonly used allocators; for instance {@link #arenaUnbounded(ResourceScope)}
47+
* and {@link #arenaBounded(long, ResourceScope)} are arena-style native allocators. Finally {@link #prefixAllocator(MemorySegment)}
4848
* returns an allocator which wraps a segment (either on-heap or off-heap) and recycles its content upon each new allocation request.
4949
*/
5050
@FunctionalInterface
@@ -319,8 +319,8 @@ default MemorySegment allocate(long bytesSize) {
319319
MemorySegment allocate(long bytesSize, long bytesAlignment);
320320

321321
/**
322-
* Returns a native arena-based allocator which allocates a single memory segment, of given size (using malloc),
323-
* and then responds to allocation request by returning different slices of that same segment
322+
* Returns a native arena-based allocator which {@linkplain MemorySegment#allocateNative(long, ResourceScope) allocates}
323+
* a single memory segment, of given size, and then responds to allocation request by returning different slices of that same segment
324324
* (until no further allocation is possible).
325325
* This can be useful when clients want to perform multiple allocation requests while avoiding the cost associated
326326
* with allocating a new off-heap memory region upon each allocation request.
@@ -333,32 +333,70 @@ default MemorySegment allocate(long bytesSize) {
333333
* the allocator capacity.
334334
*
335335
* @param size the size (in bytes) of the allocation arena.
336-
* @param scope the scope associated with the segments returned by this allocator.
336+
* @param scope the scope associated with the segments returned by the arena-based allocator.
337337
* @return a new bounded arena-based allocator
338338
* @throws IllegalArgumentException if {@code size <= 0}.
339339
* @throws IllegalStateException if {@code scope} has been already closed, or if access occurs from a thread other
340340
* than the thread owning {@code scope}.
341341
*/
342-
static SegmentAllocator arenaAllocator(long size, ResourceScope scope) {
342+
static SegmentAllocator arenaBounded(long size, ResourceScope scope) {
343343
Objects.requireNonNull(scope);
344344
return scope.ownerThread() == null ?
345345
new ArenaAllocator.BoundedSharedArenaAllocator(scope, size) :
346346
new ArenaAllocator.BoundedArenaAllocator(scope, size);
347347
}
348348

349349
/**
350-
* Returns a native unbounded arena-based allocator.
350+
* Returns a native unbounded arena-based allocator, with predefined block size.
351351
* <p>
352-
* The returned allocator allocates a memory segment {@code S} of a certain fixed size (using malloc) and then
353-
* responds to allocation requests in one of the following ways:
352+
* The returned allocator {@linkplain MemorySegment#allocateNative(long, ResourceScope) allocates} a memory segment
353+
* {@code S} of a certain (fixed) block size and then responds to allocation requests in one of the following ways:
354354
* <ul>
355355
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has a <em>free</em>
356356
* slice {@code S'} which fits that allocation request, return that {@code S'}.
357357
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has no <em>free</em>
358-
* slices which fits that allocation request, allocate a new segment {@code S'} (using malloc), which has same size as {@code S}
358+
* slices which fits that allocation request, allocate a new segment {@code S'}, which has same size as {@code S}
359359
* and set {@code S = S'}; the allocator then tries to respond to the same allocation request again.
360-
* <li>if the size of the allocation requests is bigger than the size of {@code S}, allocate a new segment {@code S'}
361-
* (using malloc), which has a sufficient size to satisfy the allocation request, and return {@code S'}.
360+
* <li>if the size of the allocation requests is bigger than the size of {@code S}, allocate a new segment {@code S'},
361+
* which has a sufficient size to satisfy the allocation request, and return {@code S'}.
362+
* </ul>
363+
* <p>
364+
* The block size of the returned arena-based allocator is unspecified, can be platform-dependent, and should generally
365+
* not be relied upon. Clients can {@linkplain #arenaUnbounded(long, ResourceScope) obtain} an unbounded arena-based allocator
366+
* with specific block size, if they so wish.
367+
* <p>
368+
* This segment allocator can be useful when clients want to perform multiple allocation requests while avoiding the
369+
* cost associated with allocating a new off-heap memory region upon each allocation request.
370+
* <p>
371+
* An allocator associated with a <em>shared</em> resource scope is thread-safe and allocation requests may be
372+
* performed concurrently; conversely, if the arena allocator is associated with a <em>confined</em> resource scope,
373+
* allocation requests can only occur from the thread owning the allocator's resource scope.
374+
* <p>
375+
* The returned allocator might throw an {@link OutOfMemoryError} if an incoming allocation request exceeds
376+
* the system capacity.
377+
*
378+
* @param scope the scope associated with the segments returned by the arena-based allocator.
379+
* @return a new unbounded arena-based allocator
380+
* @throws IllegalStateException if {@code scope} has been already closed, or if access occurs from a thread other
381+
* than the thread owning {@code scope}.
382+
*/
383+
static SegmentAllocator arenaUnbounded(ResourceScope scope) {
384+
return arenaUnbounded(ArenaAllocator.DEFAULT_BLOCK_SIZE, scope);
385+
}
386+
387+
/**
388+
* Returns a native unbounded arena-based allocator, with given block size.
389+
* <p>
390+
* The returned allocator {@linkplain MemorySegment#allocateNative(long, ResourceScope) allocates} a memory segment
391+
* {@code S} of the specified block size and then responds to allocation requests in one of the following ways:
392+
* <ul>
393+
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has a <em>free</em>
394+
* slice {@code S'} which fits that allocation request, return that {@code S'}.
395+
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has no <em>free</em>
396+
* slices which fits that allocation request, allocate a new segment {@code S'}, which has same size as {@code S}
397+
* and set {@code S = S'}; the allocator then tries to respond to the same allocation request again.
398+
* <li>if the size of the allocation requests is bigger than the size of {@code S}, allocate a new segment {@code S'},
399+
* which has a sufficient size to satisfy the allocation request, and return {@code S'}.
362400
* </ul>
363401
* <p>
364402
* This segment allocator can be useful when clients want to perform multiple allocation requests while avoiding the
@@ -371,16 +409,21 @@ static SegmentAllocator arenaAllocator(long size, ResourceScope scope) {
371409
* The returned allocator might throw an {@link OutOfMemoryError} if an incoming allocation request exceeds
372410
* the system capacity.
373411
*
374-
* @param scope the scope associated with the segments returned by this allocator.
412+
* @param blockSize the block size associated with the arena-based allocator.
413+
* @param scope the scope associated with the segments returned by the arena-based allocator.
375414
* @return a new unbounded arena-based allocator
415+
* @throws IllegalArgumentException if {@code blockSize <= 0}.
376416
* @throws IllegalStateException if {@code scope} has been already closed, or if access occurs from a thread other
377417
* than the thread owning {@code scope}.
378418
*/
379-
static SegmentAllocator arenaAllocator(ResourceScope scope) {
419+
static SegmentAllocator arenaUnbounded(long blockSize, ResourceScope scope) {
380420
Objects.requireNonNull(scope);
421+
if (blockSize <= 0) {
422+
throw new IllegalArgumentException("Invalid block size: " + blockSize);
423+
}
381424
return scope.ownerThread() == null ?
382-
new ArenaAllocator.UnboundedSharedArenaAllocator(scope) :
383-
new ArenaAllocator.UnboundedArenaAllocator(scope);
425+
new ArenaAllocator.UnboundedSharedArenaAllocator(blockSize, scope) :
426+
new ArenaAllocator.UnboundedArenaAllocator(blockSize, scope);
384427
}
385428

386429
/**

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/ArenaAllocator.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
public abstract class ArenaAllocator implements SegmentAllocator {
3333

34+
public static final long DEFAULT_BLOCK_SIZE = 4 * 1024;
35+
3436
protected MemorySegment segment;
3537

3638
protected long sp = 0L;
@@ -64,10 +66,11 @@ ResourceScope scope() {
6466

6567
public static class UnboundedArenaAllocator extends ArenaAllocator {
6668

67-
private static final long DEFAULT_BLOCK_SIZE = 4 * 1024;
69+
final long blockSize;
6870

69-
public UnboundedArenaAllocator(ResourceScope scope) {
70-
super(MemorySegment.allocateNative(DEFAULT_BLOCK_SIZE, 1, scope));
71+
public UnboundedArenaAllocator(long blockSize, ResourceScope scope) {
72+
super(MemorySegment.allocateNative(blockSize, 1, scope));
73+
this.blockSize = blockSize;
7174
}
7275

7376
private MemorySegment newSegment(long size, long align) {
@@ -83,13 +86,13 @@ public MemorySegment allocate(long bytesSize, long bytesAlignment) {
8386
return slice;
8487
} else {
8588
long maxPossibleAllocationSize = bytesSize + bytesAlignment - 1;
86-
if (maxPossibleAllocationSize > DEFAULT_BLOCK_SIZE) {
89+
if (maxPossibleAllocationSize > blockSize) {
8790
// too big
8891
return newSegment(bytesSize, bytesAlignment);
8992
} else {
9093
// allocate a new segment and slice from there
9194
sp = 0L;
92-
segment = newSegment(DEFAULT_BLOCK_SIZE, 1L);
95+
segment = newSegment(blockSize, 1L);
9396
return trySlice(bytesSize, bytesAlignment);
9497
}
9598
}
@@ -129,16 +132,18 @@ public synchronized MemorySegment allocate(long bytesSize, long bytesAlignment)
129132
public static class UnboundedSharedArenaAllocator implements SegmentAllocator {
130133

131134
final ResourceScope scope;
135+
final long blockSize;
132136

133137
final ThreadLocal<ArenaAllocator> allocators = new ThreadLocal<>() {
134138
@Override
135139
protected ArenaAllocator initialValue() {
136-
return new UnboundedArenaAllocator(scope);
140+
return new UnboundedArenaAllocator(blockSize, scope);
137141
}
138142
};
139143

140-
public UnboundedSharedArenaAllocator(ResourceScope scope) {
144+
public UnboundedSharedArenaAllocator(long blockSize, ResourceScope scope) {
141145
this.scope = scope;
146+
this.blockSize = blockSize;
142147
}
143148

144149
@Override

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public void close() {
262262
*/
263263
public static Context ofBoundedAllocator(long size) {
264264
ResourceScope scope = ResourceScope.newConfinedScope();
265-
return new Context(SegmentAllocator.arenaAllocator(size, scope), scope);
265+
return new Context(SegmentAllocator.arenaBounded(size, scope), scope);
266266
}
267267

268268
/**

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64VaList.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ public VaList build() {
494494
return EMPTY;
495495
}
496496

497-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
497+
SegmentAllocator allocator = SegmentAllocator.arenaUnbounded(scope);
498498
MemorySegment vaListSegment = allocator.allocate(LAYOUT);
499499
MemoryAddress stackArgsPtr = MemoryAddress.NULL;
500500
if (!stackArgs.isEmpty()) {

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64VaList.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public VaList build() {
209209
return EMPTY;
210210
}
211211

212-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
212+
SegmentAllocator allocator = SegmentAllocator.arenaUnbounded(scope);
213213

214214
// Each argument may occupy up to four slots
215215
MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size() * 4);

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/SysVVaList.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ public VaList build() {
419419
return EMPTY;
420420
}
421421

422-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
422+
SegmentAllocator allocator = SegmentAllocator.arenaUnbounded(scope);
423423
MemorySegment vaListSegment = allocator.allocate(LAYOUT);
424424
MemoryAddress stackArgsPtr = MemoryAddress.NULL;
425425
if (!stackArgs.isEmpty()) {

‎src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/WinVaList.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public VaList build() {
207207
if (args.isEmpty()) {
208208
return EMPTY;
209209
}
210-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
210+
SegmentAllocator allocator = SegmentAllocator.arenaUnbounded(scope);
211211
MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size());
212212
List<MemorySegment> attachedSegments = new ArrayList<>();
213213
attachedSegments.add(segment);

‎test/jdk/java/foreign/NativeTestHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public NativeScope() {
6060
this.resourceScope = ResourceScope.newConfinedScope();
6161
this.privateScope = ResourceScope.newConfinedScope();
6262
privateScope.keepAlive(resourceScope);
63-
this.allocator = SegmentAllocator.arenaAllocator(resourceScope);
63+
this.allocator = SegmentAllocator.arenaUnbounded(resourceScope);
6464
}
6565

6666
@Override

‎test/jdk/java/foreign/TestScopedOperations.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedOperatio
121121
}, "MemorySegment::mapFromFile");
122122
ScopedOperation.ofScope(scope -> VaList.make(b -> {}, scope), "VaList::make");
123123
ScopedOperation.ofScope(scope -> VaList.ofAddress(MemoryAddress.ofLong(42), scope), "VaList::make");
124-
ScopedOperation.ofScope(SegmentAllocator::arenaAllocator, "SegmentAllocator::arenaAllocator");
124+
ScopedOperation.ofScope(SegmentAllocator::arenaUnbounded, "SegmentAllocator::arenaAllocator");
125125
// segment operations
126126
ScopedOperation.ofSegment(s -> s.toArray(JAVA_BYTE), "MemorySegment::toArray(BYTE)");
127127
ScopedOperation.ofSegment(MemorySegment::address, "MemorySegment::address");
@@ -238,8 +238,8 @@ enum SegmentFactory {
238238
}
239239

240240
enum AllocatorFactory {
241-
ARENA_BOUNDED(scope -> SegmentAllocator.arenaAllocator(1000, scope)),
242-
ARENA_UNBOUNDED(SegmentAllocator::arenaAllocator),
241+
ARENA_BOUNDED(scope -> SegmentAllocator.arenaBounded(1000, scope)),
242+
ARENA_UNBOUNDED(SegmentAllocator::arenaUnbounded),
243243
FROM_SEGMENT(scope -> {
244244
MemorySegment segment = MemorySegment.allocateNative(10, scope);
245245
return SegmentAllocator.prefixAllocator(segment);

‎test/jdk/java/foreign/TestSegmentAllocators.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public <Z, L extends ValueLayout> void testAllocation(Z value, AllocationFactory
103103
@Test
104104
public void testBigAllocationInUnboundedScope() {
105105
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
106-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
106+
SegmentAllocator allocator = SegmentAllocator.arenaUnbounded(scope);
107107
for (int i = 8 ; i < SIZE_256M ; i *= 8) {
108108
MemorySegment address = allocator.allocate(i, i);
109109
//check size
@@ -117,19 +117,24 @@ public void testBigAllocationInUnboundedScope() {
117117
@Test(expectedExceptions = OutOfMemoryError.class)
118118
public void testTooBigForBoundedArena() {
119119
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
120-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(10, scope);
120+
SegmentAllocator allocator = SegmentAllocator.arenaBounded(10, scope);
121121
allocator.allocate(12);
122122
}
123123
}
124124

125125
@Test
126126
public void testBiggerThanBlockForBoundedArena() {
127127
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
128-
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(4 * 1024 * 2, scope);
128+
SegmentAllocator allocator = SegmentAllocator.arenaBounded(4 * 1024 * 2, scope);
129129
allocator.allocate(4 * 1024 + 1); // should be ok
130130
}
131131
}
132132

133+
@Test(expectedExceptions = IllegalArgumentException.class)
134+
public void testBadUnboundedArenaSize() {
135+
SegmentAllocator.arenaUnbounded(-1, ResourceScope.globalScope());
136+
}
137+
133138
@Test(dataProvider = "arrayScopes")
134139
public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) {
135140
Z arr = arrayHelper.array();
@@ -380,8 +385,8 @@ public boolean isBound() {
380385
return isBound;
381386
}
382387

383-
static AllocationFactory BOUNDED = new AllocationFactory(true, SegmentAllocator::arenaAllocator);
384-
static AllocationFactory UNBOUNDED = new AllocationFactory(false, (size, scope) -> SegmentAllocator.arenaAllocator(scope));
388+
static AllocationFactory BOUNDED = new AllocationFactory(true, SegmentAllocator::arenaBounded);
389+
static AllocationFactory UNBOUNDED = new AllocationFactory(false, (size, scope) -> SegmentAllocator.arenaUnbounded(scope));
385390
}
386391

387392
interface ToArrayHelper<T> {

‎test/micro/org/openjdk/bench/jdk/incubator/foreign/StrLenTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class StrLenTest extends CLayouts {
6060
ResourceScope scope = ResourceScope.newConfinedScope();
6161

6262
SegmentAllocator segmentAllocator;
63-
SegmentAllocator arenaAllocator = SegmentAllocator.arenaAllocator(scope);
63+
SegmentAllocator arenaAllocator = SegmentAllocator.arenaUnbounded(scope);
6464

6565
@Param({"5", "20", "100"})
6666
public int size;

0 commit comments

Comments
 (0)
Please sign in to comment.