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.osr; 014 015 import org.jikesrvm.ArchitectureSpecific.BaselineCompilerImpl; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.adaptive.controller.ControllerMemory; 018 import org.jikesrvm.adaptive.controller.ControllerPlan; 019 import org.jikesrvm.classloader.ExceptionHandlerMap; 020 import org.jikesrvm.classloader.NormalMethod; 021 import org.jikesrvm.compilers.common.CompiledMethod; 022 import org.jikesrvm.compilers.common.RuntimeCompiler; 023 import org.jikesrvm.compilers.opt.OptOptions; 024 import org.jikesrvm.compilers.opt.driver.CompilationPlan; 025 import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 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 */ 032 public 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 083 * @return a BaselineCompiledMethod 084 */ 085 public static CompiledMethod baselineCompile(ExecutionState state) { 086 NormalMethod method = state.getMethod(); 087 088 if (VM.TraceOnStackReplacement) {VM.sysWriteln("BASE : starts compiling " + method); } 089 090 /* generate prologue bytes */ 091 byte[] prologue = state.generatePrologue(); 092 093 if (VM.TraceOnStackReplacement) {VM.sysWriteln("prologue length " + prologue.length);} 094 095 // the compiler will call setForOsrSpecialization after generating the reference map 096 /* set a flag for specialization, compiler will see it, and 097 * know how to do it properly. 098 */ 099 method.setForOsrSpecialization(prologue, state.getMaxStackHeight()); 100 101 /* for baseline compilation, we do not adjust the exception table and line table 102 * because the compiler will generate maps after compilation. 103 * Any necessary adjustment should be made during the compilation 104 */ 105 CompiledMethod newCompiledMethod = BaselineCompilerImpl.compile(method); 106 107 // compiled method was already set by BaselineCompilerImpl.compile 108 // the call here does nothing 109 // method.finalizeOsrSpecialization(); 110 111 // mark the method is a specialized one 112 newCompiledMethod.setSpecialForOSR(); 113 114 if (VM.TraceOnStackReplacement) { 115 // ((BaselineCompiledMethod)newCompiledMethod).printCodeMapEntries(); 116 VM.sysWriteln("BASE : done, CMID 0x" + 117 Integer.toHexString(newCompiledMethod.getId()) + 118 "(" + newCompiledMethod.getId() + ") JTOC offset " + 119 VM.addressAsHexString(newCompiledMethod.getOsrJTOCoffset().toWord().toAddress())); 120 } 121 122 return newCompiledMethod; 123 } 124 125 /** 126 * <ol> 127 * <li>generate prologue PSEUDO_bytecode from the state. 128 * <li>make new bytecodes with prologue. 129 * <li>set method's bytecode to specialized one. 130 * <li>adjust exception map, line number map. 131 * <li>compile the method. 132 * <li>restore bytecode, exception, linenumber map to the original one. 133 * </ol> 134 */ 135 public static CompiledMethod optCompile(ExecutionState state) { 136 137 NormalMethod method = state.getMethod(); 138 if (VM.TraceOnStackReplacement) { VM.sysWriteln("OPT : starts compiling " + method); } 139 140 ControllerPlan latestPlan = ControllerMemory.findLatestPlan(method); 141 142 OptOptions _options = null; 143 if (latestPlan != null) { 144 _options = latestPlan.getCompPlan().options.dup(); 145 } else { 146 // no previous compilation plan, a long run loop promoted from baseline. 147 // this only happens when testing, not in real code 148 _options = new OptOptions(); 149 _options.setOptLevel(0); 150 } 151 // disable OSR points in specialized method 152 _options.OSR_GUARDED_INLINING = false; 153 154 CompilationPlan compPlan = 155 new CompilationPlan(method, 156 (OptimizationPlanElement[]) RuntimeCompiler.optimizationPlan, 157 null, 158 _options); 159 160 // it is also necessary to recompile the current method 161 // without OSR. 162 163 /* generate prologue bytes */ 164 byte[] prologue = state.generatePrologue(); 165 int prosize = prologue.length; 166 167 method.setForOsrSpecialization(prologue, state.getMaxStackHeight()); 168 169 int[] oldStartPCs = null; 170 int[] oldEndPCs = null; 171 int[] oldHandlerPCs = null; 172 173 /* adjust exception table. */ 174 { 175 // if (VM.TraceOnStackReplacement) { VM.sysWrite("OPT adjust exception table.\n"); } 176 177 ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap(); 178 179 if (exceptionHandlerMap != null) { 180 181 oldStartPCs = exceptionHandlerMap.getStartPC(); 182 oldEndPCs = exceptionHandlerMap.getEndPC(); 183 oldHandlerPCs = exceptionHandlerMap.getHandlerPC(); 184 185 int n = oldStartPCs.length; 186 187 int[] newStartPCs = new int[n]; 188 System.arraycopy(oldStartPCs, 0, newStartPCs, 0, n); 189 exceptionHandlerMap.setStartPC(newStartPCs); 190 191 int[] newEndPCs = new int[n]; 192 System.arraycopy(oldEndPCs, 0, newEndPCs, 0, n); 193 exceptionHandlerMap.setEndPC(newEndPCs); 194 195 int[] newHandlerPCs = new int[n]; 196 System.arraycopy(oldHandlerPCs, 0, newHandlerPCs, 0, n); 197 exceptionHandlerMap.setHandlerPC(newHandlerPCs); 198 199 for (int i = 0; i < n; i++) { 200 newStartPCs[i] += prosize; 201 newEndPCs[i] += prosize; 202 newHandlerPCs[i] += prosize; 203 } 204 } 205 } 206 207 CompiledMethod newCompiledMethod = RuntimeCompiler.recompileWithOptOnStackSpecialization(compPlan); 208 209 // restore original bytecode, exception table, and line number table 210 method.finalizeOsrSpecialization(); 211 212 { 213 ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap(); 214 215 if (exceptionHandlerMap != null) { 216 exceptionHandlerMap.setStartPC(oldStartPCs); 217 exceptionHandlerMap.setEndPC(oldEndPCs); 218 exceptionHandlerMap.setHandlerPC(oldHandlerPCs); 219 } 220 } 221 222 // compilation failed because compilation is in progress, 223 // reverse back to the baseline 224 if (newCompiledMethod == null) { 225 if (VM.TraceOnStackReplacement) { 226 VM.sysWriteln("OPT : fialed, because compilation in progress, " + "fall back to baseline"); 227 } 228 return baselineCompile(state); 229 } 230 231 // mark the method is a specialized one 232 newCompiledMethod.setSpecialForOSR(); 233 234 if (VM.TraceOnStackReplacement) VM.sysWriteln("OPT : done\n"); 235 236 return newCompiledMethod; 237 } 238 }