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.*;
  26 
  27 import java.lang.reflect.*;
  28 
  29 import jdk.vm.ci.code.*;
  30 import jdk.vm.ci.code.CompilationResult.*;
  31 import jdk.vm.ci.code.DataSection.*;
  32 import jdk.vm.ci.common.*;
  33 import jdk.vm.ci.meta.*;
  34 
  35 /**
  36  * HotSpot implementation of {@link CodeCacheProvider}.
  37  */
  38 public class HotSpotCodeCacheProvider implements CodeCacheProvider {
  39 
  40     protected final HotSpotJVMCIRuntimeProvider runtime;
  41     public final HotSpotVMConfig config;
  42     protected final TargetDescription target;
  43     protected final RegisterConfig regConfig;
  44 
  45     public HotSpotCodeCacheProvider(HotSpotJVMCIRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) {
  46         this.runtime = runtime;
  47         this.config = config;
  48         this.target = target;
  49         this.regConfig = regConfig;
  50     }
  51 
  52     @Override
  53     public String getMarkName(Mark mark) {
  54         int markId = (int) mark.id;
  55         Field[] fields = runtime.getConfig().getClass().getDeclaredFields();
  56         for (Field f : fields) {
  57             if (f.getName().startsWith("MARKID_")) {
  58                 f.setAccessible(true);
  59                 try {
  60                     if (f.getInt(runtime.getConfig()) == markId) {
  61                         return f.getName();
  62                     }
  63                 } catch (Exception e) {
  64                 }
  65             }
  66         }
  67         return CodeCacheProvider.super.getMarkName(mark);
  68     }
  69 
  70     /**
  71      * Decodes a call target to a mnemonic if possible.
  72      */
  73     @Override
  74     public String getTargetName(Call call) {
  75         Field[] fields = runtime.getConfig().getClass().getDeclaredFields();
  76         for (Field f : fields) {
  77             if (f.getName().endsWith("Stub")) {
  78                 f.setAccessible(true);
  79                 try {
  80                     Object address = f.get(runtime.getConfig());
  81                     if (address.equals(call.target)) {
  82                         return f.getName() + ":0x" + Long.toHexString((Long) address);
  83                     }
  84                 } catch (Exception e) {
  85                 }
  86             }
  87         }
  88         return CodeCacheProvider.super.getTargetName(call);
  89     }
  90 
  91     @Override
  92     public RegisterConfig getRegisterConfig() {
  93         return regConfig;
  94     }
  95 
  96     @Override
  97     public int getMinimumOutgoingSize() {
  98         return runtime.getConfig().runtimeCallStackSize;
  99     }
 100 
 101     public InstalledCode logOrDump(InstalledCode installedCode, CompilationResult compResult) {
 102         HotSpotJVMCIRuntime.runtime().notifyInstall(this, installedCode, compResult);
 103         return installedCode;
 104     }
 105 
 106     private InstalledCode installCode(CompilationResult compResult, HotSpotCompiledNmethod compiledCode, InstalledCode installedCode, SpeculationLog log) {
 107         int result = runtime.getCompilerToVM().installCode(target, compiledCode, installedCode, log);
 108         if (result != config.codeInstallResultOk) {
 109             String msg = compiledCode.getInstallationFailureMessage();
 110             String resultDesc = config.getCodeInstallResultDescription(result);
 111             if (msg != null) {
 112                 msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
 113             } else {
 114                 msg = String.format("Code installation failed: %s", resultDesc);
 115             }
 116             if (result == config.codeInstallResultDependenciesInvalid) {
 117                 throw new AssertionError(resultDesc + " " + msg);
 118             }
 119             throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg);
 120         }
 121         return logOrDump(installedCode, compResult);
 122     }
 123 
 124     public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv, boolean isDefault) {
 125         if (compResult.getId() == -1) {
 126             compResult.setId(method.allocateCompileId(compResult.getEntryBCI()));
 127         }
 128         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), isDefault);
 129         HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(method, compResult, jvmciEnv);
 130         return installCode(compResult, compiledCode, installedCode, method.getSpeculationLog());
 131     }
 132 
 133     @Override
 134     public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog log, InstalledCode predefinedInstalledCode) {
 135         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
 136         if (compResult.getId() == -1) {
 137             compResult.setId(hotspotMethod.allocateCompileId(compResult.getEntryBCI()));
 138         }
 139         InstalledCode installedCode = predefinedInstalledCode;
 140         if (installedCode == null) {
 141             HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false);
 142             installedCode = code;
 143         }
 144         HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult);
 145         return installCode(compResult, compiledCode, installedCode, log);
 146     }
 147 
 148     @Override
 149     public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) {
 150         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
 151         return installMethod(hotspotMethod, compResult, 0L, true);
 152     }
 153 
 154     public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) {
 155         HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method;
 156         if (compResult.getId() == -1) {
 157             compResult.setId(javaMethod.allocateCompileId(compResult.getEntryBCI()));
 158         }
 159         HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true);
 160         HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult);
 161         CompilerToVM vm = runtime.getCompilerToVM();
 162         int result = vm.installCode(target, compiled, code, null);
 163         if (result != runtime.getConfig().codeInstallResultOk) {
 164             return null;
 165         }
 166         return code;
 167     }
 168 
 169     public boolean needsDataPatch(JavaConstant constant) {
 170         return constant instanceof HotSpotMetaspaceConstant;
 171     }
 172 
 173     private Data createSingleDataItem(Constant constant) {
 174         int size;
 175         DataBuilder builder;
 176         if (constant instanceof VMConstant) {
 177             VMConstant vmConstant = (VMConstant) constant;
 178             boolean compressed;
 179             long raw;
 180             if (constant instanceof HotSpotObjectConstant) {
 181                 HotSpotObjectConstant c = (HotSpotObjectConstant) vmConstant;
 182                 compressed = c.isCompressed();
 183                 raw = 0xDEADDEADDEADDEADL;
 184             } else if (constant instanceof HotSpotMetaspaceConstant) {
 185                 HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) constant;
 186                 compressed = meta.isCompressed();
 187                 raw = meta.rawValue();
 188             } else {
 189                 throw new JVMCIError(String.valueOf(constant));
 190             }
 191 
 192             size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind);
 193             if (size == 4) {
 194                 builder = (buffer, patch) -> {
 195                     patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
 196                     buffer.putInt((int) raw);
 197                 };
 198             } else {
 199                 assert size == 8;
 200                 builder = (buffer, patch) -> {
 201                     patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
 202                     buffer.putLong(raw);
 203                 };
 204             }
 205         } else if (JavaConstant.isNull(constant)) {
 206             boolean compressed = COMPRESSED_NULL.equals(constant);
 207             size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind);
 208             builder = DataBuilder.zero(size);
 209         } else if (constant instanceof SerializableConstant) {
 210             SerializableConstant s = (SerializableConstant) constant;
 211             size = s.getSerializedSize();
 212             builder = DataBuilder.serializable(s);
 213         } else {
 214             throw new JVMCIError(String.valueOf(constant));
 215         }
 216 
 217         return new Data(size, size, builder);
 218     }
 219 
 220     public Data createDataItem(Constant... constants) {
 221         assert constants.length > 0;
 222         if (constants.length == 1) {
 223             return createSingleDataItem(constants[0]);
 224         } else {
 225             DataBuilder[] builders = new DataBuilder[constants.length];
 226             int size = 0;
 227             int alignment = 1;
 228             for (int i = 0; i < constants.length; i++) {
 229                 Data data = createSingleDataItem(constants[i]);
 230 
 231                 assert size % data.getAlignment() == 0 : "invalid alignment in packed constants";
 232                 alignment = DataSection.lcm(alignment, data.getAlignment());
 233 
 234                 builders[i] = data.getBuilder();
 235                 size += data.getSize();
 236             }
 237             DataBuilder ret = (buffer, patches) -> {
 238                 for (DataBuilder b : builders) {
 239                     b.emit(buffer, patches);
 240                 }
 241             };
 242             return new Data(alignment, size, ret);
 243         }
 244     }
 245 
 246     @Override
 247     public TargetDescription getTarget() {
 248         return target;
 249     }
 250 
 251     public String disassemble(InstalledCode code) {
 252         if (code.isValid()) {
 253             long codeBlob = code.getAddress();
 254             return runtime.getCompilerToVM().disassembleCodeBlob(codeBlob);
 255         }
 256         return null;
 257     }
 258 
 259     public SpeculationLog createSpeculationLog() {
 260         return new HotSpotSpeculationLog();
 261     }
 262 }