| /* | |
| * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| /* | |
| * @test | |
| * @run testng TestLayoutPaths | |
| */ | |
| import java.lang.foreign.*; | |
| import java.lang.foreign.MemoryLayout.PathElement; | |
| import org.testng.annotations.*; | |
| import java.lang.invoke.MethodHandle; | |
| import java.lang.invoke.VarHandle; | |
| import java.lang.invoke.VarHandle.AccessMode; | |
| import java.nio.ByteOrder; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.function.IntFunction; | |
| import java.util.stream.Stream; | |
| import static java.lang.foreign.MemoryLayout.PathElement.groupElement; | |
| import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; | |
| import static java.lang.foreign.ValueLayout.JAVA_INT; | |
| import static java.lang.foreign.ValueLayout.JAVA_SHORT; | |
| import static org.testng.Assert.*; | |
| public class TestLayoutPaths { | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testBadByteSelectFromSeq() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(groupElement("foo")); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testBadByteSelectFromStruct() { | |
| GroupLayout g = MemoryLayout.structLayout(JAVA_INT); | |
| g.byteOffset(sequenceElement()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testBadByteSelectFromValue() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(sequenceElement(), sequenceElement()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testUnknownByteStructField() { | |
| GroupLayout g = MemoryLayout.structLayout(JAVA_INT); | |
| g.byteOffset(groupElement("foo")); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testTooBigGroupElementIndex() { | |
| GroupLayout g = MemoryLayout.structLayout(JAVA_INT); | |
| g.byteOffset(groupElement(1)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testNegativeGroupElementIndex() { | |
| GroupLayout g = MemoryLayout.structLayout(JAVA_INT); | |
| g.byteOffset(groupElement(-1)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testByteOutOfBoundsSeqIndex() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(sequenceElement(6)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testNegativeSeqIndex() { | |
| sequenceElement(-2); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testByteNegativeSeqIndex() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(sequenceElement(-2)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testOutOfBoundsSeqRange() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(sequenceElement(6, 2)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testNegativeSeqRange() { | |
| sequenceElement(-2, 2); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testByteNegativeSeqRange() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, JAVA_INT); | |
| seq.byteOffset(sequenceElement(-2, 2)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testIncompleteAccess() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); | |
| seq.varHandle(sequenceElement()); | |
| } | |
| @Test | |
| public void testByteOffsetHandleRange() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); | |
| seq.byteOffsetHandle(sequenceElement(0, 1)); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testByteOffsetHandleBadRange() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT)); | |
| seq.byteOffsetHandle(sequenceElement(5, 1)); // invalid range (starting position is outside the sequence) | |
| } | |
| @Test | |
| public void testBadAlignmentOfRoot() { | |
| MemoryLayout struct = MemoryLayout.structLayout( | |
| JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("x")); | |
| assertEquals(struct.byteAlignment(), 4); | |
| try (Arena arena = Arena.ofConfined()) { | |
| MemorySegment seg = arena.allocate(struct.byteSize() + 2, struct.byteAlignment()).asSlice(2); | |
| assertEquals(seg.address() % JAVA_SHORT.byteAlignment(), 0); // should be aligned | |
| assertNotEquals(seg.address() % struct.byteAlignment(), 0); // should not be aligned | |
| String expectedMessage = "Target offset 0 is incompatible with alignment constraint " + struct.byteAlignment() + " (of [i4s2(x)]) for segment MemorySegment"; | |
| VarHandle vhX = struct.varHandle(groupElement("x")); | |
| IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> { | |
| vhX.set(seg, 0L, (short) 42); | |
| }); | |
| assertTrue(iae.getMessage().startsWith(expectedMessage)); | |
| MethodHandle sliceX = struct.sliceHandle(groupElement("x")); | |
| iae = expectThrows(IllegalArgumentException.class, () -> { | |
| MemorySegment slice = (MemorySegment) sliceX.invokeExact(seg, 0L); | |
| }); | |
| assertTrue(iae.getMessage().startsWith(expectedMessage)); | |
| } | |
| } | |
| @Test | |
| public void testWrongTypeRoot() { | |
| MemoryLayout struct = MemoryLayout.structLayout( | |
| JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN) | |
| ); | |
| var expectedMessage = "Bad layout path: attempting to select a sequence element from a non-sequence layout: [i4i4]"; | |
| IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> | |
| struct.select(PathElement.sequenceElement())); | |
| assertEquals(iae.getMessage(), expectedMessage); | |
| } | |
| @Test | |
| public void testWrongTypeEnclosing() { | |
| MemoryLayout struct = MemoryLayout.structLayout( | |
| MemoryLayout.sequenceLayout(2, MemoryLayout.structLayout( | |
| JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("3a"), | |
| JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("3b") | |
| ).withName("2") | |
| ).withName("1") | |
| ).withName("0"); | |
| var expectedMessage = "Bad layout path: attempting to select a sequence element from a non-sequence layout: " + | |
| "[i4(3a)i4(3b)](2), selected from: " + | |
| "[2:[i4(3a)i4(3b)](2)](1), selected from: " + | |
| "[[2:[i4(3a)i4(3b)](2)](1)](0)"; | |
| IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> | |
| struct.select(PathElement.groupElement("1"), | |
| PathElement.sequenceElement(), | |
| PathElement.sequenceElement())); | |
| assertEquals(iae.getMessage(), expectedMessage); | |
| } | |
| @Test | |
| public void testBadSequencePathInOffset() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT); | |
| // bad path elements | |
| for (PathElement e : List.of( sequenceElement(), sequenceElement(0, 2) )) { | |
| try { | |
| seq.byteOffset(e); | |
| fail(); | |
| } catch (IllegalArgumentException ex) { | |
| assertTrue(true); | |
| } | |
| } | |
| } | |
| @Test | |
| public void testBadSequencePathInSelect() { | |
| SequenceLayout seq = MemoryLayout.sequenceLayout(10, JAVA_INT); | |
| for (PathElement e : List.of( sequenceElement(0), sequenceElement(0, 2) )) { | |
| try { | |
| seq.select(e); | |
| fail(); | |
| } catch (IllegalArgumentException ex) { | |
| assertTrue(true); | |
| } | |
| } | |
| } | |
| @Test(dataProvider = "groupSelectors") | |
| public void testStructPaths(IntFunction<PathElement> groupSelector) { | |
| long[] offsets = { 0, 1, 3, 7 }; | |
| GroupLayout g = MemoryLayout.structLayout( | |
| ValueLayout.JAVA_BYTE.withName("0"), | |
| ValueLayout.JAVA_CHAR_UNALIGNED.withName("1"), | |
| ValueLayout.JAVA_FLOAT_UNALIGNED.withName("2"), | |
| ValueLayout.JAVA_LONG_UNALIGNED.withName("3") | |
| ); | |
| // test select | |
| for (int i = 0 ; i < 4 ; i++) { | |
| MemoryLayout selected = g.select(groupSelector.apply(i)); | |
| assertTrue(selected == g.memberLayouts().get(i)); | |
| } | |
| // test offset | |
| for (int i = 0 ; i < 4 ; i++) { | |
| long byteOffset = g.byteOffset(groupSelector.apply(i)); | |
| assertEquals(offsets[i], byteOffset); | |
| } | |
| } | |
| @Test(dataProvider = "groupSelectors") | |
| public void testUnionPaths(IntFunction<PathElement> groupSelector) { | |
| long[] offsets = { 0, 0, 0, 0 }; | |
| GroupLayout g = MemoryLayout.unionLayout( | |
| ValueLayout.JAVA_BYTE.withName("0"), | |
| ValueLayout.JAVA_CHAR.withName("1"), | |
| ValueLayout.JAVA_FLOAT.withName("2"), | |
| ValueLayout.JAVA_LONG.withName("3") | |
| ); | |
| // test select | |
| for (int i = 0 ; i < 4 ; i++) { | |
| MemoryLayout selected = g.select(groupSelector.apply(i)); | |
| assertTrue(selected == g.memberLayouts().get(i)); | |
| } | |
| // test offset | |
| for (int i = 0 ; i < 4 ; i++) { | |
| long byteOffset = g.byteOffset(groupSelector.apply(i)); | |
| assertEquals(offsets[i], byteOffset); | |
| } | |
| } | |
| @DataProvider | |
| public static Object[][] groupSelectors() { | |
| return new Object[][] { | |
| { (IntFunction<PathElement>) PathElement::groupElement }, // by index | |
| { (IntFunction<PathElement>) i -> PathElement.groupElement(String.valueOf(i)) } // by name | |
| }; | |
| } | |
| @Test | |
| public void testSequencePaths() { | |
| long[] offsets = { 0, 1, 2, 3 }; | |
| SequenceLayout g = MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_BYTE); | |
| // test select | |
| MemoryLayout selected = g.select(sequenceElement()); | |
| assertTrue(selected == ValueLayout.JAVA_BYTE); | |
| // test offset | |
| for (int i = 0 ; i < 4 ; i++) { | |
| long byteOffset = g.byteOffset(sequenceElement(i)); | |
| assertEquals(offsets[i], byteOffset); | |
| } | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testOffsetHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements); | |
| byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); | |
| long actualByteOffset = (long) byteOffsetHandle.invokeExact(0L, indexes); | |
| assertEquals(actualByteOffset, expectedByteOffset); | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| int[] badIndices = { -1, 10 }; | |
| MemoryLayout seqLayout = MemoryLayout.sequenceLayout(badIndices[1], layout); | |
| for (int badIndex : badIndices) { | |
| PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; | |
| long[] seqIndexes = new long[indexes.length + 1]; | |
| System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); | |
| System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length); | |
| seqPathElements[0] = PathElement.sequenceElement(); | |
| seqIndexes[0] = badIndex; | |
| MethodHandle seqByteOffsetHandle = seqLayout.byteOffsetHandle(seqPathElements) | |
| .asSpreader(long[].class, seqIndexes.length); | |
| assertThrows(IndexOutOfBoundsException.class, () -> seqByteOffsetHandle.invoke(0L, seqIndexes)); | |
| } | |
| } | |
| @Test(dataProvider = "testLayouts", expectedExceptions = ArithmeticException.class) | |
| public void testOffsetHandleOverflow(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements); | |
| byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); | |
| byteOffsetHandle.invoke(Long.MAX_VALUE, indexes); | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); | |
| PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; | |
| long[] seqIndexes = new long[indexes.length + 1]; | |
| System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); | |
| System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length); | |
| seqPathElements[0] = PathElement.sequenceElement(); | |
| seqIndexes[0] = 0; | |
| MethodHandle getter_handle = seqLayout.varHandle(seqPathElements) | |
| .toMethodHandle(AccessMode.GET) | |
| .asSpreader(long[].class, seqIndexes.length); | |
| MemorySegment segment = Arena.ofAuto().allocate(layout); | |
| assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testSliceHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); | |
| PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; | |
| long[] seqIndexes = new long[indexes.length + 1]; | |
| System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); | |
| System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length); | |
| seqPathElements[0] = PathElement.sequenceElement(); | |
| seqIndexes[0] = 0; | |
| MethodHandle getter_handle = seqLayout.sliceHandle(seqPathElements) | |
| .asSpreader(long[].class, seqIndexes.length); | |
| MemorySegment segment = Arena.ofAuto().allocate(layout); | |
| assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testArrayElementVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); | |
| PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; | |
| long[] seqIndexes = new long[indexes.length + 2]; | |
| System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); | |
| System.arraycopy(indexes, 0, seqIndexes, 2, indexes.length); | |
| seqPathElements[0] = PathElement.sequenceElement(); | |
| seqIndexes[0] = 0; | |
| seqIndexes[1] = 0; | |
| MethodHandle getter_handle = seqLayout.arrayElementVarHandle(seqPathElements) | |
| .toMethodHandle(AccessMode.GET) | |
| .asSpreader(long[].class, seqIndexes.length); | |
| MemorySegment segment = Arena.ofAuto().allocate(layout); | |
| assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); | |
| } | |
| @Test | |
| public void testHashCodeCollision() { | |
| PathElement sequenceElement = PathElement.sequenceElement(); | |
| PathElement dereferenceElement = PathElement.dereferenceElement(); | |
| assertNotEquals(sequenceElement.hashCode(), dereferenceElement.hashCode()); | |
| } | |
| @Test | |
| public void testGroupElementIndexToString() { | |
| PathElement e = PathElement.groupElement(2); | |
| assertEquals(e.toString(), "groupElement(2)"); | |
| } | |
| @Test | |
| public void testGroupElementNameToString() { | |
| PathElement e = PathElement.groupElement("x"); | |
| assertEquals(e.toString(), "groupElement(\"x\")"); | |
| } | |
| @Test | |
| public void testSequenceElementToString() { | |
| PathElement e = PathElement.sequenceElement(); | |
| assertEquals(e.toString(), "sequenceElement()"); | |
| } | |
| @Test | |
| public void testSequenceElementIndexToString() { | |
| PathElement e = PathElement.sequenceElement(2); | |
| assertEquals(e.toString(), "sequenceElement(2)"); | |
| } | |
| @Test | |
| public void testSequenceElementRangeToString() { | |
| PathElement e = PathElement.sequenceElement(2, 4); | |
| assertEquals(e.toString(), "sequenceElement(2, 4)"); | |
| } | |
| @Test | |
| public void testDerefereceElementToString() { | |
| PathElement e = PathElement.dereferenceElement(); | |
| assertEquals(e.toString(), "dereferenceElement()"); | |
| } | |
| @DataProvider | |
| public static Object[][] testLayouts() { | |
| List<Object[]> testCases = new ArrayList<>(); | |
| testCases.add(new Object[] { | |
| MemoryLayout.sequenceLayout(10, JAVA_INT), | |
| new PathElement[] { sequenceElement() }, | |
| new long[] { 4 }, | |
| JAVA_INT.byteSize() * 4 | |
| }); | |
| testCases.add(new Object[] { | |
| MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(JAVA_INT, JAVA_INT.withName("y"))), | |
| new PathElement[] { sequenceElement(), groupElement("y") }, | |
| new long[] { 4 }, | |
| (JAVA_INT.byteSize() * 2) * 4 + JAVA_INT.byteSize() | |
| }); | |
| testCases.add(new Object[] { | |
| MemoryLayout.sequenceLayout(10, MemoryLayout.structLayout(MemoryLayout.paddingLayout(4), JAVA_INT.withName("y"))), | |
| new PathElement[] { sequenceElement(), groupElement("y") }, | |
| new long[] { 4 }, | |
| (JAVA_INT.byteSize() + 4) * 4 + 4 | |
| }); | |
| testCases.add(new Object[] { | |
| MemoryLayout.sequenceLayout(10, JAVA_INT), | |
| new PathElement[] { sequenceElement() }, | |
| new long[] { 4 }, | |
| JAVA_INT.byteSize() * 4 | |
| }); | |
| testCases.add(new Object[] { | |
| MemoryLayout.structLayout( | |
| MemoryLayout.sequenceLayout(10, JAVA_INT).withName("data") | |
| ), | |
| new PathElement[] { groupElement("data"), sequenceElement() }, | |
| new long[] { 4 }, | |
| JAVA_INT.byteSize() * 4 | |
| }); | |
| MemoryLayout complexLayout = MemoryLayout.structLayout( | |
| MemoryLayout.sequenceLayout(10, | |
| MemoryLayout.sequenceLayout(10, | |
| MemoryLayout.structLayout( | |
| JAVA_INT.withName("x"), | |
| JAVA_INT.withName("y") | |
| ) | |
| ) | |
| ).withName("data") | |
| ); | |
| testCases.add(new Object[] { | |
| complexLayout, | |
| new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("x") }, | |
| new long[] { 0, 1 }, | |
| (JAVA_INT.byteSize() * 2) | |
| }); | |
| testCases.add(new Object[] { | |
| complexLayout, | |
| new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("x") }, | |
| new long[] { 1, 0 }, | |
| (JAVA_INT.byteSize() * 2) * 10 | |
| }); | |
| testCases.add(new Object[] { | |
| complexLayout, | |
| new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("y") }, | |
| new long[] { 0, 1 }, | |
| (JAVA_INT.byteSize() * 2) + JAVA_INT.byteSize() | |
| }); | |
| testCases.add(new Object[] { | |
| complexLayout, | |
| new PathElement[] { groupElement("data"), sequenceElement(), sequenceElement(), groupElement("y") }, | |
| new long[] { 1, 0 }, | |
| (JAVA_INT.byteSize() * 2) * 10 + JAVA_INT.byteSize() | |
| }); | |
| return testCases.toArray(Object[][]::new); | |
| } | |
| @Test(dataProvider = "testLayouts") | |
| public void testSliceHandle(MemoryLayout layout, PathElement[] pathElements, long[] indexes, | |
| long expectedByteOffset) throws Throwable { | |
| MemoryLayout selected = layout.select(pathElements); | |
| MethodHandle sliceHandle = layout.sliceHandle(pathElements); | |
| sliceHandle = sliceHandle.asSpreader(long[].class, indexes.length); | |
| try (Arena arena = Arena.ofConfined()) { | |
| MemorySegment segment = arena.allocate(layout); | |
| MemorySegment slice = (MemorySegment) sliceHandle.invokeExact(segment, 0L, indexes); | |
| assertEquals(slice.address() - segment.address(), expectedByteOffset); | |
| assertEquals(slice.byteSize(), selected.byteSize()); | |
| } | |
| } | |
| } |