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 }