Path: blob/master/test/jdk/java/foreign/TestMemoryAccess.java
41144 views
/*1* Copyright (c) 2019, 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* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess26* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess27* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestMemoryAccess28* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestMemoryAccess29*/3031import jdk.incubator.foreign.GroupLayout;32import jdk.incubator.foreign.MemoryLayouts;33import jdk.incubator.foreign.MemoryLayout;34import jdk.incubator.foreign.MemoryLayout.PathElement;35import jdk.incubator.foreign.MemorySegment;36import jdk.incubator.foreign.ResourceScope;37import jdk.incubator.foreign.SequenceLayout;38import jdk.incubator.foreign.ValueLayout;3940import java.lang.invoke.VarHandle;41import java.util.function.Function;4243import org.testng.annotations.*;44import static org.testng.Assert.*;4546public class TestMemoryAccess {4748@Test(dataProvider = "elements")49public void testAccess(Function<MemorySegment, MemorySegment> viewFactory, ValueLayout elemLayout, Class<?> carrier, Checker checker) {50ValueLayout layout = elemLayout.withName("elem");51testAccessInternal(viewFactory, layout, layout.varHandle(carrier), checker);52}5354@Test(dataProvider = "elements")55public void testPaddedAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) {56GroupLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem"));57testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.groupElement("elem")), checker);58}5960@Test(dataProvider = "elements")61public void testPaddedAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, Checker checker) {62SequenceLayout layout = MemoryLayout.sequenceLayout(2, elemLayout);63testAccessInternal(viewFactory, layout, layout.varHandle(carrier, PathElement.sequenceElement(1)), checker);64}6566@Test(dataProvider = "arrayElements")67public void testArrayAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {68SequenceLayout seq = MemoryLayout.sequenceLayout(10, elemLayout.withName("elem"));69testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement()), checker);70}7172@Test(dataProvider = "arrayElements")73public void testPaddedArrayAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {74SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem")));75testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("elem")), checker);76}7778@Test(dataProvider = "arrayElements")79public void testPaddedArrayAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, ArrayChecker checker) {80SequenceLayout seq = MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout));81testArrayAccessInternal(viewFactory, seq, seq.varHandle(carrier, PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(1)), checker);82}8384private void testAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout layout, VarHandle handle, Checker checker) {85MemorySegment outer_segment;86try (ResourceScope scope = ResourceScope.newConfinedScope()) {87MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(layout, scope));88boolean isRO = segment.isReadOnly();89try {90checker.check(handle, segment);91if (isRO) {92throw new AssertionError(); //not ok, memory should be immutable93}94} catch (UnsupportedOperationException ex) {95if (!isRO) {96throw new AssertionError(); //we should not have failed!97}98return;99}100try {101checker.check(handle, segment.asSlice(layout.byteSize()));102throw new AssertionError(); //not ok, out of bounds103} catch (IndexOutOfBoundsException ex) {104//ok, should fail (out of bounds)105}106outer_segment = segment; //leak!107}108try {109checker.check(handle, outer_segment);110throw new AssertionError(); //not ok, scope is closed111} catch (IllegalStateException ex) {112//ok, should fail (scope is closed)113}114}115116private void testArrayAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, SequenceLayout seq, VarHandle handle, ArrayChecker checker) {117MemorySegment outer_segment;118try (ResourceScope scope = ResourceScope.newConfinedScope()) {119MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(seq, scope));120boolean isRO = segment.isReadOnly();121try {122for (int i = 0; i < seq.elementCount().getAsLong(); i++) {123checker.check(handle, segment, i);124}125if (isRO) {126throw new AssertionError(); //not ok, memory should be immutable127}128} catch (UnsupportedOperationException ex) {129if (!isRO) {130throw new AssertionError(); //we should not have failed!131}132return;133}134try {135checker.check(handle, segment, seq.elementCount().getAsLong());136throw new AssertionError(); //not ok, out of bounds137} catch (IndexOutOfBoundsException ex) {138//ok, should fail (out of bounds)139}140outer_segment = segment; //leak!141}142try {143checker.check(handle, outer_segment, 0);144throw new AssertionError(); //not ok, scope is closed145} catch (IllegalStateException ex) {146//ok, should fail (scope is closed)147}148}149150@Test(dataProvider = "matrixElements")151public void testMatrixAccess(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {152SequenceLayout seq = MemoryLayout.sequenceLayout(20,153MemoryLayout.sequenceLayout(10, elemLayout.withName("elem")));154testMatrixAccessInternal(viewFactory, seq, seq.varHandle(carrier,155PathElement.sequenceElement(), PathElement.sequenceElement()), checker);156}157158@Test(dataProvider = "matrixElements")159public void testPaddedMatrixAccessByName(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {160SequenceLayout seq = MemoryLayout.sequenceLayout(20,161MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(elemLayout.bitSize()), elemLayout.withName("elem"))));162testMatrixAccessInternal(viewFactory, seq,163seq.varHandle(carrier,164PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.groupElement("elem")),165checker);166}167168@Test(dataProvider = "matrixElements")169public void testPaddedMatrixAccessByIndexSeq(Function<MemorySegment, MemorySegment> viewFactory, MemoryLayout elemLayout, Class<?> carrier, MatrixChecker checker) {170SequenceLayout seq = MemoryLayout.sequenceLayout(20,171MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(2, elemLayout)));172testMatrixAccessInternal(viewFactory, seq,173seq.varHandle(carrier,174PathElement.sequenceElement(), PathElement.sequenceElement(), PathElement.sequenceElement(1)),175checker);176}177178@Test(dataProvider = "badCarriers",179expectedExceptions = IllegalArgumentException.class)180public void testBadCarriers(Class<?> carrier) {181ValueLayout l = MemoryLayouts.BITS_32_LE.withName("elem");182l.varHandle(carrier);183}184185private void testMatrixAccessInternal(Function<MemorySegment, MemorySegment> viewFactory, SequenceLayout seq, VarHandle handle, MatrixChecker checker) {186MemorySegment outer_segment;187try (ResourceScope scope = ResourceScope.newConfinedScope()) {188MemorySegment segment = viewFactory.apply(MemorySegment.allocateNative(seq, scope));189boolean isRO = segment.isReadOnly();190try {191for (int i = 0; i < seq.elementCount().getAsLong(); i++) {192for (int j = 0; j < ((SequenceLayout) seq.elementLayout()).elementCount().getAsLong(); j++) {193checker.check(handle, segment, i, j);194}195}196if (isRO) {197throw new AssertionError(); //not ok, memory should be immutable198}199} catch (UnsupportedOperationException ex) {200if (!isRO) {201throw new AssertionError(); //we should not have failed!202}203return;204}205try {206checker.check(handle, segment, seq.elementCount().getAsLong(),207((SequenceLayout)seq.elementLayout()).elementCount().getAsLong());208throw new AssertionError(); //not ok, out of bounds209} catch (IndexOutOfBoundsException ex) {210//ok, should fail (out of bounds)211}212outer_segment = segment; //leak!213}214try {215checker.check(handle, outer_segment, 0, 0);216throw new AssertionError(); //not ok, scope is closed217} catch (IllegalStateException ex) {218//ok, should fail (scope is closed)219}220}221222static Function<MemorySegment, MemorySegment> ID = Function.identity();223static Function<MemorySegment, MemorySegment> IMMUTABLE = MemorySegment::asReadOnly;224225@DataProvider(name = "elements")226public Object[][] createData() {227return new Object[][] {228//BE, RW229{ ID, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE },230{ ID, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT },231{ ID, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR },232{ ID, MemoryLayouts.BITS_32_BE, int.class, Checker.INT },233{ ID, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG },234{ ID, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT },235{ ID, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE },236//BE, RO237{ IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, Checker.BYTE },238{ IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, Checker.SHORT },239{ IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, Checker.CHAR },240{ IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, Checker.INT },241{ IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, Checker.LONG },242{ IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, Checker.FLOAT },243{ IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, Checker.DOUBLE },244//LE, RW245{ ID, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE },246{ ID, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT },247{ ID, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR },248{ ID, MemoryLayouts.BITS_32_LE, int.class, Checker.INT },249{ ID, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG },250{ ID, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT },251{ ID, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE },252//LE, RO253{ IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, Checker.BYTE },254{ IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, Checker.SHORT },255{ IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, Checker.CHAR },256{ IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, Checker.INT },257{ IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, Checker.LONG },258{ IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, Checker.FLOAT },259{ IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, Checker.DOUBLE },260};261}262263interface Checker {264void check(VarHandle handle, MemorySegment segment);265266Checker BYTE = (handle, segment) -> {267handle.set(segment, (byte)42);268assertEquals(42, (byte)handle.get(segment));269};270271Checker SHORT = (handle, segment) -> {272handle.set(segment, (short)42);273assertEquals(42, (short)handle.get(segment));274};275276Checker CHAR = (handle, segment) -> {277handle.set(segment, (char)42);278assertEquals(42, (char)handle.get(segment));279};280281Checker INT = (handle, segment) -> {282handle.set(segment, 42);283assertEquals(42, (int)handle.get(segment));284};285286Checker LONG = (handle, segment) -> {287handle.set(segment, (long)42);288assertEquals(42, (long)handle.get(segment));289};290291Checker FLOAT = (handle, segment) -> {292handle.set(segment, (float)42);293assertEquals((float)42, (float)handle.get(segment));294};295296Checker DOUBLE = (handle, segment) -> {297handle.set(segment, (double)42);298assertEquals((double)42, (double)handle.get(segment));299};300}301302@DataProvider(name = "arrayElements")303public Object[][] createArrayData() {304return new Object[][] {305//BE, RW306{ ID, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE },307{ ID, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT },308{ ID, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR },309{ ID, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT },310{ ID, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG },311{ ID, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT },312{ ID, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE },313//BE, RO314{ IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, ArrayChecker.BYTE },315{ IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, ArrayChecker.SHORT },316{ IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, ArrayChecker.CHAR },317{ IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, ArrayChecker.INT },318{ IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, ArrayChecker.LONG },319{ IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, ArrayChecker.FLOAT },320{ IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, ArrayChecker.DOUBLE },321//LE, RW322{ ID, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE },323{ ID, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT },324{ ID, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR },325{ ID, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT },326{ ID, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG },327{ ID, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT },328{ ID, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE },329//LE, RO330{ IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, ArrayChecker.BYTE },331{ IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, ArrayChecker.SHORT },332{ IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, ArrayChecker.CHAR },333{ IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, ArrayChecker.INT },334{ IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, ArrayChecker.LONG },335{ IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, ArrayChecker.FLOAT },336{ IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, ArrayChecker.DOUBLE },337};338}339340interface ArrayChecker {341void check(VarHandle handle, MemorySegment segment, long index);342343ArrayChecker BYTE = (handle, segment, i) -> {344handle.set(segment, i, (byte)i);345assertEquals(i, (byte)handle.get(segment, i));346};347348ArrayChecker SHORT = (handle, segment, i) -> {349handle.set(segment, i, (short)i);350assertEquals(i, (short)handle.get(segment, i));351};352353ArrayChecker CHAR = (handle, segment, i) -> {354handle.set(segment, i, (char)i);355assertEquals(i, (char)handle.get(segment, i));356};357358ArrayChecker INT = (handle, segment, i) -> {359handle.set(segment, i, (int)i);360assertEquals(i, (int)handle.get(segment, i));361};362363ArrayChecker LONG = (handle, segment, i) -> {364handle.set(segment, i, (long)i);365assertEquals(i, (long)handle.get(segment, i));366};367368ArrayChecker FLOAT = (handle, segment, i) -> {369handle.set(segment, i, (float)i);370assertEquals((float)i, (float)handle.get(segment, i));371};372373ArrayChecker DOUBLE = (handle, segment, i) -> {374handle.set(segment, i, (double)i);375assertEquals((double)i, (double)handle.get(segment, i));376};377}378379@DataProvider(name = "matrixElements")380public Object[][] createMatrixData() {381return new Object[][] {382//BE, RW383{ ID, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE },384{ ID, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT },385{ ID, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR },386{ ID, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT },387{ ID, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG },388{ ID, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT },389{ ID, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE },390//BE, RO391{ IMMUTABLE, MemoryLayouts.BITS_8_BE, byte.class, MatrixChecker.BYTE },392{ IMMUTABLE, MemoryLayouts.BITS_16_BE, short.class, MatrixChecker.SHORT },393{ IMMUTABLE, MemoryLayouts.BITS_16_BE, char.class, MatrixChecker.CHAR },394{ IMMUTABLE, MemoryLayouts.BITS_32_BE, int.class, MatrixChecker.INT },395{ IMMUTABLE, MemoryLayouts.BITS_64_BE, long.class, MatrixChecker.LONG },396{ IMMUTABLE, MemoryLayouts.BITS_32_BE, float.class, MatrixChecker.FLOAT },397{ IMMUTABLE, MemoryLayouts.BITS_64_BE, double.class, MatrixChecker.DOUBLE },398//LE, RW399{ ID, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE },400{ ID, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT },401{ ID, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR },402{ ID, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT },403{ ID, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG },404{ ID, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT },405{ ID, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE },406//LE, RO407{ IMMUTABLE, MemoryLayouts.BITS_8_LE, byte.class, MatrixChecker.BYTE },408{ IMMUTABLE, MemoryLayouts.BITS_16_LE, short.class, MatrixChecker.SHORT },409{ IMMUTABLE, MemoryLayouts.BITS_16_LE, char.class, MatrixChecker.CHAR },410{ IMMUTABLE, MemoryLayouts.BITS_32_LE, int.class, MatrixChecker.INT },411{ IMMUTABLE, MemoryLayouts.BITS_64_LE, long.class, MatrixChecker.LONG },412{ IMMUTABLE, MemoryLayouts.BITS_32_LE, float.class, MatrixChecker.FLOAT },413{ IMMUTABLE, MemoryLayouts.BITS_64_LE, double.class, MatrixChecker.DOUBLE },414};415}416417interface MatrixChecker {418void check(VarHandle handle, MemorySegment segment, long row, long col);419420MatrixChecker BYTE = (handle, segment, r, c) -> {421handle.set(segment, r, c, (byte)(r + c));422assertEquals(r + c, (byte)handle.get(segment, r, c));423};424425MatrixChecker SHORT = (handle, segment, r, c) -> {426handle.set(segment, r, c, (short)(r + c));427assertEquals(r + c, (short)handle.get(segment, r, c));428};429430MatrixChecker CHAR = (handle, segment, r, c) -> {431handle.set(segment, r, c, (char)(r + c));432assertEquals(r + c, (char)handle.get(segment, r, c));433};434435MatrixChecker INT = (handle, segment, r, c) -> {436handle.set(segment, r, c, (int)(r + c));437assertEquals(r + c, (int)handle.get(segment, r, c));438};439440MatrixChecker LONG = (handle, segment, r, c) -> {441handle.set(segment, r, c, r + c);442assertEquals(r + c, (long)handle.get(segment, r, c));443};444445MatrixChecker FLOAT = (handle, segment, r, c) -> {446handle.set(segment, r, c, (float)(r + c));447assertEquals((float)(r + c), (float)handle.get(segment, r, c));448};449450MatrixChecker DOUBLE = (handle, segment, r, c) -> {451handle.set(segment, r, c, (double)(r + c));452assertEquals((double)(r + c), (double)handle.get(segment, r, c));453};454}455456@DataProvider(name = "badCarriers")457public Object[][] createBadCarriers() {458return new Object[][] {459{ void.class },460{ boolean.class },461{ Object.class },462{ int[].class }463};464}465}466467468