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.runtimesupport; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.IG_PATCH_POINT; 016 017 import org.jikesrvm.ArchitectureSpecific; 018 import org.jikesrvm.ArchitectureSpecificOpt; 019 import org.jikesrvm.VM; 020 import org.jikesrvm.PrintLN; 021 import org.jikesrvm.classloader.RVMArray; 022 import org.jikesrvm.classloader.MemberReference; 023 import org.jikesrvm.classloader.RVMMethod; 024 import org.jikesrvm.classloader.NormalMethod; 025 import org.jikesrvm.classloader.RVMType; 026 import org.jikesrvm.classloader.TypeReference; 027 import org.jikesrvm.compilers.common.CompiledMethod; 028 import org.jikesrvm.compilers.common.ExceptionTable; 029 import org.jikesrvm.compilers.opt.ir.IR; 030 import org.jikesrvm.compilers.opt.ir.InlineGuard; 031 import org.jikesrvm.compilers.opt.ir.Instruction; 032 import org.jikesrvm.osr.EncodedOSRMap; 033 import org.jikesrvm.runtime.DynamicLink; 034 import org.jikesrvm.runtime.ExceptionDeliverer; 035 import org.jikesrvm.runtime.Magic; 036 import org.jikesrvm.runtime.Memory; 037 import org.jikesrvm.runtime.StackBrowser; 038 import org.jikesrvm.scheduler.RVMThread; 039 import org.vmmagic.pragma.Interruptible; 040 import org.vmmagic.pragma.Uninterruptible; 041 import org.vmmagic.pragma.Unpreemptible; 042 import org.vmmagic.unboxed.Offset; 043 044 /** 045 * An implementation of CompiledMethod for the OPT compiler. 046 * 047 * <p> NOTE: OptCompiledMethod live as long as their corresponding 048 * compiled machine code. Therefore, they should only contain 049 * state that is really required to be persistent. Anything 050 * transitory should be stored on the IR object. 051 */ 052 @Uninterruptible 053 public final class OptCompiledMethod extends CompiledMethod { 054 055 public OptCompiledMethod(int id, RVMMethod m) { 056 super(id, m); 057 } 058 059 /** 060 * @return {@link CompiledMethod#OPT} 061 */ 062 @Override 063 public int getCompilerType() { 064 return CompiledMethod.OPT; 065 } 066 067 @Override 068 public String getCompilerName() { 069 return "optimizing compiler"; 070 } 071 072 @Override 073 public ExceptionDeliverer getExceptionDeliverer() { 074 return exceptionDeliverer; 075 } 076 077 /** 078 * Find "catch" block for a machine instruction of this method. 079 */ 080 @Override 081 @Unpreemptible 082 public int findCatchBlockForInstruction(Offset instructionOffset, RVMType exceptionType) { 083 if (eTable == null) { 084 return -1; 085 } else { 086 return ExceptionTable.findCatchBlockForInstruction(eTable, instructionOffset, exceptionType); 087 } 088 } 089 090 /** 091 * Fetch symbolic reference to a method that's called 092 * by one of this method's instructions. 093 * @param dynamicLink place to put return information 094 * @param instructionOffset offset of machine instruction that issued 095 * the call 096 */ 097 @Override 098 public void getDynamicLink(DynamicLink dynamicLink, Offset instructionOffset) { 099 int bci = _mcMap.getBytecodeIndexForMCOffset(instructionOffset); 100 NormalMethod realMethod = _mcMap.getMethodForMCOffset(instructionOffset); 101 if (bci == -1 || realMethod == null) { 102 VM.sysFail("Mapping to source code location not available at Dynamic Linking point\n"); 103 } 104 realMethod.getDynamicLink(dynamicLink, bci); 105 } 106 107 @Override 108 @Interruptible 109 public boolean isWithinUninterruptibleCode(Offset instructionOffset) { 110 NormalMethod realMethod = _mcMap.getMethodForMCOffset(instructionOffset); 111 return realMethod.isUninterruptible(); 112 } 113 114 /** 115 * Find source line number corresponding to one of this method's 116 * machine instructions. 117 */ 118 @Override 119 public int findLineNumberForInstruction(Offset instructionOffset) { 120 int bci = _mcMap.getBytecodeIndexForMCOffset(instructionOffset); 121 if (bci < 0) { 122 return 0; 123 } 124 return ((NormalMethod) method).getLineNumberForBCIndex(bci); 125 } 126 127 @Override 128 @Interruptible 129 public void set(StackBrowser browser, Offset instr) { 130 OptMachineCodeMap map = getMCMap(); 131 int iei = map.getInlineEncodingForMCOffset(instr); 132 if (iei >= 0) { 133 int[] inlineEncoding = map.inlineEncoding; 134 int mid = OptEncodedCallSiteTree.getMethodID(iei, inlineEncoding); 135 136 browser.setInlineEncodingIndex(iei); 137 browser.setBytecodeIndex(map.getBytecodeIndexForMCOffset(instr)); 138 browser.setCompiledMethod(this); 139 browser.setMethod(MemberReference.getMemberRef(mid).asMethodReference().peekResolvedMethod()); 140 141 if (VM.TraceStackTrace) { 142 VM.sysWrite("setting stack to frame (opt): "); 143 VM.sysWrite(browser.getMethod()); 144 VM.sysWrite(browser.getBytecodeIndex()); 145 VM.sysWrite("\n"); 146 } 147 } else { 148 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 149 } 150 } 151 152 @Override 153 @Interruptible 154 public boolean up(StackBrowser browser) { 155 OptMachineCodeMap map = getMCMap(); 156 int iei = browser.getInlineEncodingIndex(); 157 int[] ie = map.inlineEncoding; 158 int next = OptEncodedCallSiteTree.getParent(iei, ie); 159 if (next >= 0) { 160 int mid = OptEncodedCallSiteTree.getMethodID(next, ie); 161 int bci = OptEncodedCallSiteTree.getByteCodeOffset(iei, ie); 162 163 browser.setInlineEncodingIndex(next); 164 browser.setBytecodeIndex(bci); 165 browser.setMethod(MemberReference.getMemberRef(mid).asMethodReference().peekResolvedMethod()); 166 167 if (VM.TraceStackTrace) { 168 VM.sysWrite("up within frame stack (opt): "); 169 VM.sysWrite(browser.getMethod()); 170 VM.sysWrite(browser.getBytecodeIndex()); 171 VM.sysWrite("\n"); 172 } 173 174 return true; 175 } else { 176 return false; 177 } 178 } 179 180 @Override 181 @Interruptible 182 public void printStackTrace(Offset instructionOffset, PrintLN out) { 183 OptMachineCodeMap map = getMCMap(); 184 int iei = map.getInlineEncodingForMCOffset(instructionOffset); 185 if (iei >= 0) { 186 int[] inlineEncoding = map.inlineEncoding; 187 int bci = map.getBytecodeIndexForMCOffset(instructionOffset); 188 for (int j = iei; j >= 0; j = OptEncodedCallSiteTree.getParent(j, inlineEncoding)) { 189 int mid = OptEncodedCallSiteTree.getMethodID(j, inlineEncoding); 190 NormalMethod m = 191 (NormalMethod) MemberReference.getMemberRef(mid).asMethodReference().peekResolvedMethod(); 192 int lineNumber = m.getLineNumberForBCIndex(bci); // might be 0 if unavailable. 193 out.print("\tat "); 194 out.print(m.getDeclaringClass()); 195 out.print('.'); 196 out.print(m.getName()); 197 out.print('('); 198 out.print(m.getDeclaringClass().getSourceName()); 199 out.print(':'); 200 out.print(lineNumber); 201 out.print(')'); 202 out.println(); 203 if (j > 0) { 204 bci = OptEncodedCallSiteTree.getByteCodeOffset(j, inlineEncoding); 205 } 206 } 207 } else { 208 out.print("\tat "); 209 out.print(method.getDeclaringClass()); 210 out.print('.'); 211 out.print(method.getName()); 212 out.print('('); 213 out.print(method.getDeclaringClass().getSourceName()); 214 out.print("; machine code offset: "); 215 out.printHex(instructionOffset.toInt()); 216 out.print(')'); 217 out.println(); 218 } 219 } 220 221 @Override 222 @Interruptible 223 public int size() { 224 int size = TypeReference.ExceptionTable.peekType().asClass().getInstanceSize(); 225 size += _mcMap.size(); 226 if (eTable != null) size += RVMArray.IntArray.getInstanceSize(eTable.length); 227 if (patchMap != null) size += RVMArray.IntArray.getInstanceSize(patchMap.length); 228 return size; 229 } 230 231 //----------------// 232 // implementation // 233 //----------------// 234 private static final ArchitectureSpecificOpt.OptExceptionDeliverer exceptionDeliverer = 235 new ArchitectureSpecificOpt.OptExceptionDeliverer(); 236 237 private EncodedOSRMap _osrMap; 238 239 @Interruptible 240 public void createFinalOSRMap(IR ir) { 241 this._osrMap = EncodedOSRMap.makeMap(ir.MIRInfo.osrVarMap); 242 } 243 244 public EncodedOSRMap getOSRMap() { 245 return this._osrMap; 246 } 247 248 ////////////////////////////////////// 249 // Information the opt compiler needs to persistently associate 250 // with a particular compiled method. 251 252 /** The primary machine code maps */ 253 private OptMachineCodeMap _mcMap; 254 /** The encoded exception tables (null if there are none) */ 255 private int[] eTable; 256 private int[] patchMap; 257 258 /** 259 * unsigned offset (off the framepointer) of nonvolatile save area 260 * in bytes 261 */ 262 private char nonvolatileOffset; 263 /** 264 * unsigned offset (off the framepointer) of caught exception 265 * object in bytes 266 */ 267 private char exceptionObjectOffset; 268 /** 269 * size of the fixed portion of the stackframe 270 */ 271 private char stackFrameFixedSize; 272 /** 273 * first saved nonvolatile integer register (-1 if no nonvolatile 274 * GPRs) 275 */ 276 private byte firstNonvolatileGPR; 277 /** 278 * first saved nonvolatile floating point register (-1 if no 279 * nonvolatile FPRs) 280 */ 281 private byte firstNonvolatileFPR; 282 /** opt level at which the method was compiled */ 283 private byte optLevel; 284 /** were the volatile registers saved? */ 285 private boolean volatilesSaved; 286 /** is the current method executing with instrumentation */ 287 private boolean instrumented; 288 289 public int getUnsignedNonVolatileOffset() { 290 return nonvolatileOffset; 291 } 292 293 public int getUnsignedExceptionOffset() { 294 return exceptionObjectOffset; 295 } 296 297 public int getFirstNonVolatileGPR() { 298 return firstNonvolatileGPR; 299 } 300 301 public int getFirstNonVolatileFPR() { 302 return firstNonvolatileFPR; 303 } 304 305 public int getOptLevel() { 306 return optLevel; 307 } 308 309 public boolean isSaveVolatile() { 310 return volatilesSaved; 311 } 312 313 public boolean isInstrumentedMethod() { 314 return instrumented; 315 } 316 317 public int getFrameFixedSize() { 318 return stackFrameFixedSize; 319 } 320 321 public void setUnsignedNonVolatileOffset(int x) { 322 if (VM.VerifyAssertions) VM._assert(x >= 0 && x < 0xFFFF); 323 nonvolatileOffset = (char) x; 324 } 325 326 public void setUnsignedExceptionOffset(int x) { 327 if (VM.VerifyAssertions) VM._assert(x >= 0 && x < 0xFFFF); 328 exceptionObjectOffset = (char) x; 329 } 330 331 public void setFirstNonVolatileGPR(int x) { 332 if (VM.VerifyAssertions) VM._assert(x >= -1 && x < 0x7F); 333 firstNonvolatileGPR = (byte) x; 334 } 335 336 public void setFirstNonVolatileFPR(int x) { 337 if (VM.VerifyAssertions) VM._assert(x >= -1 && x < 0x7F); 338 firstNonvolatileFPR = (byte) x; 339 } 340 341 public void setOptLevel(int x) { 342 if (VM.VerifyAssertions) VM._assert(x >= 0 && x < 0x7F); 343 optLevel = (byte) x; 344 } 345 346 public void setSaveVolatile(boolean sv) { 347 volatilesSaved = sv; 348 } 349 350 public void setInstrumentedMethod(boolean _instrumented) { 351 instrumented = _instrumented; 352 } 353 354 public void setFrameFixedSize(int x) { 355 if (VM.VerifyAssertions) VM._assert(x >= 0 && x < 0xFFFF); 356 stackFrameFixedSize = (char) x; 357 } 358 359 /** 360 * Return the number of non-volatile GPRs used by this method. 361 */ 362 public int getNumberOfNonvolatileGPRs() { 363 if (VM.BuildForPowerPC) { 364 return ArchitectureSpecific.RegisterConstants.NUM_GPRS - getFirstNonVolatileGPR(); 365 } else if (VM.BuildForIA32) { 366 return ArchitectureSpecific.RegisterConstants.NUM_NONVOLATILE_GPRS - getFirstNonVolatileGPR(); 367 } else if (VM.VerifyAssertions) { 368 VM._assert(VM.NOT_REACHED); 369 } 370 return -1; 371 } 372 373 /** 374 * Return the number of non-volatile FPRs used by this method. 375 */ 376 public int getNumberOfNonvolatileFPRs() { 377 if (VM.BuildForPowerPC) { 378 return ArchitectureSpecific.RegisterConstants.NUM_FPRS - getFirstNonVolatileFPR(); 379 } else if (VM.BuildForIA32) { 380 return ArchitectureSpecific.RegisterConstants.NUM_NONVOLATILE_FPRS - getFirstNonVolatileFPR(); 381 } else if (VM.VerifyAssertions) { 382 VM._assert(VM.NOT_REACHED); 383 } 384 return -1; 385 } 386 387 /** 388 * Set the number of non-volatile GPRs used by this method. 389 */ 390 public void setNumberOfNonvolatileGPRs(short n) { 391 if (VM.BuildForPowerPC) { 392 setFirstNonVolatileGPR(ArchitectureSpecific.RegisterConstants.NUM_GPRS - n); 393 } else if (VM.BuildForIA32) { 394 setFirstNonVolatileGPR(ArchitectureSpecific.RegisterConstants.NUM_NONVOLATILE_GPRS - n); 395 } else if (VM.VerifyAssertions) { 396 VM._assert(VM.NOT_REACHED); 397 } 398 } 399 400 /** 401 * Set the number of non-volatile FPRs used by this method. 402 */ 403 public void setNumberOfNonvolatileFPRs(short n) { 404 if (VM.BuildForPowerPC) { 405 setFirstNonVolatileFPR(ArchitectureSpecific.RegisterConstants.NUM_FPRS - n); 406 } else if (VM.BuildForIA32) { 407 setFirstNonVolatileFPR(ArchitectureSpecific.RegisterConstants.NUM_NONVOLATILE_FPRS - n); 408 } else if (VM.VerifyAssertions) { 409 VM._assert(VM.NOT_REACHED); 410 } 411 } 412 413 /** 414 * Print the eTable 415 */ 416 @Interruptible 417 public void printExceptionTable() { 418 if (eTable != null) ExceptionTable.printExceptionTable(eTable); 419 } 420 421 /** 422 * @return the machine code map for the compiled method. 423 */ 424 public OptMachineCodeMap getMCMap() { 425 return _mcMap; 426 } 427 428 /** 429 * Create the final machine code map for the compiled method. 430 * Remember the offset for the end of prologue too for debugger. 431 * @param ir the ir 432 * @param machineCodeLength the number of machine code instructions. 433 */ 434 @Interruptible 435 public void createFinalMCMap(IR ir, int machineCodeLength) { 436 _mcMap = OptMachineCodeMap.create(ir, machineCodeLength); 437 } 438 439 /** 440 * Create the final exception table from the IR for the method. 441 * @param ir the ir 442 */ 443 @Interruptible 444 public void createFinalExceptionTable(IR ir) { 445 if (ir.hasReachableExceptionHandlers()) { 446 eTable = OptExceptionTable.encode(ir); 447 } 448 } 449 450 /** 451 * Create the code patching maps from the IR for the method 452 * @param ir the ir 453 */ 454 @Interruptible 455 public void createCodePatchMaps(IR ir) { 456 // (1) count the patch points 457 int patchPoints = 0; 458 for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 459 if (s.operator() == IG_PATCH_POINT) { 460 patchPoints++; 461 } 462 } 463 // (2) if we have patch points, create the map. 464 if (patchPoints != 0) { 465 patchMap = new int[patchPoints * 2]; 466 int idx = 0; 467 for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 468 if (s.operator() == IG_PATCH_POINT) { 469 int patchPoint = s.getmcOffset(); 470 int newTarget = InlineGuard.getTarget(s).target.getmcOffset(); 471 // A patch map is the offset of the last byte of the patch point 472 // and the new branch immediate to lay down if the code is ever patched. 473 if (VM.BuildForIA32) { 474 patchMap[idx++] = patchPoint - 1; 475 patchMap[idx++] = newTarget - patchPoint; 476 } else if (VM.BuildForPowerPC) { 477 478 // otherwise, it must be RFOR_POWERPC 479 /* since currently we use only one NOP scheme, the offset 480 * is adjusted for one word 481 */ 482 patchMap[idx++] = (patchPoint >> ArchitectureSpecific.RegisterConstants.LG_INSTRUCTION_WIDTH) - 1; 483 patchMap[idx++] = 484 (newTarget - patchPoint + (1 << ArchitectureSpecific.RegisterConstants.LG_INSTRUCTION_WIDTH)); 485 } else if (VM.VerifyAssertions) { 486 VM._assert(VM.NOT_REACHED); 487 } 488 } 489 } 490 } 491 } 492 493 /** 494 * Apply the code patches to the INSTRUCTION array of cm 495 */ 496 @Interruptible 497 public void applyCodePatches(CompiledMethod cm) { 498 if (patchMap != null) { 499 for (int idx = 0; idx < patchMap.length; idx += 2) { 500 ArchitectureSpecific.CodeArray code = cm.codeArrayForOffset(Offset.fromIntZeroExtend(patchMap[idx])); 501 if (VM.BuildForIA32) { 502 ArchitectureSpecific.Assembler.patchCode(code, patchMap[idx], patchMap[idx + 1]); 503 } else if (VM.BuildForPowerPC) { 504 ArchitectureSpecificOpt.AssemblerOpt.patchCode(code, patchMap[idx], patchMap[idx + 1]); 505 } else if (VM.VerifyAssertions) { 506 VM._assert(VM.NOT_REACHED); 507 } 508 } 509 510 if (VM.BuildForPowerPC) { 511 /* we need synchronization on PPC to handle the weak memory model 512 * and its icache/dcache synchronization requriements. 513 * before the class loading finish, other processor should get 514 * synchronized. 515 */ 516 boolean DEBUG_CODE_PATCH = false; 517 518 // let other processors see changes; although really physical processors 519 // need synchronization, we set each virtual processor to execute 520 // isync at thread switch point. 521 Magic.sync(); 522 523 // All other processors now will see the patched code in their data cache. 524 // We now need to force everyone's instruction caches to be in synch with their 525 // data caches. Some of the work of this call is redundant (since we already have 526 // forced the data caches to be in synch), but we need the icbi instructions 527 Memory.sync(Magic.objectAsAddress(instructions), 528 instructions.length() << ArchitectureSpecific.RegisterConstants.LG_INSTRUCTION_WIDTH); 529 RVMThread.softHandshake(codePatchSyncRequestVisitor); 530 531 if (DEBUG_CODE_PATCH) { 532 VM.sysWrite("all processors get synchronized!\n"); 533 } 534 } 535 536 } 537 } 538 539 private static RVMThread.SoftHandshakeVisitor codePatchSyncRequestVisitor = 540 new RVMThread.SoftHandshakeVisitor() { 541 @Override 542 @Uninterruptible 543 public boolean checkAndSignal(RVMThread t) { 544 t.codePatchSyncRequested = true; 545 return true; // handshake with everyone but ourselves. 546 } 547 }; 548 }