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