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 }