Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/foreign/TestByteBuffer.java
41144 views
1
/*
2
* Copyright (c) 2019, 2021, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @modules java.base/sun.nio.ch
27
* jdk.incubator.foreign/jdk.internal.foreign
28
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestByteBuffer
29
*/
30
31
import jdk.incubator.foreign.MemoryAccess;
32
import jdk.incubator.foreign.MemoryLayouts;
33
import jdk.incubator.foreign.MemoryLayout;
34
import jdk.incubator.foreign.MemoryAddress;
35
import jdk.incubator.foreign.MemorySegment;
36
import jdk.incubator.foreign.MemoryLayout.PathElement;
37
import jdk.incubator.foreign.ResourceScope;
38
import jdk.incubator.foreign.SequenceLayout;
39
40
import java.io.File;
41
import java.io.IOException;
42
import java.lang.invoke.MethodHandle;
43
import java.lang.invoke.MethodHandles;
44
import java.lang.invoke.VarHandle;
45
import java.lang.ref.Cleaner;
46
import java.lang.ref.WeakReference;
47
import java.lang.reflect.InvocationTargetException;
48
import java.lang.reflect.Method;
49
import java.lang.reflect.Modifier;
50
import java.net.URI;
51
import java.nio.Buffer;
52
import java.nio.ByteBuffer;
53
import java.nio.ByteOrder;
54
import java.nio.CharBuffer;
55
import java.nio.DoubleBuffer;
56
import java.nio.FloatBuffer;
57
import java.nio.IntBuffer;
58
import java.nio.LongBuffer;
59
import java.nio.MappedByteBuffer;
60
import java.nio.ShortBuffer;
61
import java.nio.channels.FileChannel;
62
import java.nio.file.Files;
63
import java.nio.file.Path;
64
import java.nio.file.StandardOpenOption;
65
import java.util.ArrayList;
66
import java.util.Arrays;
67
import java.util.HashMap;
68
import java.util.List;
69
import java.util.Map;
70
import java.util.function.BiConsumer;
71
import java.util.function.BiFunction;
72
import java.util.function.Consumer;
73
import java.util.function.Function;
74
import java.util.function.Predicate;
75
import java.util.function.Supplier;
76
import java.util.stream.Stream;
77
78
import jdk.internal.foreign.HeapMemorySegmentImpl;
79
import jdk.internal.foreign.MappedMemorySegmentImpl;
80
import jdk.internal.foreign.NativeMemorySegmentImpl;
81
import org.testng.SkipException;
82
import org.testng.annotations.*;
83
import sun.nio.ch.DirectBuffer;
84
85
import static org.testng.Assert.*;
86
87
public class TestByteBuffer {
88
89
static Path tempPath;
90
91
static {
92
try {
93
File file = File.createTempFile("buffer", "txt");
94
file.deleteOnExit();
95
tempPath = file.toPath();
96
Files.write(file.toPath(), new byte[256], StandardOpenOption.WRITE);
97
98
} catch (IOException ex) {
99
throw new ExceptionInInitializerError(ex);
100
}
101
}
102
103
static SequenceLayout tuples = MemoryLayout.sequenceLayout(500,
104
MemoryLayout.structLayout(
105
MemoryLayouts.BITS_32_BE.withName("index"),
106
MemoryLayouts.BITS_32_BE.withName("value")
107
));
108
109
static SequenceLayout bytes = MemoryLayout.sequenceLayout(100,
110
MemoryLayouts.BITS_8_BE
111
);
112
113
static SequenceLayout chars = MemoryLayout.sequenceLayout(100,
114
MemoryLayouts.BITS_16_BE
115
);
116
117
static SequenceLayout shorts = MemoryLayout.sequenceLayout(100,
118
MemoryLayouts.BITS_16_BE
119
);
120
121
static SequenceLayout ints = MemoryLayout.sequenceLayout(100,
122
MemoryLayouts.BITS_32_BE
123
);
124
125
static SequenceLayout floats = MemoryLayout.sequenceLayout(100,
126
MemoryLayouts.BITS_32_BE
127
);
128
129
static SequenceLayout longs = MemoryLayout.sequenceLayout(100,
130
MemoryLayouts.BITS_64_BE
131
);
132
133
static SequenceLayout doubles = MemoryLayout.sequenceLayout(100,
134
MemoryLayouts.BITS_64_BE
135
);
136
137
static VarHandle indexHandle = tuples.varHandle(int.class, PathElement.sequenceElement(), PathElement.groupElement("index"));
138
static VarHandle valueHandle = tuples.varHandle(float.class, PathElement.sequenceElement(), PathElement.groupElement("value"));
139
140
static void initTuples(MemorySegment base, long count) {
141
for (long i = 0; i < count ; i++) {
142
indexHandle.set(base, i, (int)i);
143
valueHandle.set(base, i, (float)(i / 500f));
144
}
145
}
146
147
static void checkTuples(MemorySegment base, ByteBuffer bb, long count) {
148
for (long i = 0; i < count ; i++) {
149
int index;
150
float value;
151
assertEquals(index = bb.getInt(), (int)indexHandle.get(base, i));
152
assertEquals(value = bb.getFloat(), (float)valueHandle.get(base, i));
153
assertEquals(value, index / 500f);
154
}
155
}
156
157
static void initBytes(MemorySegment base, SequenceLayout seq, BiConsumer<MemorySegment, Long> handleSetter) {
158
for (long i = 0; i < seq.elementCount().getAsLong() ; i++) {
159
handleSetter.accept(base, i);
160
}
161
}
162
163
static <Z extends Buffer> void checkBytes(MemorySegment base, SequenceLayout layout,
164
Function<ByteBuffer, Z> bufFactory,
165
BiFunction<MemorySegment, Long, Object> handleExtractor,
166
Function<Z, Object> bufferExtractor) {
167
long nelems = layout.elementCount().getAsLong();
168
long elemSize = layout.elementLayout().byteSize();
169
for (long i = 0 ; i < nelems ; i++) {
170
long limit = nelems - i;
171
MemorySegment resizedSegment = base.asSlice(i * elemSize, limit * elemSize);
172
ByteBuffer bb = resizedSegment.asByteBuffer();
173
Z z = bufFactory.apply(bb);
174
for (long j = i ; j < limit ; j++) {
175
Object handleValue = handleExtractor.apply(resizedSegment, j - i);
176
Object bufferValue = bufferExtractor.apply(z);
177
if (handleValue instanceof Number) {
178
assertEquals(((Number)handleValue).longValue(), j);
179
assertEquals(((Number)bufferValue).longValue(), j);
180
} else {
181
assertEquals((long)(char)handleValue, j);
182
assertEquals((long)(char)bufferValue, j);
183
}
184
}
185
}
186
}
187
188
@Test
189
public void testOffheap() {
190
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
191
MemorySegment segment = MemorySegment.allocateNative(tuples, scope);
192
initTuples(segment, tuples.elementCount().getAsLong());
193
194
ByteBuffer bb = segment.asByteBuffer();
195
checkTuples(segment, bb, tuples.elementCount().getAsLong());
196
}
197
}
198
199
@Test
200
public void testHeap() {
201
byte[] arr = new byte[(int) tuples.byteSize()];
202
MemorySegment region = MemorySegment.ofArray(arr);
203
initTuples(region, tuples.elementCount().getAsLong());
204
205
ByteBuffer bb = region.asByteBuffer();
206
checkTuples(region, bb, tuples.elementCount().getAsLong());
207
}
208
209
@Test
210
public void testChannel() throws Throwable {
211
File f = new File("test.out");
212
assertTrue(f.createNewFile());
213
f.deleteOnExit();
214
215
//write to channel
216
try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
217
withMappedBuffer(channel, FileChannel.MapMode.READ_WRITE, 0, tuples.byteSize(), mbb -> {
218
MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
219
initTuples(segment, tuples.elementCount().getAsLong());
220
mbb.force();
221
});
222
}
223
224
//read from channel
225
try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
226
withMappedBuffer(channel, FileChannel.MapMode.READ_ONLY, 0, tuples.byteSize(), mbb -> {
227
MemorySegment segment = MemorySegment.ofByteBuffer(mbb);
228
checkTuples(segment, mbb, tuples.elementCount().getAsLong());
229
});
230
}
231
}
232
233
@Test
234
public void testDefaultAccessModesMappedSegment() throws Throwable {
235
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
236
MemorySegment segment = MemorySegment.mapFile(tempPath, 0L, 8, FileChannel.MapMode.READ_WRITE, scope);
237
assertFalse(segment.isReadOnly());
238
}
239
240
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
241
MemorySegment segment = MemorySegment.mapFile(tempPath, 0L, 8, FileChannel.MapMode.READ_ONLY, scope);
242
assertTrue(segment.isReadOnly());
243
}
244
}
245
246
@Test
247
public void testMappedSegment() throws Throwable {
248
File f = new File("test2.out");
249
f.createNewFile();
250
f.deleteOnExit();
251
252
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
253
//write to channel
254
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, tuples.byteSize(), FileChannel.MapMode.READ_WRITE, scope);
255
initTuples(segment, tuples.elementCount().getAsLong());
256
segment.force();
257
}
258
259
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
260
//read from channel
261
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, tuples.byteSize(), FileChannel.MapMode.READ_ONLY, scope);
262
checkTuples(segment, segment.asByteBuffer(), tuples.elementCount().getAsLong());
263
}
264
}
265
266
@Test(dataProvider = "mappedOps", expectedExceptions = UnsupportedOperationException.class)
267
public void testMappedSegmentOperations(MappedSegmentOp mappedBufferOp) throws Throwable {
268
File f = new File("test3.out");
269
f.createNewFile();
270
f.deleteOnExit();
271
272
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, 8, FileChannel.MapMode.READ_WRITE, ResourceScope.newImplicitScope());
273
assertTrue(segment.isMapped());
274
segment.scope().close();
275
mappedBufferOp.apply(segment);
276
}
277
278
@Test
279
public void testMappedSegmentOffset() throws Throwable {
280
File f = new File("test3.out");
281
f.createNewFile();
282
f.deleteOnExit();
283
284
MemoryLayout tupleLayout = tuples.elementLayout();
285
286
// write one at a time
287
for (int i = 0 ; i < tuples.byteSize() ; i += tupleLayout.byteSize()) {
288
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
289
//write to channel
290
MemorySegment segment = MemorySegment.mapFile(f.toPath(), i, tuples.byteSize(), FileChannel.MapMode.READ_WRITE, scope);
291
initTuples(segment, 1);
292
segment.force();
293
}
294
}
295
296
// check one at a time
297
for (int i = 0 ; i < tuples.byteSize() ; i += tupleLayout.byteSize()) {
298
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
299
//read from channel
300
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, tuples.byteSize(), FileChannel.MapMode.READ_ONLY, scope);
301
checkTuples(segment, segment.asByteBuffer(), 1);
302
}
303
}
304
}
305
306
static final long LARGE_SIZE = 3L * 1024L * 1024L * 1024L; // 3GB
307
308
@Test
309
public void testLargeMappedSegment() throws Throwable {
310
if (System.getProperty("sun.arch.data.model").equals("32")) {
311
throw new SkipException("large mapped files not supported on 32-bit systems");
312
}
313
314
File f = new File("testLargeMappedSegment.out");
315
f.createNewFile();
316
f.deleteOnExit();
317
318
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
319
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0, LARGE_SIZE, FileChannel.MapMode.READ_WRITE, scope);
320
segment.isLoaded();
321
segment.load();
322
segment.isLoaded();
323
segment.force();
324
segment.isLoaded();
325
segment.unload();
326
segment.isLoaded();
327
}
328
}
329
330
static void withMappedBuffer(FileChannel channel, FileChannel.MapMode mode, long pos, long size, Consumer<MappedByteBuffer> action) throws Throwable {
331
MappedByteBuffer mbb = channel.map(mode, pos, size);
332
var ref = new WeakReference<>(mbb);
333
action.accept(mbb);
334
mbb = null;
335
//wait for it to be GCed
336
System.gc();
337
while (ref.get() != null) {
338
Thread.sleep(20);
339
}
340
}
341
342
static void checkByteArrayAlignment(MemoryLayout layout) {
343
if (layout.bitSize() > 32
344
&& System.getProperty("sun.arch.data.model").equals("32")) {
345
throw new SkipException("avoid unaligned access on 32-bit system");
346
}
347
}
348
349
@Test(dataProvider = "bufferOps")
350
public void testScopedBuffer(Function<ByteBuffer, Buffer> bufferFactory, @NoInjection Method method, Object[] args) {
351
Buffer bb;
352
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
353
MemorySegment segment = MemorySegment.allocateNative(bytes, scope);
354
bb = bufferFactory.apply(segment.asByteBuffer());
355
}
356
//outside of scope!!
357
try {
358
method.invoke(bb, args);
359
fail("Exception expected");
360
} catch (InvocationTargetException ex) {
361
Throwable cause = ex.getCause();
362
if (cause instanceof IllegalStateException) {
363
//all get/set buffer operation should fail because of the scope check
364
assertTrue(ex.getCause().getMessage().contains("Already closed"));
365
} else {
366
//all other exceptions were unexpected - fail
367
fail("Unexpected exception", cause);
368
}
369
} catch (Throwable ex) {
370
//unexpected exception - fail
371
fail("Unexpected exception", ex);
372
}
373
}
374
375
@Test(dataProvider = "bufferHandleOps")
376
public void testScopedBufferAndVarHandle(VarHandle bufferHandle) {
377
ByteBuffer bb;
378
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
379
MemorySegment segment = MemorySegment.allocateNative(bytes, scope);
380
bb = segment.asByteBuffer();
381
for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
382
MethodHandle handle = e.getKey().bindTo(bufferHandle)
383
.asSpreader(Object[].class, e.getValue().length);
384
try {
385
handle.invoke(e.getValue());
386
} catch (UnsupportedOperationException ex) {
387
//skip
388
} catch (Throwable ex) {
389
//should not fail - segment is alive!
390
fail();
391
}
392
}
393
}
394
for (Map.Entry<MethodHandle, Object[]> e : varHandleMembers(bb, bufferHandle).entrySet()) {
395
try {
396
MethodHandle handle = e.getKey().bindTo(bufferHandle)
397
.asSpreader(Object[].class, e.getValue().length);
398
handle.invoke(e.getValue());
399
fail();
400
} catch (IllegalStateException ex) {
401
assertTrue(ex.getMessage().contains("Already closed"));
402
} catch (UnsupportedOperationException ex) {
403
//skip
404
} catch (Throwable ex) {
405
fail();
406
}
407
}
408
}
409
410
@Test(dataProvider = "bufferOps")
411
public void testDirectBuffer(Function<ByteBuffer, Buffer> bufferFactory, @NoInjection Method method, Object[] args) {
412
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
413
MemorySegment segment = MemorySegment.allocateNative(bytes, scope);
414
Buffer bb = bufferFactory.apply(segment.asByteBuffer());
415
assertTrue(bb.isDirect());
416
DirectBuffer directBuffer = ((DirectBuffer)bb);
417
assertEquals(directBuffer.address(), segment.address().toRawLongValue());
418
assertTrue((directBuffer.attachment() == null) == (bb instanceof ByteBuffer));
419
assertTrue(directBuffer.cleaner() == null);
420
}
421
}
422
423
@Test(dataProvider="resizeOps")
424
public void testResizeOffheap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
425
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
426
MemorySegment segment = MemorySegment.allocateNative(seq, scope);
427
initializer.accept(segment);
428
checker.accept(segment);
429
}
430
}
431
432
@Test(dataProvider="resizeOps")
433
public void testResizeHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
434
checkByteArrayAlignment(seq.elementLayout());
435
int capacity = (int)seq.byteSize();
436
MemorySegment base = MemorySegment.ofArray(new byte[capacity]);
437
initializer.accept(base);
438
checker.accept(base);
439
}
440
441
@Test(dataProvider="resizeOps")
442
public void testResizeBuffer(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
443
checkByteArrayAlignment(seq.elementLayout());
444
int capacity = (int)seq.byteSize();
445
MemorySegment base = MemorySegment.ofByteBuffer(ByteBuffer.wrap(new byte[capacity]));
446
initializer.accept(base);
447
checker.accept(base);
448
}
449
450
@Test(dataProvider="resizeOps")
451
public void testResizeRoundtripHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
452
checkByteArrayAlignment(seq.elementLayout());
453
int capacity = (int)seq.byteSize();
454
byte[] arr = new byte[capacity];
455
MemorySegment segment = MemorySegment.ofArray(arr);
456
initializer.accept(segment);
457
MemorySegment second = MemorySegment.ofByteBuffer(segment.asByteBuffer());
458
checker.accept(second);
459
}
460
461
@Test(dataProvider="resizeOps")
462
public void testResizeRoundtripNative(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
463
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
464
MemorySegment segment = MemorySegment.allocateNative(seq, scope);
465
initializer.accept(segment);
466
MemorySegment second = MemorySegment.ofByteBuffer(segment.asByteBuffer());
467
checker.accept(second);
468
}
469
}
470
471
@Test(expectedExceptions = IllegalStateException.class)
472
public void testBufferOnClosedScope() {
473
MemorySegment leaked;
474
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
475
leaked = MemorySegment.allocateNative(bytes, scope);
476
}
477
ByteBuffer byteBuffer = leaked.asByteBuffer(); // ok
478
byteBuffer.get(); // should throw
479
}
480
481
@Test(expectedExceptions = IllegalStateException.class)
482
public void testTooBigForByteBuffer() {
483
MemorySegment segment = MemoryAddress.NULL.asSegment(Integer.MAX_VALUE + 10L, ResourceScope.globalScope());
484
segment.asByteBuffer();
485
}
486
487
@Test(expectedExceptions = IllegalArgumentException.class)
488
public void testBadMapNegativeSize() throws IOException {
489
File f = new File("testNeg1.out");
490
f.createNewFile();
491
f.deleteOnExit();
492
MemorySegment.mapFile(f.toPath(), 0L, -1, FileChannel.MapMode.READ_WRITE, ResourceScope.newImplicitScope());
493
}
494
495
@Test(expectedExceptions = IllegalArgumentException.class)
496
public void testBadMapNegativeOffset() throws IOException {
497
File f = new File("testNeg2.out");
498
f.createNewFile();
499
f.deleteOnExit();
500
MemorySegment.mapFile(f.toPath(), -1, 1, FileChannel.MapMode.READ_WRITE, ResourceScope.newImplicitScope());
501
}
502
503
@Test
504
public void testMapOffset() throws IOException {
505
File f = new File("testMapOffset.out");
506
f.createNewFile();
507
f.deleteOnExit();
508
509
int SIZE = Byte.MAX_VALUE;
510
511
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
512
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0, SIZE, FileChannel.MapMode.READ_WRITE, scope);
513
for (byte offset = 0; offset < SIZE; offset++) {
514
MemoryAccess.setByteAtOffset(segment, offset, offset);
515
}
516
segment.force();
517
}
518
519
for (int offset = 0 ; offset < SIZE ; offset++) {
520
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
521
MemorySegment segment = MemorySegment.mapFile(f.toPath(), offset, SIZE - offset, FileChannel.MapMode.READ_ONLY, scope);
522
assertEquals(MemoryAccess.getByte(segment), offset);
523
}
524
}
525
}
526
527
@Test
528
public void testMapZeroSize() throws IOException {
529
File f = new File("testPos1.out");
530
f.createNewFile();
531
f.deleteOnExit();
532
//RW
533
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
534
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, 0L, FileChannel.MapMode.READ_WRITE, scope);
535
assertEquals(segment.byteSize(), 0);
536
assertEquals(segment.isMapped(), true);
537
assertFalse(segment.isReadOnly());
538
segment.force();
539
segment.load();
540
segment.isLoaded();
541
segment.unload();
542
}
543
//RO
544
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
545
MemorySegment segment = MemorySegment.mapFile(f.toPath(), 0L, 0L, FileChannel.MapMode.READ_ONLY, scope);
546
assertEquals(segment.byteSize(), 0);
547
assertEquals(segment.isMapped(), true);
548
assertTrue(segment.isReadOnly());
549
segment.force();
550
segment.load();
551
segment.isLoaded();
552
segment.unload();
553
}
554
}
555
556
@Test(expectedExceptions = IllegalArgumentException.class)
557
public void testMapCustomPath() throws IOException {
558
Path path = Path.of(URI.create("jrt:/"));
559
MemorySegment.mapFile(path, 0L, 0L, FileChannel.MapMode.READ_WRITE, ResourceScope.newImplicitScope());
560
}
561
562
@Test(dataProvider="resizeOps")
563
public void testCopyHeapToNative(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
564
checkByteArrayAlignment(seq.elementLayout());
565
int bytes = (int)seq.byteSize();
566
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
567
MemorySegment nativeArray = MemorySegment.allocateNative(bytes, 1, scope);
568
MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes]);
569
initializer.accept(heapArray);
570
nativeArray.copyFrom(heapArray);
571
checker.accept(nativeArray);
572
}
573
}
574
575
@Test(dataProvider="resizeOps")
576
public void testCopyNativeToHeap(Consumer<MemorySegment> checker, Consumer<MemorySegment> initializer, SequenceLayout seq) {
577
checkByteArrayAlignment(seq.elementLayout());
578
int bytes = (int)seq.byteSize();
579
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
580
MemorySegment nativeArray = MemorySegment.allocateNative(seq, scope);
581
MemorySegment heapArray = MemorySegment.ofArray(new byte[bytes]);
582
initializer.accept(nativeArray);
583
heapArray.copyFrom(nativeArray);
584
checker.accept(heapArray);
585
}
586
}
587
588
@Test
589
public void testDefaultAccessModesOfBuffer() {
590
ByteBuffer rwBuffer = ByteBuffer.wrap(new byte[4]);
591
{
592
MemorySegment segment = MemorySegment.ofByteBuffer(rwBuffer);
593
assertFalse(segment.isReadOnly());
594
}
595
596
{
597
ByteBuffer roBuffer = rwBuffer.asReadOnlyBuffer();
598
MemorySegment segment = MemorySegment.ofByteBuffer(roBuffer);
599
assertTrue(segment.isReadOnly());
600
}
601
}
602
603
@Test(dataProvider="bufferSources")
604
public void testBufferToSegment(ByteBuffer bb, Predicate<MemorySegment> segmentChecker) {
605
MemorySegment segment = MemorySegment.ofByteBuffer(bb);
606
assertEquals(segment.isReadOnly(), bb.isReadOnly());
607
assertTrue(segmentChecker.test(segment));
608
assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
609
assertEquals(bb.capacity(), segment.byteSize());
610
//another round trip
611
segment = MemorySegment.ofByteBuffer(segment.asByteBuffer());
612
assertEquals(segment.isReadOnly(), bb.isReadOnly());
613
assertTrue(segmentChecker.test(segment));
614
assertTrue(segmentChecker.test(segment.asSlice(0, segment.byteSize())));
615
assertEquals(bb.capacity(), segment.byteSize());
616
}
617
618
@Test(dataProvider="bufferSources")
619
public void bufferProperties(ByteBuffer bb, Predicate<MemorySegment> _unused) {
620
MemorySegment segment = MemorySegment.ofByteBuffer(bb);
621
ByteBuffer buffer = segment.asByteBuffer();
622
assertEquals(buffer.position(), 0);
623
assertEquals(buffer.capacity(), segment.byteSize());
624
assertEquals(buffer.limit(), segment.byteSize());
625
}
626
627
@Test
628
public void testRoundTripAccess() {
629
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
630
MemorySegment ms = MemorySegment.allocateNative(4, 1, scope);
631
MemorySegment msNoAccess = ms.asReadOnly();
632
MemorySegment msRoundTrip = MemorySegment.ofByteBuffer(msNoAccess.asByteBuffer());
633
assertEquals(msNoAccess.isReadOnly(), msRoundTrip.isReadOnly());
634
}
635
}
636
637
@Test(expectedExceptions = IllegalStateException.class)
638
public void testDeadAccessOnClosedBufferSegment() {
639
MemorySegment s1 = MemorySegment.allocateNative(MemoryLayouts.JAVA_INT, ResourceScope.newConfinedScope());
640
MemorySegment s2 = MemorySegment.ofByteBuffer(s1.asByteBuffer());
641
642
// memory freed
643
s1.scope().close();
644
645
MemoryAccess.setInt(s2, 10); // Dead access!
646
}
647
648
@Test(dataProvider = "allScopes")
649
public void testIOOnSegmentBuffer(Supplier<ResourceScope> scopeSupplier) throws IOException {
650
File tmp = File.createTempFile("tmp", "txt");
651
tmp.deleteOnExit();
652
ResourceScope scope;
653
try (FileChannel channel = FileChannel.open(tmp.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE) ;
654
ResourceScope scp = closeableScopeOrNull(scope = scopeSupplier.get())) {
655
MemorySegment segment = MemorySegment.allocateNative(10, 1, scope);
656
for (int i = 0; i < 10; i++) {
657
MemoryAccess.setByteAtOffset(segment, i, (byte) i);
658
}
659
ByteBuffer bb = segment.asByteBuffer();
660
assertEquals(channel.write(bb), 10);
661
segment.fill((byte)0x00);
662
assertEquals(bb.clear(), ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
663
assertEquals(channel.position(0).read(bb.clear()), 10);
664
assertEquals(bb.flip(), ByteBuffer.wrap(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
665
}
666
}
667
668
static final Class<IllegalStateException> ISE = IllegalStateException.class;
669
670
@Test(dataProvider = "closeableScopes")
671
public void testIOOnClosedSegmentBuffer(Supplier<ResourceScope> scopeSupplier) throws IOException {
672
File tmp = File.createTempFile("tmp", "txt");
673
tmp.deleteOnExit();
674
try (FileChannel channel = FileChannel.open(tmp.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
675
MemorySegment segment = MemorySegment.allocateNative(10, scopeSupplier.get());
676
for (int i = 0; i < 10; i++) {
677
MemoryAccess.setByteAtOffset(segment, i, (byte) i);
678
}
679
ByteBuffer bb = segment.asByteBuffer();
680
segment.scope().close();
681
assertThrows(ISE, () -> channel.read(bb));
682
assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}));
683
assertThrows(ISE, () -> channel.read(new ByteBuffer[] {bb}, 0, 1));
684
assertThrows(ISE, () -> channel.write(bb));
685
assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}));
686
assertThrows(ISE, () -> channel.write(new ByteBuffer[] {bb}, 0 ,1));
687
}
688
}
689
690
@Test
691
public void buffersAndArraysFromSlices() {
692
try (ResourceScope scope = ResourceScope.newSharedScope()) {
693
MemorySegment segment = MemorySegment.allocateNative(16, scope);
694
int newSize = 8;
695
var slice = segment.asSlice(4, newSize);
696
697
var bytes = slice.toByteArray();
698
assertEquals(newSize, bytes.length);
699
700
var buffer = slice.asByteBuffer();
701
// Fails for heap segments, but passes for native segments:
702
assertEquals(0, buffer.position());
703
assertEquals(newSize, buffer.limit());
704
assertEquals(newSize, buffer.capacity());
705
}
706
}
707
708
@Test
709
public void viewsFromSharedSegment() {
710
try (ResourceScope scope = ResourceScope.newSharedScope()) {
711
MemorySegment segment = MemorySegment.allocateNative(16, scope);
712
var byteBuffer = segment.asByteBuffer();
713
byteBuffer.asReadOnlyBuffer();
714
byteBuffer.slice(0, 8);
715
}
716
}
717
718
@DataProvider(name = "segments")
719
public static Object[][] segments() throws Throwable {
720
return new Object[][] {
721
{ (Supplier<MemorySegment>) () -> MemorySegment.allocateNative(16, ResourceScope.newImplicitScope()) },
722
{ (Supplier<MemorySegment>) () -> MemorySegment.ofArray(new byte[16]) }
723
};
724
}
725
726
@DataProvider(name = "closeableScopes")
727
public static Object[][] closeableScopes() {
728
return new Object[][] {
729
{ (Supplier<ResourceScope>) () -> ResourceScope.newSharedScope() },
730
{ (Supplier<ResourceScope>) () -> ResourceScope.newConfinedScope() },
731
{ (Supplier<ResourceScope>) () -> ResourceScope.newSharedScope(Cleaner.create()) },
732
{ (Supplier<ResourceScope>) () -> ResourceScope.newConfinedScope(Cleaner.create()) }
733
};
734
}
735
736
@DataProvider(name = "implicitScopes")
737
public static Object[][] implicitScopes() {
738
return new Object[][] {
739
{ (Supplier<ResourceScope>) ResourceScope::newImplicitScope },
740
{ (Supplier<ResourceScope>) ResourceScope::globalScope },
741
};
742
}
743
744
@DataProvider(name = "allScopes")
745
public static Object[][] allScopes() {
746
return Stream.of(implicitScopes(), closeableScopes())
747
.flatMap(Arrays::stream)
748
.toArray(Object[][]::new);
749
}
750
751
static ResourceScope closeableScopeOrNull(ResourceScope scope) {
752
if (scope.isImplicit())
753
return null;
754
return scope;
755
}
756
757
@DataProvider(name = "bufferOps")
758
public static Object[][] bufferOps() throws Throwable {
759
List<Object[]> args = new ArrayList<>();
760
bufferOpsArgs(args, bb -> bb, ByteBuffer.class);
761
bufferOpsArgs(args, ByteBuffer::asCharBuffer, CharBuffer.class);
762
bufferOpsArgs(args, ByteBuffer::asShortBuffer, ShortBuffer.class);
763
bufferOpsArgs(args, ByteBuffer::asIntBuffer, IntBuffer.class);
764
bufferOpsArgs(args, ByteBuffer::asFloatBuffer, FloatBuffer.class);
765
bufferOpsArgs(args, ByteBuffer::asLongBuffer, LongBuffer.class);
766
bufferOpsArgs(args, ByteBuffer::asDoubleBuffer, DoubleBuffer.class);
767
return args.toArray(Object[][]::new);
768
}
769
770
static void bufferOpsArgs(List<Object[]> argsList, Function<ByteBuffer, Buffer> factory, Class<?> bufferClass) {
771
for (Method m : bufferClass.getMethods()) {
772
//skip statics and method declared in j.l.Object
773
if (m.getDeclaringClass().equals(Object.class)
774
|| ((m.getModifiers() & Modifier.STATIC) != 0)
775
|| (!m.getName().contains("get") && !m.getName().contains("put"))
776
|| m.getParameterCount() > 2) continue;
777
Object[] args = Stream.of(m.getParameterTypes())
778
.map(TestByteBuffer::defaultValue)
779
.toArray();
780
argsList.add(new Object[] { factory, m, args });
781
}
782
}
783
784
@DataProvider(name = "bufferHandleOps")
785
public static Object[][] bufferHandleOps() throws Throwable {
786
return new Object[][]{
787
{ MethodHandles.byteBufferViewVarHandle(char[].class, ByteOrder.nativeOrder()) },
788
{ MethodHandles.byteBufferViewVarHandle(short[].class, ByteOrder.nativeOrder()) },
789
{ MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.nativeOrder()) },
790
{ MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder()) },
791
{ MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.nativeOrder()) },
792
{ MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.nativeOrder()) }
793
};
794
}
795
796
static Map<MethodHandle, Object[]> varHandleMembers(ByteBuffer bb, VarHandle handle) {
797
Map<MethodHandle, Object[]> members = new HashMap<>();
798
for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
799
Class<?>[] params = handle.accessModeType(mode).parameterArray();
800
Object[] args = Stream.concat(Stream.of(bb), Stream.of(params).skip(1)
801
.map(TestByteBuffer::defaultValue))
802
.toArray();
803
try {
804
members.put(MethodHandles.varHandleInvoker(mode, handle.accessModeType(mode)), args);
805
} catch (Throwable ex) {
806
throw new AssertionError(ex);
807
}
808
}
809
return members;
810
}
811
812
@DataProvider(name = "resizeOps")
813
public Object[][] resizeOps() {
814
Consumer<MemorySegment> byteInitializer =
815
(base) -> initBytes(base, bytes, (addr, pos) -> MemoryAccess.setByteAtOffset(addr, pos, (byte)(long)pos));
816
Consumer<MemorySegment> charInitializer =
817
(base) -> initBytes(base, chars, (addr, pos) -> MemoryAccess.setCharAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (char)(long)pos));
818
Consumer<MemorySegment> shortInitializer =
819
(base) -> initBytes(base, shorts, (addr, pos) -> MemoryAccess.setShortAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (short)(long)pos));
820
Consumer<MemorySegment> intInitializer =
821
(base) -> initBytes(base, ints, (addr, pos) -> MemoryAccess.setIntAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (int)(long)pos));
822
Consumer<MemorySegment> floatInitializer =
823
(base) -> initBytes(base, floats, (addr, pos) -> MemoryAccess.setFloatAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (float)(long)pos));
824
Consumer<MemorySegment> longInitializer =
825
(base) -> initBytes(base, longs, (addr, pos) -> MemoryAccess.setLongAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (long)pos));
826
Consumer<MemorySegment> doubleInitializer =
827
(base) -> initBytes(base, doubles, (addr, pos) -> MemoryAccess.setDoubleAtIndex(addr, pos, ByteOrder.BIG_ENDIAN, (double)(long)pos));
828
829
Consumer<MemorySegment> byteChecker =
830
(base) -> checkBytes(base, bytes, Function.identity(), (addr, pos) -> MemoryAccess.getByteAtOffset(addr, pos), ByteBuffer::get);
831
Consumer<MemorySegment> charChecker =
832
(base) -> checkBytes(base, chars, ByteBuffer::asCharBuffer, (addr, pos) -> MemoryAccess.getCharAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), CharBuffer::get);
833
Consumer<MemorySegment> shortChecker =
834
(base) -> checkBytes(base, shorts, ByteBuffer::asShortBuffer, (addr, pos) -> MemoryAccess.getShortAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), ShortBuffer::get);
835
Consumer<MemorySegment> intChecker =
836
(base) -> checkBytes(base, ints, ByteBuffer::asIntBuffer, (addr, pos) -> MemoryAccess.getIntAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), IntBuffer::get);
837
Consumer<MemorySegment> floatChecker =
838
(base) -> checkBytes(base, floats, ByteBuffer::asFloatBuffer, (addr, pos) -> MemoryAccess.getFloatAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), FloatBuffer::get);
839
Consumer<MemorySegment> longChecker =
840
(base) -> checkBytes(base, longs, ByteBuffer::asLongBuffer, (addr, pos) -> MemoryAccess.getLongAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), LongBuffer::get);
841
Consumer<MemorySegment> doubleChecker =
842
(base) -> checkBytes(base, doubles, ByteBuffer::asDoubleBuffer, (addr, pos) -> MemoryAccess.getDoubleAtIndex(addr, pos, ByteOrder.BIG_ENDIAN), DoubleBuffer::get);
843
844
return new Object[][]{
845
{byteChecker, byteInitializer, bytes},
846
{charChecker, charInitializer, chars},
847
{shortChecker, shortInitializer, shorts},
848
{intChecker, intInitializer, ints},
849
{floatChecker, floatInitializer, floats},
850
{longChecker, longInitializer, longs},
851
{doubleChecker, doubleInitializer, doubles}
852
};
853
}
854
855
static Object defaultValue(Class<?> c) {
856
if (c.isPrimitive()) {
857
if (c == char.class) {
858
return (char)0;
859
} else if (c == boolean.class) {
860
return false;
861
} else if (c == byte.class) {
862
return (byte)0;
863
} else if (c == short.class) {
864
return (short)0;
865
} else if (c == int.class) {
866
return 0;
867
} else if (c == long.class) {
868
return 0L;
869
} else if (c == float.class) {
870
return 0f;
871
} else if (c == double.class) {
872
return 0d;
873
} else {
874
throw new IllegalStateException();
875
}
876
} else if (c.isArray()) {
877
if (c == char[].class) {
878
return new char[1];
879
} else if (c == boolean[].class) {
880
return new boolean[1];
881
} else if (c == byte[].class) {
882
return new byte[1];
883
} else if (c == short[].class) {
884
return new short[1];
885
} else if (c == int[].class) {
886
return new int[1];
887
} else if (c == long[].class) {
888
return new long[1];
889
} else if (c == float[].class) {
890
return new float[1];
891
} else if (c == double[].class) {
892
return new double[1];
893
} else {
894
throw new IllegalStateException();
895
}
896
} else if (c == String.class) {
897
return "asdf";
898
} else if (c == ByteBuffer.class) {
899
return ByteBuffer.wrap(new byte[1]);
900
} else if (c == CharBuffer.class) {
901
return CharBuffer.wrap(new char[1]);
902
} else if (c == ShortBuffer.class) {
903
return ShortBuffer.wrap(new short[1]);
904
} else if (c == IntBuffer.class) {
905
return IntBuffer.wrap(new int[1]);
906
} else if (c == FloatBuffer.class) {
907
return FloatBuffer.wrap(new float[1]);
908
} else if (c == LongBuffer.class) {
909
return LongBuffer.wrap(new long[1]);
910
} else if (c == DoubleBuffer.class) {
911
return DoubleBuffer.wrap(new double[1]);
912
} else {
913
return null;
914
}
915
}
916
917
@DataProvider(name = "bufferSources")
918
public static Object[][] bufferSources() {
919
Predicate<MemorySegment> heapTest = segment -> segment instanceof HeapMemorySegmentImpl;
920
Predicate<MemorySegment> nativeTest = segment -> segment instanceof NativeMemorySegmentImpl;
921
Predicate<MemorySegment> mappedTest = segment -> segment instanceof MappedMemorySegmentImpl;
922
try (FileChannel channel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
923
return new Object[][]{
924
{ ByteBuffer.wrap(new byte[256]), heapTest },
925
{ ByteBuffer.allocate(256), heapTest },
926
{ ByteBuffer.allocateDirect(256), nativeTest },
927
{ channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256), mappedTest },
928
929
{ ByteBuffer.wrap(new byte[256]).asReadOnlyBuffer(), heapTest },
930
{ ByteBuffer.allocate(256).asReadOnlyBuffer(), heapTest },
931
{ ByteBuffer.allocateDirect(256).asReadOnlyBuffer(), nativeTest },
932
{ channel.map(FileChannel.MapMode.READ_WRITE, 0L, 256).asReadOnlyBuffer(),
933
nativeTest /* this seems to be an existing bug in the BB implementation */ }
934
};
935
} catch (IOException ex) {
936
throw new ExceptionInInitializerError(ex);
937
}
938
}
939
940
enum MappedSegmentOp {
941
LOAD(MemorySegment::load),
942
UNLOAD(MemorySegment::unload),
943
IS_LOADED(MemorySegment::isLoaded),
944
FORCE(MemorySegment::force),
945
BUFFER_LOAD(m -> ((MappedByteBuffer)m.asByteBuffer()).load()),
946
BUFFER_IS_LOADED(m -> ((MappedByteBuffer)m.asByteBuffer()).isLoaded()),
947
BUFFER_FORCE(m -> ((MappedByteBuffer)m.asByteBuffer()).force());
948
949
950
private Consumer<MemorySegment> segmentOp;
951
952
MappedSegmentOp(Consumer<MemorySegment> segmentOp) {
953
this.segmentOp = segmentOp;
954
}
955
956
void apply(MemorySegment segment) {
957
segmentOp.accept(segment);
958
}
959
}
960
961
@DataProvider(name = "mappedOps")
962
public static Object[][] mappedOps() {
963
return Stream.of(MappedSegmentOp.values())
964
.map(op -> new Object[] { op })
965
.toArray(Object[][]::new);
966
}
967
}
968
969