1 /*
  2  *  Copyright (c) 2019, 2020, 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 TestMemoryAlignment
 27  */
 28 
 29 import jdk.incubator.foreign.MemoryLayouts;
 30 import jdk.incubator.foreign.MemoryLayout;
 31 
 32 import jdk.incubator.foreign.GroupLayout;
 33 import jdk.incubator.foreign.MemoryLayout.PathElement;
 34 import jdk.incubator.foreign.MemorySegment;
 35 import jdk.incubator.foreign.ResourceScope;
 36 import jdk.incubator.foreign.SequenceLayout;
 37 import jdk.incubator.foreign.ValueLayout;
 38 import java.lang.invoke.VarHandle;
 39 import java.util.stream.LongStream;
 40 
 41 import org.testng.annotations.*;
 42 import static org.testng.Assert.*;
 43 
 44 public class TestMemoryAlignment {
 45 
 46     @Test(dataProvider = "alignments")
 47     public void testAlignedAccess(long align) {
 48         ValueLayout layout = MemoryLayouts.BITS_32_BE;
 49         assertEquals(layout.bitAlignment(), 32);
 50         ValueLayout aligned = layout.withBitAlignment(align);
 51         assertEquals(aligned.bitAlignment(), align); //unreasonable alignment here, to make sure access throws
 52         VarHandle vh = aligned.varHandle(int.class);
 53         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 54             MemorySegment segment = MemorySegment.allocateNative(aligned, scope);
 55             vh.set(segment, -42);
 56             int val = (int)vh.get(segment);
 57             assertEquals(val, -42);
 58         }
 59     }
 60 
 61     @Test(dataProvider = "alignments")
 62     public void testUnalignedAccess(long align) {
 63         ValueLayout layout = MemoryLayouts.BITS_32_BE;
 64         assertEquals(layout.bitAlignment(), 32);
 65         ValueLayout aligned = layout.withBitAlignment(align);
 66         MemoryLayout alignedGroup = MemoryLayout.structLayout(MemoryLayouts.PAD_8, aligned);
 67         assertEquals(alignedGroup.bitAlignment(), align);
 68         VarHandle vh = aligned.varHandle(int.class);
 69         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 70             MemorySegment segment = MemorySegment.allocateNative(alignedGroup, scope);
 71             vh.set(segment.asSlice(1L), -42);
 72             assertEquals(align, 8); //this is the only case where access is aligned
 73         } catch (IllegalStateException ex) {
 74             assertNotEquals(align, 8); //if align != 8, access is always unaligned
 75         }
 76     }
 77 
 78     @Test(dataProvider = "alignments")
 79     public void testUnalignedPath(long align) {
 80         MemoryLayout layout = MemoryLayouts.BITS_32_BE;
 81         MemoryLayout aligned = layout.withBitAlignment(align).withName("value");
 82         GroupLayout alignedGroup = MemoryLayout.structLayout(MemoryLayouts.PAD_8, aligned);
 83         try {
 84             alignedGroup.varHandle(int.class, PathElement.groupElement("value"));
 85             assertEquals(align, 8); //this is the only case where path is aligned
 86         } catch (UnsupportedOperationException ex) {
 87             assertNotEquals(align, 8); //if align != 8, path is always unaligned
 88         }
 89     }
 90 
 91     @Test(dataProvider = "alignments")
 92     public void testUnalignedSequence(long align) {
 93         SequenceLayout layout = MemoryLayout.sequenceLayout(5, MemoryLayouts.BITS_32_BE.withBitAlignment(align));
 94         try {
 95             VarHandle vh = layout.varHandle(int.class, PathElement.sequenceElement());
 96             try (ResourceScope scope = ResourceScope.newConfinedScope()) {
 97                 MemorySegment segment = MemorySegment.allocateNative(layout, scope);
 98                 for (long i = 0 ; i < 5 ; i++) {
 99                     vh.set(segment, i, -42);
100                 }
101             }
102         } catch (UnsupportedOperationException ex) {
103             assertTrue(align > 32); //if align > 32, access is always unaligned (for some elements)
104         }
105     }
106 
107     @Test
108     public void testPackedAccess() {
109         ValueLayout vChar = MemoryLayouts.BITS_8_BE;
110         ValueLayout vShort = MemoryLayouts.BITS_16_BE;
111         ValueLayout vInt = MemoryLayouts.BITS_32_BE;
112         //mimic pragma pack(1)
113         GroupLayout g = MemoryLayout.structLayout(vChar.withBitAlignment(8).withName("a"),
114                                vShort.withBitAlignment(8).withName("b"),
115                                vInt.withBitAlignment(8).withName("c"));
116         assertEquals(g.bitAlignment(), 8);
117         VarHandle vh_c = g.varHandle(byte.class, PathElement.groupElement("a"));
118         VarHandle vh_s = g.varHandle(short.class, PathElement.groupElement("b"));
119         VarHandle vh_i = g.varHandle(int.class, PathElement.groupElement("c"));
120         try (ResourceScope scope = ResourceScope.newConfinedScope()) {
121             MemorySegment segment = MemorySegment.allocateNative(g, scope);
122             vh_c.set(segment, Byte.MIN_VALUE);
123             assertEquals(vh_c.get(segment), Byte.MIN_VALUE);
124             vh_s.set(segment, Short.MIN_VALUE);
125             assertEquals(vh_s.get(segment), Short.MIN_VALUE);
126             vh_i.set(segment, Integer.MIN_VALUE);
127             assertEquals(vh_i.get(segment), Integer.MIN_VALUE);
128         }
129     }
130 
131     @DataProvider(name = "alignments")
132     public Object[][] createAlignments() {
133         return LongStream.range(3, 32)
134                 .mapToObj(v -> new Object[] { 1L << v })
135                 .toArray(Object[][]::new);
136     }
137 }