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