< prev index next >

test/jdk/java/foreign/TestLayoutPaths.java

Print this page

 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 /*
 26  * @test
 27  * @run testng TestLayoutPaths
 28  */
 29 
 30 import jdk.incubator.foreign.GroupLayout;
 31 import jdk.incubator.foreign.MemoryLayouts;
 32 import jdk.incubator.foreign.MemoryLayout;
 33 import jdk.incubator.foreign.MemoryLayout.PathElement;
 34 import jdk.incubator.foreign.MemorySegment;
 35 import jdk.incubator.foreign.ResourceScope;
 36 import jdk.incubator.foreign.SequenceLayout;
 37 

 38 import org.testng.SkipException;
 39 import org.testng.annotations.*;
 40 
 41 import java.lang.invoke.MethodHandle;
 42 import java.nio.ByteOrder;
 43 import java.util.ArrayList;
 44 import java.util.List;
 45 
 46 import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
 47 import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement;
 48 import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT;
 49 import static org.testng.Assert.*;
 50 
 51 public class TestLayoutPaths {
 52 
 53     @Test(expectedExceptions = IllegalArgumentException.class)
 54     public void testBadBitSelectFromSeq() {
 55         SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);
 56         seq.bitOffset(groupElement("foo"));
 57     }
 58 
 59     @Test(expectedExceptions = IllegalArgumentException.class)
 60     public void testBadByteSelectFromSeq() {
 61         SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);
 62         seq.byteOffset(groupElement("foo"));
 63     }
 64 
 65     @Test(expectedExceptions = IllegalArgumentException.class)
 66     public void testBadBitSelectFromStruct() {
 67         GroupLayout g = MemoryLayout.structLayout(JAVA_INT);
 68         g.bitOffset(sequenceElement());

136     @Test(expectedExceptions = IllegalArgumentException.class)
137     public void testNegativeSeqRange() {
138         sequenceElement(-2, 2);
139     }
140 
141     @Test(expectedExceptions = IllegalArgumentException.class)
142     public void testBitNegativeSeqRange() {
143         SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);
144         seq.bitOffset(sequenceElement(-2, 2));
145     }
146 
147     @Test(expectedExceptions = IllegalArgumentException.class)
148     public void testByteNegativeSeqRange() {
149         SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);
150         seq.byteOffset(sequenceElement(-2, 2));
151     }
152 
153     @Test(expectedExceptions = IllegalArgumentException.class)
154     public void testIncompleteAccess() {
155         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
156         seq.varHandle(int.class, sequenceElement());
157     }
158 
159     @Test(expectedExceptions = IllegalArgumentException.class)
160     public void testBitOffsetHandleBadRange() {
161         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
162         seq.bitOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
163     }
164 
165     @Test(expectedExceptions = IllegalArgumentException.class)
166     public void testByteOffsetHandleBadRange() {
167         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
168         seq.byteOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
169     }
170 
171     @Test(expectedExceptions = UnsupportedOperationException.class)
172     public void testBadMultiple() {
173         GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(3), JAVA_INT.withName("foo"));
174         g.byteOffset(groupElement("foo"));
175     }
176 

204         layout.byteOffset(groupElement("x"));
205     }
206 
207     @Test(expectedExceptions = UnsupportedOperationException.class)
208     public void testBadByteOffsetHandleNoMultipleOf8() throws Throwable {
209         MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));
210         MethodHandle handle = layout.byteOffsetHandle(groupElement("x"));
211         handle.invoke();
212     }
213 
214     @Test
215     public void testBadContainerAlign() {
216         GroupLayout g = MemoryLayout.structLayout(JAVA_INT.withBitAlignment(16).withName("foo")).withBitAlignment(8);
217         try {
218             g.bitOffset(groupElement("foo"));
219             g.byteOffset(groupElement("foo"));
220         } catch (Throwable ex) {
221             throw new AssertionError(ex); // should be ok!
222         }
223         try {
224             g.varHandle(int.class, groupElement("foo")); //ok
225             assertTrue(false); //should fail!
226         } catch (UnsupportedOperationException ex) {
227             //ok
228         } catch (Throwable ex) {
229             throw new AssertionError(ex); //should fail!
230         }
231     }
232 
233     @Test
234     public void testBadAlignOffset() {
235         GroupLayout g = MemoryLayout.structLayout(MemoryLayouts.PAD_8, JAVA_INT.withBitAlignment(16).withName("foo"));
236         try {
237             g.bitOffset(groupElement("foo"));
238             g.byteOffset(groupElement("foo"));
239         } catch (Throwable ex) {
240             throw new AssertionError(ex); // should be ok!
241         }
242         try {
243             g.varHandle(int.class, groupElement("foo")); //ok
244             assertTrue(false); //should fail!
245         } catch (UnsupportedOperationException ex) {
246             //ok
247         } catch (Throwable ex) {
248             throw new AssertionError(ex); //should fail!
249         }
250     }
251 
252     @Test
253     public void testBadSequencePathInOffset() {
254         SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);
255         // bad path elements
256         for (PathElement e : List.of( sequenceElement(), sequenceElement(0, 2) )) {
257             try {
258                 seq.bitOffset(e);
259                 fail();
260             } catch (IllegalArgumentException ex) {
261                 assertTrue(true);
262             }
263             try {

282         }
283     }
284 
285     @Test
286     public void testBadSequencePathInMap() {
287         SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);
288         for (PathElement e : List.of( sequenceElement(0), sequenceElement(0, 2) )) {
289             try {
290                 seq.map(l -> l, e);
291                 fail();
292             } catch (IllegalArgumentException ex) {
293                 assertTrue(true);
294             }
295         }
296     }
297 
298     @Test
299     public void testStructPaths() {
300         long[] offsets = { 0, 8, 24, 56 };
301         GroupLayout g = MemoryLayout.structLayout(
302                 MemoryLayouts.JAVA_BYTE.withName("1"),
303                 MemoryLayouts.JAVA_CHAR.withName("2"),
304                 MemoryLayouts.JAVA_FLOAT.withName("3"),
305                 MemoryLayouts.JAVA_LONG.withName("4")
306         );
307 
308         // test select
309 
310         for (int i = 1 ; i <= 4 ; i++) {
311             MemoryLayout selected = g.select(groupElement(String.valueOf(i)));
312             assertTrue(selected == g.memberLayouts().get(i - 1));
313         }
314 
315         // test offset
316 
317         for (int i = 1 ; i <= 4 ; i++) {
318             long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));
319             assertEquals(offsets[i - 1], bitOffset);
320             long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));
321             assertEquals((offsets[i - 1]) >>> 3, byteOffset);
322         }
323 
324         // test map
325 
326         for (int i = 1 ; i <= 4 ; i++) {
327             GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i)));
328             assertTrue(g2.isStruct());
329             for (int j = 0 ; j < 4 ; j++) {
330                 if (j == i - 1) {
331                     assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE);
332                 } else {
333                     assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));
334                 }
335             }
336         }
337     }
338 
339     @Test
340     public void testUnionPaths() {
341         long[] offsets = { 0, 0, 0, 0 };
342         GroupLayout g = MemoryLayout.unionLayout(
343                 MemoryLayouts.JAVA_BYTE.withName("1"),
344                 MemoryLayouts.JAVA_CHAR.withName("2"),
345                 MemoryLayouts.JAVA_FLOAT.withName("3"),
346                 MemoryLayouts.JAVA_LONG.withName("4")
347         );
348 
349         // test select
350 
351         for (int i = 1 ; i <= 4 ; i++) {
352             MemoryLayout selected = g.select(groupElement(String.valueOf(i)));
353             assertTrue(selected == g.memberLayouts().get(i - 1));
354         }
355 
356         // test offset
357 
358         for (int i = 1 ; i <= 4 ; i++) {
359             long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));
360             assertEquals(offsets[i - 1], bitOffset);
361             long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));
362             assertEquals((offsets[i - 1]) >>> 3, byteOffset);
363         }
364 
365         // test map
366 
367         for (int i = 1 ; i <= 4 ; i++) {
368             GroupLayout g2 = (GroupLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, groupElement(String.valueOf(i)));
369             assertTrue(g2.isUnion());
370             for (int j = 0 ; j < 4 ; j++) {
371                 if (j == i - 1) {
372                     assertEquals(g2.memberLayouts().get(j), MemoryLayouts.JAVA_DOUBLE);
373                 } else {
374                     assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));
375                 }
376             }
377         }
378     }
379 
380     @Test
381     public void testSequencePaths() {
382         long[] offsets = { 0, 8, 16, 24 };
383         SequenceLayout g = MemoryLayout.sequenceLayout(4, MemoryLayouts.JAVA_BYTE);
384 
385         // test select
386 
387         MemoryLayout selected = g.select(sequenceElement());
388         assertTrue(selected == MemoryLayouts.JAVA_BYTE);
389 
390         // test offset
391 
392         for (int i = 0 ; i < 4 ; i++) {
393             long bitOffset = g.bitOffset(sequenceElement(i));
394             assertEquals(offsets[i], bitOffset);
395             long byteOffset = g.byteOffset(sequenceElement(i));
396             assertEquals((offsets[i]) >>> 3, byteOffset);
397         }
398 
399         // test map
400 
401         SequenceLayout seq2 = (SequenceLayout)g.map(l -> MemoryLayouts.JAVA_DOUBLE, sequenceElement());
402         assertTrue(seq2.elementLayout() == MemoryLayouts.JAVA_DOUBLE);
403     }
404 
405     @Test(dataProvider = "testLayouts")
406     public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
407                                  long expectedBitOffset) throws Throwable {
408         MethodHandle bitOffsetHandle = layout.bitOffsetHandle(pathElements);
409         bitOffsetHandle = bitOffsetHandle.asSpreader(long[].class, indexes.length);
410         long actualBitOffset = (long) bitOffsetHandle.invokeExact(indexes);
411         assertEquals(actualBitOffset, expectedBitOffset);
412         if (expectedBitOffset % 8 == 0) {
413             MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements);
414             byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length);
415             long actualByteOffset = (long) byteOffsetHandle.invokeExact(indexes);
416             assertEquals(actualByteOffset, expectedBitOffset / 8);
417         }
418     }
419 
420     @DataProvider
421     public static Object[][] testLayouts() {
422         List<Object[]> testCases = new ArrayList<>();

489             new long[] { 1, 0 },
490             (JAVA_INT.bitSize() * 2) * 10 + JAVA_INT.bitSize()
491         });
492 
493         return testCases.toArray(Object[][]::new);
494     }
495 
496     @Test(dataProvider = "testLayouts")
497     public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
498                                 long expectedBitOffset) throws Throwable {
499         if (expectedBitOffset % 8 != 0)
500             throw new SkipException("Offset not a multiple of 8");
501 
502         MemoryLayout selected = layout.select(pathElements);
503         MethodHandle sliceHandle = layout.sliceHandle(pathElements);
504         sliceHandle = sliceHandle.asSpreader(long[].class, indexes.length);
505 
506         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
507             MemorySegment segment = MemorySegment.allocateNative(layout, scope);
508             MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, indexes);
509             assertEquals(slice.address().segmentOffset(segment), expectedBitOffset / 8);
510             assertEquals(slice.byteSize(), selected.byteSize());
511         }
512     }
513 
514     @Test(expectedExceptions = UnsupportedOperationException.class)
515     public void testSliceHandleUOEInvalidSize() {
516         MemoryLayout layout = MemoryLayout.structLayout(
517             MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("x"),
518             MemoryLayout.valueLayout(31, ByteOrder.nativeOrder()).withName("y") // size not a multiple of 8
519         );
520 
521         layout.sliceHandle(groupElement("y")); // should throw
522     }
523 
524     @Test(expectedExceptions = UnsupportedOperationException.class)
525     public void testSliceHandleUOEInvalidOffsetEager() throws Throwable {
526         MemoryLayout layout = MemoryLayout.structLayout(
527             MemoryLayout.paddingLayout(5),
528             MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8
529         );
530 
531         layout.sliceHandle(groupElement("y")); // should throw
532     }
533 
534     @Test(expectedExceptions = UnsupportedOperationException.class)
535     public void testSliceHandleUOEInvalidOffsetLate() throws Throwable {
536         MemoryLayout layout = MemoryLayout.sequenceLayout(3,
537             MemoryLayout.structLayout(
538                 MemoryLayout.paddingLayout(4),
539                 MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("y") // offset not a multiple of 8
540             )
541         );
542 
543         MethodHandle sliceHandle;
544         try {
545             sliceHandle = layout.sliceHandle(sequenceElement(), groupElement("y")); // should work
546         } catch (UnsupportedOperationException uoe) {
547             fail("Unexpected exception", uoe);
548             return;
549         }
550 
551         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
552             MemorySegment segment = MemorySegment.allocateNative(layout, scope);
553 
554             try {
555                 sliceHandle.invokeExact(segment, 1); // should work
556             } catch (UnsupportedOperationException uoe) {
557                 fail("Unexpected exception", uoe);
558                 return;
559             }

 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 /*
 26  * @test
 27  * @run testng TestLayoutPaths
 28  */
 29 
 30 import jdk.incubator.foreign.GroupLayout;

 31 import jdk.incubator.foreign.MemoryLayout;
 32 import jdk.incubator.foreign.MemoryLayout.PathElement;
 33 import jdk.incubator.foreign.MemorySegment;
 34 import jdk.incubator.foreign.ResourceScope;
 35 import jdk.incubator.foreign.SequenceLayout;
 36 
 37 import jdk.incubator.foreign.ValueLayout;
 38 import org.testng.SkipException;
 39 import org.testng.annotations.*;
 40 
 41 import java.lang.invoke.MethodHandle;

 42 import java.util.ArrayList;
 43 import java.util.List;
 44 
 45 import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
 46 import static jdk.incubator.foreign.MemoryLayout.PathElement.sequenceElement;
 47 import static jdk.incubator.foreign.ValueLayout.JAVA_INT;
 48 import static org.testng.Assert.*;
 49 
 50 public class TestLayoutPaths {
 51 
 52     @Test(expectedExceptions = IllegalArgumentException.class)
 53     public void testBadBitSelectFromSeq() {
 54         SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);
 55         seq.bitOffset(groupElement("foo"));
 56     }
 57 
 58     @Test(expectedExceptions = IllegalArgumentException.class)
 59     public void testBadByteSelectFromSeq() {
 60         SequenceLayout seq = MemoryLayout.sequenceLayout(JAVA_INT);
 61         seq.byteOffset(groupElement("foo"));
 62     }
 63 
 64     @Test(expectedExceptions = IllegalArgumentException.class)
 65     public void testBadBitSelectFromStruct() {
 66         GroupLayout g = MemoryLayout.structLayout(JAVA_INT);
 67         g.bitOffset(sequenceElement());

135     @Test(expectedExceptions = IllegalArgumentException.class)
136     public void testNegativeSeqRange() {
137         sequenceElement(-2, 2);
138     }
139 
140     @Test(expectedExceptions = IllegalArgumentException.class)
141     public void testBitNegativeSeqRange() {
142         SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);
143         seq.bitOffset(sequenceElement(-2, 2));
144     }
145 
146     @Test(expectedExceptions = IllegalArgumentException.class)
147     public void testByteNegativeSeqRange() {
148         SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT);
149         seq.byteOffset(sequenceElement(-2, 2));
150     }
151 
152     @Test(expectedExceptions = IllegalArgumentException.class)
153     public void testIncompleteAccess() {
154         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
155         seq.varHandle(sequenceElement());
156     }
157 
158     @Test(expectedExceptions = IllegalArgumentException.class)
159     public void testBitOffsetHandleBadRange() {
160         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
161         seq.bitOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
162     }
163 
164     @Test(expectedExceptions = IllegalArgumentException.class)
165     public void testByteOffsetHandleBadRange() {
166         SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
167         seq.byteOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
168     }
169 
170     @Test(expectedExceptions = UnsupportedOperationException.class)
171     public void testBadMultiple() {
172         GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(3), JAVA_INT.withName("foo"));
173         g.byteOffset(groupElement("foo"));
174     }
175 

203         layout.byteOffset(groupElement("x"));
204     }
205 
206     @Test(expectedExceptions = UnsupportedOperationException.class)
207     public void testBadByteOffsetHandleNoMultipleOf8() throws Throwable {
208         MemoryLayout layout = MemoryLayout.structLayout(MemoryLayout.paddingLayout(7), JAVA_INT.withName("x"));
209         MethodHandle handle = layout.byteOffsetHandle(groupElement("x"));
210         handle.invoke();
211     }
212 
213     @Test
214     public void testBadContainerAlign() {
215         GroupLayout g = MemoryLayout.structLayout(JAVA_INT.withBitAlignment(16).withName("foo")).withBitAlignment(8);
216         try {
217             g.bitOffset(groupElement("foo"));
218             g.byteOffset(groupElement("foo"));
219         } catch (Throwable ex) {
220             throw new AssertionError(ex); // should be ok!
221         }
222         try {
223             g.varHandle(groupElement("foo")); //ok
224             assertTrue(false); //should fail!
225         } catch (UnsupportedOperationException ex) {
226             //ok
227         } catch (Throwable ex) {
228             throw new AssertionError(ex); //should fail!
229         }
230     }
231 
232     @Test
233     public void testBadAlignOffset() {
234         GroupLayout g = MemoryLayout.structLayout(MemoryLayout.paddingLayout(8), JAVA_INT.withBitAlignment(16).withName("foo"));
235         try {
236             g.bitOffset(groupElement("foo"));
237             g.byteOffset(groupElement("foo"));
238         } catch (Throwable ex) {
239             throw new AssertionError(ex); // should be ok!
240         }
241         try {
242             g.varHandle(groupElement("foo")); //ok
243             assertTrue(false); //should fail!
244         } catch (UnsupportedOperationException ex) {
245             //ok
246         } catch (Throwable ex) {
247             throw new AssertionError(ex); //should fail!
248         }
249     }
250 
251     @Test
252     public void testBadSequencePathInOffset() {
253         SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);
254         // bad path elements
255         for (PathElement e : List.of( sequenceElement(), sequenceElement(0, 2) )) {
256             try {
257                 seq.bitOffset(e);
258                 fail();
259             } catch (IllegalArgumentException ex) {
260                 assertTrue(true);
261             }
262             try {

281         }
282     }
283 
284     @Test
285     public void testBadSequencePathInMap() {
286         SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT);
287         for (PathElement e : List.of( sequenceElement(0), sequenceElement(0, 2) )) {
288             try {
289                 seq.map(l -> l, e);
290                 fail();
291             } catch (IllegalArgumentException ex) {
292                 assertTrue(true);
293             }
294         }
295     }
296 
297     @Test
298     public void testStructPaths() {
299         long[] offsets = { 0, 8, 24, 56 };
300         GroupLayout g = MemoryLayout.structLayout(
301                 ValueLayout.JAVA_BYTE.withName("1"),
302                 ValueLayout.JAVA_CHAR.withName("2"),
303                 ValueLayout.JAVA_FLOAT.withName("3"),
304                 ValueLayout.JAVA_LONG.withName("4")
305         );
306 
307         // test select
308 
309         for (int i = 1 ; i <= 4 ; i++) {
310             MemoryLayout selected = g.select(groupElement(String.valueOf(i)));
311             assertTrue(selected == g.memberLayouts().get(i - 1));
312         }
313 
314         // test offset
315 
316         for (int i = 1 ; i <= 4 ; i++) {
317             long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));
318             assertEquals(offsets[i - 1], bitOffset);
319             long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));
320             assertEquals((offsets[i - 1]) >>> 3, byteOffset);
321         }
322 
323         // test map
324 
325         for (int i = 1 ; i <= 4 ; i++) {
326             GroupLayout g2 = (GroupLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, groupElement(String.valueOf(i)));
327             assertTrue(g2.isStruct());
328             for (int j = 0 ; j < 4 ; j++) {
329                 if (j == i - 1) {
330                     assertEquals(g2.memberLayouts().get(j), ValueLayout.JAVA_DOUBLE);
331                 } else {
332                     assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));
333                 }
334             }
335         }
336     }
337 
338     @Test
339     public void testUnionPaths() {
340         long[] offsets = { 0, 0, 0, 0 };
341         GroupLayout g = MemoryLayout.unionLayout(
342                 ValueLayout.JAVA_BYTE.withName("1"),
343                 ValueLayout.JAVA_CHAR.withName("2"),
344                 ValueLayout.JAVA_FLOAT.withName("3"),
345                 ValueLayout.JAVA_LONG.withName("4")
346         );
347 
348         // test select
349 
350         for (int i = 1 ; i <= 4 ; i++) {
351             MemoryLayout selected = g.select(groupElement(String.valueOf(i)));
352             assertTrue(selected == g.memberLayouts().get(i - 1));
353         }
354 
355         // test offset
356 
357         for (int i = 1 ; i <= 4 ; i++) {
358             long bitOffset = g.bitOffset(groupElement(String.valueOf(i)));
359             assertEquals(offsets[i - 1], bitOffset);
360             long byteOffset = g.byteOffset(groupElement(String.valueOf(i)));
361             assertEquals((offsets[i - 1]) >>> 3, byteOffset);
362         }
363 
364         // test map
365 
366         for (int i = 1 ; i <= 4 ; i++) {
367             GroupLayout g2 = (GroupLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, groupElement(String.valueOf(i)));
368             assertTrue(g2.isUnion());
369             for (int j = 0 ; j < 4 ; j++) {
370                 if (j == i - 1) {
371                     assertEquals(g2.memberLayouts().get(j), ValueLayout.JAVA_DOUBLE);
372                 } else {
373                     assertEquals(g2.memberLayouts().get(j), g.memberLayouts().get(j));
374                 }
375             }
376         }
377     }
378 
379     @Test
380     public void testSequencePaths() {
381         long[] offsets = { 0, 8, 16, 24 };
382         SequenceLayout g = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_BYTE);
383 
384         // test select
385 
386         MemoryLayout selected = g.select(sequenceElement());
387         assertTrue(selected == ValueLayout.JAVA_BYTE);
388 
389         // test offset
390 
391         for (int i = 0 ; i < 4 ; i++) {
392             long bitOffset = g.bitOffset(sequenceElement(i));
393             assertEquals(offsets[i], bitOffset);
394             long byteOffset = g.byteOffset(sequenceElement(i));
395             assertEquals((offsets[i]) >>> 3, byteOffset);
396         }
397 
398         // test map
399 
400         SequenceLayout seq2 = (SequenceLayout)g.map(l -> ValueLayout.JAVA_DOUBLE, sequenceElement());
401         assertTrue(seq2.elementLayout() == ValueLayout.JAVA_DOUBLE);
402     }
403 
404     @Test(dataProvider = "testLayouts")
405     public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
406                                  long expectedBitOffset) throws Throwable {
407         MethodHandle bitOffsetHandle = layout.bitOffsetHandle(pathElements);
408         bitOffsetHandle = bitOffsetHandle.asSpreader(long[].class, indexes.length);
409         long actualBitOffset = (long) bitOffsetHandle.invokeExact(indexes);
410         assertEquals(actualBitOffset, expectedBitOffset);
411         if (expectedBitOffset % 8 == 0) {
412             MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements);
413             byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length);
414             long actualByteOffset = (long) byteOffsetHandle.invokeExact(indexes);
415             assertEquals(actualByteOffset, expectedBitOffset / 8);
416         }
417     }
418 
419     @DataProvider
420     public static Object[][] testLayouts() {
421         List<Object[]> testCases = new ArrayList<>();

488             new long[] { 1, 0 },
489             (JAVA_INT.bitSize() * 2) * 10 + JAVA_INT.bitSize()
490         });
491 
492         return testCases.toArray(Object[][]::new);
493     }
494 
495     @Test(dataProvider = "testLayouts")
496     public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes,
497                                 long expectedBitOffset) throws Throwable {
498         if (expectedBitOffset % 8 != 0)
499             throw new SkipException("Offset not a multiple of 8");
500 
501         MemoryLayout selected = layout.select(pathElements);
502         MethodHandle sliceHandle = layout.sliceHandle(pathElements);
503         sliceHandle = sliceHandle.asSpreader(long[].class, indexes.length);
504 
505         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
506             MemorySegment segment = MemorySegment.allocateNative(layout, scope);
507             MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, indexes);
508             assertEquals(slice.address().toRawLongValue() - segment.address().toRawLongValue(), expectedBitOffset / 8);
509             assertEquals(slice.byteSize(), selected.byteSize());
510         }
511     }
512 










513     @Test(expectedExceptions = UnsupportedOperationException.class)
514     public void testSliceHandleUOEInvalidOffsetEager() throws Throwable {
515         MemoryLayout layout = MemoryLayout.structLayout(
516             MemoryLayout.paddingLayout(5),
517             JAVA_INT.withName("y") // offset not a multiple of 8
518         );
519 
520         layout.sliceHandle(groupElement("y")); // should throw
521     }
522 
523     @Test(expectedExceptions = UnsupportedOperationException.class)
524     public void testSliceHandleUOEInvalidOffsetLate() throws Throwable {
525         MemoryLayout layout = MemoryLayout.sequenceLayout(3,
526             MemoryLayout.structLayout(
527                 MemoryLayout.paddingLayout(4),
528                     JAVA_INT.withName("y") // offset not a multiple of 8
529             )
530         );
531 
532         MethodHandle sliceHandle;
533         try {
534             sliceHandle = layout.sliceHandle(sequenceElement(), groupElement("y")); // should work
535         } catch (UnsupportedOperationException uoe) {
536             fail("Unexpected exception", uoe);
537             return;
538         }
539 
540         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
541             MemorySegment segment = MemorySegment.allocateNative(layout, scope);
542 
543             try {
544                 sliceHandle.invokeExact(segment, 1); // should work
545             } catch (UnsupportedOperationException uoe) {
546                 fail("Unexpected exception", uoe);
547                 return;
548             }
< prev index next >