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 */ 013package org.jikesrvm.osr; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.adaptive.controller.ControllerMemory; 017import org.jikesrvm.adaptive.controller.ControllerPlan; 018import org.jikesrvm.classloader.ExceptionHandlerMap; 019import org.jikesrvm.classloader.NormalMethod; 020import org.jikesrvm.compilers.common.CompiledMethod; 021import org.jikesrvm.compilers.common.RuntimeCompiler; 022import org.jikesrvm.compilers.opt.OptOptions; 023import org.jikesrvm.compilers.opt.driver.CompilationPlan; 024import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 025import org.jikesrvm.util.Services; 026 027/** 028 * SpecialCompiler is a wrapper for compiling specialized byte code. 029 * It accepts an instance of ExecutionState, generates the specialized 030 * byte code, and compiles it to machine code instructions. 031 */ 032public class SpecialCompiler { 033 034 /** 035 * recompile an execution state 036 * @param state a list of execution states 037 * @param invalidate Is this an invalidation? 038 * @return the compiled method for the root state 039 */ 040 public static CompiledMethod recompileState(ExecutionState state, boolean invalidate) { 041 042 // compile from callee to caller 043 CompiledMethod newCM = null; 044 do { 045 if (!invalidate) { 046 newCM = optCompile(state); 047 } else { 048 newCM = baselineCompile(state); 049 } 050 051 if (VM.TraceOnStackReplacement) { 052 VM.sysWriteln("new CMID 0x" + Integer.toHexString(newCM.getId()) + "(" + newCM.getId() + ") for " + newCM.getMethod()); 053 } 054 055 if (state.callerState == null) break; 056 state = state.callerState; 057 // set callee_cmid of the caller 058 state.callee_cmid = newCM.getId(); 059 060 } while (true); 061 062 return newCM; 063 } 064 065 /** 066 * Compiles the method with the baseline compiler. 067 * <ol> 068 * <li>generate prologue (PSEUDO_bytecode) from the state. 069 * <li>make up new byte code with prologue. 070 * <li>set method's bytecode to the specilizaed byte code. 071 * <li>call BaselineCompilerImpl.compile, 072 * the 'compile' method is customized to process pseudo instructions, 073 * and it will reset the byte code to the original one, and adjust 074 * the map from bytecode to the generated machine code. then the 075 * reference map can be generated corrected relying on the original 076 * bytecode. 077 * </ol> 078 * <p> 079 * NOTE: this is different from optCompile which resets the 080 * bytecode after compilation. I believe this minimizes the 081 * work to change both compilers. 082 * @param state the execution state for the compilation 083 * @return the compiled method produced by the baseline compiler 084 */ 085 public static CompiledMethod baselineCompile(ExecutionState state) { 086 NormalMethod method = state.getMethod(); 087 088 if (VM.TraceOnStackReplacement) { 089 VM.sysWriteln("BASE : starts compiling " + method); 090 } 091 092 /* generate prologue bytes */ 093 byte[] prologue = state.generatePrologue(); 094 095 if (VM.TraceOnStackReplacement) { 096 VM.sysWriteln("prologue length " + prologue.length); 097 } 098 099 // the compiler will call setForOsrSpecialization after generating the reference map 100 /* set a flag for specialization, compiler will see it, and 101 * know how to do it properly. 102 */ 103 method.setForOsrSpecialization(prologue, state.getMaxStackHeight()); 104 105 /* for baseline compilation, we do not adjust the exception table and line table 106 * because the compiler will generate maps after compilation. 107 * Any necessary adjustment should be made during the compilation 108 */ 109 CompiledMethod newCompiledMethod; 110 if (VM.BuildForIA32) { 111 newCompiledMethod = org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.compile(method); 112 } else { 113 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 114 newCompiledMethod = org.jikesrvm.compilers.baseline.ppc.BaselineCompilerImpl.compile(method); 115 } 116 117 // compiled method was already set by BaselineCompilerImpl.compile 118 // the call here does nothing 119// method.finalizeOsrSpecialization(); 120 121 // mark the method is a specialized one 122 newCompiledMethod.setSpecialForOSR(); 123 124 if (VM.TraceOnStackReplacement) { 125// ((BaselineCompiledMethod)newCompiledMethod).printCodeMapEntries(); 126 VM.sysWriteln("BASE : done, CMID 0x" + 127 Integer.toHexString(newCompiledMethod.getId()) + 128 "(" + newCompiledMethod.getId() + ") JTOC offset " + 129 Services.addressAsHexString(newCompiledMethod.getOsrJTOCoffset().toWord().toAddress())); 130 } 131 132 return newCompiledMethod; 133 } 134 135 /** 136 * <ol> 137 * <li>generate prologue PSEUDO_bytecode from the state. 138 * <li>make new bytecodes with prologue. 139 * <li>set method's bytecode to specialized one. 140 * <li>adjust exception map, line number map. 141 * <li>compile the method. 142 * <li>restore bytecode, exception, linenumber map to the original one. 143 * </ol> 144 * 145 * @param state the execution state for the compilation 146 * @return the compiled method produced by the optimizing compiler 147 */ 148 public static CompiledMethod optCompile(ExecutionState state) { 149 150 NormalMethod method = state.getMethod(); 151 if (VM.TraceOnStackReplacement) { 152 VM.sysWriteln("OPT : starts compiling " + method); 153 } 154 155 ControllerPlan latestPlan = ControllerMemory.findLatestPlan(method); 156 157 OptOptions _options = null; 158 if (latestPlan != null) { 159 _options = latestPlan.getCompPlan().options.dup(); 160 } else { 161 // no previous compilation plan, a long run loop promoted from baseline. 162 // this only happens when testing, not in real code 163 _options = new OptOptions(); 164 _options.setOptLevel(0); 165 } 166 // disable OSR points in specialized method 167 _options.OSR_GUARDED_INLINING = false; 168 169 CompilationPlan compPlan = 170 new CompilationPlan(method, 171 (OptimizationPlanElement[]) RuntimeCompiler.optimizationPlan, 172 null, 173 _options); 174 175 // it is also necessary to recompile the current method 176 // without OSR. 177 178 /* generate prologue bytes */ 179 byte[] prologue = state.generatePrologue(); 180 int prosize = prologue.length; 181 182 method.setForOsrSpecialization(prologue, state.getMaxStackHeight()); 183 184 int[] oldStartPCs = null; 185 int[] oldEndPCs = null; 186 int[] oldHandlerPCs = null; 187 188 /* adjust exception table. */ 189 { 190 // if (VM.TraceOnStackReplacement) { VM.sysWrite("OPT adjust exception table.\n"); } 191 192 ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap(); 193 194 if (exceptionHandlerMap != null) { 195 196 oldStartPCs = exceptionHandlerMap.getStartPC(); 197 oldEndPCs = exceptionHandlerMap.getEndPC(); 198 oldHandlerPCs = exceptionHandlerMap.getHandlerPC(); 199 200 int n = oldStartPCs.length; 201 202 int[] newStartPCs = new int[n]; 203 System.arraycopy(oldStartPCs, 0, newStartPCs, 0, n); 204 exceptionHandlerMap.setStartPC(newStartPCs); 205 206 int[] newEndPCs = new int[n]; 207 System.arraycopy(oldEndPCs, 0, newEndPCs, 0, n); 208 exceptionHandlerMap.setEndPC(newEndPCs); 209 210 int[] newHandlerPCs = new int[n]; 211 System.arraycopy(oldHandlerPCs, 0, newHandlerPCs, 0, n); 212 exceptionHandlerMap.setHandlerPC(newHandlerPCs); 213 214 for (int i = 0; i < n; i++) { 215 newStartPCs[i] += prosize; 216 newEndPCs[i] += prosize; 217 newHandlerPCs[i] += prosize; 218 } 219 } 220 } 221 222 CompiledMethod newCompiledMethod = RuntimeCompiler.recompileWithOptOnStackSpecialization(compPlan); 223 224 // restore original bytecode, exception table, and line number table 225 method.finalizeOsrSpecialization(); 226 227 { 228 ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap(); 229 230 if (exceptionHandlerMap != null) { 231 exceptionHandlerMap.setStartPC(oldStartPCs); 232 exceptionHandlerMap.setEndPC(oldEndPCs); 233 exceptionHandlerMap.setHandlerPC(oldHandlerPCs); 234 } 235 } 236 237 // compilation failed because compilation is in progress, 238 // reverse back to the baseline 239 if (newCompiledMethod == null) { 240 if (VM.TraceOnStackReplacement) { 241 VM.sysWriteln("OPT : fialed, because compilation in progress, " + "fall back to baseline"); 242 } 243 return baselineCompile(state); 244 } 245 246 // mark the method is a specialized one 247 newCompiledMethod.setSpecialForOSR(); 248 249 if (VM.TraceOnStackReplacement) VM.sysWriteln("OPT : done\n"); 250 251 return newCompiledMethod; 252 } 253}