001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.compilers.baseline; 014 015 import org.jikesrvm.ArchitectureSpecific.Assembler; 016 import org.jikesrvm.ArchitectureSpecific.CodeArray; 017 import org.jikesrvm.ArchitectureSpecific.BaselineCompilerImpl; 018 import org.jikesrvm.ArchitectureSpecific.MachineCode; 019 import org.jikesrvm.VM; 020 import org.jikesrvm.classloader.NormalMethod; 021 import org.jikesrvm.compilers.common.CompiledMethod; 022 import org.jikesrvm.compilers.common.CompiledMethods; 023 import org.jikesrvm.osr.BytecodeTraverser; 024 import org.jikesrvm.runtime.Time; 025 import org.vmmagic.unboxed.Offset; 026 027 /** 028 * Baseline compiler - platform independent code. 029 * Platform dependent versions extend this class and define 030 * the host of abstract methods defined by TemplateCompilerFramework to complete 031 * the implementation of a baseline compiler for a particular target, 032 */ 033 public abstract class BaselineCompiler extends TemplateCompilerFramework { 034 035 private static long gcMapNanos; 036 private static long osrSetupNanos; 037 private static long codeGenNanos; 038 private static long encodingNanos; 039 040 /** 041 * Options used during base compiler execution 042 */ 043 public static BaselineOptions options; 044 045 /** 046 * Next edge counter entry to allocate 047 */ 048 protected int edgeCounterIdx; 049 050 protected final Offset getEdgeCounterOffset() { 051 return Offset.fromIntZeroExtend(method.getId() << LOG_BYTES_IN_ADDRESS); 052 } 053 054 protected final int getEdgeCounterIndex() { 055 return method.getId(); 056 } 057 058 /** 059 * The types that locals can take. 060 * There are two types of locals. First the parameters of the method, they only have one type 061 * Second, the other locals, numbers get reused when stack shrinks and grows again. 062 * Therefore, these can have more than one type assigned. 063 * The compiler can use this information to assign registers to locals 064 * See the BaselineCompilerImpl constructor. 065 */ 066 protected final byte[] localTypes; 067 068 /** 069 * Construct a BaselineCompilerImpl 070 */ 071 protected BaselineCompiler(BaselineCompiledMethod cm) { 072 super(cm); 073 shouldPrint = 074 (!VM.runningTool && 075 (options.PRINT_MACHINECODE) && 076 (!options.hasMETHOD_TO_PRINT() || options.fuzzyMatchMETHOD_TO_PRINT(method.toString()))); 077 if (!VM.runningTool && options.PRINT_METHOD) printMethodMessage(); 078 if (shouldPrint && VM.runningVM && !fullyBootedVM) { 079 shouldPrint = false; 080 if (options.PRINT_METHOD) { 081 VM.sysWriteln("\ttoo early in VM.boot() to print machine code"); 082 } 083 } 084 asm = new Assembler(bcodes.length(), shouldPrint, (BaselineCompilerImpl) this); 085 localTypes = new byte[method.getLocalWords()]; 086 } 087 088 /** 089 * Clear out crud from bootimage writing 090 */ 091 public static void initOptions() { 092 options = new BaselineOptions(); 093 } 094 095 /** 096 * Now that VM is fully booted, enable options 097 * such as PRINT_MACHINE_CODE that require a fully booted VM. 098 */ 099 public static void fullyBootedVM() { 100 // If the user has requested machine code dumps, then force a test 101 // of method to print option so extra classes needed to process 102 // matching will be loaded and compiled upfront. Thus avoiding getting 103 // stuck looping by just asking if we have a match in the middle of 104 // compilation. Pick an obscure string for the check. 105 if (options.hasMETHOD_TO_PRINT() && options.fuzzyMatchMETHOD_TO_PRINT("???")) { 106 VM.sysWrite("??? is not a sensible string to specify for method name"); 107 } 108 fullyBootedVM = true; 109 } 110 111 /** 112 * Process a command line argument 113 * @param prefix 114 * @param arg Command line argument with prefix stripped off 115 */ 116 public static void processCommandLineArg(String prefix, String arg) { 117 if (!options.processAsOption(prefix, arg)) { 118 VM.sysWrite("BaselineCompiler: Unrecognized argument \"" + arg + "\"\n"); 119 VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 120 } 121 } 122 123 /** 124 * Generate a report of time spent in various phases of the baseline compiler. 125 * <p> NB: This method may be called in a context where class loading and/or 126 * GC cannot be allowed. Therefore we must use primitive sysWrites for output and avoid string 127 * appends and other allocations. 128 * <p> 129 * FIXME should this method be uninterruptible? 130 * 131 * @param explain Should an explanation of the metrics be generated? 132 */ 133 public static void generateBaselineCompilerSubsystemReport(boolean explain) { 134 if (!VM.MeasureCompilationPhases) return; 135 136 VM.sysWriteln("\n\t\tBaseline Compiler SubSystem"); 137 VM.sysWriteln("\tPhase\t\t\t Time"); 138 VM.sysWriteln("\t\t\t\t(ms) (%ofTotal)"); 139 140 double gcMapTime = Time.nanosToMillis(gcMapNanos); 141 double osrSetupTime = Time.nanosToMillis(osrSetupNanos); 142 double codeGenTime = Time.nanosToMillis(codeGenNanos); 143 double encodingTime = Time.nanosToMillis(encodingNanos); 144 double total = gcMapTime + osrSetupTime + codeGenTime + encodingTime; 145 146 VM.sysWrite("\tCompute GC Maps\t\t", gcMapTime); 147 VM.sysWriteln("\t", 100 * gcMapTime / total); 148 149 if (osrSetupTime > 0) { 150 VM.sysWrite("\tOSR setup \t\t", osrSetupTime); 151 VM.sysWriteln("\t", 100 * osrSetupTime / total); 152 } 153 154 VM.sysWrite("\tCode generation\t\t", codeGenTime); 155 VM.sysWriteln("\t", 100 * codeGenTime / total); 156 157 VM.sysWrite("\tEncode GC/MC maps\t", encodingTime); 158 VM.sysWriteln("\t", 100 * encodingTime / total); 159 160 VM.sysWriteln("\tTOTAL\t\t\t", total); 161 } 162 163 /** 164 * Compile the given method with the baseline compiler. 165 * 166 * @param method the NormalMethod to compile. 167 * @return the generated CompiledMethod for said NormalMethod. 168 */ 169 public static CompiledMethod compile(NormalMethod method) { 170 if (VM.VerifyAssertions) VM._assert(!method.getDeclaringClass().hasSaveVolatileAnnotation(), "Baseline compiler doesn't implement SaveVolatile"); 171 172 BaselineCompiledMethod cm = 173 (BaselineCompiledMethod) CompiledMethods.createCompiledMethod(method, CompiledMethod.BASELINE); 174 cm.compile(); 175 return cm; 176 } 177 178 protected abstract void initializeCompiler(); 179 180 /** 181 * Top level driver for baseline compilation of a method. 182 */ 183 protected void compile() { 184 if (shouldPrint) printStartHeader(method); 185 186 // Phase 1: GC map computation 187 long start = 0; 188 ReferenceMaps refMaps; 189 try { 190 if (VM.MeasureCompilationPhases) { 191 start = Time.nanoTime(); 192 } 193 refMaps = new ReferenceMaps((BaselineCompiledMethod) compiledMethod, stackHeights, localTypes); 194 } finally { 195 if (VM.MeasureCompilationPhases) { 196 long end = Time.nanoTime(); 197 gcMapNanos += end - start; 198 } 199 } 200 201 /* reference map and stackheights were computed using original bytecodes 202 * and possibly new operand words 203 * recompute the stack height, but keep the operand words of the code 204 * generation consistent with reference map 205 * TODO: revisit this code as part of OSR redesign 206 */ 207 // Phase 2: OSR setup\ 208 boolean edge_counters = options.PROFILE_EDGE_COUNTERS; 209 try { 210 if (VM.MeasureCompilationPhases) { 211 start = Time.nanoTime(); 212 } 213 if (VM.BuildForAdaptiveSystem && method.isForOsrSpecialization()) { 214 options.PROFILE_EDGE_COUNTERS = false; 215 // we already allocated enough space for stackHeights, shift it back first 216 System.arraycopy(stackHeights, 217 0, 218 stackHeights, 219 method.getOsrPrologueLength(), 220 method.getBytecodeLength()); // NB: getBytecodeLength returns back the length of original bytecodes 221 222 // compute stack height for prologue 223 new BytecodeTraverser().prologueStackHeights(method, method.getOsrPrologue(), stackHeights); 224 } 225 } finally { 226 if (VM.MeasureCompilationPhases) { 227 long end = Time.nanoTime(); 228 osrSetupNanos += end - start; 229 } 230 } 231 232 // Phase 3: Code generation 233 int[] bcMap; 234 MachineCode machineCode; 235 CodeArray instructions; 236 try { 237 if (VM.MeasureCompilationPhases) { 238 start = Time.nanoTime(); 239 } 240 241 // determine if we are going to insert edge counters for this method 242 if (options.PROFILE_EDGE_COUNTERS && 243 !method.getDeclaringClass().hasBridgeFromNativeAnnotation() && 244 (method.hasCondBranch() || method.hasSwitch())) { 245 ((BaselineCompiledMethod) compiledMethod).setHasCounterArray(); // yes, we will inject counters for this method. 246 } 247 248 //do platform specific tasks before generating code; 249 initializeCompiler(); 250 251 machineCode = genCode(); 252 instructions = machineCode.getInstructions(); 253 bcMap = machineCode.getBytecodeMap(); 254 } finally { 255 if (VM.MeasureCompilationPhases) { 256 long end = Time.nanoTime(); 257 codeGenNanos += end - start; 258 } 259 } 260 261 /* adjust machine code map, and restore original bytecode 262 * for building reference map later. 263 * TODO: revisit this code as part of OSR redesign 264 */ 265 // Phase 4: OSR part 2 266 try { 267 if (VM.MeasureCompilationPhases) { 268 start = Time.nanoTime(); 269 } 270 if (VM.BuildForAdaptiveSystem && method.isForOsrSpecialization()) { 271 int[] newmap = new int[bcMap.length - method.getOsrPrologueLength()]; 272 System.arraycopy(bcMap, method.getOsrPrologueLength(), newmap, 0, newmap.length); 273 machineCode.setBytecodeMap(newmap); 274 bcMap = newmap; 275 // switch back to original state 276 method.finalizeOsrSpecialization(); 277 // restore options 278 options.PROFILE_EDGE_COUNTERS = edge_counters; 279 } 280 } finally { 281 if (VM.MeasureCompilationPhases) { 282 long end = Time.nanoTime(); 283 osrSetupNanos += end - start; 284 } 285 } 286 287 // Phase 5: Encode machine code maps 288 try { 289 if (VM.MeasureCompilationPhases) { 290 start = Time.nanoTime(); 291 } 292 if (method.isSynchronized()) { 293 ((BaselineCompiledMethod) compiledMethod).setLockAcquisitionOffset(lockOffset); 294 } 295 ((BaselineCompiledMethod) compiledMethod).encodeMappingInfo(refMaps, bcMap); 296 compiledMethod.compileComplete(instructions); 297 if (edgeCounterIdx > 0) { 298 EdgeCounts.allocateCounters(method, edgeCounterIdx); 299 } 300 if (shouldPrint) { 301 ((BaselineCompiledMethod) compiledMethod).printExceptionTable(); 302 printEndHeader(method); 303 } 304 } finally { 305 if (VM.MeasureCompilationPhases) { 306 long end = Time.nanoTime(); 307 encodingNanos += end - start; 308 } 309 } 310 } 311 312 @Override 313 protected String getCompilerName() { 314 return "baseline"; 315 } 316 }