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 }