1 /* 2 * Copyright (c) 2019, 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 * @run testng TestLayouts 27 */ 28 29 import jdk.incubator.foreign.MemoryLayouts; 30 import jdk.incubator.foreign.MemoryLayout; 31 32 import java.lang.invoke.VarHandle; 33 import java.nio.ByteOrder; 34 import java.util.function.LongFunction; 35 36 import jdk.incubator.foreign.MemorySegment; 37 import org.testng.annotations.*; 38 import static org.testng.Assert.*; 39 40 public class TestLayouts { 41 42 @Test(dataProvider = "badLayoutSizes", expectedExceptions = IllegalArgumentException.class) 43 public void testBadLayoutSize(SizedLayoutFactory factory, long size) { 44 factory.make(size); 45 } 46 47 @Test(dataProvider = "badAlignments", expectedExceptions = IllegalArgumentException.class) 48 public void testBadLayoutAlignment(MemoryLayout layout, long alignment) { 49 layout.withBitAlignment(alignment); 50 } 51 52 @Test 53 public void testVLAInStruct() { 54 MemoryLayout layout = MemoryLayout.ofStruct( 55 MemoryLayouts.JAVA_INT.withName("size"), 56 MemoryLayout.ofPaddingBits(32), 57 MemoryLayout.ofSequence(MemoryLayouts.JAVA_DOUBLE).withName("arr")); 58 VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size")); 59 VarHandle array_elem_handle = layout.varHandle(double.class, 60 MemoryLayout.PathElement.groupElement("arr"), 61 MemoryLayout.PathElement.sequenceElement()); 62 try (MemorySegment segment = MemorySegment.allocateNative(8 + 8 * 4)) { 63 size_handle.set(segment.baseAddress(), 4); 64 for (int i = 0 ; i < 4 ; i++) { 65 array_elem_handle.set(segment.baseAddress(), i, (double)i); 66 } 67 //check 68 assertEquals(4, (int)size_handle.get(segment.baseAddress())); 69 for (int i = 0 ; i < 4 ; i++) { 70 assertEquals((double)i, (double)array_elem_handle.get(segment.baseAddress(), i)); 71 } 72 } 73 } 74 75 @Test 76 public void testVLAInSequence() { 77 MemoryLayout layout = MemoryLayout.ofStruct( 78 MemoryLayouts.JAVA_INT.withName("size"), 79 MemoryLayout.ofPaddingBits(32), 80 MemoryLayout.ofSequence(1, MemoryLayout.ofSequence(MemoryLayouts.JAVA_DOUBLE)).withName("arr")); 81 VarHandle size_handle = layout.varHandle(int.class, MemoryLayout.PathElement.groupElement("size")); 82 VarHandle array_elem_handle = layout.varHandle(double.class, 83 MemoryLayout.PathElement.groupElement("arr"), 84 MemoryLayout.PathElement.sequenceElement(0), 85 MemoryLayout.PathElement.sequenceElement()); 86 try (MemorySegment segment = MemorySegment.allocateNative(8 + 8 * 4)) { 87 size_handle.set(segment.baseAddress(), 4); 88 for (int i = 0 ; i < 4 ; i++) { 89 array_elem_handle.set(segment.baseAddress(), i, (double)i); 90 } 91 //check 92 assertEquals(4, (int)size_handle.get(segment.baseAddress())); 93 for (int i = 0 ; i < 4 ; i++) { 94 assertEquals((double)i, (double)array_elem_handle.get(segment.baseAddress(), i)); 95 } 96 } 97 } 98 99 @Test(dataProvider = "unboundLayouts", expectedExceptions = UnsupportedOperationException.class) 100 public void testUnboundSize(MemoryLayout layout, long align) { 101 layout.bitSize(); 102 } 103 104 @Test(dataProvider = "unboundLayouts") 105 public void testUnboundAlignment(MemoryLayout layout, long align) { 106 assertEquals(align, layout.bitAlignment()); 107 } 108 109 @Test(dataProvider = "unboundLayouts") 110 public void testUnboundEquals(MemoryLayout layout, long align) { 111 assertTrue(layout.equals(layout)); 112 } 113 114 @Test(dataProvider = "unboundLayouts") 115 public void testUnboundHash(MemoryLayout layout, long align) { 116 layout.hashCode(); 117 } 118 119 @Test 120 public void testEmptyGroup() { 121 MemoryLayout struct = MemoryLayout.ofStruct(); 122 assertEquals(struct.bitSize(), 0); 123 assertEquals(struct.bitAlignment(), 1); 124 125 MemoryLayout union = MemoryLayout.ofUnion(); 126 assertEquals(union.bitSize(), 0); 127 assertEquals(union.bitAlignment(), 1); 128 } 129 130 @Test 131 public void testStructSizeAndAlign() { 132 MemoryLayout struct = MemoryLayout.ofStruct( 133 MemoryLayout.ofPaddingBits(8), 134 MemoryLayouts.JAVA_BYTE, 135 MemoryLayouts.JAVA_CHAR, 136 MemoryLayouts.JAVA_INT, 137 MemoryLayouts.JAVA_LONG 138 ); 139 assertEquals(struct.byteSize(), 1 + 1 + 2 + 4 + 8); 140 assertEquals(struct.byteAlignment(), 8); 141 } 142 143 @Test 144 public void testUnionSizeAndAlign() { 145 MemoryLayout struct = MemoryLayout.ofUnion( 146 MemoryLayouts.JAVA_BYTE, 147 MemoryLayouts.JAVA_CHAR, 148 MemoryLayouts.JAVA_INT, 149 MemoryLayouts.JAVA_LONG 150 ); 151 assertEquals(struct.byteSize(), 8); 152 assertEquals(struct.byteAlignment(), 8); 153 } 154 155 @Test(dataProvider="layoutsAndAlignments") 156 public void testAlignmentString(MemoryLayout layout, long bitAlign) { 157 long[] alignments = { 8, 16, 32, 64, 128 }; 158 for (long a : alignments) { 159 assertFalse(layout.toString().contains("%")); 160 assertEquals(layout.withBitAlignment(a).toString().contains("%"), a != bitAlign); 161 } 162 } 163 164 @DataProvider(name = "badLayoutSizes") 165 public Object[][] factoriesAndSizes() { 166 return new Object[][] { 167 { SizedLayoutFactory.VALUE_BE, 0 }, 168 { SizedLayoutFactory.VALUE_BE, -1 }, 169 { SizedLayoutFactory.VALUE_LE, 0 }, 170 { SizedLayoutFactory.VALUE_LE, -1 }, 171 { SizedLayoutFactory.PADDING, 0 }, 172 { SizedLayoutFactory.PADDING, -1 }, 173 { SizedLayoutFactory.SEQUENCE, -1 } 174 }; 175 } 176 177 @DataProvider(name = "unboundLayouts") 178 public Object[][] unboundLayouts() { 179 return new Object[][] { 180 { MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT), 32 }, 181 { MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 }, 182 { MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 }, 183 { MemoryLayout.ofStruct(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 }, 184 { MemoryLayout.ofStruct(MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 }, 185 { MemoryLayout.ofStruct(MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 }, 186 { MemoryLayout.ofUnion(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)), 32 }, 187 { MemoryLayout.ofUnion(MemoryLayout.ofSequence(MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 }, 188 { MemoryLayout.ofUnion(MemoryLayout.ofSequence(4, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT))), 32 }, 189 }; 190 } 191 192 @DataProvider(name = "badAlignments") 193 public Object[][] layoutsAndBadAlignments() { 194 LayoutKind[] layoutKinds = LayoutKind.values(); 195 Object[][] values = new Object[layoutKinds.length * 2][2]; 196 for (int i = 0; i < layoutKinds.length ; i++) { 197 values[i * 2] = new Object[] { layoutKinds[i].layout, 3 }; // smaller than 8 198 values[(i * 2) + 1] = new Object[] { layoutKinds[i].layout, 18 }; // not a power of 2 199 } 200 return values; 201 } 202 203 enum SizedLayoutFactory { 204 VALUE_LE(size -> MemoryLayout.ofValueBits(size, ByteOrder.LITTLE_ENDIAN)), 205 VALUE_BE(size -> MemoryLayout.ofValueBits(size, ByteOrder.BIG_ENDIAN)), 206 PADDING(MemoryLayout::ofPaddingBits), 207 SEQUENCE(size -> MemoryLayout.ofSequence(size, MemoryLayouts.PAD_8)); 208 209 private final LongFunction<MemoryLayout> factory; 210 211 SizedLayoutFactory(LongFunction<MemoryLayout> factory) { 212 this.factory = factory; 213 } 214 215 MemoryLayout make(long size) { 216 return factory.apply(size); 217 } 218 } 219 220 enum LayoutKind { 221 VALUE_LE(MemoryLayouts.BITS_8_LE), 222 VALUE_BE(MemoryLayouts.BITS_8_BE), 223 PADDING(MemoryLayouts.PAD_8), 224 SEQUENCE(MemoryLayout.ofSequence(1, MemoryLayouts.PAD_8)), 225 STRUCT(MemoryLayout.ofStruct(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8)), 226 UNION(MemoryLayout.ofUnion(MemoryLayouts.PAD_8, MemoryLayouts.PAD_8)); 227 228 final MemoryLayout layout; 229 230 LayoutKind(MemoryLayout layout) { 231 this.layout = layout; 232 } 233 } 234 235 @DataProvider(name = "layoutsAndAlignments") 236 public Object[][] layoutsAndAlignments() { 237 MemoryLayout[] basicLayouts = { 238 MemoryLayouts.JAVA_BYTE, 239 MemoryLayouts.JAVA_CHAR, 240 MemoryLayouts.JAVA_SHORT, 241 MemoryLayouts.JAVA_INT, 242 MemoryLayouts.JAVA_FLOAT, 243 MemoryLayouts.JAVA_LONG, 244 MemoryLayouts.JAVA_DOUBLE, 245 }; 246 Object[][] layoutsAndAlignments = new Object[basicLayouts.length * 5][]; 247 int i = 0; 248 //add basic layouts 249 for (MemoryLayout l : basicLayouts) { 250 layoutsAndAlignments[i++] = new Object[] { l, l.bitAlignment() }; 251 } 252 //add basic layouts wrapped in a sequence with unspecified size 253 for (MemoryLayout l : basicLayouts) { 254 layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofSequence(l), l.bitAlignment() }; 255 } 256 //add basic layouts wrapped in a sequence with given size 257 for (MemoryLayout l : basicLayouts) { 258 layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofSequence(4, l), l.bitAlignment() }; 259 } 260 //add basic layouts wrapped in a struct 261 for (MemoryLayout l : basicLayouts) { 262 layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofStruct(l), l.bitAlignment() }; 263 } 264 //add basic layouts wrapped in a union 265 for (MemoryLayout l : basicLayouts) { 266 layoutsAndAlignments[i++] = new Object[] { MemoryLayout.ofUnion(l), l.bitAlignment() }; 267 } 268 return layoutsAndAlignments; 269 } 270 }