Path: blob/master/test/jdk/java/foreign/TestScopedOperations.java
41145 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"26* @run testng/othervm --enable-native-access=ALL-UNNAMED TestScopedOperations27*/2829import jdk.incubator.foreign.CLinker;30import jdk.incubator.foreign.MemoryAddress;31import jdk.incubator.foreign.MemoryLayout;32import jdk.incubator.foreign.MemoryLayouts;33import jdk.incubator.foreign.MemorySegment;34import jdk.incubator.foreign.ResourceScope;35import jdk.incubator.foreign.SegmentAllocator;36import org.testng.annotations.DataProvider;37import org.testng.annotations.Test;3839import java.io.File;40import java.io.IOException;41import java.nio.channels.FileChannel;42import java.nio.file.Path;43import java.util.ArrayList;44import java.util.List;45import java.util.concurrent.atomic.AtomicReference;46import java.util.function.Consumer;47import java.util.function.Function;4849import static org.testng.Assert.assertEquals;50import static org.testng.Assert.assertNotNull;51import static org.testng.Assert.assertTrue;52import static org.testng.Assert.fail;5354public class TestScopedOperations {5556static Path tempPath;5758static {59try {60File file = File.createTempFile("scopedBuffer", "txt");61file.deleteOnExit();62tempPath = file.toPath();63} catch (IOException ex) {64throw new ExceptionInInitializerError(ex);65}66}6768@Test(dataProvider = "scopedOperations")69public void testOpAfterClose(String name, ScopedOperation scopedOperation) {70ResourceScope scope = ResourceScope.newConfinedScope();71scope.close();72try {73scopedOperation.accept(scope);74fail();75} catch (IllegalStateException ex) {76assertTrue(ex.getMessage().contains("closed"));77}78}7980@Test(dataProvider = "scopedOperations")81public void testOpOutsideConfinement(String name, ScopedOperation scopedOperation) {82try (ResourceScope scope = ResourceScope.newConfinedScope()) {83AtomicReference<Throwable> failed = new AtomicReference<>();84Thread t = new Thread(() -> {85try {86scopedOperation.accept(scope);87} catch (Throwable ex) {88failed.set(ex);89}90});91t.start();92t.join();93assertNotNull(failed.get());94assertEquals(failed.get().getClass(), IllegalStateException.class);95assertTrue(failed.get().getMessage().contains("outside"));96} catch (InterruptedException ex) {97throw new AssertionError(ex);98}99}100101static List<ScopedOperation> scopedOperations = new ArrayList<>();102103static {104// scope operations105ScopedOperation.ofScope(scope -> scope.addCloseAction(() -> {106}), "ResourceScope::addOnClose");107ScopedOperation.ofScope(scope -> {108ResourceScope.Handle handle = scope.acquire();109scope.release(handle);110}, "ResourceScope::lock");111ScopedOperation.ofScope(scope -> MemorySegment.allocateNative(100, scope), "MemorySegment::allocateNative");112ScopedOperation.ofScope(scope -> {113try {114MemorySegment.mapFile(tempPath, 0, 10, FileChannel.MapMode.READ_WRITE, scope);115} catch (IOException ex) {116fail();117}118}, "MemorySegment::mapFromFile");119ScopedOperation.ofScope(scope -> CLinker.VaList.make(b -> {}, scope), "VaList::make");120ScopedOperation.ofScope(scope -> CLinker.VaList.ofAddress(MemoryAddress.ofLong(42), scope), "VaList::make");121ScopedOperation.ofScope(scope -> CLinker.toCString("Hello", scope), "CLinker::toCString");122ScopedOperation.ofScope(SegmentAllocator::arenaAllocator, "SegmentAllocator::arenaAllocator");123// segment operations124ScopedOperation.ofSegment(MemorySegment::toByteArray, "MemorySegment::toByteArray");125ScopedOperation.ofSegment(MemorySegment::toCharArray, "MemorySegment::toCharArray");126ScopedOperation.ofSegment(MemorySegment::toShortArray, "MemorySegment::toShortArray");127ScopedOperation.ofSegment(MemorySegment::toIntArray, "MemorySegment::toIntArray");128ScopedOperation.ofSegment(MemorySegment::toFloatArray, "MemorySegment::toFloatArray");129ScopedOperation.ofSegment(MemorySegment::toLongArray, "MemorySegment::toLongArray");130ScopedOperation.ofSegment(MemorySegment::toDoubleArray, "MemorySegment::toDoubleArray");131ScopedOperation.ofSegment(MemorySegment::address, "MemorySegment::address");132ScopedOperation.ofSegment(s -> MemoryLayout.sequenceLayout(s.byteSize(), MemoryLayouts.JAVA_BYTE), "MemorySegment::spliterator");133ScopedOperation.ofSegment(s -> s.copyFrom(s), "MemorySegment::copyFrom");134ScopedOperation.ofSegment(s -> s.mismatch(s), "MemorySegment::mismatch");135ScopedOperation.ofSegment(s -> s.fill((byte) 0), "MemorySegment::fill");136// address operations137ScopedOperation.ofAddress(a -> a.toRawLongValue(), "MemoryAddress::toRawLongValue");138ScopedOperation.ofAddress(a -> a.asSegment(100, ResourceScope.globalScope()), "MemoryAddress::asSegment");139// valist operations140ScopedOperation.ofVaList(CLinker.VaList::address, "VaList::address");141ScopedOperation.ofVaList(CLinker.VaList::copy, "VaList::copy");142ScopedOperation.ofVaList(list -> list.vargAsAddress(MemoryLayouts.ADDRESS), "VaList::vargAsAddress");143ScopedOperation.ofVaList(list -> list.vargAsInt(MemoryLayouts.JAVA_INT), "VaList::vargAsInt");144ScopedOperation.ofVaList(list -> list.vargAsLong(MemoryLayouts.JAVA_LONG), "VaList::vargAsLong");145ScopedOperation.ofVaList(list -> list.vargAsDouble(MemoryLayouts.JAVA_DOUBLE), "VaList::vargAsDouble");146ScopedOperation.ofVaList(CLinker.VaList::skip, "VaList::skip");147ScopedOperation.ofVaList(list -> list.vargAsSegment(MemoryLayout.structLayout(MemoryLayouts.JAVA_INT), ResourceScope.newImplicitScope()), "VaList::vargAsSegment/1");148// allocator operations149ScopedOperation.ofAllocator(a -> a.allocate(1), "NativeAllocator::allocate/size");150ScopedOperation.ofAllocator(a -> a.allocate(1, 1), "NativeAllocator::allocate/size/align");151ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_BYTE), "NativeAllocator::allocate/layout");152ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_BYTE, (byte) 0), "NativeAllocator::allocate/byte");153ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_CHAR, (char) 0), "NativeAllocator::allocate/char");154ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_SHORT, (short) 0), "NativeAllocator::allocate/short");155ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_INT, 0), "NativeAllocator::allocate/int");156ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_FLOAT, 0f), "NativeAllocator::allocate/float");157ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_LONG, 0L), "NativeAllocator::allocate/long");158ScopedOperation.ofAllocator(a -> a.allocate(MemoryLayouts.JAVA_DOUBLE, 0d), "NativeAllocator::allocate/double");159ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_BYTE, 1L), "NativeAllocator::allocateArray/size");160ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_BYTE, new byte[]{0}), "NativeAllocator::allocateArray/byte");161ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_CHAR, new char[]{0}), "NativeAllocator::allocateArray/char");162ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_SHORT, new short[]{0}), "NativeAllocator::allocateArray/short");163ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_INT, new int[]{0}), "NativeAllocator::allocateArray/int");164ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_FLOAT, new float[]{0}), "NativeAllocator::allocateArray/float");165ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_LONG, new long[]{0}), "NativeAllocator::allocateArray/long");166ScopedOperation.ofAllocator(a -> a.allocateArray(MemoryLayouts.JAVA_DOUBLE, new double[]{0}), "NativeAllocator::allocateArray/double");167};168169@DataProvider(name = "scopedOperations")170static Object[][] scopedOperations() {171return scopedOperations.stream().map(op -> new Object[] { op.name, op }).toArray(Object[][]::new);172}173174static class ScopedOperation implements Consumer<ResourceScope> {175176final Consumer<ResourceScope> scopeConsumer;177final String name;178179private ScopedOperation(Consumer<ResourceScope> scopeConsumer, String name) {180this.scopeConsumer = scopeConsumer;181this.name = name;182}183184@Override185public void accept(ResourceScope scope) {186scopeConsumer.accept(scope);187}188189static void ofScope(Consumer<ResourceScope> scopeConsumer, String name) {190scopedOperations.add(new ScopedOperation(scopeConsumer::accept, name));191}192193static void ofVaList(Consumer<CLinker.VaList> vaListConsumer, String name) {194scopedOperations.add(new ScopedOperation(scope -> {195CLinker.VaList vaList = CLinker.VaList.make((builder) -> {}, scope);196vaListConsumer.accept(vaList);197}, name));198}199200static void ofSegment(Consumer<MemorySegment> segmentConsumer, String name) {201for (SegmentFactory segmentFactory : SegmentFactory.values()) {202scopedOperations.add(new ScopedOperation(scope -> {203MemorySegment segment = segmentFactory.segmentFactory.apply(scope);204segmentConsumer.accept(segment);205}, segmentFactory.name() + "/" + name));206}207}208209static void ofAddress(Consumer<MemoryAddress> addressConsumer, String name) {210for (SegmentFactory segmentFactory : SegmentFactory.values()) {211scopedOperations.add(new ScopedOperation(scope -> {212MemoryAddress segment = segmentFactory.segmentFactory.apply(scope).address();213addressConsumer.accept(segment);214}, segmentFactory.name() + "/" + name));215}216}217218static void ofAllocator(Consumer<SegmentAllocator> allocatorConsumer, String name) {219for (AllocatorFactory allocatorFactory : AllocatorFactory.values()) {220scopedOperations.add(new ScopedOperation(scope -> {221SegmentAllocator allocator = allocatorFactory.allocatorFactory.apply(scope);222allocatorConsumer.accept(allocator);223}, allocatorFactory.name() + "/" + name));224}225}226227enum SegmentFactory {228229NATIVE(scope -> MemorySegment.allocateNative(10, scope)),230MAPPED(scope -> {231try {232return MemorySegment.mapFile(Path.of("foo.txt"), 0, 10, FileChannel.MapMode.READ_WRITE, scope);233} catch (IOException ex) {234throw new AssertionError(ex);235}236}),237UNSAFE(scope -> MemoryAddress.NULL.asSegment(10, scope));238239static {240try {241File f = new File("foo.txt");242f.createNewFile();243f.deleteOnExit();244} catch (IOException ex) {245throw new ExceptionInInitializerError(ex);246}247}248249final Function<ResourceScope, MemorySegment> segmentFactory;250251SegmentFactory(Function<ResourceScope, MemorySegment> segmentFactory) {252this.segmentFactory = segmentFactory;253}254}255256enum AllocatorFactory {257ARENA_BOUNDED(scope -> SegmentAllocator.arenaAllocator(1000, scope)),258ARENA_UNBOUNDED(SegmentAllocator::arenaAllocator),259FROM_SEGMENT(scope -> {260MemorySegment segment = MemorySegment.allocateNative(10, scope);261return SegmentAllocator.ofSegment(segment);262}),263FROM_SCOPE(SegmentAllocator::ofScope);264265final Function<ResourceScope, SegmentAllocator> allocatorFactory;266267AllocatorFactory(Function<ResourceScope, SegmentAllocator> allocatorFactory) {268this.allocatorFactory = allocatorFactory;269}270}271}272}273274275