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