| /* | |
| * Copyright (c) 2023, 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 TestDereferencePath | |
| */ | |
| import java.lang.foreign.Arena; | |
| import java.lang.foreign.MemoryLayout; | |
| import java.lang.foreign.MemoryLayout.PathElement; | |
| import java.lang.foreign.MemorySegment; | |
| import java.lang.foreign.ValueLayout; | |
| import org.testng.annotations.*; | |
| import java.lang.invoke.VarHandle; | |
| import static org.testng.Assert.*; | |
| public class TestDereferencePath { | |
| static final MemoryLayout C = MemoryLayout.structLayout( | |
| ValueLayout.JAVA_INT.withName("x") | |
| ); | |
| static final MemoryLayout B = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("c") | |
| .withTargetLayout(C) | |
| ); | |
| static final MemoryLayout A = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("b") | |
| .withTargetLayout(B) | |
| ); | |
| static final VarHandle abcx = A.varHandle( | |
| PathElement.groupElement("b"), PathElement.dereferenceElement(), | |
| PathElement.groupElement("c"), PathElement.dereferenceElement(), | |
| PathElement.groupElement("x")); | |
| @Test | |
| public void testSingle() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| // init structs | |
| MemorySegment a = arena.allocate(A); | |
| MemorySegment b = arena.allocate(B); | |
| MemorySegment c = arena.allocate(C); | |
| // init struct fields | |
| a.set(ValueLayout.ADDRESS, 0, b); | |
| b.set(ValueLayout.ADDRESS, 0, c); | |
| c.set(ValueLayout.JAVA_INT, 0, 42); | |
| // dereference | |
| int val = (int) abcx.get(a, 0L); | |
| assertEquals(val, 42); | |
| } | |
| } | |
| static final MemoryLayout B_MULTI = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("cs") | |
| .withTargetLayout(MemoryLayout.sequenceLayout(2, C)) | |
| ); | |
| static final MemoryLayout A_MULTI = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("bs") | |
| .withTargetLayout(MemoryLayout.sequenceLayout(2, B_MULTI)) | |
| ); | |
| static final VarHandle abcx_multi = A_MULTI.varHandle( | |
| PathElement.groupElement("bs"), PathElement.dereferenceElement(), PathElement.sequenceElement(), | |
| PathElement.groupElement("cs"), PathElement.dereferenceElement(), PathElement.sequenceElement(), | |
| PathElement.groupElement("x")); | |
| @Test | |
| public void testMulti() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| // init structs | |
| MemorySegment a = arena.allocate(A); | |
| MemorySegment b = arena.allocate(B, 2); | |
| MemorySegment c = arena.allocate(C, 4); | |
| // init struct fields | |
| a.set(ValueLayout.ADDRESS, 0, b); | |
| b.set(ValueLayout.ADDRESS, 0, c); | |
| b.setAtIndex(ValueLayout.ADDRESS, 1, c.asSlice(C.byteSize() * 2)); | |
| c.setAtIndex(ValueLayout.JAVA_INT, 0, 1); | |
| c.setAtIndex(ValueLayout.JAVA_INT, 1, 2); | |
| c.setAtIndex(ValueLayout.JAVA_INT, 2, 3); | |
| c.setAtIndex(ValueLayout.JAVA_INT, 3, 4); | |
| // dereference | |
| int val00 = (int) abcx_multi.get(a, 0L, 0, 0); // a->b[0]->c[0] = 1 | |
| assertEquals(val00, 1); | |
| int val10 = (int) abcx_multi.get(a, 0L, 1, 0); // a->b[1]->c[0] = 3 | |
| assertEquals(val10, 3); | |
| int val01 = (int) abcx_multi.get(a, 0L, 0, 1); // a->b[0]->c[1] = 2 | |
| assertEquals(val01, 2); | |
| int val11 = (int) abcx_multi.get(a, 0L, 1, 1); // a->b[1]->c[1] = 4 | |
| assertEquals(val11, 4); | |
| } | |
| } | |
| static final MemoryLayout A_VALUE = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("b") | |
| .withTargetLayout(ValueLayout.JAVA_INT) | |
| ); | |
| static final VarHandle a_value = A_VALUE.varHandle( | |
| PathElement.groupElement("b"), PathElement.dereferenceElement()); | |
| @Test | |
| public void testDerefValue() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| // init structs | |
| MemorySegment a = arena.allocate(A); | |
| MemorySegment b = arena.allocate(ValueLayout.JAVA_INT); | |
| // init struct fields | |
| a.set(ValueLayout.ADDRESS, 0, b); | |
| b.set(ValueLayout.JAVA_INT, 0, 42); | |
| // dereference | |
| int val = (int) a_value.get(a, 0L); | |
| assertEquals(val, 42); | |
| } | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| void testBadDerefInSelect() { | |
| A.select(PathElement.groupElement("b"), PathElement.dereferenceElement()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| void testBadDerefInOffset() { | |
| A.byteOffset(PathElement.groupElement("b"), PathElement.dereferenceElement()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| void testBadDerefInSlice() { | |
| A.sliceHandle(PathElement.groupElement("b"), PathElement.dereferenceElement()); | |
| } | |
| static final MemoryLayout A_MULTI_NO_TARGET = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withName("bs") | |
| ); | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| void badDerefAddressNoTarget() { | |
| A_MULTI_NO_TARGET.varHandle(PathElement.groupElement("bs"), PathElement.dereferenceElement()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| void badDerefMisAligned() { | |
| MemoryLayout struct = MemoryLayout.structLayout( | |
| ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT).withName("x")); | |
| try (Arena arena = Arena.ofConfined()) { | |
| MemorySegment segment = arena.allocate(struct.byteSize() + 1, struct.byteAlignment()).asSlice(1); | |
| VarHandle vhX = struct.varHandle(PathElement.groupElement("x"), PathElement.dereferenceElement()); | |
| vhX.set(segment, 0L, 42); // should throw | |
| } | |
| } | |
| } |