1 /*
  2  * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 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  * @test
 26  * @enablePreview
 27  * @requires jdk.foreign.linker != "UNSUPPORTED"
 28  * @run testng/othervm --enable-native-access=ALL-UNNAMED TestHeapAlignment
 29  */
 30 
 31 import java.lang.foreign.AddressLayout;
 32 import java.lang.foreign.MemoryLayout;
 33 import java.lang.foreign.MemorySegment;
 34 import java.lang.foreign.Arena;
 35 import java.lang.foreign.ValueLayout;
 36 import java.util.ArrayList;
 37 import java.util.List;
 38 import java.util.function.Function;
 39 import org.testng.annotations.DataProvider;
 40 import org.testng.annotations.Test;
 41 
 42 import static org.testng.Assert.fail;
 43 
 44 public class TestHeapAlignment {
 45 
 46     @Test(dataProvider = "layouts")
 47     public void testHeapAlignment(MemorySegment segment, int align, Object val, Object arr, ValueLayout layout, Function<Object, MemorySegment> segmentFactory) {
 48         assertAligned(align, layout, () -> layout.varHandle().get(segment));
 49         assertAligned(align, layout, () -> layout.varHandle().set(segment, val));
 50         MemoryLayout seq = MemoryLayout.sequenceLayout(10, layout);
 51         assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).get(segment, 0L));
 52         assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).set(segment, 0L, val));
 53         assertAligned(align, layout, () -> segment.spliterator(layout));
 54         if (arr != null) {
 55             assertAligned(align, layout, () -> MemorySegment.copy(arr, 0, segment, layout, 0, 1));
 56             assertAligned(align, layout, () -> MemorySegment.copy(segment, layout, 0, arr, 0, 1));
 57             assertAligned(align, layout, () -> {
 58                 MemorySegment other = segmentFactory.apply(arr);
 59                 MemorySegment.copy(other, layout, 0, segment, layout, 0, 1);
 60             });
 61             MemorySegment other = segmentFactory.apply(arr);
 62             assertAligned(align, layout, () -> {
 63                 MemorySegment.copy(segment, layout, 0, other, layout, 0, 1);
 64             });
 65             assertAligned(align, layout, () -> {
 66                 MemorySegment.copy(other, layout, 0, segment, layout, 0, 1);
 67             });
 68         }
 69     }
 70 
 71     static void assertAligned(int align, ValueLayout layout, Runnable runnable) {
 72         boolean shouldFail = layout.byteAlignment() > align && align != -1;
 73         try {
 74             runnable.run();
 75             if (shouldFail) {
 76                 fail("Should not get here!");
 77             }
 78         } catch (IllegalArgumentException ex) {
 79             if (!shouldFail) {
 80                 fail("Should not get here!");
 81             } else if (!ex.getMessage().contains("alignment") && !ex.getMessage().contains("Misaligned")) {
 82                 fail("Unexpected exception: " + ex);
 83             }
 84         }
 85     }
 86 
 87     enum SegmentAndAlignment {
 88         HEAP_BYTE(MemorySegment.ofArray(new byte[8]), 1),
 89         HEAP_SHORT(MemorySegment.ofArray(new short[4]), 2),
 90         HEAP_CHAR(MemorySegment.ofArray(new char[4]), 2),
 91         HEAP_INT(MemorySegment.ofArray(new int[2]), 4),
 92         HEAP_FLOAT(MemorySegment.ofArray(new float[2]), 4),
 93         HEAP_LONG(MemorySegment.ofArray(new long[1]), 8),
 94         HEAP_DOUBLE(MemorySegment.ofArray(new double[1]), 8),
 95         NATIVE(Arena.ofAuto().allocate(8, 1), -1);
 96 
 97         final MemorySegment segment;
 98         final int align;
 99 
100         SegmentAndAlignment(MemorySegment segment, int align) {
101             this.segment = segment;
102             this.align = align;
103         }
104     }
105 
106     @DataProvider
107     public static Object[][] layouts() {
108         List<Object[]> layouts = new ArrayList<>();
109         for (SegmentAndAlignment testCase : SegmentAndAlignment.values()) {
110             layouts.add(new Object[] { testCase.segment, testCase.align, (byte) 42, new byte[]{42}, ValueLayout.JAVA_BYTE, (Function<byte[], MemorySegment>)MemorySegment::ofArray });
111             layouts.add(new Object[] { testCase.segment, testCase.align, true, null, ValueLayout.JAVA_BOOLEAN, null });
112             layouts.add(new Object[] { testCase.segment, testCase.align, (char) 42, new char[]{42}, ValueLayout.JAVA_CHAR, (Function<char[], MemorySegment>)MemorySegment::ofArray });
113             layouts.add(new Object[] { testCase.segment, testCase.align, (short) 42, new short[]{42}, ValueLayout.JAVA_SHORT, (Function<short[], MemorySegment>)MemorySegment::ofArray });
114             layouts.add(new Object[] { testCase.segment, testCase.align, 42, new int[]{42}, ValueLayout.JAVA_INT, (Function<int[], MemorySegment>)MemorySegment::ofArray });
115             layouts.add(new Object[] { testCase.segment, testCase.align, 42f, new float[]{42}, ValueLayout.JAVA_FLOAT, (Function<float[], MemorySegment>)MemorySegment::ofArray });
116             layouts.add(new Object[] { testCase.segment, testCase.align, 42L, new long[]{42}, ValueLayout.JAVA_LONG, (Function<long[], MemorySegment>)MemorySegment::ofArray });
117             layouts.add(new Object[] { testCase.segment, testCase.align, 42d, new double[]{42}, ValueLayout.JAVA_DOUBLE, (Function<double[], MemorySegment>)MemorySegment::ofArray });
118             layouts.add(new Object[] { testCase.segment, testCase.align, MemorySegment.ofAddress(42), null, ValueLayout.ADDRESS, null });
119         }
120         return layouts.toArray(new Object[0][]);
121     }
122 }