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.opt.bc2ir; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.OSR_BARRIER_opcode; 016 017 import java.util.Enumeration; 018 import java.util.LinkedList; 019 020 import org.jikesrvm.VM; 021 import org.jikesrvm.classloader.NormalMethod; 022 import org.jikesrvm.compilers.opt.OptOptions; 023 import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations; 024 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 025 import org.jikesrvm.compilers.opt.ir.BasicBlock; 026 import org.jikesrvm.compilers.opt.ir.IR; 027 import org.jikesrvm.compilers.opt.ir.Instruction; 028 import org.jikesrvm.compilers.opt.ir.OsrBarrier; 029 import org.jikesrvm.compilers.opt.ir.OsrPoint; 030 import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand; 031 import org.jikesrvm.compilers.opt.ir.operand.Operand; 032 import org.jikesrvm.compilers.opt.ir.operand.OsrTypeInfoOperand; 033 034 /** 035 * A phase in the OPT compiler for construction OsrPoint instructions 036 * after inlining. 037 */ 038 public class OsrPointConstructor extends CompilerPhase { 039 040 @Override 041 public final boolean shouldPerform(OptOptions options) { 042 return VM.runningVM && options.OSR_GUARDED_INLINING; 043 } 044 045 /** 046 * Return this instance of this phase. This phase contains no 047 * per-compilation instance fields. 048 * @param ir not used 049 * @return this 050 */ 051 @Override 052 public CompilerPhase newExecution(IR ir) { 053 return this; 054 } 055 056 @Override 057 public final String getName() { 058 return "OsrPointConstructor"; 059 } 060 061 /** 062 * Need to run branch optimizations after 063 */ 064 private final BranchOptimizations branchOpts; 065 066 /** 067 * Constructor 068 */ 069 public OsrPointConstructor() { 070 branchOpts = new BranchOptimizations(-1, false, false); 071 } 072 073 /** 074 * Goes through each instruction, reconstruct OsrPoint instructions. 075 */ 076 @Override 077 public void perform(IR ir) { 078 // 1. collecting OsrPoint instructions 079 LinkedList<Instruction> osrs = collectOsrPoints(ir); 080 081 // new IRPrinter("before renovating osrs").perform(ir); 082 083 // 2. trace OsrBarrier for each OsrPoint, and rebuild OsrPoint 084 renovateOsrPoints(osrs, ir); 085 086 // new IRPrinter("before removing barriers").perform(ir); 087 088 // 3. remove OsrBarriers 089 removeOsrBarriers(ir); 090 091 // new IRPrinter("after removing barriers").perform(ir); 092 093 // 4. reconstruct CFG, cut off pieces after OsrPoint. 094 fixupCFGForOsr(osrs, ir); 095 /* 096 if (VM.TraceOnStackReplacement && (0 != osrs.size())) { 097 new IRPrinter("After OsrPointConstructor").perform(ir); 098 } 099 */ 100 /* 101 if (VM.TraceOnStackReplacement && (0 != osrs.size())) { 102 verifyNoOsrBarriers(ir); 103 } 104 */ 105 branchOpts.perform(ir); 106 } 107 108 /** Iterates instructions, build a list of OsrPoint instructions. */ 109 private LinkedList<Instruction> collectOsrPoints(IR ir) { 110 LinkedList<Instruction> osrs = new LinkedList<Instruction>(); 111 112 Enumeration<Instruction> instenum = ir.forwardInstrEnumerator(); 113 while (instenum.hasMoreElements()) { 114 Instruction inst = instenum.nextElement(); 115 116 if (OsrPoint.conforms(inst)) { 117 osrs.add(inst); 118 } 119 } 120 121 return osrs; 122 } 123 124 /** 125 * For each OsrPoint instruction, traces its OsrBarriers created by 126 * inlining. rebuild OsrPoint instruction to hold all necessary 127 * information to recover from inlined activation. 128 */ 129 private void renovateOsrPoints(LinkedList<Instruction> osrs, IR ir) { 130 131 for (int osrIdx = 0, osrSize = osrs.size(); osrIdx < osrSize; osrIdx++) { 132 Instruction osr = osrs.get(osrIdx); 133 LinkedList<Instruction> barriers = new LinkedList<Instruction>(); 134 135 // Step 1: collect barriers put before inlined method 136 // in the order of from inner to outer 137 { 138 Instruction bar = (Instruction) osr.scratchObject; 139 140 if (osr.position == null) osr.position = bar.position; 141 142 adjustBCIndex(osr); 143 144 while (bar != null) { 145 146 barriers.add(bar); 147 148 // verify each barrier is clean 149 if (VM.VerifyAssertions) { 150 if (!isBarrierClean(bar)) { 151 VM.sysWriteln("Barrier " + bar + " is not clean!"); 152 } 153 VM._assert(isBarrierClean(bar)); 154 } 155 156 Instruction callsite = bar.position.getCallSite(); 157 if (callsite != null) { 158 bar = (Instruction) callsite.scratchObject; 159 160 if (bar == null) { 161 VM.sysWrite("call site :" + callsite); 162 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 163 } 164 165 adjustBCIndex(bar); 166 } else { 167 bar = null; 168 } 169 } 170 } 171 172 int inlineDepth = barriers.size(); 173 174 if (VM.VerifyAssertions) { 175 if (inlineDepth == 0) { 176 VM.sysWriteln("Inlining depth for " + osr + " is 0!"); 177 } 178 VM._assert(inlineDepth != 0); 179 } 180 181 // Step 2: make a new InlinedOsrTypeOperand from barriers 182 int[] methodids = new int[inlineDepth]; 183 int[] bcindexes = new int[inlineDepth]; 184 byte[][] localTypeCodes = new byte[inlineDepth][]; 185 byte[][] stackTypeCodes = new byte[inlineDepth][]; 186 187 int totalOperands = 0; 188 // first iteration, count the size of total locals and stack sizes 189 for (int barIdx = 0, barSize = barriers.size(); barIdx < barSize; barIdx++) { 190 191 Instruction bar = barriers.get(barIdx); 192 methodids[barIdx] = bar.position.method.getId(); 193 bcindexes[barIdx] = bar.bcIndex; 194 195 OsrTypeInfoOperand typeInfo = OsrBarrier.getTypeInfo(bar); 196 localTypeCodes[barIdx] = typeInfo.localTypeCodes; 197 stackTypeCodes[barIdx] = typeInfo.stackTypeCodes; 198 199 // count the number of operand, but ignore VoidTypeCode 200 totalOperands += OsrBarrier.getNumberOfElements(bar); 201 202 /* 203 if (VM.TraceOnStackReplacement) { 204 VM.sysWriteln("OsrBarrier : "+bar.bcIndex 205 +"@"+bar.position.method 206 +" "+typeInfo); 207 } 208 */ 209 } 210 211 // new make InlinedOsrTypeInfoOperand 212 InlinedOsrTypeInfoOperand typeInfo = 213 new InlinedOsrTypeInfoOperand(methodids, bcindexes, localTypeCodes, stackTypeCodes); 214 215 OsrPoint.mutate(osr, osr.operator(), typeInfo, totalOperands); 216 217 // Step 3: second iteration, copy operands 218 int opIndex = 0; 219 for (int barIdx = 0, barSize = barriers.size(); barIdx < barSize; barIdx++) { 220 221 Instruction bar = barriers.get(barIdx); 222 for (int elmIdx = 0, elmSize = OsrBarrier.getNumberOfElements(bar); elmIdx < elmSize; elmIdx++) { 223 224 Operand op = OsrBarrier.getElement(bar, elmIdx); 225 226 if (VM.VerifyAssertions) { 227 if (op == null) { 228 VM.sysWriteln(elmIdx + "th Operand of " + bar + " is null!"); 229 } 230 VM._assert(op != null); 231 } 232 233 if (op.isRegister()) { 234 op = op.asRegister().copyU2U(); 235 } else { 236 op = op.copy(); 237 } 238 239 OsrPoint.setElement(osr, opIndex, op); 240 opIndex++; 241 } 242 } 243 /* 244 if (VM.TraceOnStackReplacement) { 245 VM.sysWriteln("renovated OsrPoint instruction "+osr); 246 VM.sysWriteln(" position "+osr.bcIndex+"@"+osr.position.method); 247 } 248 */ 249 // the last OsrBarrier should in the current method 250 if (VM.VerifyAssertions) { 251 Instruction lastBar = barriers.getLast(); 252 if (ir.method != lastBar.position.method) { 253 VM.sysWriteln("The last barrier is not in the same method as osr:"); 254 VM.sysWriteln(lastBar + "@" + lastBar.position.method); 255 VM.sysWriteln("current method @" + ir.method); 256 } 257 VM._assert(ir.method == lastBar.position.method); 258 259 if (opIndex != totalOperands) { 260 VM.sysWriteln("opIndex and totalOperands do not match:"); 261 VM.sysWriteln("opIndex = " + opIndex); 262 VM.sysWriteln("totalOperands = " + totalOperands); 263 } 264 VM._assert(opIndex == totalOperands); 265 } // end of assertion 266 } // end of for loop 267 } 268 269 /** 270 * The OsrBarrier instruction is not in IR, so the bc index was not 271 * adjusted in OSR_AdjustBCIndex 272 */ 273 private void adjustBCIndex(Instruction barrier) { 274 NormalMethod source = barrier.position.method; 275 if (source.isForOsrSpecialization()) { 276 barrier.bcIndex -= source.getOsrPrologueLength(); 277 } 278 } 279 280 /** remove OsrBarrier instructions. */ 281 private void removeOsrBarriers(IR ir) { 282 Enumeration<Instruction> instenum = ir.forwardInstrEnumerator(); 283 while (instenum.hasMoreElements()) { 284 Instruction inst = instenum.nextElement(); 285 // clean the scratObjects of each instruction 286 inst.scratchObject = null; 287 if (OsrBarrier.conforms(inst)) { 288 inst.remove(); 289 } 290 } 291 } 292 293 @SuppressWarnings("unused") 294 // it's a debugging tool 295 private void verifyNoOsrBarriers(IR ir) { 296 VM.sysWrite("Verifying no osr barriers"); 297 Enumeration<Instruction> instenum = ir.forwardInstrEnumerator(); 298 while (instenum.hasMoreElements()) { 299 Instruction inst = instenum.nextElement(); 300 if (inst.operator().opcode == OSR_BARRIER_opcode) { 301 VM.sysWriteln(" NOT SANE"); 302 VM.sysWriteln(inst.toString()); 303 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 304 break; 305 } 306 } 307 VM.sysWriteln(" SANE"); 308 } 309 310 /** verify barrier is clean by checking the number of valid operands */ 311 private boolean isBarrierClean(Instruction barrier) { 312 OsrTypeInfoOperand typeInfo = OsrBarrier.getTypeInfo(barrier); 313 int totalOperands = countNonVoidTypes(typeInfo.localTypeCodes); 314 totalOperands += countNonVoidTypes(typeInfo.stackTypeCodes); 315 return (totalOperands == OsrBarrier.getNumberOfElements(barrier)); 316 } 317 318 private int countNonVoidTypes(byte[] typeCodes) { 319 int count = 0; 320 for (int idx = 0, size = typeCodes.length; idx < size; idx++) { 321 if (typeCodes[idx] != org.jikesrvm.osr.OSRConstants.VoidTypeCode) { 322 count++; 323 } 324 } 325 return count; 326 } 327 328 /** 329 * Split each OsrPoint, and connect it to the exit point. 330 */ 331 private void fixupCFGForOsr(LinkedList<Instruction> osrs, IR ir) { 332 333 for (int i = 0, n = osrs.size(); i < n; i++) { 334 Instruction osr = osrs.get(i); 335 BasicBlock bb = osr.getBasicBlock(); 336 BasicBlock newBB = bb.segregateInstruction(osr, ir); 337 bb.recomputeNormalOut(ir); 338 newBB.recomputeNormalOut(ir); 339 } 340 } 341 }