1 /*
   2  * Copyright (c) 2013, 2015, 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.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL;
  26 
  27 import java.lang.reflect.Field;
  28 
  29 import jdk.vm.ci.code.BailoutException;
  30 import jdk.vm.ci.code.CodeCacheProvider;
  31 import jdk.vm.ci.code.CompilationRequest;
  32 import jdk.vm.ci.code.CompilationResult;
  33 import jdk.vm.ci.code.CompilationResult.Call;
  34 import jdk.vm.ci.code.CompilationResult.ConstantReference;
  35 import jdk.vm.ci.code.CompilationResult.DataPatch;
  36 import jdk.vm.ci.code.CompilationResult.Mark;
  37 import jdk.vm.ci.code.DataSection;
  38 import jdk.vm.ci.code.DataSection.Data;
  39 import jdk.vm.ci.code.DataSection.DataBuilder;
  40 import jdk.vm.ci.code.InstalledCode;
  41 import jdk.vm.ci.code.RegisterConfig;
  42 import jdk.vm.ci.code.TargetDescription;
  43 import jdk.vm.ci.common.JVMCIError;
  44 import jdk.vm.ci.meta.Constant;
  45 import jdk.vm.ci.meta.JavaConstant;
  46 import jdk.vm.ci.meta.SerializableConstant;
  47 import jdk.vm.ci.meta.SpeculationLog;
  48 import jdk.vm.ci.meta.VMConstant;
  49 
  50 /**
  51  * HotSpot implementation of {@link CodeCacheProvider}.
  52  */
  53 public class HotSpotCodeCacheProvider implements CodeCacheProvider {
  54 
  55     protected final HotSpotJVMCIRuntimeProvider runtime;
  56     public final HotSpotVMConfig config;
  57     protected final TargetDescription target;
  58     protected final RegisterConfig regConfig;
  59 
  60     public HotSpotCodeCacheProvider(HotSpotJVMCIRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) {
  61         this.runtime = runtime;
  62         this.config = config;
  63         this.target = target;
  64         this.regConfig = regConfig;
  65     }
  66 
  67     @Override
  68     public String getMarkName(Mark mark) {
  69         int markId = (int) mark.id;
  70         Field[] fields = runtime.getConfig().getClass().getDeclaredFields();
  71         for (Field f : fields) {
  72             if (f.getName().startsWith("MARKID_")) {
  73                 f.setAccessible(true);
  74                 try {
  75                     if (f.getInt(runtime.getConfig()) == markId) {
  76                         return f.getName();
  77                     }
  78                 } catch (Exception e) {
  79                 }
  80             }
  81         }
  82         return CodeCacheProvider.super.getMarkName(mark);
  83     }
  84 
  85     /**
  86      * Decodes a call target to a mnemonic if possible.
  87      */
  88     @Override
  89     public String getTargetName(Call call) {
  90         Field[] fields = runtime.getConfig().getClass().getDeclaredFields();
  91         for (Field f : fields) {
  92             if (f.getName().endsWith("Stub")) {
  93                 f.setAccessible(true);
  94                 try {
  95                     Object address = f.get(runtime.getConfig());
  96                     if (address.equals(call.target)) {
  97                         return f.getName() + ":0x" + Long.toHexString((Long) address);
  98                     }
  99                 } catch (Exception e) {
 100                 }
 101             }
 102         }
 103         return CodeCacheProvider.super.getTargetName(call);
 104     }
 105 
 106     @Override
 107     public RegisterConfig getRegisterConfig() {
 108         return regConfig;
 109     }
 110 
 111     @Override
 112     public int getMinimumOutgoingSize() {
 113         return runtime.getConfig().runtimeCallStackSize;
 114     }
 115 
 116     private InstalledCode logOrDump(InstalledCode installedCode, CompilationResult compResult) {
 117         ((HotSpotJVMCIRuntime) runtime).notifyInstall(this, installedCode, compResult);
 118         return installedCode;
 119     }
 120 
 121     public InstalledCode installCode(CompilationRequest compRequest, CompilationResult compResult, InstalledCode installedCode, SpeculationLog log, boolean isDefault) {
 122         HotSpotResolvedJavaMethod method = compRequest != null ? (HotSpotResolvedJavaMethod) compRequest.getMethod() : null;
 123         InstalledCode resultInstalledCode;
 124         if (installedCode == null) {
 125             if (method == null) {
 126                 // Must be a stub
 127                 resultInstalledCode = new HotSpotRuntimeStub(compResult.getName());
 128             } else {
 129                 resultInstalledCode = new HotSpotNmethod(method, compResult.getName(), isDefault);
 130             }
 131         } else {
 132             resultInstalledCode = installedCode;
 133         }
 134         HotSpotCompiledCode compiledCode;
 135         if (method != null) {
 136             final int id;
 137             final long jvmciEnv;
 138             if (compRequest instanceof HotSpotCompilationRequest) {
 139                 HotSpotCompilationRequest hsCompRequest = (HotSpotCompilationRequest) compRequest;
 140                 id = hsCompRequest.getId();
 141                 jvmciEnv = hsCompRequest.getJvmciEnv();
 142             } else {
 143                 id = method.allocateCompileId(compRequest.getEntryBCI());
 144                 jvmciEnv = 0L;
 145             }
 146             compiledCode = new HotSpotCompiledNmethod(method, compResult, id, jvmciEnv);
 147         } else {
 148             compiledCode = new HotSpotCompiledCode(compResult);
 149         }
 150         int result = runtime.getCompilerToVM().installCode(target, compiledCode, resultInstalledCode, (HotSpotSpeculationLog) log);
 151         if (result != config.codeInstallResultOk) {
 152             String resultDesc = config.getCodeInstallResultDescription(result);
 153             if (compiledCode instanceof HotSpotCompiledNmethod) {
 154                 HotSpotCompiledNmethod compiledNmethod = (HotSpotCompiledNmethod) compiledCode;
 155                 String msg = compiledNmethod.getInstallationFailureMessage();
 156                 if (msg != null) {
 157                     msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
 158                 } else {
 159                     msg = String.format("Code installation failed: %s", resultDesc);
 160                 }
 161                 if (result == config.codeInstallResultDependenciesInvalid) {
 162                     throw new AssertionError(resultDesc + " " + msg);
 163                 }
 164                 throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg);
 165             } else {
 166                 throw new BailoutException("Error installing %s: %s", compResult.getName(), resultDesc);
 167             }
 168         }
 169         return logOrDump(resultInstalledCode, compResult);
 170     }
 171 
 172     public void invalidateInstalledCode(InstalledCode installedCode) {
 173         runtime.getCompilerToVM().invalidateInstalledCode(installedCode);
 174     }
 175 
 176     public boolean needsDataPatch(JavaConstant constant) {
 177         return constant instanceof HotSpotMetaspaceConstant;
 178     }
 179 
 180     private Data createSingleDataItem(Constant constant) {
 181         int size;
 182         DataBuilder builder;
 183         if (constant instanceof VMConstant) {
 184             VMConstant vmConstant = (VMConstant) constant;
 185             boolean compressed;
 186             if (constant instanceof HotSpotConstant) {
 187                 HotSpotConstant c = (HotSpotConstant) vmConstant;
 188                 compressed = c.isCompressed();
 189             } else {
 190                 throw new JVMCIError(String.valueOf(constant));
 191             }
 192 
 193             size = compressed ? 4 : target.wordSize;
 194             if (size == 4) {
 195                 builder = (buffer, patch) -> {
 196                     patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
 197                     buffer.putInt(0xDEADDEAD);
 198                 };
 199             } else {
 200                 assert size == 8;
 201                 builder = (buffer, patch) -> {
 202                     patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
 203                     buffer.putLong(0xDEADDEADDEADDEADL);
 204                 };
 205             }
 206         } else if (JavaConstant.isNull(constant)) {
 207             boolean compressed = COMPRESSED_NULL.equals(constant);
 208             size = compressed ? 4 : target.wordSize;
 209             builder = DataBuilder.zero(size);
 210         } else if (constant instanceof SerializableConstant) {
 211             SerializableConstant s = (SerializableConstant) constant;
 212             size = s.getSerializedSize();
 213             builder = DataBuilder.serializable(s);
 214         } else {
 215             throw new JVMCIError(String.valueOf(constant));
 216         }
 217 
 218         return new Data(size, size, builder);
 219     }
 220 
 221     public Data createDataItem(Constant... constants) {
 222         assert constants.length > 0;
 223         if (constants.length == 1) {
 224             return createSingleDataItem(constants[0]);
 225         } else {
 226             DataBuilder[] builders = new DataBuilder[constants.length];
 227             int size = 0;
 228             int alignment = 1;
 229             for (int i = 0; i < constants.length; i++) {
 230                 Data data = createSingleDataItem(constants[i]);
 231 
 232                 assert size % data.getAlignment() == 0 : "invalid alignment in packed constants";
 233                 alignment = DataSection.lcm(alignment, data.getAlignment());
 234 
 235                 builders[i] = data.getBuilder();
 236                 size += data.getSize();
 237             }
 238             DataBuilder ret = (buffer, patches) -> {
 239                 for (DataBuilder b : builders) {
 240                     b.emit(buffer, patches);
 241                 }
 242             };
 243             return new Data(alignment, size, ret);
 244         }
 245     }
 246 
 247     @Override
 248     public TargetDescription getTarget() {
 249         return target;
 250     }
 251 
 252     public String disassemble(InstalledCode code) {
 253         if (code.isValid()) {
 254             return runtime.getCompilerToVM().disassembleCodeBlob(code);
 255         }
 256         return null;
 257     }
 258 
 259     public SpeculationLog createSpeculationLog() {
 260         return new HotSpotSpeculationLog();
 261     }
 262 
 263     public long getMaxCallTargetOffset(long address) {
 264         return runtime.getCompilerToVM().getMaxCallTargetOffset(address);
 265     }
 266 
 267     public boolean shouldDebugNonSafepoints() {
 268         return runtime.getCompilerToVM().shouldDebugNonSafepoints();
 269     }
 270 
 271     /**
 272      * Notifies the VM of statistics for a completed compilation.
 273      *
 274      * @param id the identifier of the compilation
 275      * @param method the method compiled
 276      * @param osr specifies if the compilation was for on-stack-replacement
 277      * @param processedBytecodes the number of bytecodes processed during the compilation, including
 278      *            the bytecodes of all inlined methods
 279      * @param time the amount time spent compiling {@code method}
 280      * @param timeUnitsPerSecond the granularity of the units for the {@code time} value
 281      * @param installedCode the nmethod installed as a result of the compilation
 282      */
 283     public void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethod method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond, InstalledCode installedCode) {
 284         runtime.getCompilerToVM().notifyCompilationStatistics(id, (HotSpotResolvedJavaMethodImpl) method, osr, processedBytecodes, time, timeUnitsPerSecond, installedCode);
 285     }
 286 
 287     /**
 288      * Resets all compilation statistics.
 289      */
 290     public void resetCompilationStatistics() {
 291         runtime.getCompilerToVM().resetCompilationStatistics();
 292     }
 293 }