1 /* 2 * Copyright (c) 2019, 2023, 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 /* 26 * @test 27 * @run testng TestSegmentCopy 28 */ 29 30 import java.lang.foreign.Arena; 31 import java.lang.foreign.MemorySegment; 32 import java.lang.foreign.ValueLayout; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.VarHandle; 35 import java.nio.ByteOrder; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.List; 39 import java.util.function.IntFunction; 40 41 import org.testng.SkipException; 42 import org.testng.annotations.DataProvider; 43 import org.testng.annotations.Test; 44 45 import static java.lang.foreign.ValueLayout.JAVA_BYTE; 46 import static org.testng.Assert.*; 47 48 public class TestSegmentCopy { 49 50 static final int TEST_BYTE_SIZE = 16; 51 52 @Test(dataProvider = "segmentKinds") 53 public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { 54 MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); 55 MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); 56 57 // for all offsets 58 for (int s1Offset = 0; s1Offset < s1.byteSize(); s1Offset++) { 59 for (int s2Offset = 0; s2Offset < s2.byteSize(); s2Offset++) { 60 long slice1ByteSize = s1.byteSize() - s1Offset; 61 long slice2ByteSize = s2.byteSize() - s2Offset; 62 63 long copySize = Math.min(slice1ByteSize, slice2ByteSize); 64 65 //prepare source slice 66 for (int i = 0 ; i < copySize; i++) { 67 Type.BYTE.set(s1, s1Offset, i, i); 68 } 69 //perform copy 70 MemorySegment.copy(s1, Type.BYTE.layout, s1Offset, s2, Type.BYTE.layout, s2Offset, copySize); 71 //check that copy actually worked 72 for (int i = 0; i < copySize; i++) { 73 Type.BYTE.check(s2, s2Offset, i, i); 74 } 75 } 76 } 77 } 78 79 @Test(expectedExceptions = UnsupportedOperationException.class, dataProvider = "segmentKinds") 80 public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { 81 MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); 82 MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); 83 // check failure with read-only dest 84 MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0); 85 } 86 87 @Test(expectedExceptions = IndexOutOfBoundsException.class, dataProvider = "types") 88 public void testBadOverflow(Type type) { 89 if (type.layout.byteSize() > 1) { 90 MemorySegment segment = MemorySegment.ofArray(new byte[100]); 91 MemorySegment.copy(segment, type.layout, 0, segment, type.layout, 0, Long.MAX_VALUE); 92 } else { 93 throw new SkipException("Byte layouts do not overflow"); 94 } 95 } 96 97 @Test(dataProvider = "segmentKindsAndTypes") 98 public void testElementCopy(SegmentKind kind1, SegmentKind kind2, Type type1, Type type2) { 99 MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); 100 MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE); 101 102 // for all offsets 103 for (int s1Offset = 0; s1Offset < s1.byteSize(); s1Offset++) { 104 for (int s2Offset = 0; s2Offset < s2.byteSize(); s2Offset++) { 105 long slice1ByteSize = s1.byteSize() - s1Offset; 106 long slice2ByteSize = s2.byteSize() - s2Offset; 107 108 long slice1ElementSize = slice1ByteSize / type1.size(); 109 long slice2ElementSize = slice2ByteSize / type2.size(); 110 111 long copySize = Math.min(slice1ElementSize, slice2ElementSize); 112 113 //prepare source slice 114 for (int i = 0 ; i < copySize; i++) { 115 type1.set(s1, s1Offset, i, i); 116 } 117 //perform copy 118 MemorySegment.copy(s1, type1.layout, s1Offset, s2, type2.layout, s2Offset, copySize); 119 //check that copy actually worked 120 for (int i = 0; i < copySize; i++) { 121 type2.check(s2, s2Offset, i, i); 122 } 123 } 124 } 125 } 126 127 @Test(expectedExceptions = IllegalArgumentException.class) 128 public void testHyperAlignedSrc() { 129 MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); 130 MemorySegment.copy(segment, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4); 131 } 132 133 @Test(expectedExceptions = IllegalArgumentException.class) 134 public void testHyperAlignedDst() { 135 MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); 136 MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); 137 } 138 139 enum Type { 140 // Byte 141 BYTE(byte.class, JAVA_BYTE, i -> (byte)i), 142 //LE 143 SHORT_LE(short.class, ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (short)i), 144 CHAR_LE(char.class, ValueLayout.JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (char)i), 145 INT_LE(int.class, ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> i), 146 FLOAT_LE(float.class, ValueLayout.JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (float)i), 147 LONG_LE(long.class, ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (long)i), 148 DOUBLE_LE(double.class, ValueLayout.JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (double)i), 149 //BE 150 SHORT_BE(short.class, ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> (short)i), 151 CHAR_BE(char.class, ValueLayout.JAVA_CHAR_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> (char)i), 152 INT_BE(int.class, ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> i), 153 FLOAT_BE(float.class, ValueLayout.JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> (float)i), 154 LONG_BE(long.class, ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> (long)i), 155 DOUBLE_BE(double.class, ValueLayout.JAVA_DOUBLE_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN), i -> (double)i); 156 157 final ValueLayout layout; 158 final IntFunction<Object> valueConverter; 159 final Class<?> carrier; 160 161 @SuppressWarnings("unchecked") 162 <Z> Type(Class<Z> carrier, ValueLayout layout, IntFunction<Z> valueConverter) { 163 this.carrier = carrier; 164 this.layout = layout; 165 this.valueConverter = (IntFunction<Object>)valueConverter; 166 } 167 168 long size() { 169 return layout.byteSize(); 170 } 171 172 VarHandle handle() { 173 return layout.varHandle(); 174 } 175 176 void set(MemorySegment segment, long offset, int index, int val) { 177 handle().set(segment, offset + (index * size()), valueConverter.apply(val)); 178 } 179 180 void check(MemorySegment segment, long offset, int index, int val) { 181 assertEquals(handle().get(segment, offset + (index * size())), valueConverter.apply(val)); 182 } 183 } 184 185 enum SegmentKind { 186 NATIVE(i -> Arena.ofAuto().allocate(i, 1)), 187 ARRAY(i -> MemorySegment.ofArray(new byte[i])); 188 189 final IntFunction<MemorySegment> segmentFactory; 190 191 SegmentKind(IntFunction<MemorySegment> segmentFactory) { 192 this.segmentFactory = segmentFactory; 193 } 194 195 MemorySegment makeSegment(int size) { 196 return segmentFactory.apply(size); 197 } 198 } 199 200 @DataProvider 201 static Object[][] segmentKinds() { 202 List<Object[]> cases = new ArrayList<>(); 203 for (SegmentKind kind1 : SegmentKind.values()) { 204 for (SegmentKind kind2 : SegmentKind.values()) { 205 cases.add(new Object[] {kind1, kind2}); 206 } 207 } 208 return cases.toArray(Object[][]::new); 209 } 210 211 @DataProvider 212 static Object[][] types() { 213 return Arrays.stream(Type.values()) 214 .map(t -> new Object[] { t }) 215 .toArray(Object[][]::new); 216 } 217 218 @DataProvider 219 static Object[][] segmentKindsAndTypes() { 220 List<Object[]> cases = new ArrayList<>(); 221 for (Object[] segmentKinds : segmentKinds()) { 222 for (Type type1 : Type.values()) { 223 for (Type type2 : Type.values()) { 224 if (type1.layout.carrier() == type2.layout.carrier()) { 225 cases.add(new Object[]{segmentKinds[0], segmentKinds[1], type1, type2}); 226 } 227 } 228 } 229 } 230 return cases.toArray(Object[][]::new); 231 } 232 }