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 package jdk.vm.ci.hotspot.test; 25 26 import static jdk.vm.ci.hotspot.test.TestHelper.ARRAYS_MAP; 27 import static jdk.vm.ci.hotspot.test.TestHelper.ARRAY_ARRAYS_MAP; 28 import static jdk.vm.ci.hotspot.test.TestHelper.CONSTANT_REFLECTION_PROVIDER; 29 import static jdk.vm.ci.hotspot.test.TestHelper.DUMMY_CLASS_CONSTANT; 30 import static jdk.vm.ci.hotspot.test.TestHelper.DUMMY_CLASS_INSTANCE; 31 import static jdk.vm.ci.hotspot.test.TestHelper.getResolvedJavaField; 32 import static jdk.vm.ci.hotspot.test.TestHelper.INSTANCE_STABLE_FIELDS_MAP; 33 import static jdk.vm.ci.hotspot.test.TestHelper.INSTANCE_FIELDS_MAP; 34 import static jdk.vm.ci.hotspot.test.TestHelper.STABLE_ARRAYS_MAP; 35 import static jdk.vm.ci.hotspot.test.TestHelper.STABLE_ARRAY_ARRAYS_MAP; 36 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 43 import jdk.vm.ci.meta.JavaConstant; 44 import org.testng.annotations.DataProvider; 45 import jdk.internal.misc.Unsafe; 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<ArrayFieldParams> NON_STABLE_ARRAY_NAMES 52 = new LinkedList<>(); 53 54 static { 55 NON_STABLE_ARRAY_NAMES.add( 56 new ArrayFieldParams("booleanArrayWithValues", Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 57 Unsafe.ARRAY_BOOLEAN_INDEX_SCALE)); 58 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("byteArrayWithValues", 59 Unsafe.ARRAY_BYTE_BASE_OFFSET, 60 Unsafe.ARRAY_BYTE_INDEX_SCALE)); 61 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("shortArrayWithValues", 62 Unsafe.ARRAY_SHORT_BASE_OFFSET, 63 Unsafe.ARRAY_SHORT_INDEX_SCALE)); 64 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("charArrayWithValues", 65 Unsafe.ARRAY_CHAR_BASE_OFFSET, 66 Unsafe.ARRAY_CHAR_INDEX_SCALE)); 67 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("intArrayWithValues", 68 Unsafe.ARRAY_INT_BASE_OFFSET, 69 Unsafe.ARRAY_INT_INDEX_SCALE)); 70 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("longArrayWithValues", 71 Unsafe.ARRAY_LONG_BASE_OFFSET, 72 Unsafe.ARRAY_LONG_INDEX_SCALE)); 73 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("floatArrayWithValues", 74 Unsafe.ARRAY_FLOAT_BASE_OFFSET, 75 Unsafe.ARRAY_FLOAT_INDEX_SCALE)); 76 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("doubleArrayWithValues", 77 Unsafe.ARRAY_DOUBLE_BASE_OFFSET, 78 Unsafe.ARRAY_DOUBLE_INDEX_SCALE)); 79 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("objectArrayWithValues", 80 Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 81 Unsafe.ARRAY_BOOLEAN_INDEX_SCALE)); 82 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("booleanArrayArrayWithValues", 83 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 84 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 85 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("byteArrayArrayWithValues", 86 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 87 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 88 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("shortArrayArrayWithValues", 89 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 90 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 91 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("charArrayArrayWithValues", 92 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 93 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 94 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("intArrayArrayWithValues", 95 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 96 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 97 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("longArrayArrayWithValues", 98 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 99 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 100 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("floatArrayArrayWithValues", 101 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 102 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 103 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("doubleArrayArrayWithValues", 104 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 105 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 106 NON_STABLE_ARRAY_NAMES.add(new ArrayFieldParams("objectArrayArrayWithValues", 107 Unsafe.ARRAY_OBJECT_BASE_OFFSET, 108 Unsafe.ARRAY_OBJECT_INDEX_SCALE)); 109 } 110 111 // Stable array fields names mapped to their base offsets and index scale 112 private static final List<ArrayFieldParams> STABLE_ARRAY_NAMES 113 = new LinkedList<>(); 114 115 static { 116 NON_STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 117 String nsFieldName = entry.name; 118 char firstChar = nsFieldName.charAt(0); 119 char newFirstChar = Character.toUpperCase(firstChar); 120 String sFieldName = nsFieldName.replaceFirst("" + firstChar, 121 "" + newFirstChar); 122 sFieldName = "stable" + sFieldName; 123 STABLE_ARRAY_NAMES.add(new ArrayFieldParams(sFieldName, entry.offsetBase, entry.scale)); 124 }); 125 } 126 127 @DataProvider(name = "readConstantArrayElementDataProvider") 128 public static Object[][] readConstantArrayElementDataProvider() { 129 LinkedList<Object[]> cfgSet = new LinkedList<>(); 130 for (int i : new int[]{0, 1}) { 131 NON_STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 132 String fieldName = entry.name; 133 cfgSet.add(new Object[]{ 134 readFieldValue(fieldName), 135 i, 136 null, 137 "array field \"" + fieldName + "\" for index " + i}); 138 }); 139 STABLE_ARRAY_NAMES.stream().forEach((entry) -> { 140 String fieldName = entry.name; 141 cfgSet.add(new Object[]{ 142 readFieldValue(fieldName), 143 i, 144 i == 0 ? getJavaConstant(fieldName) : null, 145 "array field \"" + fieldName + "\" for index " + i}); 146 }); 147 } 148 Stream<Map.Entry<ResolvedJavaField, JavaConstant>> arraysStream1 149 = Stream.concat(ARRAYS_MAP.entrySet().stream(), 150 ARRAY_ARRAYS_MAP.entrySet().stream()); 151 Stream<Map.Entry<ResolvedJavaField, JavaConstant>> arraysStream2 152 = Stream.concat(STABLE_ARRAYS_MAP.entrySet().stream(), 153 STABLE_ARRAY_ARRAYS_MAP.entrySet().stream()); 154 Stream.concat(arraysStream1, arraysStream2).forEach((array) -> { 155 for (int i : new int[]{-1, 2}) { 156 cfgSet.add(new Object[]{ 157 array.getValue(), 158 i, 159 null, 160 "array field \"" + array.getKey() + "\" for index " + i}); 161 } 162 }); 163 cfgSet.add(new Object[]{null, 0, null, "null"}); 164 cfgSet.add(new Object[]{JavaConstant.NULL_POINTER, 0, null, "JavaConstant.NULL_POINTER"}); 165 INSTANCE_FIELDS_MAP.values().forEach((constant) -> { 166 cfgSet.add(new Object[]{constant, 0, null, "non-stable non-array field"}); 167 }); 168 INSTANCE_STABLE_FIELDS_MAP.values().forEach((constant) -> { 169 cfgSet.add(new Object[]{constant, 0, null, "stable non-array field"}); 170 }); 171 return cfgSet.toArray(new Object[0][0]); 172 } 173 174 @DataProvider(name = "readConstantArrayElementForOffsetDataProvider") 175 public static Object[][] readConstantArrayElementForOffsetDataProvider() { 176 LinkedList<Object[]> cfgSet = new LinkedList<>(); 177 // Testing non-stable arrays. Result should be null in all cases 178 for (double i : new double[]{-1, 0, 0.5, 1, 1.5, 2}) { 179 NON_STABLE_ARRAY_NAMES.stream().forEach(entry -> { 180 String fieldName = entry.name; 181 long offset = (long) (entry.offsetBase + i * entry.scale); 182 cfgSet.add(new Object[]{ 183 readFieldValue(fieldName), 184 offset, 185 null, 186 "array field \"" + fieldName + "\" for offset " + offset}); 187 }); 188 } 189 // Testing stable arrays. Result should be null in all cases except "offset = base + 0" 190 for (double i : new double[]{-1, 0.5, 1, 1.5, 2}) { 191 STABLE_ARRAY_NAMES.stream().forEach(entry -> { 192 String fieldName = entry.name; 193 long offset = (long) Math.ceil(entry.offsetBase + i * entry.scale); 194 cfgSet.add(new Object[]{ 195 readFieldValue(fieldName), 196 offset, 197 null, 198 "array field \"" + fieldName + "\" for offset " + offset}); 199 }); 200 } 201 // Testing stable arrays "offset = base + 0". Result should be non-null 202 STABLE_ARRAY_NAMES.stream().forEach(entry -> { 203 String fieldName = entry.name; 204 long offset = (long) entry.offsetBase; 205 cfgSet.add(new Object[]{ 206 readFieldValue(fieldName), 207 offset, 208 getJavaConstant(fieldName), 209 "array field \"" + fieldName + "\" for offset " + offset}); 210 }); 211 // Testing null as array 212 cfgSet.add(new Object[]{null, 0, null, "null"}); 213 // Testing JavaConstant.NULL_POINTER as array 214 cfgSet.add(new Object[]{JavaConstant.NULL_POINTER, 0, null, "JavaConstant.NULL_POINTER"}); 215 // Testing non-stable non-array fields 216 INSTANCE_FIELDS_MAP.values().forEach((constant) -> { 217 cfgSet.add(new Object[]{constant, 0, null, "non-stable non-array field"}); 218 }); 219 // Testing stable non-array fields 220 INSTANCE_STABLE_FIELDS_MAP.values().forEach((constant) -> { 221 cfgSet.add(new Object[]{constant, 0, null, "stable non-array field"}); 222 }); 223 return cfgSet.toArray(new Object[0][0]); 224 } 225 226 private static JavaConstant readFieldValue(String fieldName) { 227 return CONSTANT_REFLECTION_PROVIDER.readFieldValue(getResolvedJavaField(DummyClass.class, fieldName), 228 DUMMY_CLASS_CONSTANT); 229 } 230 231 private static JavaConstant getJavaConstant(String fieldName) { 232 Class<DummyClass> 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 279 private static class ArrayFieldParams { 280 public final String name; 281 public final int offsetBase; 282 public final int scale; 283 284 ArrayFieldParams(String name, int offsetBase, int scale) { 285 this.name = name; 286 this.offsetBase = offsetBase; 287 this.scale = scale; 288 } 289 } 290 }