1 /* 2 * Copyright (c) 2019, 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 import java.lang.foreign.Arena; 26 import java.lang.foreign.MemoryLayout; 27 import java.lang.foreign.MemorySegment; 28 import java.lang.foreign.ValueLayout; 29 import java.lang.invoke.VarHandle; 30 import java.util.ArrayList; 31 import java.util.List; 32 33 import org.testng.annotations.*; 34 import static org.testng.Assert.*; 35 36 /* 37 * @test 38 * @enablePreview 39 * @run testng/othervm -Xverify:all TestSlices 40 */ 41 public class TestSlices { 42 43 static MemoryLayout LAYOUT = MemoryLayout.sequenceLayout(2, 44 MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_INT)); 45 46 static VarHandle VH_ALL = LAYOUT.varHandle( 47 MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement()); 48 49 @Test(dataProvider = "slices") 50 public void testSlices(VarHandle handle, int lo, int hi, int[] values) { 51 try (Arena arena = Arena.ofConfined()) { 52 MemorySegment segment = arena.allocate(LAYOUT);; 53 //init 54 for (long i = 0 ; i < 2 ; i++) { 55 for (long j = 0 ; j < 5 ; j++) { 56 VH_ALL.set(segment, i, j, (int)j + 1 + ((int)i * 5)); 57 } 58 } 59 60 checkSlice(segment, handle, lo, hi, values); 61 } 62 } 63 64 @Test(dataProvider = "slices") 65 public void testSliceBadIndex(VarHandle handle, int lo, int hi, int[] values) { 66 try (Arena arena = Arena.ofConfined()) { 67 MemorySegment segment = arena.allocate(LAYOUT);; 68 assertThrows(() -> handle.get(segment, lo, 0)); 69 assertThrows(() -> handle.get(segment, 0, hi)); 70 } 71 } 72 73 static void checkSlice(MemorySegment segment, VarHandle handle, long i_max, long j_max, int... values) { 74 int index = 0; 75 for (long i = 0 ; i < i_max ; i++) { 76 for (long j = 0 ; j < j_max ; j++) { 77 int x = (int) handle.get(segment, i, j); 78 assertEquals(x, values[index++]); 79 } 80 } 81 assertEquals(index, values.length); 82 } 83 84 @Test(expectedExceptions = IndexOutOfBoundsException.class) 85 public void testSliceNegativeOffset() { 86 MemorySegment.ofArray(new byte[100]).asSlice(-1); 87 } 88 89 @Test(expectedExceptions = IndexOutOfBoundsException.class) 90 public void testSliceNegativeOffsetGoodSize() { 91 MemorySegment.ofArray(new byte[100]).asSlice(-1, 10); 92 } 93 94 @Test(expectedExceptions = IndexOutOfBoundsException.class) 95 public void testSliceGoodOffsetNegativeSize() { 96 MemorySegment.ofArray(new byte[100]).asSlice(10, -1); 97 } 98 99 @Test(expectedExceptions = IndexOutOfBoundsException.class) 100 public void testSliceNegativeOffsetGoodLayout() { 101 MemorySegment.ofArray(new byte[100]).asSlice(-1, ValueLayout.JAVA_INT); 102 } 103 104 @Test(expectedExceptions = IndexOutOfBoundsException.class) 105 public void testSliceOffsetTooBig() { 106 MemorySegment.ofArray(new byte[100]).asSlice(120); 107 } 108 109 @Test(expectedExceptions = IndexOutOfBoundsException.class) 110 public void testSliceOffsetTooBigSizeGood() { 111 MemorySegment.ofArray(new byte[100]).asSlice(120, 0); 112 } 113 114 @Test(expectedExceptions = IndexOutOfBoundsException.class) 115 public void testSliceOffsetOkSizeTooBig() { 116 MemorySegment.ofArray(new byte[100]).asSlice(0, 120); 117 } 118 119 @Test(expectedExceptions = IndexOutOfBoundsException.class) 120 public void testSliceLayoutTooBig() { 121 MemorySegment.ofArray(new byte[100]) 122 .asSlice(0, MemoryLayout.sequenceLayout(120, ValueLayout.JAVA_BYTE)); 123 } 124 125 @Test(dataProvider = "segmentsAndLayouts") 126 public void testSliceAlignment(MemorySegment segment, long alignment, ValueLayout layout) { 127 boolean badAlign = layout.byteAlignment() > alignment; 128 try { 129 segment.asSlice(0, layout); 130 assertFalse(badAlign); 131 } catch (IllegalArgumentException ex) { 132 assertTrue(badAlign); 133 assertTrue(ex.getMessage().contains("incompatible with alignment constraints")); 134 } 135 } 136 137 @Test 138 public void testSliceAlignmentPowerOfTwo() { 139 try (Arena arena = Arena.ofConfined()) { 140 MemorySegment segment = arena.allocate(100, 4096); 141 for (int i = 8 ; i < 4096 ; i++) { 142 boolean badAlign = Long.bitCount(i) != 1; // not a power of two 143 try { 144 segment.asSlice(0, 100, i); 145 assertFalse(badAlign); 146 } catch (IllegalArgumentException iae) { 147 assertTrue(badAlign); 148 } 149 } 150 } 151 } 152 153 @DataProvider(name = "slices") 154 static Object[][] slices() { 155 return new Object[][] { 156 // x 157 { VH_ALL, 2, 5, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } }, 158 // x[0::2] 159 { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), 160 MemoryLayout.PathElement.sequenceElement(0, 2)), 2, 3, new int[] { 1, 3, 5, 6, 8, 10 } }, 161 // x[1::2] 162 { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), 163 MemoryLayout.PathElement.sequenceElement(1, 2)), 2, 2, new int[] { 2, 4, 7, 9 } }, 164 // x[4::-2] 165 { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), 166 MemoryLayout.PathElement.sequenceElement(4, -2)), 2, 3, new int[] { 5, 3, 1, 10, 8, 6 } }, 167 // x[3::-2] 168 { LAYOUT.varHandle(MemoryLayout.PathElement.sequenceElement(), 169 MemoryLayout.PathElement.sequenceElement(3, -2)), 2, 2, new int[] { 4, 2, 9, 7 } }, 170 }; 171 } 172 173 @DataProvider(name = "segmentsAndLayouts") 174 static Object[][] segmentsAndLayouts() { 175 List<Object[]> segmentsAndLayouts = new ArrayList<>(); 176 for (SegmentKind sk : SegmentKind.values()) { 177 for (LayoutKind lk : LayoutKind.values()) { 178 for (int align : new int[]{ 1, 2, 4, 8 }) { 179 if (align > sk.maxAlign) break; 180 segmentsAndLayouts.add(new Object[] { sk.segment.asSlice(align), align, lk.layout }); 181 } 182 } 183 } 184 return segmentsAndLayouts.toArray(Object[][]::new); 185 } 186 187 enum SegmentKind { 188 NATIVE(Arena.ofAuto().allocate(100), 8), 189 BYTE_ARRAY(MemorySegment.ofArray(new byte[100]), 1), 190 CHAR_ARRAY(MemorySegment.ofArray(new char[100]), 2), 191 SHORT_ARRAY(MemorySegment.ofArray(new short[100]), 2), 192 INT_ARRAY(MemorySegment.ofArray(new int[100]), 4), 193 FLOAT_ARRAY(MemorySegment.ofArray(new float[100]), 4), 194 LONG_ARRAY(MemorySegment.ofArray(new long[100]), 8), 195 DOUBLE_ARRAY(MemorySegment.ofArray(new double[100]), 8); 196 197 198 final MemorySegment segment; 199 final int maxAlign; 200 201 SegmentKind(MemorySegment segment, int maxAlign) { 202 this.segment = segment; 203 this.maxAlign = maxAlign; 204 } 205 } 206 207 enum LayoutKind { 208 BOOL(ValueLayout.JAVA_BOOLEAN), 209 CHAR(ValueLayout.JAVA_CHAR), 210 SHORT(ValueLayout.JAVA_SHORT), 211 INT(ValueLayout.JAVA_INT), 212 FLOAT(ValueLayout.JAVA_FLOAT), 213 LONG(ValueLayout.JAVA_LONG), 214 DOUBLE(ValueLayout.JAVA_DOUBLE), 215 ADDRESS(ValueLayout.ADDRESS); 216 217 218 final ValueLayout layout; 219 220 LayoutKind(ValueLayout segment) { 221 this.layout = segment; 222 } 223 } 224 }