1 /* 2 * Copyright (c) 2016, 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 package compiler.jvmci.constantReflectionProviderTest; 26 27 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.ARRAYS_MAP; 28 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.ARRAY_ARRAYS_MAP; 29 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.CONSTANT_REFLECTION_PROVIDER; 30 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.DUMMY_CLASS_CONSTANT; 31 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.DUMMY_CLASS_INSTANCE; 32 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.getResolvedJavaField; 33 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.INSTANCE_STABLE_FIELDS_MAP; 34 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.INSTANCE_FIELDS_MAP; 35 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.STABLE_ARRAYS_MAP; 36 import static compiler.jvmci.constantReflectionProviderTest.TestHelper.STABLE_ARRAY_ARRAYS_MAP; 37 import java.lang.reflect.Field; 38 import java.util.LinkedList; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.stream.Stream; 42 import jdk.vm.ci.meta.JavaConstant; 43 import org.testng.annotations.DataProvider; 44 import jdk.internal.misc.Unsafe; 45 import jdk.test.lib.Triple; 46 import jdk.vm.ci.meta.ResolvedJavaField; 47 48 public class ReadConstantArrayElementDataProvider { 49 50 // Non-stable array fields names mapped to their base offsets and index scale 51 private static final List<Triple<String, Integer, Integer>> NON_STABLE_ARRAY_NAMES 52 = new LinkedList<>(); 53 static { 54 NON_STABLE_ARRAY_NAMES.add(new Triple<>("booleanArrayWithValues", 55 Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 56 Unsafe.ARRAY_BOOLEAN_INDEX_SCALE)); 57 NON_STABLE_ARRAY_NAMES.add(new Triple<>("byteArrayWithValues", 58 Unsafe.ARRAY_BYTE_BASE_OFFSET, 59 Unsafe.ARRAY_BYTE_INDEX_SCALE)); 60 NON_STABLE_ARRAY_NAMES.add(new Triple<>("shortArrayWithValues", 61 Unsafe.ARRAY_SHORT_BASE_OFFSET, 62 Unsafe.ARRAY_SHORT_INDEX_SCALE)); 63 NON_STABLE_ARRAY_NAMES.add(new Triple<>("charArrayWithValues", 64 Unsafe.ARRAY_CHAR_BASE_OFFSET, 65 Unsafe.ARRAY_CHAR_INDEX_SCALE)); 66 NON_STABLE_ARRAY_NAMES.add(new Triple<>("intArrayWithValues", 67 Unsafe.ARRAY_INT_BASE_OFFSET, 68 Unsafe.ARRAY_INT_INDEX_SCALE)); 69 NON_STABLE_ARRAY_NAMES.add(new Triple<>("longArrayWithValues", 70 Unsafe.ARRAY_LONG_BASE_OFFSET, 71 Unsafe.ARRAY_LONG_INDEX_SCALE)); 72 NON_STABLE_ARRAY_NAMES.add(new Triple<>("floatArrayWithValues", 73 Unsafe.ARRAY_FLOAT_BASE_OFFSET, 74 Unsafe.ARRAY_FLOAT_INDEX_SCALE)); 75 NON_STABLE_ARRAY_NAMES.add(new Triple<>("doubleArrayWithValues", 76 Unsafe.ARRAY_DOUBLE_BASE_OFFSET, 77 Unsafe.ARRAY_DOUBLE_INDEX_SCALE)); 78 NON_STABLE_ARRAY_NAMES.add(new Triple<>("objectArrayWithValues", 79 Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 80 Unsafe.ARRAY_BOOLEAN_INDEX_SCALE)); 81 NON_STABLE_ARRAY_NAMES.add(new Triple<>("booleanArrayArrayWithValues", 82 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 83 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 84 NON_STABLE_ARRAY_NAMES.add(new Triple<>("byteArrayArrayWithValues", 85 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 86 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 87 NON_STABLE_ARRAY_NAMES.add(new Triple<>("shortArrayArrayWithValues", 88 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 89 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 90 NON_STABLE_ARRAY_NAMES.add(new Triple<>("charArrayArrayWithValues", 91 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 92 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 93 NON_STABLE_ARRAY_NAMES.add(new Triple<>("intArrayArrayWithValues", 94 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 95 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 96 NON_STABLE_ARRAY_NAMES.add(new Triple<>("longArrayArrayWithValues", 97 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 98 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 99 NON_STABLE_ARRAY_NAMES.add(new Triple<>("floatArrayArrayWithValues", 100 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 101 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 102 NON_STABLE_ARRAY_NAMES.add(new Triple<>("doubleArrayArrayWithValues", 103 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 104 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 105 NON_STABLE_ARRAY_NAMES.add(new Triple<>("objectArrayArrayWithValues", 106 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 107 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 108 } 109 // Stable array fields names mapped to their base offsets and index scale 110 private static final List<Triple<String, Integer, Integer>> STABLE_ARRAY_NAMES 111 = new LinkedList<>(); 112 static { 113 NON_STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 114 String nsFieldName = entry.getFirst(); 115 char firstChar = nsFieldName.charAt(0); 116 char newFirstChar = Character.toUpperCase(firstChar); 117 String sFieldName = nsFieldName.replaceFirst("" + firstChar, 118 "" + newFirstChar); 119 sFieldName = "stable" + sFieldName; 120 STABLE_ARRAY_NAMES.add(new Triple<>(sFieldName, 121 entry.getSecond(), 122 entry.getThird())); 123 }); 124 } 125 126 @DataProvider(name = "readConstantArrayElementDataProvider") 127 public static Object[][] readConstantArrayElementDataProvider() { 128 LinkedList<Object[]> cfgSet = new LinkedList<>(); 129 for (int i : new int[]{0, 1}) { 130 NON_STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 131 String fieldName = entry.getFirst(); 132 cfgSet.add(new Object[]{ 133 readFieldValue(fieldName), 134 i, 135 null, 136 "array field \"" + fieldName + "\" for index " + i}); 137 }); 138 STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 139 String fieldName = entry.getFirst(); 140 cfgSet.add(new Object[]{ 141 readFieldValue(fieldName), 142 i, 143 i == 0 ? getJavaConstant(fieldName) : null, 144 "array field \"" + fieldName + "\" for index " + i}); 145 }); 146 } 147 Stream<Map.Entry<ResolvedJavaField, JavaConstant>> arraysStream1 148 = Stream.concat(ARRAYS_MAP.entrySet().stream(), 149 ARRAY_ARRAYS_MAP.entrySet().stream()); 150 Stream<Map.Entry<ResolvedJavaField, JavaConstant>> arraysStream2 151 = Stream.concat(STABLE_ARRAYS_MAP.entrySet().stream(), 152 STABLE_ARRAY_ARRAYS_MAP.entrySet().stream()); 153 Stream.concat(arraysStream1, arraysStream2).forEach((array) -> { 154 for (int i : new int[]{-1, 2}) { 155 cfgSet.add(new Object[]{ 156 array.getValue(), 157 i, 158 null, 159 "array field \"" + array.getKey() + "\" for index " + i}); 160 } 161 }); 162 cfgSet.add(new Object[]{null, 0, null, "null"}); 163 cfgSet.add(new Object[]{JavaConstant.NULL_POINTER, 0, null, "JavaConstant.NULL_POINTER"}); 164 INSTANCE_FIELDS_MAP.values().forEach((constant) -> { 165 cfgSet.add(new Object[]{constant, 0, null, "non-stable non-array field"}); 166 }); 167 INSTANCE_STABLE_FIELDS_MAP.values().forEach((constant) -> { 168 cfgSet.add(new Object[]{constant, 0, null, "stable non-array field"}); 169 }); 170 return cfgSet.toArray(new Object[0][0]); 171 } 172 173 @DataProvider(name = "readConstantArrayElementForOffsetDataProvider") 174 public static Object[][] readConstantArrayElementForOffsetDataProvider() { 175 LinkedList<Object[]> cfgSet = new LinkedList<>(); 176 // Testing non-stable arrays. Result should be null in all cases 177 for (double i : new double[]{-1, 0, 0.5, 1, 1.5, 2}) { 178 NON_STABLE_ARRAY_NAMES.stream().forEach(entry -> { 179 String fieldName = entry.getFirst(); 180 long offset = (long) (entry.getSecond() + i * entry.getThird()); 181 cfgSet.add(new Object[]{ 182 readFieldValue(fieldName), 183 offset, 184 null, 185 "array field \"" + fieldName + "\" for offset " + offset}); 186 }); 187 } 188 // Testing stable arrays. Result should be null in all cases except "offset = base + 0" 189 for (double i : new double[]{-1, 0.5, 1, 1.5, 2}) { 190 STABLE_ARRAY_NAMES.stream().forEach(entry -> { 191 String fieldName = entry.getFirst(); 192 long offset = (long) Math.ceil(entry.getSecond() + i * entry.getThird()); 193 cfgSet.add(new Object[]{ 194 readFieldValue(fieldName), 195 offset, 196 null, 197 "array field \"" + fieldName + "\" for offset " + offset}); 198 }); 199 } 200 // Testing stable arrays "offset = base + 0". Result should be non-null 201 STABLE_ARRAY_NAMES.stream().forEach(entry -> { 202 String fieldName = entry.getFirst(); 203 long offset = (long) entry.getSecond(); 204 cfgSet.add(new Object[]{ 205 readFieldValue(fieldName), 206 offset, 207 getJavaConstant(fieldName), 208 "array field \"" + fieldName + "\" for offset " + offset}); 209 }); 210 // Testing null as array 211 cfgSet.add(new Object[]{null, 0, null, "null"}); 212 // Testing JavaConstant.NULL_POINTER as array 213 cfgSet.add(new Object[]{JavaConstant.NULL_POINTER, 0, null, "JavaConstant.NULL_POINTER"}); 214 // Testing non-stable non-array fields 215 INSTANCE_FIELDS_MAP.values().forEach((constant) -> { 216 cfgSet.add(new Object[]{constant, 0, null, "non-stable non-array field"}); 217 }); 218 // Testing stable non-array fields 219 INSTANCE_STABLE_FIELDS_MAP.values().forEach((constant) -> { 220 cfgSet.add(new Object[]{constant, 0, null, "stable non-array field"}); 221 }); 222 return cfgSet.toArray(new Object[0][0]); 223 } 224 225 private static JavaConstant readFieldValue(String fieldName) { 226 return CONSTANT_REFLECTION_PROVIDER 227 .readFieldValue(getResolvedJavaField(DummyClass.class, fieldName), 228 DUMMY_CLASS_CONSTANT); 229 } 230 231 private static JavaConstant getJavaConstant(String fieldName) { 232 Class dummyClass = DummyClass.class; 233 Field arrayField; 234 try { 235 arrayField = dummyClass.getDeclaredField(fieldName); 236 } catch (NoSuchFieldException ex) { 237 throw new Error("Test bug: wrong field name " + ex, ex); 238 } catch (SecurityException ex) { 239 throw new Error("Unexpected error: " + ex, ex); 240 } 241 arrayField.setAccessible(true); 242 Class componentType = arrayField.getType().getComponentType(); 243 if (componentType == null) { 244 throw new Error("Test error: field is not an array"); 245 } 246 Object value; 247 try { 248 value = arrayField.get(DUMMY_CLASS_INSTANCE); 249 } catch (IllegalArgumentException | IllegalAccessException ex) { 250 throw new Error("Unexpected error: " + ex, ex); 251 } 252 if (componentType == boolean.class) { 253 return JavaConstant.forBoolean(((boolean[])value)[0]); 254 } 255 if (componentType == byte.class) { 256 return JavaConstant.forByte(((byte[])value)[0]); 257 } 258 if (componentType == short.class) { 259 return JavaConstant.forShort(((short[])value)[0]); 260 } 261 if (componentType == char.class) { 262 return JavaConstant.forChar(((char[])value)[0]); 263 } 264 if (componentType == int.class) { 265 return JavaConstant.forInt(((int[])value)[0]); 266 } 267 if (componentType == long.class) { 268 return JavaConstant.forLong(((long[])value)[0]); 269 } 270 if (componentType == float.class) { 271 return JavaConstant.forFloat(((float[])value)[0]); 272 } 273 if (componentType == double.class) { 274 return JavaConstant.forDouble(((double[])value)[0]); 275 } 276 return CONSTANT_REFLECTION_PROVIDER.forObject(((Object[])value)[0]); 277 } 278 }