Path: blob/master/test/jdk/java/foreign/TestLayoutPaths.java
41145 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*22*/2324/*25* @test26* @run testng TestLayoutPaths27*/2829import jdk.incubator.foreign.GroupLayout;30import jdk.incubator.foreign.MemoryLayouts;31import jdk.incubator.foreign.MemoryLayout;32import jdk.incubator.foreign.MemoryLayout.PathElement;33import jdk.incubator.foreign.MemorySegment;34import jdk.incubator.foreign.ResourceScope;35import jdk.incubator.foreign.SequenceLayout;3637import org.testng.SkipException;38import org.testng.annotations.*;3940import java.lang.invoke.MethodHandle;41import java.nio.ByteOrder;42import java.util.ArrayList;43import java.util.List;4445import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;46import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement;47import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT;48import static org.testng.Assert.*;4950public class TestLayoutPaths {5152@Test(expectedExceptions = IllegalArgumentException.class)53public void testBadBitSelectFromSeq() {54SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);55seq.bitOffset(groupElement("foo"));56}5758@Test(expectedExceptions = IllegalArgumentException.class)59public void testBadByteSelectFromSeq() {60SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);61seq.byteOffset(groupElement("foo"));62}6364@Test(expectedExceptions = IllegalArgumentException.class)65public void testBadBitSelectFromStruct() {66GroupLayout g = MemoryLayout.structLayout(JAVA_INT);67g.bitOffset(sequenceElement());68}6970@Test(expectedExceptions = IllegalArgumentException.class)71public void testBadByteSelectFromStruct() {72GroupLayout g = MemoryLayout.structLayout(JAVA_INT);73g.byteOffset(sequenceElement());74}7576@Test(expectedExceptions = IllegalArgumentException.class)77public void testBadBitSelectFromValue() {78SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);79seq.bitOffset(sequenceElement(), sequenceElement());80}8182@Test(expectedExceptions = IllegalArgumentException.class)83public void testBadByteSelectFromValue() {84SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);85seq.byteOffset(sequenceElement(), sequenceElement());86}8788@Test(expectedExceptions = IllegalArgumentException.class)89public void testUnknownBitStructField() {90GroupLayout g = MemoryLayout.structLayout(JAVA_INT);91g.bitOffset(groupElement("foo"));92}9394@Test(expectedExceptions = IllegalArgumentException.class)95public void testUnknownByteStructField() {96GroupLayout g = MemoryLayout.structLayout(JAVA_INT);97g.byteOffset(groupElement("foo"));98}99100@Test(expectedExceptions = IllegalArgumentException.class)101public void testBitOutOfBoundsSeqIndex() {102SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);103seq.bitOffset(sequenceElement(6));104}105106@Test(expectedExceptions = IllegalArgumentException.class)107public void testByteOutOfBoundsSeqIndex() {108SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);109seq.byteOffset(sequenceElement(6));110}111112@Test(expectedExceptions = IllegalArgumentException.class)113public void testNegativeSeqIndex() {114sequenceElement(-2);115}116117@Test(expectedExceptions = IllegalArgumentException.class)118public void testBitNegativeSeqIndex() {119SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);120seq.bitOffset(sequenceElement(-2));121}122123@Test(expectedExceptions = IllegalArgumentException.class)124public void testByteNegativeSeqIndex() {125SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);126seq.byteOffset(sequenceElement(-2));127}128129@Test(expectedExceptions = IllegalArgumentException.class)130public void testOutOfBoundsSeqRange() {131SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);132seq.bitOffset(sequenceElement(6, 2));133}134135@Test(expectedExceptions = IllegalArgumentException.class)136public void testNegativeSeqRange() {137sequenceElement(-2, 2);138}139140@Test(expectedExceptions = IllegalArgumentException.class)141public void testBitNegativeSeqRange() {142SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);143seq.bitOffset(sequenceElement(-2, 2));144}145146@Test(expectedExceptions = IllegalArgumentException.class)147public void testByteNegativeSeqRange() {148SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);149seq.byteOffset(sequenceElement(-2, 2));150}151152@Test(expectedExceptions = IllegalArgumentException.class)153public void testIncompleteAccess() {154SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));155seq.varHandle(int.class, sequenceElement());156}157158@Test(expectedExceptions = IllegalArgumentException.class)159public void testBitOffsetHandleBadRange() {160SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));161seq.bitOffsetHandle(sequenceElement(0, 1)); // ranges not accepted162}163164@Test(expectedExceptions = IllegalArgumentException.class)165public void testByteOffsetHandleBadRange() {166SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));167seq.byteOffsetHandle(sequenceElement(0, 1)); // ranges not accepted168}169170@Test(expectedExceptions = UnsupportedOperationException.class)171public void testBadMultiple() {172GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(3), JAVA_INT.withName("foo"));173g.byteOffset(groupElement("foo"));174}175176@Test(expectedExceptions = UnsupportedOperationException.class)177public void testBitOffsetBadUnboundedSequenceTraverse() {178MemoryLayout layout = MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(JAVA_INT));179layout.bitOffset(sequenceElement(1), sequenceElement(0));180}181182@Test(expectedExceptions = UnsupportedOperationException.class)183public void testByteOffsetBadUnboundedSequenceTraverse() {184MemoryLayout layout = MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(JAVA_INT));185layout.byteOffset(sequenceElement(1), sequenceElement(0));186}187188@Test(expectedExceptions = UnsupportedOperationException.class)189public void testBitOffsetHandleBadUnboundedSequenceTraverse() {190MemoryLayout layout = MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(JAVA_INT));191layout.bitOffsetHandle(sequenceElement(1), sequenceElement(0));192}193194@Test(expectedExceptions = UnsupportedOperationException.class)195public void testByteOffsetHandleBadUnboundedSequenceTraverse() {196MemoryLayout layout = MemoryLayout.sequenceLayout(MemoryLayout.sequenceLayout(JAVA_INT));197layout.byteOffsetHandle(sequenceElement(1), sequenceElement(0));198}199200@Test(expectedExceptions = UnsupportedOperationException.class)201public void testBadByteOffsetNoMultipleOf8() {202MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));203layout.byteOffset(groupElement("x"));204}205206@Test(expectedExceptions = UnsupportedOperationException.class)207public void testBadByteOffsetHandleNoMultipleOf8() throws Throwable {208MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));209MethodHandle handle = layout.byteOffsetHandle(groupElement("x"));210handle.invoke();211}212213@Test214public void testBadContainerAlign() {215GroupLayout g = MemoryLayout.structLayout(JAVA_INT.withBitAlignment(16).withName("foo")).withBitAlignment(8);216try {217g.bitOffset(groupElement("foo"));218g.byteOffset(groupElement("foo"));219} catch (Throwable ex) {220throw new AssertionError(ex); // should be ok!221}222try {223g.varHandle(int.class, groupElement("foo")); //ok224assertTrue(false); //should fail!225} catch (UnsupportedOperationException ex) {226//ok227} catch (Throwable ex) {228throw new AssertionError(ex); //should fail!229}230}231232@Test233public void testBadAlignOffset() {234GroupLayout g = MemoryLayout.structLayout(MemoryLayouts.PAD_8, JAVA_INT.withBitAlignment(16).withName("foo"));235try {236g.bitOffset(groupElement("foo"));237g.byteOffset(groupElement("foo"));238} catch (Throwable ex) {239throw new AssertionError(ex); // should be ok!240}241try {242g.varHandle(int.class, groupElement("foo")); //ok243assertTrue(false); //should fail!244} catch (UnsupportedOperationException ex) {245//ok246} catch (Throwable ex) {247throw new AssertionError(ex); //should fail!248}249}250251@Test252public void testBadSequencePathInOffset() {253SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);254// bad path elements255for (PathElement e : List.of( sequenceElement(), sequenceElement(0, 2) )) {256try {257seq.bitOffset(e);258fail();259} catch (IllegalArgumentException ex) {260assertTrue(true);261}262try {263seq.byteOffset(e);264fail();265} catch (IllegalArgumentException ex) {266assertTrue(true);267}268}269}270271@Test272public void testBadSequencePathInSelect() {273SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);274for (PathElement e : List.of( sequenceElement(0), sequenceElement(0, 2) )) {275try {276seq.select(e);277fail();278} catch (IllegalArgumentException ex) {279assertTrue(true);280}281}282}283284@Test285public void testBadSequencePathInMap() {286SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);287for (PathElement e : List.of( sequenceElement(0), sequenceElement(0, 2) )) {288try {289seq.map(l -> l, e);290fail();291} catch (IllegalArgumentException ex) {292assertTrue(true);293}294}295}296297@Test298public void testStructPaths() {299long[] offsets = { 0, 8, 24, 56 };300GroupLayout g = MemoryLayout.structLayout(301MemoryLayouts.JAVA_BYTE.withName("1"),302MemoryLayouts.JAVA_CHAR.withName("2"),303MemoryLayouts.JAVA_FLOAT.withName("3"),304MemoryLayouts.JAVA_LONG.withName("4")305);306307// test select308309for (int i = 1 ; i <= 4 ; i++) {310MemoryLayout selected = g.select(groupElement(String.valueOf(i)));311assertTrue(selected == g.memberLayouts().get(i - 1));312}313314// test offset315316for (int i = 1 ; i <= 4 ; i++) {317long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));318assertEquals(offsets[i - 1], bitOffset);319long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));320assertEquals((offsets[i - 1]) >>> 3, byteOffset);321}322323// test map324325for (int i = 1 ; i <= 4 ; i++) {326GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i)));327assertTrue(g2.isStruct());328for (int j = 0 ; j < 4 ; j++) {329if (j == i - 1) {330assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE);331} else {332assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));333}334}335}336}337338@Test339public void testUnionPaths() {340long[] offsets = { 0, 0, 0, 0 };341GroupLayout g = MemoryLayout.unionLayout(342MemoryLayouts.JAVA_BYTE.withName("1"),343MemoryLayouts.JAVA_CHAR.withName("2"),344MemoryLayouts.JAVA_FLOAT.withName("3"),345MemoryLayouts.JAVA_LONG.withName("4")346);347348// test select349350for (int i = 1 ; i <= 4 ; i++) {351MemoryLayout selected = g.select(groupElement(String.valueOf(i)));352assertTrue(selected == g.memberLayouts().get(i - 1));353}354355// test offset356357for (int i = 1 ; i <= 4 ; i++) {358long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));359assertEquals(offsets[i - 1], bitOffset);360long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));361assertEquals((offsets[i - 1]) >>> 3, byteOffset);362}363364// test map365366for (int i = 1 ; i <= 4 ; i++) {367GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i)));368assertTrue(g2.isUnion());369for (int j = 0 ; j < 4 ; j++) {370if (j == i - 1) {371assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE);372} else {373assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));374}375}376}377}378379@Test380public void testSequencePaths() {381long[] offsets = { 0, 8, 16, 24 };382SequenceLayout g = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_BYTE);383384// test select385386MemoryLayout selected = g.select(sequenceElement());387assertTrue(selected == MemoryLayouts.JAVA_BYTE);388389// test offset390391for (int i = 0 ; i < 4 ; i++) {392long bitOffset = g.bitOffset(sequenceElement(i));393assertEquals(offsets[i], bitOffset);394long byteOffset = g.byteOffset(sequenceElement(i));395assertEquals((offsets[i]) >>> 3, byteOffset);396}397398// test map399400SequenceLayout seq2 = (SequenceLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, sequenceElement());401assertTrue(seq2.elementLayout() == MemoryLayouts.JAVA_DOUBLE);402}403404@Test(dataProvider = "testLayouts")405public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,406long expectedBitOffset) throws Throwable {407MethodHandle bitOffsetHandle = layout.bitOffsetHandle(pathElements);408bitOffsetHandle = bitOffsetHandle.asSpreader(long[].class, indexes.length);409long actualBitOffset = (long) bitOffsetHandle.invokeExact(indexes);410assertEquals(actualBitOffset, expectedBitOffset);411if (expectedBitOffset % 8 == 0) {412MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements);413byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length);414long actualByteOffset = (long) byteOffsetHandle.invokeExact(indexes);415assertEquals(actualByteOffset, expectedBitOffset / 8);416}417}418419@DataProvider420public static Object[][] testLayouts() {421List<Object[]> testCases = new ArrayList<>();422423testCases.add(new Object[] {424MemoryLayout.sequenceLayout(10, JAVA_INT),425new PathElement[] { sequenceElement() },426new long[] { 4 },427JAVA_INT.bitSize() * 4428});429testCases.add(new Object[] {430MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(JAVA_INT, JAVA_INT.withName("y"))),431new PathElement[] { sequenceElement(), groupElement("y") },432new long[] { 4 },433(JAVA_INT.bitSize() * 2) * 4 + JAVA_INT.bitSize()434});435testCases.add(new Object[] {436MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(5), JAVA_INT.withName("y"))),437new PathElement[] { sequenceElement(), groupElement("y") },438new long[] { 4 },439(JAVA_INT.bitSize() + 5) * 4 + 5440});441testCases.add(new Object[] {442MemoryLayout.sequenceLayout(10, JAVA_INT),443new PathElement[] { sequenceElement() },444new long[] { 4 },445JAVA_INT.bitSize() * 4446});447testCases.add(new Object[] {448MemoryLayout.structLayout(449MemoryLayout.sequenceLayout(10, JAVA_INT).withName("data")450),451new PathElement[] { groupElement("data"), sequenceElement() },452new long[] { 4 },453JAVA_INT.bitSize() * 4454});455456MemoryLayout complexLayout = MemoryLayout.structLayout(457MemoryLayout.sequenceLayout(10,458MemoryLayout.sequenceLayout(10,459MemoryLayout.structLayout(460JAVA_INT.withName("x"),461JAVA_INT.withName("y")462)463)464).withName("data")465);466467testCases.add(new Object[] {468complexLayout,469new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("x") },470new long[] { 0, 1 },471(JAVA_INT.bitSize() * 2)472});473testCases.add(new Object[] {474complexLayout,475new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("x") },476new long[] { 1, 0 },477(JAVA_INT.bitSize() * 2) * 10478});479testCases.add(new Object[] {480complexLayout,481new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("y") },482new long[] { 0, 1 },483(JAVA_INT.bitSize() * 2) + JAVA_INT.bitSize()484});485testCases.add(new Object[] {486complexLayout,487new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("y") },488new long[] { 1, 0 },489(JAVA_INT.bitSize() * 2) * 10 + JAVA_INT.bitSize()490});491492return testCases.toArray(Object[][]::new);493}494495@Test(dataProvider = "testLayouts")496public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,497long expectedBitOffset) throws Throwable {498if (expectedBitOffset % 8 != 0)499throw new SkipException("Offset not a multiple of 8");500501MemoryLayout selected = layout.select(pathElements);502MethodHandle sliceHandle = layout.sliceHandle(pathElements);503sliceHandle = sliceHandle.asSpreader(long[].class, indexes.length);504505try (ResourceScope scope = ResourceScope.newConfinedScope()) {506MemorySegment segment = MemorySegment.allocateNative(layout, scope);507MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, indexes);508assertEquals(slice.address().segmentOffset(segment), expectedBitOffset / 8);509assertEquals(slice.byteSize(), selected.byteSize());510}511}512513@Test(expectedExceptions = UnsupportedOperationException.class)514public void testSliceHandleUOEInvalidSize() {515MemoryLayout layout = MemoryLayout.structLayout(516MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("x"),517MemoryLayout.valueLayout(31, ByteOrder.nativeOrder()).withName("y") // size not a multiple of 8518);519520layout.sliceHandle(groupElement("y")); // should throw521}522523@Test(expectedExceptions = UnsupportedOperationException.class)524public void testSliceHandleUOEInvalidOffsetEager() throws Throwable {525MemoryLayout layout = MemoryLayout.structLayout(526MemoryLayout.paddingLayout(5),527MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8528);529530layout.sliceHandle(groupElement("y")); // should throw531}532533@Test(expectedExceptions = UnsupportedOperationException.class)534public void testSliceHandleUOEInvalidOffsetLate() throws Throwable {535MemoryLayout layout = MemoryLayout.sequenceLayout(3,536MemoryLayout.structLayout(537MemoryLayout.paddingLayout(4),538MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8539)540);541542MethodHandle sliceHandle;543try {544sliceHandle = layout.sliceHandle(sequenceElement(), groupElement("y")); // should work545} catch (UnsupportedOperationException uoe) {546fail("Unexpected exception", uoe);547return;548}549550try (ResourceScope scope = ResourceScope.newConfinedScope()) {551MemorySegment segment = MemorySegment.allocateNative(layout, scope);552553try {554sliceHandle.invokeExact(segment, 1); // should work555} catch (UnsupportedOperationException uoe) {556fail("Unexpected exception", uoe);557return;558}559560sliceHandle.invokeExact(segment, 0); // should throw561}562}563}564565566567