1 /*
  2  * Copyright (c) 2020, 2022, 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  * @enablePreview
 27  * @run testng TestMemoryDereference
 28  */
 29 
 30 import java.lang.foreign.MemorySegment;
 31 
 32 import java.nio.ByteBuffer;
 33 import java.nio.ByteOrder;
 34 
 35 import java.lang.foreign.ValueLayout;
 36 import org.testng.annotations.*;
 37 
 38 import static java.lang.foreign.ValueLayout.*;
 39 import static org.testng.Assert.*;
 40 
 41 public class TestMemoryDereference {
 42 
 43     static class Accessor<X> {
 44 
 45         interface SegmentGetter<X> {
 46             X get(MemorySegment segment);
 47         }
 48 
 49         interface SegmentSetter<X> {
 50             void set(MemorySegment segment, X o);
 51         }
 52 
 53         interface BufferGetter<X> {
 54             X get(ByteBuffer segment);
 55         }
 56 
 57         interface BufferSetter<X> {
 58             void set(ByteBuffer buffer, X o);
 59         }
 60 
 61         final X value;
 62         final SegmentGetter<X> segmentGetter;
 63         final SegmentSetter<X> segmentSetter;
 64         final BufferGetter<X> bufferGetter;
 65         final BufferSetter<X> bufferSetter;
 66 
 67         Accessor(X value,
 68                  SegmentGetter<X> segmentGetter, SegmentSetter<X> segmentSetter,
 69                  BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) {
 70             this.value = value;
 71             this.segmentGetter = segmentGetter;
 72             this.segmentSetter = segmentSetter;
 73             this.bufferGetter = bufferGetter;
 74             this.bufferSetter = bufferSetter;
 75         }
 76 
 77         void test() {
 78             MemorySegment segment = MemorySegment.ofArray(new byte[32]);
 79             ByteBuffer buffer = segment.asByteBuffer();
 80             segmentSetter.set(segment, value);
 81             assertEquals(bufferGetter.get(buffer), value);
 82             bufferSetter.set(buffer, value);
 83             assertEquals(value, segmentGetter.get(segment));
 84         }
 85 
 86         <Z> Accessor<Z> of(Z value,
 87                            SegmentGetter<Z> segmentGetter, SegmentSetter<Z> segmentSetter,
 88                            BufferGetter<Z> bufferGetter, BufferSetter<Z> bufferSetter) {
 89             return new Accessor<>(value, segmentGetter, segmentSetter, bufferGetter, bufferSetter);
 90         }
 91     }
 92 
 93     @Test(dataProvider = "accessors")
 94     public void testMemoryAccess(String testName, Accessor<?> accessor) {
 95         accessor.test();
 96     }
 97 
 98     static final ByteOrder BE = ByteOrder.BIG_ENDIAN;
 99     static final ByteOrder LE = ByteOrder.LITTLE_ENDIAN;
100     static final ByteOrder NE = ByteOrder.nativeOrder();
101 
102     @DataProvider(name = "accessors")
103     static Object[][] accessors() {
104         return new Object[][]{
105 
106                 // byte, offset
107                 {"byte/offset", new Accessor<>((byte) 42,
108                         s -> s.get(JAVA_BYTE, 8), (s, x) -> s.set(JAVA_BYTE, 8, x),
109                         (bb) -> bb.get(8), (bb, v) -> bb.put(8, v))
110                 },
111                 // bool, offset
112                 {"bool", new Accessor<>(false,
113                         s -> s.get(JAVA_BOOLEAN, 8), (s, x) -> s.set(JAVA_BOOLEAN, 8, x),
114                         (bb) -> bb.get(8) != 0, (bb, v) -> bb.put(8, v ? (byte)1 : (byte)0))
115                 },
116                 // char, offset
117                 {"char/offset", new Accessor<>((char) 42,
118                         s -> s.get(JAVA_CHAR_UNALIGNED, 8), (s, x) -> s.set(JAVA_CHAR_UNALIGNED, 8, x),
119                         (bb) -> bb.order(NE).getChar(8), (bb, v) -> bb.order(NE).putChar(8, v))
120                 },
121                 {"char/offset/LE", new Accessor<>((char) 42,
122                         s -> s.get(JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8),
123                         (s, x) -> s.set(JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x),
124                         (bb) -> bb.order(LE).getChar(8), (bb, v) -> bb.order(LE).putChar(8, v))
125                 },
126                 {"char/offset/BE", new Accessor<>((char) 42,
127                         s -> s.get(JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8),
128                         (s, x) -> s.set(JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8, x),
129                         (bb) -> bb.order(BE).getChar(8), (bb, v) -> bb.order(BE).putChar(8, v))
130                 },
131                 // short, offset
132                 {"short/offset", new Accessor<>((short) 42,
133                         s -> s.get(JAVA_SHORT_UNALIGNED, 8), (s, x) -> s.set(JAVA_SHORT_UNALIGNED, 8, x),
134                         (bb) -> bb.order(NE).getShort(8), (bb, v) -> bb.order(NE).putShort(8, v))
135                 },
136                 {"short/offset/LE", new Accessor<>((short) 42,
137                         s -> s.get(JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8),
138                         (s, x) -> s.set(JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x),
139                         (bb) -> bb.order(LE).getShort(8), (bb, v) -> bb.order(LE).putShort(8, v))
140                 },
141                 {"short/offset/BE", new Accessor<>((short) 42,
142                         s -> s.get(JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8),
143                         (s, x) -> s.set(JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8, x),
144                         (bb) -> bb.order(BE).getShort(8), (bb, v) -> bb.order(BE).putShort(8, v))
145                 },
146                 // int, offset
147                 {"int/offset", new Accessor<>(42,
148                         s -> s.get(JAVA_INT_UNALIGNED, 8), (s, x) -> s.set(JAVA_INT_UNALIGNED, 8, x),
149                         (bb) -> bb.order(NE).getInt(8), (bb, v) -> bb.order(NE).putInt(8, v))
150                 },
151                 {"int/offset/LE", new Accessor<>(42,
152                         s -> s.get(JAVA_INT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8),
153                         (s, x) -> s.set(JAVA_INT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x),
154                         (bb) -> bb.order(LE).getInt(8), (bb, v) -> bb.order(LE).putInt(8, v))
155                 },
156                 {"int/offset/BE", new Accessor<>(42,
157                         s -> s.get(JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8),
158                         (s, x) -> s.set(JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8, x),
159                         (bb) -> bb.order(BE).getInt(8), (bb, v) -> bb.order(BE).putInt(8, v))
160                 },
161                 // float, offset
162                 {"float/offset", new Accessor<>(42f,
163                         s -> s.get(JAVA_FLOAT_UNALIGNED, 8), (s, x) -> s.set(JAVA_FLOAT_UNALIGNED, 8, x),
164                         (bb) -> bb.order(NE).getFloat(8), (bb, v) -> bb.order(NE).putFloat(8, v))
165                 },
166                 {"float/offset/LE", new Accessor<>(42f,
167                         s -> s.get(JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8),
168                         (s, x) -> s.set(JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x),
169                         (bb) -> bb.order(LE).getFloat(8), (bb, v) -> bb.order(LE).putFloat(8, v))
170                 },
171                 {"float/offset/BE", new Accessor<>(42f,
172                         s -> s.get(JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8),
173                         (s, x) -> s.set(JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8, x),
174                         (bb) -> bb.order(BE).getFloat(8), (bb, v) -> bb.order(BE).putFloat(8, v))
175                 },
176                 // double, offset
177                 {"double/offset", new Accessor<>(42d,
178                         s -> s.get(JAVA_DOUBLE_UNALIGNED, 8), (s, x) -> s.set(JAVA_DOUBLE_UNALIGNED, 8, x),
179                         (bb) -> bb.order(NE).getDouble(8), (bb, v) -> bb.order(NE).putDouble(8, v))
180                 },
181                 {"double/offset/LE", new Accessor<>(42d,
182                         s -> s.get(JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8),
183                         (s, x) -> s.set(JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), 8, x),
184                         (bb) -> bb.order(LE).getDouble(8), (bb, v) -> bb.order(LE).putDouble(8, v))
185                 },
186                 {"double/offset/BE", new Accessor<>(42d,
187                         s -> s.get(JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8),
188                         (s, x) -> s.set(JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), 8, x),
189                         (bb) -> bb.order(BE).getDouble(8), (bb, v) -> bb.order(BE).putDouble(8, v))
190                 },
191                 { "address/offset", new Accessor<>(MemorySegment.ofAddress(42),
192                         s -> s.get(ADDRESS_UNALIGNED, 8), (s, x) -> s.set(ADDRESS_UNALIGNED, 8, x),
193                         (bb) -> {
194                             ByteBuffer nb = bb.order(NE);
195                             long addr = ADDRESS_UNALIGNED.byteSize() == 8 ?
196                                     nb.getLong(8) : nb.getInt(8);
197                             return MemorySegment.ofAddress(addr);
198                         },
199                         (bb, v) -> {
200                             ByteBuffer nb = bb.order(NE);
201                             if (ADDRESS_UNALIGNED.byteSize() == 8) {
202                                 nb.putLong(8, v.address());
203                             } else {
204                                 nb.putInt(8, (int)v.address());
205                             }
206                         })
207                 },
208         };
209     }
210 }