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