1 /*
   2  * Copyright (c) 2016, 2018, 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 static jdk.vm.ci.common.InitTimer.timer;
  26 
  27 import java.util.Arrays;
  28 import java.util.Collections;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 import java.util.TreeMap;
  33 
  34 import jdk.vm.ci.common.InitTimer;
  35 import jdk.vm.ci.common.JVMCIError;
  36 
  37 /**
  38  * Access to VM configuration data.
  39  */
  40 public final class HotSpotVMConfigStore {
  41 
  42     /**
  43      * Gets the C++ symbols whose addresses are exposed by this object.
  44      *
  45      * @return an unmodifiable map from the symbol names to their addresses
  46      */
  47     public Map<String, Long> getAddresses() {
  48         return Collections.unmodifiableMap(vmAddresses);
  49     }
  50 
  51     /**
  52      * Gets the C++ constants exposed by this object.
  53      *
  54      * @return an unmodifiable map from the names of C++ constants to their values
  55      */
  56     public Map<String, Long> getConstants() {
  57         return Collections.unmodifiableMap(vmConstants);
  58     }
  59 
  60     /**
  61      * Gets the VM flags exposed by this object.
  62      *
  63      * @return an unmodifiable map from VM flag names to {@link VMFlag} objects
  64      */
  65     public Map<String, VMFlag> getFlags() {
  66         return Collections.unmodifiableMap(vmFlags);
  67     }
  68 
  69     /**
  70      * Gets the C++ fields exposed by this object.
  71      *
  72      * @return an unmodifiable map from VM field names to {@link VMField} objects
  73      */
  74     public Map<String, VMField> getFields() {
  75         return Collections.unmodifiableMap(vmFields);
  76     }
  77 
  78     /**
  79      * Gets the VM intrinsic descriptions exposed by this object.
  80      */
  81     public List<VMIntrinsicMethod> getIntrinsics() {
  82         return Collections.unmodifiableList(vmIntrinsics);
  83     }
  84 
  85     final HashMap<String, VMField> vmFields;
  86     final HashMap<String, Long> vmConstants;
  87     final HashMap<String, Long> vmAddresses;
  88     final HashMap<String, VMFlag> vmFlags;
  89     final List<VMIntrinsicMethod> vmIntrinsics;
  90     final CompilerToVM compilerToVm;
  91 
  92     /**
  93      * Reads the database of VM info. The return value encodes the info in a nested object array
  94      * that is described by the pseudo Java object {@code info} below:
  95      *
  96      * <pre>
  97      *     info = [
  98      *         VMField[] vmFields,
  99      *         [String name, Long value, ...] vmConstants,
 100      *         [String name, Long value, ...] vmAddresses,
 101      *         VMFlag[] vmFlags
 102      *         VMIntrinsicMethod[] vmIntrinsics
 103      *     ]
 104      * </pre>
 105      */
 106     @SuppressWarnings("try")
 107     HotSpotVMConfigStore(CompilerToVM compilerToVm) {
 108         this.compilerToVm = compilerToVm;
 109         Object[] data;
 110         try (InitTimer t = timer("CompilerToVm readConfiguration")) {
 111             data = compilerToVm.readConfiguration();
 112         }
 113         if (data.length != 5) {
 114             throw new JVMCIError("Expected data.length to be 5, not %d", data.length);
 115         }
 116 
 117         // @formatter:off
 118         VMField[] vmFieldsInfo    = (VMField[]) data[0];
 119         Object[] vmConstantsInfo  = (Object[])  data[1];
 120         Object[] vmAddressesInfo  = (Object[])  data[2];
 121         VMFlag[] vmFlagsInfo      = (VMFlag[])  data[3];
 122 
 123         vmFields     = new HashMap<>(vmFieldsInfo.length);
 124         vmConstants  = new HashMap<>(vmConstantsInfo.length);
 125         vmAddresses  = new HashMap<>(vmAddressesInfo.length);
 126         vmFlags      = new HashMap<>(vmFlagsInfo.length);
 127         vmIntrinsics = Arrays.asList((VMIntrinsicMethod[]) data[4]);
 128         // @formatter:on
 129 
 130         try (InitTimer t = timer("HotSpotVMConfigStore<init> fill maps")) {
 131             for (VMField vmField : vmFieldsInfo) {
 132                 vmFields.put(vmField.name, vmField);
 133             }
 134 
 135             for (int i = 0; i < vmConstantsInfo.length / 2; i++) {
 136                 String name = (String) vmConstantsInfo[i * 2];
 137                 Long value = (Long) vmConstantsInfo[i * 2 + 1];
 138                 vmConstants.put(name, value);
 139             }
 140 
 141             for (int i = 0; i < vmAddressesInfo.length / 2; i++) {
 142                 String name = (String) vmAddressesInfo[i * 2];
 143                 Long value = (Long) vmAddressesInfo[i * 2 + 1];
 144                 vmAddresses.put(name, value);
 145             }
 146 
 147             for (VMFlag vmFlag : vmFlagsInfo) {
 148                 vmFlags.put(vmFlag.name, vmFlag);
 149             }
 150         }
 151     }
 152 
 153     @Override
 154     public String toString() {
 155         return String.format("%s[%d fields, %d constants, %d addresses, %d flags, %d intrinsics]",
 156                         getClass().getSimpleName(),
 157                         vmFields.size(),
 158                         vmConstants.size(),
 159                         vmAddresses.size(),
 160                         vmFlags.size(),
 161                         vmIntrinsics.size());
 162     }
 163 
 164     void printConfig() {
 165         CompilerToVM vm = compilerToVm;
 166         TreeMap<String, VMField> fields = new TreeMap<>(getFields());
 167         for (VMField field : fields.values()) {
 168             if (!field.isStatic()) {
 169                 printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset);
 170             } else {
 171                 String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value);
 172                 printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
 173             }
 174         }
 175         TreeMap<String, VMFlag> flags = new TreeMap<>(getFlags());
 176         for (VMFlag flag : flags.values()) {
 177             printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
 178         }
 179         TreeMap<String, Long> addresses = new TreeMap<>(getAddresses());
 180         for (Map.Entry<String, Long> e : addresses.entrySet()) {
 181             printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
 182         }
 183         TreeMap<String, Long> constants = new TreeMap<>(getConstants());
 184         for (Map.Entry<String, Long> e : constants.entrySet()) {
 185             printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
 186         }
 187         for (VMIntrinsicMethod e : getIntrinsics()) {
 188             printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
 189         }
 190     }
 191 
 192     @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!")
 193     private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
 194         String line = String.format(format, args);
 195         byte[] lineBytes = line.getBytes();
 196         vm.writeDebugOutput(lineBytes, 0, lineBytes.length);
 197         vm.flushDebugOutput();
 198     }
 199 
 200 }