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