1 /* 2 * Copyright (c) 2016, 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 package jdk.vm.ci.hotspot; 24 25 import java.util.Set; 26 import java.util.stream.Collectors; 27 28 import jdk.vm.ci.common.JVMCIError; 29 30 /** 31 * Access to VM configuration data. 32 */ 33 public class HotSpotVMConfigAccess { 34 35 /** 36 * Gets the available configuration data. 37 */ 38 public HotSpotVMConfigStore getStore() { 39 return store; 40 } 41 42 /** 43 * Gets the address of a C++ symbol. 44 * 45 * @param name name of C++ symbol 46 * @param notPresent if non-null and the symbol is not present then this value is returned 47 * @return the address of the symbol 48 * @throws JVMCIError if the symbol is not present and {@code notPresent == null} 49 */ 50 public long getAddress(String name, Long notPresent) { 51 Long entry = store.vmAddresses.get(name); 52 if (entry == null) { 53 if (notPresent != null) { 54 return notPresent; 55 } 56 throw missingEntry("address", name, store.vmFlags.keySet()); 57 58 } 59 return entry; 60 } 61 62 /** 63 * Gets the address of a C++ symbol. 64 * 65 * @param name name of C++ symbol 66 * @return the address of the symbol 67 * @throws JVMCIError if the symbol is not present 68 */ 69 public long getAddress(String name) { 70 return getAddress(name, null); 71 } 72 73 /** 74 * Gets the value of a C++ constant. 75 * 76 * @param name name of the constant (e.g., {@code "frame::arg_reg_save_area_bytes"}) 77 * @param type the boxed type to which the constant value will be converted 78 * @param notPresent if non-null and the constant is not present then this value is returned 79 * @return the constant value converted to {@code type} 80 * @throws JVMCIError if the constant is not present and {@code notPresent == null} 81 */ 82 public <T> T getConstant(String name, Class<T> type, T notPresent) { 83 Long c = store.vmConstants.get(name); 84 if (c == null) { 85 if (notPresent != null) { 86 return notPresent; 87 } 88 throw missingEntry("constant", name, store.vmConstants.keySet()); 89 } 90 return type.cast(convertValue(name, type, c, null)); 91 } 92 93 /** 94 * Gets the value of a C++ constant. 95 * 96 * @param name name of the constant (e.g., {@code "frame::arg_reg_save_area_bytes"}) 97 * @param type the boxed type to which the constant value will be converted 98 * @return the constant value converted to {@code type} 99 * @throws JVMCIError if the constant is not present 100 */ 101 public <T> T getConstant(String name, Class<T> type) { 102 return getConstant(name, type, null); 103 } 104 105 /** 106 * Gets the offset of a non-static C++ field. 107 * 108 * @param name fully qualified name of the field 109 * @param type the boxed type to which the offset value will be converted (must be 110 * {@link Integer} or {@link Long}) 111 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 112 * @param notPresent if non-null and the field is not present then this value is returned 113 * @return the offset in bytes of the requested field 114 * @throws JVMCIError if the field is static or not present and {@code notPresent} is null 115 */ 116 public <T> T getFieldOffset(String name, Class<T> type, String cppType, T notPresent) { 117 return getFieldOffset0(name, type, notPresent, cppType, null); 118 } 119 120 /** 121 * Gets the offset of a non-static C++ field. 122 * 123 * @param name fully qualified name of the field 124 * @param type the boxed type to which the offset value will be converted (must be 125 * {@link Integer} or {@link Long}) 126 * @param notPresent if non-null and the field is not present then this value is returned 127 * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is 128 * returned in element 0 of this array 129 * @return the offset in bytes of the requested field 130 * @throws JVMCIError if the field is static or not present and {@code notPresent} is null 131 */ 132 public <T> T getFieldOffset(String name, Class<T> type, T notPresent, String[] outCppType) { 133 return getFieldOffset0(name, type, notPresent, null, outCppType); 134 } 135 136 /** 137 * Gets the offset of a non-static C++ field. 138 * 139 * @param name fully qualified name of the field 140 * @param type the boxed type to which the offset value will be converted (must be 141 * {@link Integer} or {@link Long}) 142 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 143 * @return the offset in bytes of the requested field 144 * @throws JVMCIError if the field is static or not present 145 */ 146 public <T> T getFieldOffset(String name, Class<T> type, String cppType) { 147 return getFieldOffset0(name, type, null, cppType, null); 148 } 149 150 /** 151 * Gets the offset of a non-static C++ field. 152 * 153 * @param name fully qualified name of the field 154 * @param type the boxed type to which the offset value will be converted (must be 155 * {@link Integer} or {@link Long}) 156 * @return the offset in bytes of the requested field 157 * @throws JVMCIError if the field is static or not present 158 */ 159 public <T> T getFieldOffset(String name, Class<T> type) { 160 return getFieldOffset0(name, type, null, null, null); 161 } 162 163 private <T> T getFieldOffset0(String name, Class<T> type, T notPresent, String inCppType, String[] outCppType) { 164 assert type == Integer.class || type == Long.class; 165 VMField entry = getField(name, inCppType, notPresent == null); 166 if (entry == null) { 167 return notPresent; 168 } 169 if (entry.address != 0) { 170 throw new JVMCIError("cannot get offset of static field " + name); 171 } 172 if (outCppType != null) { 173 outCppType[0] = entry.type; 174 } 175 return type.cast(convertValue(name, type, entry.offset, inCppType)); 176 } 177 178 /** 179 * Gets the address of a static C++ field. 180 * 181 * @param name fully qualified name of the field 182 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 183 * @param notPresent if non-null and the field is not present then this value is returned 184 * @return the address of the requested field 185 * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null 186 */ 187 public long getFieldAddress(String name, String cppType, Long notPresent) { 188 return getFieldAddress0(name, notPresent, cppType, null); 189 } 190 191 /** 192 * Gets the address of a static C++ field. 193 * 194 * @param name fully qualified name of the field 195 * @param notPresent if non-null and the field is not present then this value is returned 196 * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is 197 * returned in element 0 of this array 198 * @return the address of the requested field 199 * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null 200 */ 201 public long getFieldAddress(String name, Long notPresent, String[] outCppType) { 202 return getFieldAddress0(name, notPresent, null, outCppType); 203 } 204 205 /** 206 * Gets the address of a static C++ field. 207 * 208 * @param name fully qualified name of the field 209 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 210 * @return the address of the requested field 211 * @throws JVMCIError if the field is not static or not present 212 */ 213 public long getFieldAddress(String name, String cppType) { 214 return getFieldAddress0(name, null, cppType, null); 215 } 216 217 private long getFieldAddress0(String name, Long notPresent, String inCppType, String[] outCppType) { 218 VMField entry = getField(name, inCppType, notPresent == null); 219 if (entry == null) { 220 return notPresent; 221 } 222 if (entry.address == 0) { 223 throw new JVMCIError(name + " is not a static field"); 224 } 225 if (outCppType != null) { 226 outCppType[0] = entry.type; 227 } 228 return entry.address; 229 } 230 231 /** 232 * Gets the value of a static C++ field. 233 * 234 * @param name fully qualified name of the field 235 * @param type the boxed type to which the constant value will be converted 236 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 237 * @param notPresent if non-null and the field is not present then this value is returned 238 * @return the value of the requested field 239 * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null 240 */ 241 public <T> T getFieldValue(String name, Class<T> type, String cppType, T notPresent) { 242 return getFieldValue0(name, type, notPresent, cppType, null); 243 } 244 245 /** 246 * Gets the value of a static C++ field. 247 * 248 * @param name fully qualified name of the field 249 * @param type the boxed type to which the constant value will be converted 250 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 251 * @return the value of the requested field 252 * @throws JVMCIError if the field is not static or not present 253 */ 254 public <T> T getFieldValue(String name, Class<T> type, String cppType) { 255 return getFieldValue0(name, type, null, cppType, null); 256 } 257 258 /** 259 * Gets the value of a static C++ field. 260 * 261 * @param name fully qualified name of the field 262 * @param type the boxed type to which the constant value will be converted 263 * @param notPresent if non-null and the field is not present then this value is returned 264 * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is 265 * returned in element 0 of this array 266 * @return the value of the requested field 267 * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null 268 */ 269 public <T> T getFieldValue(String name, Class<T> type, T notPresent, String[] outCppType) { 270 return getFieldValue0(name, type, notPresent, null, outCppType); 271 } 272 273 /** 274 * Gets the value of a static C++ field. 275 * 276 * @param name fully qualified name of the field 277 * @param type the boxed type to which the constant value will be converted 278 * @return the value of the requested field 279 * @throws JVMCIError if the field is not static or not present 280 */ 281 public <T> T getFieldValue(String name, Class<T> type) { 282 return getFieldValue0(name, type, null, null, null); 283 } 284 285 private <T> T getFieldValue0(String name, Class<T> type, T notPresent, String inCppType, String[] outCppType) { 286 VMField entry = getField(name, inCppType, notPresent == null); 287 if (entry == null) { 288 return notPresent; 289 } 290 if (entry.value == null) { 291 throw new JVMCIError(name + " is not a static field "); 292 } 293 if (outCppType != null) { 294 outCppType[0] = entry.type; 295 } 296 return type.cast(convertValue(name, type, entry.value, inCppType)); 297 } 298 299 private boolean typeEquals(String t1, String t2) { 300 if (t1.equals("int64_t") && t2.equals("intx")) { 301 return true; 302 } 303 return t1.equals(t2); 304 } 305 306 /** 307 * Gets a C++ field. 308 * 309 * @param name fully qualified name of the field 310 * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) 311 * @param required specifies if the field must be present 312 * @return the field 313 * @throws JVMCIError if the field is not present and {@code required == true} 314 */ 315 private VMField getField(String name, String cppType, boolean required) { 316 VMField entry = store.vmFields.get(name); 317 if (entry == null) { 318 if (!required) { 319 return null; 320 } 321 throw missingEntry("field", name, store.vmFields.keySet()); 322 } 323 324 // Make sure the native type is still the type we expect. 325 if (cppType != null && !typeEquals(cppType, entry.type)) { 326 throw new JVMCIError("expected type " + cppType + " but VM field " + name + " is of type " + entry.type); 327 } 328 return entry; 329 } 330 331 /** 332 * Gets a VM flag value. 333 * 334 * @param name name of the flag (e.g., {@code "CompileTheWorldStartAt"}) 335 * @param type the boxed type to which the flag's value will be converted 336 * @return the flag's value converted to {@code type} or {@code notPresent} if the flag is not 337 * present 338 * @throws JVMCIError if the flag is not present 339 */ 340 public <T> T getFlag(String name, Class<T> type) { 341 return getFlag(name, type, null); 342 } 343 344 /** 345 * Gets a VM flag value. 346 * 347 * @param name name of the flag (e.g., {@code "CompileTheWorldStartAt"}) 348 * @param type the boxed type to which the flag's value will be converted 349 * @param notPresent if non-null and the flag is not present then this value is returned 350 * @return the flag's value converted to {@code type} or {@code notPresent} if the flag is not 351 * present 352 * @throws JVMCIError if the flag is not present and {@code notPresent == null} 353 */ 354 public <T> T getFlag(String name, Class<T> type, T notPresent) { 355 VMFlag entry = store.vmFlags.get(name); 356 Object value; 357 String cppType; 358 if (entry == null) { 359 // Fall back to VM call 360 value = store.compilerToVm.getFlagValue(name); 361 if (value == store.compilerToVm) { 362 if (notPresent != null) { 363 return notPresent; 364 } 365 throw missingEntry("flag", name, store.vmFlags.keySet()); 366 } else { 367 cppType = null; 368 } 369 } else { 370 value = entry.value; 371 cppType = entry.type; 372 } 373 return type.cast(convertValue(name, type, value, cppType)); 374 } 375 376 private JVMCIError missingEntry(String category, String name, Set<String> keys) { 377 throw new JVMCIError("expected VM %s not found in %s: %s%nAvailable values:%n %s", category, store, name, 378 keys.stream().sorted().collect(Collectors.joining(System.lineSeparator() + " "))); 379 } 380 381 private static <T> Object convertValue(String name, Class<T> toType, Object value, String cppType) throws JVMCIError { 382 if (toType == Boolean.class) { 383 if (value instanceof String) { 384 return Boolean.valueOf((String) value); 385 } else if (value instanceof Boolean) { 386 return value; 387 } else if (value instanceof Long) { 388 return ((long) value) != 0; 389 } 390 } else if (toType == Byte.class) { 391 if (value instanceof Long) { 392 return (byte) (long) value; 393 } 394 } else if (toType == Integer.class) { 395 if (value instanceof Integer) { 396 return value; 397 } else if (value instanceof Long) { 398 return (int) (long) value; 399 } 400 } else if (toType == String.class) { 401 if (value == null || value instanceof String) { 402 return value; 403 } 404 } else if (toType == Long.class) { 405 return value; 406 } 407 408 throw new JVMCIError("cannot convert " + name + " of type " + value.getClass().getSimpleName() + (cppType == null ? "" : " [" + cppType + "]") + " to " + toType.getSimpleName()); 409 } 410 411 private final HotSpotVMConfigStore store; 412 413 public HotSpotVMConfigAccess(HotSpotVMConfigStore store) { 414 this.store = store; 415 } 416 }