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