001/* 002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot; 024 025import static jdk.internal.jvmci.common.UnsafeAccess.*; 026import static jdk.internal.jvmci.compiler.Compiler.*; 027 028import java.util.concurrent.*; 029 030import com.oracle.graal.debug.*; 031import com.oracle.graal.debug.Debug.Scope; 032import com.oracle.graal.debug.internal.*; 033 034import jdk.internal.jvmci.code.*; 035import jdk.internal.jvmci.compiler.Compiler; 036import jdk.internal.jvmci.hotspot.*; 037import jdk.internal.jvmci.hotspot.events.*; 038import jdk.internal.jvmci.hotspot.events.EventProvider.CompilationEvent; 039import jdk.internal.jvmci.hotspot.events.EventProvider.CompilerFailureEvent; 040import jdk.internal.jvmci.meta.*; 041import jdk.internal.jvmci.service.*; 042 043//JaCoCo Exclude 044 045public class CompilationTask { 046 047 private static final DebugMetric BAILOUTS = Debug.metric("Bailouts"); 048 049 private static final EventProvider eventProvider; 050 static { 051 EventProvider provider = Services.loadSingle(EventProvider.class, false); 052 if (provider == null) { 053 eventProvider = new EmptyEventProvider(); 054 } else { 055 eventProvider = provider; 056 } 057 } 058 private static final Compiler compiler = Services.loadSingle(Compiler.class, true); 059 060 private final HotSpotResolvedJavaMethod method; 061 private final int entryBCI; 062 private final int id; 063 064 /** 065 * Specifies whether the compilation result is installed as the 066 * {@linkplain HotSpotNmethod#isDefault() default} nmethod for the compiled method. 067 */ 068 private final boolean installAsDefault; 069 070 static class Lazy { 071 /** 072 * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the 073 * current compiler thread, e.g. total allocated bytes. 074 */ 075 static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean(); 076 } 077 078 /** 079 * The address of the JVMCIEnv associated with this compilation or 0L if no such object exists. 080 */ 081 private final long jvmciEnv; 082 083 public CompilationTask(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id, boolean installAsDefault) { 084 this.method = method; 085 this.entryBCI = entryBCI; 086 this.id = id; 087 this.jvmciEnv = jvmciEnv; 088 this.installAsDefault = installAsDefault; 089 } 090 091 public ResolvedJavaMethod getMethod() { 092 return method; 093 } 094 095 /** 096 * Returns the compilation id of this task. 097 * 098 * @return compile id 099 */ 100 public int getId() { 101 return id; 102 } 103 104 public int getEntryBCI() { 105 return entryBCI; 106 } 107 108 /** 109 * Time spent in compilation. 110 */ 111 private static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); 112 113 /** 114 * Meters the {@linkplain CompilationResult#getBytecodeSize() bytecodes} compiled. 115 */ 116 private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes"); 117 118 public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); 119 120 public void runCompilation() { 121 HotSpotVMConfig config = HotSpotJVMCIRuntime.runtime().getConfig(); 122 final long threadId = Thread.currentThread().getId(); 123 long startCompilationTime = System.nanoTime(); 124 HotSpotInstalledCode installedCode = null; 125 final boolean isOSR = entryBCI != Compiler.INVOCATION_ENTRY_BCI; 126 127 // Log a compilation event. 128 CompilationEvent compilationEvent = eventProvider.newCompilationEvent(); 129 130 // If there is already compiled code for this method on our level we simply return. 131 // JVMCI compiles are always at the highest compile level, even in non-tiered mode so we 132 // only need to check for that value. 133 if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { 134 return; 135 } 136 137 CompilationResult result = null; 138 try (DebugCloseable a = CompilationTime.start()) { 139 CompilationStatistics stats = CompilationStatistics.create(method, isOSR); 140 final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); 141 final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed(); 142 if (printCompilation) { 143 TTY.println(getMethodDescription() + "..."); 144 } 145 146 TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); 147 final long start; 148 final long allocatedBytesBefore; 149 if (printAfterCompilation || printCompilation) { 150 start = System.currentTimeMillis(); 151 allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L; 152 } else { 153 start = 0L; 154 allocatedBytesBefore = 0L; 155 } 156 157 try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { 158 // Begin the compilation event. 159 compilationEvent.begin(); 160 161 result = compiler.compile(method, entryBCI, mustRecordMethodInlining(config)); 162 163 result.setId(getId()); 164 } catch (Throwable e) { 165 throw Debug.handle(e); 166 } finally { 167 // End the compilation event. 168 compilationEvent.end(); 169 170 filter.remove(); 171 172 if (printAfterCompilation || printCompilation) { 173 final long stop = System.currentTimeMillis(); 174 final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; 175 final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId); 176 final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; 177 178 if (printAfterCompilation) { 179 TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes)); 180 } else if (printCompilation) { 181 TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dkB", id, "", "", "", stop - start, targetCodeSize, allocatedBytes)); 182 } 183 } 184 } 185 186 try (DebugCloseable b = CodeInstallationTime.start()) { 187 installedCode = (HotSpotInstalledCode) installMethod(result); 188 } 189 stats.finish(method, installedCode); 190 } catch (BailoutException bailout) { 191 BAILOUTS.increment(); 192 if (ExitVMOnBailout.getValue()) { 193 TTY.out.println(method.format("Bailout in %H.%n(%p)")); 194 bailout.printStackTrace(TTY.out); 195 System.exit(-1); 196 } else if (PrintBailout.getValue()) { 197 TTY.out.println(method.format("Bailout in %H.%n(%p)")); 198 bailout.printStackTrace(TTY.out); 199 } 200 } catch (Throwable t) { 201 if (PrintStackTraceOnException.getValue() || ExitVMOnException.getValue()) { 202 t.printStackTrace(TTY.out); 203 } 204 205 // Log a failure event. 206 CompilerFailureEvent event = eventProvider.newCompilerFailureEvent(); 207 if (event.shouldWrite()) { 208 event.setCompileId(getId()); 209 event.setMessage(t.getMessage()); 210 event.commit(); 211 } 212 213 if (ExitVMOnException.getValue()) { 214 System.exit(-1); 215 } 216 } finally { 217 int compiledBytecodes = 0; 218 int codeSize = 0; 219 if (result != null) { 220 compiledBytecodes = result.getBytecodeSize(); 221 } 222 if (installedCode != null) { 223 codeSize = installedCode.getSize(); 224 } 225 CompiledBytecodes.add(compiledBytecodes); 226 227 // Log a compilation event. 228 if (compilationEvent.shouldWrite()) { 229 compilationEvent.setMethod(method.format("%H.%n(%p)")); 230 compilationEvent.setCompileId(getId()); 231 compilationEvent.setCompileLevel(config.compilationLevelFullOptimization); 232 compilationEvent.setSucceeded(result != null && installedCode != null); 233 compilationEvent.setIsOsr(isOSR); 234 compilationEvent.setCodeSize(codeSize); 235 compilationEvent.setInlinedBytes(compiledBytecodes); 236 compilationEvent.commit(); 237 } 238 239 if (jvmciEnv != 0) { 240 long ctask = unsafe.getAddress(jvmciEnv + config.jvmciEnvTaskOffset); 241 assert ctask != 0L; 242 unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes); 243 } 244 long compilationTime = System.nanoTime() - startCompilationTime; 245 if ((config.ciTime || config.ciTimeEach) && installedCode != null) { 246 long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); 247 CompilerToVM c2vm = HotSpotJVMCIRuntime.runtime().getCompilerToVM(); 248 c2vm.notifyCompilationStatistics(id, method, entryBCI != Compiler.INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode); 249 } 250 } 251 } 252 253 /** 254 * Determines whether to disable method inlining recording for the method being compiled. 255 */ 256 private boolean mustRecordMethodInlining(HotSpotVMConfig config) { 257 if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) { 258 return true; 259 } 260 if (jvmciEnv == 0 || unsafe.getByte(jvmciEnv + config.jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) { 261 return true; 262 } 263 return false; 264 } 265 266 private String getMethodDescription() { 267 return String.format("%-6d JVMCI %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(), 268 entryBCI == Compiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "); 269 } 270 271 private InstalledCode installMethod(final CompilationResult compResult) { 272 final HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getCodeCache(); 273 InstalledCode installedCode = null; 274 try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) { 275 installedCode = codeCache.installMethod(method, compResult, jvmciEnv, installAsDefault); 276 } catch (Throwable e) { 277 throw Debug.handle(e); 278 } 279 return installedCode; 280 } 281 282 @Override 283 public String toString() { 284 return "Compilation[id=" + id + ", " + method.format("%H.%n(%p)") + (entryBCI == Compiler.INVOCATION_ENTRY_BCI ? "" : "@" + entryBCI) + "]"; 285 } 286 287 /** 288 * Compiles a method to machine code. 289 */ 290 public static void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { 291 // Ensure a debug configuration for this thread is initialized 292 if (Debug.isEnabled() && DebugScope.getConfig() == null) { 293 DebugEnvironment.initialize(TTY.out); 294 } 295 296 CompilationTask task = new CompilationTask(method, entryBCI, jvmciEnv, id, true); 297 try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig())) { 298 task.runCompilation(); 299 } 300 return; 301 } 302}