Skip to content

Commit 4fa32dd

Browse files
authored
Merge pull request #13 from minborg/revert-factories
Revert MemorySegment factories
2 parents f54bfe3 + c7d09ad commit 4fa32dd

File tree

57 files changed

+358
-348
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+358
-348
lines changed

src/java.base/share/classes/java/lang/foreign/MemorySegment.java

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
package java.lang.foreign;
2828

2929
import java.io.UncheckedIOException;
30+
import java.lang.ref.Cleaner;
3031
import java.lang.reflect.Array;
3132
import java.lang.invoke.MethodHandles;
3233
import java.nio.Buffer;
@@ -66,7 +67,7 @@
6667
* Heap segments can be obtained by calling one of the {@link MemorySegment#ofArray(int[])} factory methods.
6768
* These methods return a memory segment backed by the on-heap region that holds the specified Java array.
6869
* <p>
69-
* Native segments can be obtained by calling one of the {@link MemorySegment#allocateNative(long, long)}
70+
* Native segments can be obtained by calling one of the {@link MemorySegment#allocateNative(long, long, MemorySession)}
7071
* factory methods, which return a memory segment backed by a newly allocated off-heap region with the given size
7172
* and aligned to the given alignment constraint. Alternatively, native segments can be obtained by
7273
* {@link FileChannel#map(MapMode, long, long, MemorySession) mapping} a file into a new off-heap region
@@ -94,8 +95,8 @@
9495
* Every memory segment has a {@linkplain #byteSize() size}. The size of a heap segment is derived from the Java array
9596
* from which it is obtained. This size is predictable across Java runtimes.
9697
* The size of a native segment is either passed explicitly
97-
* (as in {@link MemorySegment#allocateNative(long)}) or derived from a {@link MemoryLayout}
98-
* (as in {@link MemorySegment#allocateNative(MemoryLayout)}). The size of a memory segment is typically
98+
* (as in {@link MemorySegment#allocateNative(long, MemorySession)}) or derived from a {@link MemoryLayout}
99+
* (as in {@link MemorySegment#allocateNative(MemoryLayout, MemorySession)}). The size of a memory segment is typically
99100
* a positive number but may be <a href="#wrapping-addresses">zero</a>, but never negative.
100101
* <p>
101102
* The address and size of a memory segment jointly ensure that access operations on the segment cannot fall
@@ -244,8 +245,8 @@
244245
* <p>
245246
* The alignment constraint used to access a segment is typically dictated by the shape of the data structure stored
246247
* in the segment. For example, if the programmer wishes to store a sequence of 8-byte values in a native segment, then
247-
* the segment should be allocated by specifying a 8-byte alignment constraint, either via {@link #allocateNative(long, long)}
248-
* or {@link #allocateNative(MemoryLayout)}. These factories ensure that the off-heap region of memory backing
248+
* the segment should be allocated by specifying a 8-byte alignment constraint, either via {@link #allocateNative(long, long, MemorySession)}
249+
* or {@link #allocateNative(MemoryLayout, MemorySession)}. These factories ensure that the off-heap region of memory backing
249250
* the returned segment has a starting address that is 8-byte aligned. Subsequently, the programmer can access the
250251
* segment at the offsets of interest -- 0, 8, 16, 24, etc -- in the knowledge that every such access is aligned.
251252
* <p>
@@ -509,7 +510,7 @@ default MemorySegment asSlice(long offset) {
509510

510511
/**
511512
* Returns {@code true} if this segment is a native segment. A native segment is
512-
* created e.g. using the {@link #allocateNative(long)} (and related) factory, or by
513+
* created e.g. using the {@link #allocateNative(long, MemorySession)} (and related) factory, or by
513514
* {@linkplain #ofBuffer(Buffer) wrapping} a {@linkplain ByteBuffer#allocateDirect(int) direct buffer}.
514515
* @return {@code true} if this segment is native segment.
515516
*/
@@ -1114,72 +1115,81 @@ static MemorySegment ofAddress(long address, long byteSize, MemorySession sessio
11141115
}
11151116

11161117
/**
1117-
* Creates a native segment with the given layout.
1118+
* Creates a native segment with the given layout and memory session.
1119+
* <p>
1120+
* Clients are responsible for ensuring that the memory session associated with the returned segment is
1121+
* closed when segments are no longer in use. Failure to do so will result in off-heap memory leaks. As an
1122+
* alternative to explicitly invoke {@link MemorySession#close()}, sessions backed with a {@link Cleaner}
1123+
* (such as {@linkplain MemorySession#openImplicit()}) can be used, allowing the returned segment to be
1124+
* automatically released some unspecified time after the session is no longer referenced.
11181125
* <p>
11191126
* The {@linkplain #address() address} of the returned memory segment is the starting address of
11201127
* the newly allocated off-heap region backing the segment. Moreover, the {@linkplain #address() address}
11211128
* of the returned segment will be aligned according to the alignment constraint of the provided layout.
11221129
* <p>
1123-
* The returned memory segment is associated with a new {@linkplain MemorySession#openImplicit implicit}
1124-
* memory session. As such, the off-heap region which backs the returned segment is
1125-
* freed <em>automatically</em>, some unspecified time after it is no longer referenced.
1126-
* <p>
1127-
* Native segments featuring deterministic deallocation can be obtained using the
1128-
* {@link MemorySession#allocate(MemoryLayout)} method.
1129-
* <p>
11301130
* This is equivalent to the following code:
11311131
* {@snippet lang=java :
1132-
* MemorySession.openImplicit()
1133-
* .allocate(layout.bytesSize(), layout.bytesAlignment());
1132+
* session.allocate(layout.bytesSize(), layout.bytesAlignment());
11341133
* }
11351134
* <p>
11361135
* The region of off-heap region backing the returned native segment is initialized to zero.
11371136
*
11381137
* @param layout the layout of the off-heap memory region backing the native segment.
1138+
* @param session the session to which the returned segment is associated.
11391139
* @return a new native segment.
1140+
* @throws IllegalStateException if the {@code session} is not {@linkplain MemorySession#isAlive() alive}.
1141+
* @throws WrongThreadException if this method is called from a thread other than the thread owning {@code session}.
11401142
* @see MemorySession#allocate(MemoryLayout)
11411143
*/
1142-
static MemorySegment allocateNative(MemoryLayout layout) {
1144+
static MemorySegment allocateNative(MemoryLayout layout, MemorySession session) {
11431145
Objects.requireNonNull(layout);
1144-
return allocateNative(layout.byteSize(), layout.byteAlignment());
1146+
return session.allocate(layout.byteSize(), layout.byteAlignment());
11451147
}
11461148

11471149
/**
1148-
* Creates a native segment with the given size (in bytes).
1150+
* Creates a native segment with the given size (in bytes) and memory session.
1151+
* <p>
1152+
* Clients are responsible for ensuring that the memory session associated with the returned segment is
1153+
* closed when segments are no longer in use. Failure to do so will result in off-heap memory leaks. As an
1154+
* alternative to explicitly invoke {@link MemorySession#close()}, sessions backed with a {@link Cleaner}
1155+
* (such as {@linkplain MemorySession#openImplicit()}) can be used, allowing the returned segment to be
1156+
* automatically released some unspecified time after the session is no longer referenced.
11491157
* <p>
11501158
* The {@linkplain #address() address} of the returned memory segment is the starting address of
11511159
* the newly allocated off-heap region backing the segment. Moreover, the {@linkplain #address() address}
11521160
* of the returned segment is guaranteed to be at least 1-byte aligned.
11531161
* <p>
1154-
* The returned memory segment is associated with a new {@linkplain MemorySession#openImplicit implicit}
1155-
* memory session. As such, the off-heap region which backs the returned segment is
1156-
* freed <em>automatically</em>, some unspecified time after it is no longer referenced.
1157-
* <p>
1158-
* Native segments featuring deterministic deallocation can be obtained using the
1159-
* {@link MemorySession#allocate(long)} method.
1160-
* <p>
11611162
* This is equivalent to the following code:
11621163
* {@snippet lang=java :
1163-
* MemorySession.openImplicit()
1164-
* .allocate(byteSize, 1)
1164+
* session.allocate(byteSize, 1);
11651165
* }
11661166
* <p>
11671167
* The region of off-heap region backing the returned native segment is initialized to zero.
11681168
* <p>
11691169
* This method corresponds to the {@link ByteBuffer#allocateDirect(int)} method and has similar behavior.
11701170
*
11711171
* @param byteSize the size (in bytes) of the off-heap memory region of memory backing the native memory segment.
1172+
* @param session the session to which the returned segment is associated.
11721173
* @return a new native memory segment.
11731174
* @throws IllegalArgumentException if {@code byteSize < 0}.
1175+
* @throws IllegalStateException if the {@code session} is not {@linkplain MemorySession#isAlive() alive}.
1176+
* @throws WrongThreadException if this method is called from a thread other than the thread owning {@code session}.
11741177
* @see ByteBuffer#allocateDirect(int)
11751178
* @see MemorySession#allocate(long)
11761179
*/
1177-
static MemorySegment allocateNative(long byteSize) {
1178-
return allocateNative(byteSize, 1L);
1180+
static MemorySegment allocateNative(long byteSize, MemorySession session) {
1181+
Utils.checkAllocationSizeAndAlign(byteSize, 1L);
1182+
return session.allocate(byteSize, 1L);
11791183
}
11801184

11811185
/**
1182-
* Creates a native segment with the given size (in bytes) and alignment (in bytes).
1186+
* Creates a native segment with the given size (in bytes), alignment (in bytes) and session.
1187+
* <p>
1188+
* Clients are responsible for ensuring that the memory session associated with the returned segment is
1189+
* closed when segments are no longer in use. Failure to do so will result in off-heap memory leaks. As an
1190+
* alternative to explicitly invoke {@link MemorySession#close()}, sessions backed with a {@link Cleaner}
1191+
* (such as {@linkplain MemorySession#openImplicit()}) can be used, allowing the returned segment to be
1192+
* automatically released some unspecified time after the session is no longer referenced.
11831193
* <p>
11841194
* The {@linkplain #address() address} of the returned memory segment is the starting address of
11851195
* the newly allocated off-heap region backing the segment. Moreover, the {@linkplain #address() address}
@@ -1189,28 +1199,26 @@ static MemorySegment allocateNative(long byteSize) {
11891199
* memory session. As such, the off-heap region which backs the returned segment is
11901200
* freed <em>automatically</em>, some unspecified time after it is no longer referenced.
11911201
* <p>
1192-
* Native segments featuring deterministic deallocation can be obtained using the
1193-
* {@link MemorySession#allocate(long,long)} method.
1194-
* <p>
11951202
* This is equivalent to the following code:
11961203
* {@snippet lang=java :
1197-
* MemorySession.openImplicit()
1198-
* .allocate(byteSize, byteAlignment)
1204+
* session.allocate(byteSize, byteAlignment);
11991205
* }
12001206
* <p>
12011207
* The region of off-heap region backing the returned native segment is initialized to zero.
12021208
*
12031209
* @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
12041210
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
1211+
* @param session the session to which the returned segment is associated.
12051212
* @return a new native memory segment.
12061213
* @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
1207-
* is not a power of 2.
1214+
* is not a power of 2.
1215+
* @throws IllegalStateException if the {@code session} is not {@linkplain MemorySession#isAlive() alive}.
1216+
* @throws WrongThreadException if this method is called from a thread other than the thread owning {@code session}.
12081217
* @see MemorySession#allocate(long, long)
12091218
*/
1210-
static MemorySegment allocateNative(long byteSize, long byteAlignment) {
1219+
static MemorySegment allocateNative(long byteSize, long byteAlignment, MemorySession session) {
12111220
Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment);
1212-
return MemorySession.openImplicit()
1213-
.allocate(byteSize, byteAlignment);
1221+
return session.allocate(byteSize, byteAlignment);
12141222
}
12151223

12161224
/**

src/java.base/share/classes/java/lang/foreign/MemorySession.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public sealed interface MemorySession extends AutoCloseable, SegmentAllocator pe
232232
* @throws IllegalStateException if this session is not {@linkplain MemorySession#isAlive() alive}.
233233
* @throws WrongThreadException if this method is called from a thread other than the thread
234234
* {@linkplain MemorySession#ownerThread() owning} this session.
235-
* @see MemorySegment#allocateNative(long, long)
235+
* @see MemorySegment#allocateNative(long, long, MemorySession)
236236
*/
237237
@Override
238238
default MemorySegment allocate(long byteSize, long byteAlignment) {

src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,16 @@ static SegmentAllocator prefixAllocator(MemorySegment segment) {
454454
* Returns an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
455455
* Equivalent to (but likely more efficient than) the following code:
456456
* {@snippet lang=java :
457-
* SegmentAllocator implicitAllocator = MemorySegment::allocateNative;
457+
* SegmentAllocator implicitAllocator = (byteSize, byteAlignment) ->
458+
* MemorySegment.allocateNative(byteSize, byteAlignment, MemorySession.openImplicit());
458459
* }
459460
*
460461
* @return an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
461462
*/
462463
static SegmentAllocator implicitAllocator() {
463464
final class Holder {
464-
static final SegmentAllocator IMPLICIT_ALLOCATOR = MemorySegment::allocateNative;
465+
static final SegmentAllocator IMPLICIT_ALLOCATOR = (byteSize, byteAlignment) -> MemorySession.openImplicit()
466+
.allocate(byteSize, byteAlignment);
465467
}
466468
return Holder.IMPLICIT_ALLOCATOR;
467469
}

src/java.base/share/classes/java/lang/foreign/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* and fill it with values ranging from {@code 0} to {@code 9}, we can use the following code:
4343
*
4444
* {@snippet lang=java :
45-
* MemorySegment segment = MemorySegment.allocateNative(10 * 4);
45+
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, MemorySession.openImplicit());
4646
* for (int i = 0 ; i < 10 ; i++) {
4747
* segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
4848
* }

test/jdk/java/foreign/CallGeneratorHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,11 @@ static void generateUpcallFunction(String fName, Ret ret, List<ParamType> params
378378
@SuppressWarnings("unchecked")
379379
static Object makeArg(MemoryLayout layout, List<Consumer<Object>> checks, boolean check) throws ReflectiveOperationException {
380380
if (layout instanceof GroupLayout) {
381-
MemorySegment segment = MemorySegment.allocateNative(layout);
381+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
382382
initStruct(segment, (GroupLayout)layout, checks, check);
383383
return segment;
384384
} else if (isPointer(layout)) {
385-
MemorySegment segment = MemorySegment.allocateNative(1L);
385+
MemorySegment segment = MemorySegment.allocateNative(1L, MemorySession.openImplicit());
386386
if (check) {
387387
checks.add(o -> {
388388
try {

test/jdk/java/foreign/TestAdaptVarHandles.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public class TestAdaptVarHandles {
9393
@Test
9494
public void testFilterValue() throws Throwable {
9595
ValueLayout layout = ValueLayout.JAVA_INT;
96-
MemorySegment segment = MemorySegment.allocateNative(layout);
96+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
9797
VarHandle intHandle = layout.varHandle();
9898
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, S2I, I2S);
9999
i2SHandle.set(segment, "1");
@@ -112,7 +112,7 @@ public void testFilterValue() throws Throwable {
112112
@Test
113113
public void testFilterValueComposite() throws Throwable {
114114
ValueLayout layout = ValueLayout.JAVA_INT;
115-
MemorySegment segment = MemorySegment.allocateNative(layout);
115+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
116116
VarHandle intHandle = layout.varHandle();
117117
MethodHandle CTX_S2I = MethodHandles.dropArguments(S2I, 0, String.class, String.class);
118118
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, CTX_S2I, CTX_I2S);
@@ -133,7 +133,7 @@ public void testFilterValueComposite() throws Throwable {
133133
@Test
134134
public void testFilterValueLoose() throws Throwable {
135135
ValueLayout layout = ValueLayout.JAVA_INT;
136-
MemorySegment segment = MemorySegment.allocateNative(layout);
136+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
137137
VarHandle intHandle = layout.varHandle();
138138
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, O2I, I2O);
139139
i2SHandle.set(segment, "1");
@@ -210,7 +210,7 @@ public void testBadFilterUnboxHandleException() {
210210
@Test
211211
public void testFilterCoordinates() throws Throwable {
212212
ValueLayout layout = ValueLayout.JAVA_INT;
213-
MemorySegment segment = MemorySegment.allocateNative(layout);
213+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
214214
VarHandle intHandle_longIndex = MethodHandles.filterCoordinates(intHandleIndexed, 0, BASE_ADDR, S2L);
215215
intHandle_longIndex.set(segment, "0", 1);
216216
int oldValue = (int)intHandle_longIndex.getAndAdd(segment, "0", 42);
@@ -253,7 +253,7 @@ public void testBadFilterCoordinatesTooManyFilters() {
253253
@Test
254254
public void testInsertCoordinates() throws Throwable {
255255
ValueLayout layout = ValueLayout.JAVA_INT;
256-
MemorySegment segment = MemorySegment.allocateNative(layout);
256+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
257257
VarHandle intHandle_longIndex = MethodHandles.insertCoordinates(intHandleIndexed, 0, segment, 0L);
258258
intHandle_longIndex.set(1);
259259
int oldValue = (int)intHandle_longIndex.getAndAdd(42);
@@ -291,7 +291,7 @@ public void testBadInsertCoordinatesTooManyValues() {
291291
@Test
292292
public void testPermuteCoordinates() throws Throwable {
293293
ValueLayout layout = ValueLayout.JAVA_INT;
294-
MemorySegment segment = MemorySegment.allocateNative(layout);
294+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
295295
VarHandle intHandle_swap = MethodHandles.permuteCoordinates(intHandleIndexed,
296296
List.of(long.class, MemorySegment.class), 1, 0);
297297
intHandle_swap.set(0L, segment, 1);
@@ -330,7 +330,7 @@ public void testBadPermuteCoordinatesIndexTooSmall() {
330330
@Test
331331
public void testCollectCoordinates() throws Throwable {
332332
ValueLayout layout = ValueLayout.JAVA_INT;
333-
MemorySegment segment = MemorySegment.allocateNative(layout);
333+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
334334
VarHandle intHandle_sum = MethodHandles.collectCoordinates(intHandleIndexed, 1, SUM_OFFSETS);
335335
intHandle_sum.set(segment, -2L, 2L, 1);
336336
int oldValue = (int)intHandle_sum.getAndAdd(segment, -2L, 2L, 42);
@@ -373,7 +373,7 @@ public void testBadCollectCoordinatesWrongFilterException() {
373373
@Test
374374
public void testDropCoordinates() throws Throwable {
375375
ValueLayout layout = ValueLayout.JAVA_INT;
376-
MemorySegment segment = MemorySegment.allocateNative(layout);
376+
MemorySegment segment = MemorySegment.allocateNative(layout, MemorySession.openImplicit());
377377
VarHandle intHandle_dummy = MethodHandles.dropCoordinates(intHandleIndexed, 1, float.class, String.class);
378378
intHandle_dummy.set(segment, 1f, "hello", 0L, 1);
379379
int oldValue = (int)intHandle_dummy.getAndAdd(segment, 1f, "hello", 0L, 42);

0 commit comments

Comments
 (0)