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 * @test 26 * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes 27 * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes 28 * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes 29 * @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes 30 */ 31 32 import java.lang.foreign.AddressLayout; 33 import java.lang.foreign.Arena; 34 import java.lang.foreign.MemoryLayout; 35 import java.lang.foreign.MemorySegment; 36 import java.lang.foreign.ValueLayout; 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.MethodType; 40 import java.lang.invoke.VarHandle; 41 import java.lang.invoke.VarHandle.AccessMode; 42 import java.util.ArrayList; 43 import java.util.EnumSet; 44 import java.util.List; 45 import java.util.Set; 46 47 import org.testng.annotations.*; 48 49 import static org.testng.Assert.*; 50 public class TestAccessModes { 51 52 @Test(dataProvider = "segmentsAndLayoutsAndModes") 53 public void testAccessModes(MemorySegment segment, ValueLayout layout, AccessMode mode) throws Throwable { 54 VarHandle varHandle = layout.varHandle(); 55 MethodHandle methodHandle = varHandle.toMethodHandle(mode); 56 boolean compatible = AccessModeKind.supportedModes(layout).contains(AccessModeKind.of(mode)); 57 try { 58 Object o = methodHandle.invokeWithArguments(makeArgs(segment, varHandle.accessModeType(mode))); 59 assertTrue(compatible); 60 } catch (UnsupportedOperationException ex) { 61 assertFalse(compatible); 62 } catch (IllegalArgumentException ex) { 63 // access is unaligned, but access mode is supported 64 assertTrue(compatible); 65 } 66 } 67 68 Object[] makeArgs(MemorySegment segment, MethodType type) throws Throwable { 69 List<Object> args = new ArrayList<>(); 70 args.add(segment); 71 for (Class argType : type.dropParameterTypes(0, 1).parameterList()) { 72 args.add(defaultValue(argType)); 73 } 74 return args.toArray(); 75 } 76 77 Object defaultValue(Class<?> clazz) throws Throwable { 78 if (clazz == MemorySegment.class) { 79 return MemorySegment.NULL; 80 } else if (clazz.isPrimitive()) { 81 return MethodHandles.zero(clazz).invoke(); 82 } else { 83 throw new UnsupportedOperationException(); 84 } 85 } 86 87 /* 88 * See the javadoc of MemoryLayout::varHandle. 89 */ 90 enum AccessModeKind { 91 PLAIN, 92 READ_WRITE, 93 ATOMIC_UPDATE, 94 ATOMIC_NUMERIC_UPDATE, 95 ATOMIC_BITWISE_UPDATE; 96 97 static AccessModeKind of(AccessMode mode) { 98 return switch (mode) { 99 case GET, SET -> PLAIN; 100 case GET_ACQUIRE, GET_OPAQUE, GET_VOLATILE, SET_VOLATILE, 101 SET_OPAQUE, SET_RELEASE -> READ_WRITE; 102 case GET_AND_SET, GET_AND_SET_ACQUIRE, GET_AND_SET_RELEASE, 103 WEAK_COMPARE_AND_SET, WEAK_COMPARE_AND_SET_RELEASE, 104 WEAK_COMPARE_AND_SET_ACQUIRE, WEAK_COMPARE_AND_SET_PLAIN, 105 COMPARE_AND_EXCHANGE, COMPARE_AND_EXCHANGE_ACQUIRE, 106 COMPARE_AND_EXCHANGE_RELEASE, COMPARE_AND_SET -> ATOMIC_UPDATE; 107 case GET_AND_ADD, GET_AND_ADD_ACQUIRE, GET_AND_ADD_RELEASE -> ATOMIC_NUMERIC_UPDATE; 108 default -> ATOMIC_BITWISE_UPDATE; 109 }; 110 } 111 112 static Set<AccessModeKind> supportedModes(ValueLayout layout) { 113 Set<AccessModeKind> supportedModes = EnumSet.noneOf(AccessModeKind.class); 114 supportedModes.add(PLAIN); 115 if (layout.byteAlignment() >= layout.byteSize()) { 116 supportedModes.add(READ_WRITE); 117 if (layout instanceof ValueLayout.OfInt || layout instanceof ValueLayout.OfLong || 118 layout instanceof ValueLayout.OfFloat || layout instanceof ValueLayout.OfDouble || 119 layout instanceof AddressLayout) { 120 supportedModes.add(ATOMIC_UPDATE); 121 } 122 if (layout instanceof ValueLayout.OfInt || layout instanceof ValueLayout.OfLong || 123 layout instanceof AddressLayout) { 124 supportedModes.add(ATOMIC_NUMERIC_UPDATE); 125 supportedModes.add(ATOMIC_BITWISE_UPDATE); 126 } 127 } 128 return supportedModes; 129 } 130 } 131 132 static MemoryLayout[] layouts() { 133 MemoryLayout[] valueLayouts = { 134 ValueLayout.JAVA_BOOLEAN, 135 ValueLayout.JAVA_CHAR, 136 ValueLayout.JAVA_BYTE, 137 ValueLayout.JAVA_SHORT, 138 ValueLayout.JAVA_INT, 139 ValueLayout.JAVA_FLOAT, 140 ValueLayout.JAVA_LONG, 141 ValueLayout.JAVA_DOUBLE, 142 ValueLayout.ADDRESS 143 }; 144 List<MemoryLayout> layouts = new ArrayList<>(); 145 for (MemoryLayout layout : valueLayouts) { 146 for (int align : new int[] { 1, 2, 4, 8 }) { 147 layouts.add(layout.withByteAlignment(align)); 148 } 149 } 150 return layouts.toArray(new MemoryLayout[0]); 151 } 152 153 static MemorySegment[] segments() { 154 return new MemorySegment[]{ 155 Arena.ofAuto().allocate(8), 156 MemorySegment.ofArray(new byte[8]), 157 MemorySegment.ofArray(new char[4]), 158 MemorySegment.ofArray(new short[4]), 159 MemorySegment.ofArray(new int[2]), 160 MemorySegment.ofArray(new float[2]), 161 MemorySegment.ofArray(new long[1]), 162 MemorySegment.ofArray(new double[1]) 163 }; 164 } 165 166 @DataProvider(name = "segmentsAndLayoutsAndModes") 167 static Object[][] segmentsAndLayoutsAndModes() { 168 List<Object[]> segmentsAndLayouts = new ArrayList<>(); 169 for (MemorySegment segment : segments()) { 170 for (MemoryLayout layout : layouts()) { 171 for (AccessMode mode : AccessMode.values()) { 172 segmentsAndLayouts.add(new Object[]{segment, layout, mode}); 173 } 174 } 175 } 176 return segmentsAndLayouts.toArray(new Object[0][]); 177 } 178 179 }