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.liveness; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.PHI; 016 import static org.jikesrvm.osr.OSRConstants.LongTypeCode; 017 import static org.jikesrvm.osr.OSRConstants.VoidTypeCode; 018 019 import java.lang.reflect.Constructor; 020 import java.util.ArrayList; 021 import java.util.Enumeration; 022 import java.util.HashSet; 023 import java.util.Iterator; 024 import java.util.LinkedList; 025 import java.util.List; 026 import java.util.Stack; 027 028 import org.jikesrvm.VM; 029 import org.jikesrvm.classloader.TypeReference; 030 import org.jikesrvm.compilers.opt.DefUse; 031 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 032 import org.jikesrvm.compilers.opt.ir.BasicBlock; 033 import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock; 034 import org.jikesrvm.compilers.opt.ir.GCIRMap; 035 import org.jikesrvm.compilers.opt.ir.IR; 036 import org.jikesrvm.compilers.opt.ir.Instruction; 037 import org.jikesrvm.compilers.opt.ir.OsrPoint; 038 import org.jikesrvm.compilers.opt.ir.Phi; 039 import org.jikesrvm.compilers.opt.ir.RegSpillListElement; 040 import org.jikesrvm.compilers.opt.ir.Register; 041 import org.jikesrvm.compilers.opt.ir.operand.BasicBlockOperand; 042 import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand; 043 import org.jikesrvm.compilers.opt.ir.operand.Operand; 044 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 045 import org.jikesrvm.compilers.opt.regalloc.LiveIntervalElement; 046 import org.jikesrvm.compilers.opt.util.SortedGraphIterator; 047 import org.jikesrvm.osr.OSRConstants; 048 import org.jikesrvm.osr.LocalRegPair; 049 import org.jikesrvm.osr.MethodVariables; 050 import org.jikesrvm.osr.VariableMap; 051 import org.jikesrvm.util.EmptyIterator; 052 053 /** 054 * This class performs a flow-sensitive iterative live variable analysis. 055 * The result of this analysis is live ranges for each basic block. 056 * (@see BasicBlock)<p> 057 * 058 * This class can also optionally construct GC maps. These GC maps 059 * are later used to create the final gc map (see OptReferenceMap.java).<p> 060 * 061 * Previously we used to be concerned that we didn't lose any 062 * precision due to imprecise modeling of exceptions. 063 * However, the troublesome situation cannot occur in Java. The rest of the 064 * comment for this class explains why that situation cannot occur.<p> 065 * 066 * The Java SPEC forces the compiler to declare a variable as uninitialized 067 * in those case that would be problematic. Consider the following 068 * ***ILLEGAL*** example: 069 * 070 * <pre> 071 * static void main(String arg[]) { 072 * Object x; 073 * 074 * try { 075 * foo(); 076 * x = null; 077 * bar(); 078 * } 079 * catch (FooException e) { 080 * } 081 * 082 * catch (BarException e) { 083 * Object a = x; 084 * } 085 * } 086 * </pre> 087 * 088 * <p> 089 * Here x is live in the Bar catch block, but not above the assignment 090 * in the try block. We only kill off values coming from 091 * catch blocks if they are in the first PEI region (above the call 092 * to foo). Thus, our analysis will conservatively record that x 093 * is live above the assignment.<p> 094 * 095 * However, the Java SPEC requires compilers to state that x is uninitialized 096 * here, even though it isn't. Thus, this scenario cannot occur. 097 * Basically, every variable used in a catch block needs to be defined 098 * before the TRY statement. (The SPEC doesn't explicitly state this, but 099 * on page 398 (Sec 16.2.13) it says that every variable used in a *finally* 100 * block needs to be defined before the TRY statement, which is even more 101 * restrictive.<p> 102 * 103 * Bottomline: losing precision is not a concern! 104 */ 105 public final class LiveAnalysis extends CompilerPhase { 106 // Real Instance Variables 107 /** 108 * Should we also create GC maps while we are computing liveness 109 */ 110 private final boolean createGCMaps; 111 112 /** 113 * Should we store liveness information at the top of each handler block? 114 */ 115 private final boolean storeLiveAtHandlers; 116 117 /** 118 * Should we skip guard registers? 119 */ 120 private final boolean skipGuards; 121 122 /** 123 * Should we skip the (final) local propagation phase? 124 */ 125 private final boolean skipLocal; 126 127 /** 128 * The current LiveSet that we will carry around 129 */ 130 private LiveSet currentSet; 131 132 /** 133 * Temporary live information associated with each basic block 134 */ 135 private BBLiveElement[] bbLiveInfo; 136 137 /** 138 * The GC map associated with the IR, optionally filled by this class 139 */ 140 private final GCIRMap map; 141 142 private final VariableMap osrMap; 143 144 /** 145 * For each register, the set of live interval elements describing the 146 * register. 147 */ 148 private ArrayList<LiveIntervalElement>[] registerMap; 149 150 /** Debugging info */ 151 private static final boolean DEBUG = false; 152 153 /** Even more debugging info */ 154 private static final boolean VERBOSE = false; 155 156 @Override 157 public String getName() { 158 return "Live Analysis"; 159 } 160 161 /** 162 * The constructor is used to specify whether GC maps should be computed 163 * along with live analysis. 164 * 165 * @param createGCMaps should we create GC maps? 166 * @param skipLocal should we skip the (final) local propagation phase? 167 */ 168 public LiveAnalysis(boolean createGCMaps, boolean skipLocal) { 169 this(createGCMaps, skipLocal, false, true); 170 } 171 172 /** 173 * The constructor is used to specify whether GC maps should be computed 174 * along with live analysis. 175 * 176 * @param createGCMaps should we create GC maps? 177 * @param skipLocal should we skip the (final) local propagation phase? 178 * @param storeLiveAtHandlers should we store liveness info at the 179 * top of each handler block? 180 */ 181 public LiveAnalysis(boolean createGCMaps, boolean skipLocal, boolean storeLiveAtHandlers) { 182 this(createGCMaps, skipLocal, storeLiveAtHandlers, true); 183 } 184 185 /** 186 * The constructor is used to specify whether GC maps should be computed 187 * along with live analysis. 188 * 189 * @param createGCMaps should we create GC maps? 190 * @param skipLocal should we skip the (final) local propagation phase? 191 * @param storeLiveAtHandlers should we store liveness info at the 192 * top of each handler block? 193 * @param skipGuards should we ignore validation registers? 194 */ 195 public LiveAnalysis(boolean createGCMaps, boolean skipLocal, boolean storeLiveAtHandlers, boolean skipGuards) { 196 super(new Object[]{createGCMaps, skipLocal, storeLiveAtHandlers, skipGuards}); 197 this.createGCMaps = createGCMaps; 198 this.skipLocal = skipLocal; 199 this.storeLiveAtHandlers = storeLiveAtHandlers; 200 this.skipGuards = skipGuards; 201 if (createGCMaps) { 202 // Create the IR-based Map we will use during compilation 203 // At a later phase this map is converted into the "runtime" 204 // map, which is called OptReferenceMap. 205 map = new GCIRMap(); 206 osrMap = new VariableMap(); 207 } else { 208 map = null; 209 osrMap = null; 210 } 211 } 212 213 /** 214 * By default we don't create GC maps and do perform the local prop phase 215 */ 216 public LiveAnalysis() { 217 this(false, false, false, true); 218 } 219 220 /** 221 * Constructor for this compiler phase 222 */ 223 private static final Constructor<CompilerPhase> constructor = 224 getCompilerPhaseConstructor(LiveAnalysis.class, 225 new Class[]{Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE}); 226 227 /** 228 * Get a constructor object for this compiler phase 229 * @return compiler phase constructor 230 */ 231 @Override 232 public Constructor<CompilerPhase> getClassConstructor() { 233 return constructor; 234 } 235 236 /** 237 * The entry point into this class 238 * Perform live variable analysis on this IR, constructing live 239 * range info and (optionally) GC map info as we go. 240 * 241 * @param ir the ir 242 */ 243 @Override 244 public void perform(IR ir) { 245 246 // Debugging information 247 // Live Intervals, GC Maps, and fixed-point results 248 final boolean dumpFinalLiveIntervals = DEBUG || 249 ir.options.PRINT_GC_MAPS && 250 (!ir.options.hasMETHOD_TO_PRINT() || 251 (ir.options.hasMETHOD_TO_PRINT() && ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) 252 ); 253 final boolean dumpFinalMaps = dumpFinalLiveIntervals; 254 final boolean dumpFixedPointResults = dumpFinalLiveIntervals; 255 256 // make sure IR info is up-to-date 257 DefUse.recomputeSpansBasicBlock(ir); 258 debugBegining(ir, createGCMaps, dumpFinalLiveIntervals, dumpFinalMaps, dumpFixedPointResults); 259 bbLiveInfo = new BBLiveElement[ir.cfg.numberOfNodes()]; 260 261 for (int i = 0; i < ir.cfg.numberOfNodes(); i++) { 262 bbLiveInfo[i] = new BBLiveElement(); 263 } 264 265 // allocate the "currentSet" which is used to cache the current results 266 currentSet = new LiveSet(); 267 boolean reuseCurrentSet = false; 268 269 // make sure reverse top sort order is built 270 // currentBlock is the first node in the list 271 BasicBlock currentBlock = (BasicBlock) ir.cfg.buildRevTopSort(); 272 273 // 2nd param: true means forward analysis; false means backward analysis 274 SortedGraphIterator bbIter = new SortedGraphIterator(currentBlock, false); 275 while (currentBlock != null) { 276 boolean changed = processBlock(currentBlock, reuseCurrentSet, ir); 277 278 // mark this block as processed and get the next one 279 BasicBlock nextBlock = (BasicBlock) bbIter.markAndGetNextTopSort(changed); 280 281 // check to see if nextBlock has only one successor, currentBlock. 282 // If so, we can reuse the current set and avoid performing a meet. 283 reuseCurrentSet = nextBlock != null && bbIter.isSinglePredecessor(currentBlock, nextBlock); 284 currentBlock = nextBlock; 285 } 286 debugPostGlobal(ir, dumpFinalLiveIntervals, dumpFinalMaps, dumpFixedPointResults); 287 288 // Now compute live ranges, using results from the fixed point computation 289 // Also, optionally create GC maps 290 // SSA doesn't need this part so we allow it to be optional. 291 // However, if we don't perform it than the final maps and intervals aren't 292 // created, so we can't print them. 293 if (!skipLocal) { 294 performLocalPropagation(ir, createGCMaps); 295 296 if (createGCMaps && dumpFinalMaps) { 297 System.out.println("**** START OF IR for method: " + 298 ir.method.getName() + 299 " in class: " + 300 ir.method.getDeclaringClass()); 301 ir.printInstructions(); 302 System.out.println("**** END OF IR INSTRUCTION DUMP ****"); 303 304 printFinalMaps(ir); 305 } 306 if (dumpFinalLiveIntervals) { 307 printFinalLiveIntervals(ir); 308 } 309 // If we performed the local propagation, live interval information 310 // lives off of each basic block. 311 // Thus, we no longer need bbLiveInfo (the fixed points results) 312 // When we don't perform the local propagation, such as translating 313 // out of SSA, then we need to keep bbLiveInfo around 314 bbLiveInfo = null; 315 316 // compute the mapping from registers to live interval elements 317 computeRegisterMap(ir); 318 } 319 320 // No longer need currentSet, which is simply a cache of a LiveSet). 321 currentSet = null; 322 323 // This will be null if createGCMaps is false 324 if (createGCMaps) { 325 ir.MIRInfo.gcIRMap = map; 326 ir.MIRInfo.osrVarMap = osrMap; 327 } 328 329 // record whether or not we stored liveness information for handlers. 330 ir.setHandlerLivenessComputed(storeLiveAtHandlers); 331 } 332 333 /** 334 * Return an iterator over all the live interval elements for a given 335 * register. 336 */ 337 public Iterator<LiveIntervalElement> iterateLiveIntervals(Register r) { 338 ArrayList<LiveIntervalElement> set = registerMap[r.getNumber()]; 339 if (set == null) { 340 return EmptyIterator.<LiveIntervalElement>getInstance(); 341 } else { 342 return set.iterator(); 343 } 344 } 345 346 /** 347 * Update the data structures to reflect that all live intervals for r2 348 * are now intervals for r1. 349 */ 350 public void merge(Register r1, Register r2) { 351 ArrayList<LiveIntervalElement> toRemove = new ArrayList<LiveIntervalElement>(5); 352 353 for (Iterator<LiveIntervalElement> i = iterateLiveIntervals(r2); i.hasNext();) { 354 LiveIntervalElement interval = i.next(); 355 interval.setRegister(r1); 356 addToRegisterMap(r1, interval); 357 // defer removing the interval to avoid concurrent modification of 358 // the iterator's backing set. 359 toRemove.add(interval); 360 } 361 // perform deferred removals 362 for (LiveIntervalElement interval : toRemove) { 363 removeFromRegisterMap(r2, interval); 364 } 365 } 366 367 /** 368 * Set up a mapping from each register to the set of live intervals for 369 * the register. 370 * <p> 371 * Side effect: map each live interval element to its basic block. 372 */ 373 @SuppressWarnings("unchecked") 374 private void computeRegisterMap(IR ir) { 375 registerMap = new ArrayList[ir.regpool.getNumberOfSymbolicRegisters()]; 376 for (Enumeration e = ir.getBasicBlocks(); e.hasMoreElements();) { 377 BasicBlock bb = (BasicBlock) e.nextElement(); 378 for (Enumeration i = bb.enumerateLiveIntervals(); i.hasMoreElements();) { 379 LiveIntervalElement lie = (LiveIntervalElement) i.nextElement(); 380 lie.setBasicBlock(bb); 381 if (lie.getRegister().isSymbolic()) { 382 addToRegisterMap(lie.getRegister(), lie); 383 } 384 } 385 } 386 } 387 388 /** 389 * Add the live interval element i to the map for register r. 390 */ 391 private void addToRegisterMap(Register r, LiveIntervalElement i) { 392 ArrayList<LiveIntervalElement> set = registerMap[r.getNumber()]; 393 if (set == null) { 394 set = new ArrayList<LiveIntervalElement>(3); 395 registerMap[r.getNumber()] = set; 396 } 397 set.add(i); 398 } 399 400 /** 401 * Remove the live interval element i from the map for register r. 402 */ 403 private void removeFromRegisterMap(Register r, LiveIntervalElement i) { 404 ArrayList<LiveIntervalElement> set = registerMap[r.getNumber()]; 405 if (set != null) { 406 set.remove(i); 407 } 408 } 409 410 /** 411 * Compute summary (local) live variable analysis for a basic block, which 412 * is basically Gen and Kill information. 413 * 414 * @param bblock the basic block 415 * @param ir the governing if 416 * @see "Efficient and Precise Modeling of Exceptions for the 417 * Analysis of Java Programs" by Choi, Grove, Hind, Sarkar 418 * in ACM PASTE99 workshop (available at 419 * www.research.ibm.com/jalapeno)" 420 */ 421 private void computeBlockGenAndKill(BasicBlock bblock, IR ir) { 422 if (VERBOSE) { 423 System.out.println(" --> Computing Gen/Kill for block " + bblock); 424 } 425 426 // Tells whether we've seen the first PEI 427 boolean seenFirstPEI = false; 428 429 // Because control flow may emanate from a potentially excepting 430 // instruction (PEI) out of the basic block, care must be taken 431 // when computing what can be killed by a basic block. 432 // 433 // S1: y = 434 // S2: <exception-raising inst> 435 // S3: x = 436 // For example in the block above, live variables coming from 437 // the normal exit of the block (i.e., after S3) can be killed 438 // by S1 or S3 (depending on the variable). However, live variables 439 // coming from the PEI edge (at S2) can only be killed by S1. 440 // Thus, when a block contains PEIs, we need to distinguish the 441 // kill sets. Namely, we need 442 // Kill_tot - what can be killed anywhere in the block 443 // Kill_n - what can be killed from PEI_n on up 444 // Kill_n-1 - what can be killed from PEI_n-1 on up 445 // ... 446 // Kill_1 - what can be killed from PEI_1 on up 447 // We would then compute In as follows 448 // 449 // In = Out_norm - Kill_tot (all vars entering from bottom are eligible 450 // to be killed) 451 // U Out_n - Kill_n 452 // U Out_n-1 - Kill_n-1 453 // ... 454 // U Out_1 - Kill_1 455 // U Gen 456 // where Out_n is the out information at PEI i, i.e., the IN information 457 // for whatever handlers may catch PEI i 458 // ... 459 // PEI 1 460 // ... 461 // PEI n-1 462 // ... 463 // PEI n 464 // ... 465 // If we conservatively assume all handlers for the block of interest 466 // can be reached by all PEIs in this block then the equation becomes 467 // In = (Out_norm - Kill_tot) 468 // U (Out_hand - Kill_n) 469 // U (Out_hand - Kill_n-1) 470 // ... 471 // U (Out_hand - Kill_1) 472 // U Gen 473 // where "Out_hand" is the union of the in sets for all handlers. 474 // Since Kill_i is a subset of Kill_j, for i < j, we can simplify to 475 // In = (Out_norm - Kill_tot) 476 // U (Out_hand - Kill_1) (1) 477 // U Gen 478 // Since kill_1 is a subset of kill_tot, we don't need the 479 // the parenthesis (and the intermediate set) 480 // If there are no handlers than (1) is empty and we don't need 481 // to compute Kill_1. We will take this approach for now. 482 // So for each block we will have at most 2 kill sets: Kill_tot and Kill_1 483 // This code finds the first PEI in the block 484 485 Instruction firstPEI = null; 486 if (bblock.canThrowExceptions()) { 487 for (Instruction inst = bblock.firstInstruction(); inst != bblock.lastInstruction(); inst = 488 inst.nextInstructionInCodeOrder()) { 489 if (inst.isPEI() && bblock.getApplicableExceptionalOut(inst).hasMoreElements()) { 490 firstPEI = inst; 491 // remember that this block has a PEI with a handler for use 492 // later in "processBlock" 493 bbLiveInfo[bblock.getNumber()].setContainsPEIWithHandler(true); 494 break; 495 } 496 } 497 } 498 499 // Get any uses from PHIs, which are in the successor blocks 500 getUsesFromPhis(bblock); 501 502 // Traverse instructions in reverse order within the basic block. 503 for (Instruction inst = bblock.lastInstruction(); inst != bblock.firstInstruction(); inst = 504 inst.prevInstructionInCodeOrder()) { 505 506 // traverse from defs to uses becauses uses happen after 507 // (in a backward sense) defs 508 Enumeration<Operand> defs = inst.getPureDefs(); 509 while (defs.hasMoreElements()) { 510 Operand def = defs.nextElement(); 511 if (def instanceof RegisterOperand) { 512 RegisterOperand regOp = (RegisterOperand) def; 513 514 // Do we care about this reg? 515 if (isSkippableReg(regOp, ir)) { 516 continue; 517 } 518 TypeReference regType = regOp.getType(); 519 520 // Because the summary we compute is used to propagate to other 521 // basic blocks, if a register is block local, we don't need to 522 // include it. It will be picked up later by local propagation phase. 523 if (regOp.getRegister().spansBasicBlock() && regType != null) { 524 525 // if it is a DEF we place it is the BBKillSet and remove it from 526 // the GEN set, (GEN should only contain upward-exposed uses, 527 // i.e., uses that are NOT dominated by a DEF). 528 // We don't need to worry about PEIs here because 529 // later instructions (traversing backwards like we are) 530 // will always dominate earlier instructions *of this block* 531 bbLiveInfo[bblock.getNumber()].BBKillSet().add(regOp); 532 bbLiveInfo[bblock.getNumber()].getGen().remove(regOp); 533 534 // However, if an exception can emanate from this basic block 535 // we are not guaranteed that all instructions will be executed 536 // in this block. We allow killing of instructions 537 // after the last (in a backwards sense) potential exception 538 // throwing statement. (PEI) 539 // If there are no PEIs in this block we don't bother to add 540 if (seenFirstPEI) { 541 bbLiveInfo[bblock.getNumber()].firstPEIKillSet().add(regOp); 542 } 543 } 544 } 545 } 546 547 // Now process the uses, unless this is a PHI operator 548 if (inst.operator() != PHI) { 549 for (Enumeration<Operand> uses = inst.getUses(); uses.hasMoreElements();) { 550 Operand use = uses.nextElement(); 551 if (use instanceof RegisterOperand) { 552 RegisterOperand regOp = (RegisterOperand) use; 553 554 // Do we care about this reg? 555 if (isSkippableReg(regOp, ir)) { 556 continue; 557 } 558 559 TypeReference regType = regOp.getType(); 560 561 // Because the summary we compute is used to propagate to 562 // other basic blocks, if a register is block local, 563 // we don't need to include it. It will be picked up 564 // later by local propagation phase. 565 if (regOp.getRegister().spansBasicBlock() && regType != null) { 566 bbLiveInfo[bblock.getNumber()].getGen().add(regOp); 567 } 568 } // is RegOp 569 } // foreach use 570 } // not a PHI 571 // check whether the instruction we just processed is the first 572 // (last, thinking backwards) exception-raising instruction. 573 // If so, set the flag so we can start killing. 574 if (firstPEI == inst) { 575 seenFirstPEI = true; 576 } 577 } // foreach instruction in block 578 if (VERBOSE) { 579 System.out.println(" Gen: " + bbLiveInfo[bblock.getNumber()].getGen()); 580 System.out.println(" Kill: " + bbLiveInfo[bblock.getNumber()].BBKillSet()); 581 System.out.println(" 1st PEI Kill: " + bbLiveInfo[bblock.getNumber()].firstPEIKillSet()); 582 System.out.println(" ---> Done computing Gen/Kill for block"); 583 } 584 } 585 586 /** 587 * The rvals of phi nodes are logically uses in the phi's predecessor 588 * blocks, so here we collect phi rvals from the current block's 589 * successors into the gen set for this block, being careful to 590 * collect only the appropriate rval 591 * 592 * @param bblock the basic block of interest 593 * 594 * pre: Assumes the liveInfo array is allocated for this block 595 * post: May add to liveInfo for this block 596 */ 597 private void getUsesFromPhis(BasicBlock bblock) { 598 Enumeration<BasicBlock> successors = bblock.getOut(); 599 while (successors.hasMoreElements()) { 600 BasicBlock sb = successors.nextElement(); 601 if (sb.isExit()) { 602 continue; 603 } 604 605 for (Instruction phi = sb.firstInstruction(); phi != sb.lastInstruction(); phi = 606 phi.nextInstructionInCodeOrder()) { 607 if (phi.operator() == PHI) { 608 for (int j = 0; j < Phi.getNumberOfValues(phi); j++) { 609 BasicBlockOperand bbop = Phi.getPred(phi, j); 610 if (bbop.block == bblock) { 611 Operand myRval = Phi.getValue(phi, j); 612 if (myRval instanceof RegisterOperand) { 613 RegisterOperand regOp = (RegisterOperand) myRval; 614 TypeReference regType = regOp.getType(); 615 if (regOp.getRegister().spansBasicBlock() && regType != null) { 616 bbLiveInfo[bblock.getNumber()].getGen().add(regOp); 617 } 618 } 619 } 620 } 621 } 622 } 623 } 624 } 625 626 /** 627 * Compute the in set for this block given the out, gen, and kill set 628 * @param block the block of interest 629 * @param reuseCurrentSet whether we can reuse the "currentSet" or else 630 * clear it out and recompute the meet of our succs 631 * @param ir the governing ir 632 */ 633 private boolean processBlock(BasicBlock block, boolean reuseCurrentSet, IR ir) { 634 if (VERBOSE) { 635 System.out.println(" *** processing block " + block + " # out edges: " + block.getNumberOfOut()); 636 block.printExtended(); 637 } 638 639 // We compute Gen and Kill the first time we process the block. 640 // This computation must happen early iun this method because it also computes 641 // summary information about the block (eg getContainsPEIWithHandler). 642 if (bbLiveInfo[block.getNumber()].BBKillSet() == null) { 643 bbLiveInfo[block.getNumber()].createKillAndGen(); 644 computeBlockGenAndKill(block, ir); 645 } 646 647 // A summary of the IN sets of all exception handlers for the block 648 LiveSet exceptionBlockSummary = new LiveSet(); 649 650 boolean blockHasHandlers = bbLiveInfo[block.getNumber()].getContainsPEIWithHandler(); 651 652 // The computation of the Kill set takes into consideration exception 653 // semantics, i.e., that live information may flow into the middle 654 // of a basic block due to implicit edges at exception points. 655 // We keep 2 kill sets. 656 // BBKillSet() contains variables that are killed if the block 657 // is exited in the normal fashion 658 // firstPEIKillSet() contains variables that are definitely killed 659 // before the first PEI is executed. 660 // This set contains only variables that are definitely 661 // killed in this block despite the implicit exception edges. 662 // 663 if (!reuseCurrentSet) { 664 currentSet.clear(); 665 666 // visit each successor, if it is a regular successor, add 667 // it to "currentSet". If it is a handler block, add it to 668 // ExceptionBlockSummary. 669 for (Enumeration<BasicBlock> bbEnum = block.getOut(); bbEnum.hasMoreElements();) { 670 BasicBlock succ = bbEnum.nextElement(); 671 672 // sometimes we may have a CFG edge to a handler, but no longer a 673 // PEI that can make the edge realizable. Thus, we have two 674 // conditions in the following test. 675 if (blockHasHandlers && succ.isExceptionHandlerBasicBlock()) { 676 exceptionBlockSummary.add(bbLiveInfo[succ.getNumber()].getIn()); 677 } else { 678 currentSet.add(bbLiveInfo[succ.getNumber()].getIn()); 679 } 680 } 681 } 682 if (VERBOSE) { 683 System.out.println("\t Before applying transfor function:"); 684 System.out.println("\t currentSet: " + currentSet); 685 System.out.println("\t exceptionBlockSummary: " + exceptionBlockSummary); 686 } 687 688 // At this point, currentSet contains the union of our normal successors' 689 // IN sets. 690 // Compute: In = currentSet - BBKillSet 691 // U (exceptionBlockSummary - firstPEIKillSet) (1) 692 // U Gen 693 // Since firstPEIKillSet is a subset of BBKillSet, we don't need the 694 // the parenthesis (and the intermediate set) 695 // 696 // If there are no handlers than exceptionBlockSummary is empty and 697 // we don't need to perform line (1) 698 699 // currentSet = currentSet - BBKillSet 700 // first kill off variables that are killed anywhere in the block 701 currentSet.remove(bbLiveInfo[block.getNumber()].BBKillSet()); 702 if (blockHasHandlers) { 703 704 // currentSet = currentSet U exceptionBlockSummary 705 // add in the IN sets for the handlers 706 currentSet.add(exceptionBlockSummary); 707 708 // currentSet = currentSet - firstPEIKillSet 709 // kill off variables that are definitely killed, i.e., killed before 710 // the first PEI 711 currentSet.remove(bbLiveInfo[block.getNumber()].firstPEIKillSet()); 712 } 713 714 // currentSet = currentSet U gen 715 // add in the GEN set 716 currentSet.add(bbLiveInfo[block.getNumber()].getGen()); 717 718 // since we have monotonicity, we can add currentSet to 719 // the previous In set. If it results in an addition we have 720 // a change and return true, otherwise return false. 721 if (bbLiveInfo[block.getNumber()].getIn().add(currentSet)) { 722 if (VERBOSE) { 723 System.out.println(" *** processBlock returning true, currentSet: " + currentSet); 724 } 725 return true; 726 } else { 727 if (VERBOSE) { 728 System.out.println(" *** processBlock returning false, currentSet: " + currentSet); 729 } 730 return false; 731 } 732 } 733 734 /** 735 * This method performs the last phase of the analysis, local propagation. 736 * It uses the results from the fixed point analysis to determine the 737 * local live information within a basic block.<p> 738 * 739 * It walks the IR and, using the live information computed for each 740 * basic block, i.e., the results of the iterative solution, makes a single 741 * pass backward walk through the basic block, GENing and KILLing 742 * local information. This produces the set of live variables at each 743 * instruction.<p> 744 * 745 * This information is saved into two data structures: 746 * <ul> 747 * <li>at all GC points, live references are recorded 748 * <li>at all instructions, live range information is recorded 749 * </ul> 750 * 751 * @param ir the IR 752 */ 753 private void performLocalPropagation(IR ir, boolean createGCMaps) { 754 if (DEBUG) { 755 System.out.println(" .... starting local propagation\n"); 756 } 757 Stack<MapElement> blockStack = null; 758 if (createGCMaps) { 759 // We want to add GC map entries in IR instruction order. However, we are 760 // visiting instructions in reverse order within a block. We solve this 761 // by pushing all additions to a local stack and pop (and add) 762 // the information to the GC map after the block has been processed. 763 blockStack = new Stack<MapElement>(); 764 } 765 for (BasicBlock block = ir.firstBasicBlockInCodeOrder(); block != null; block = 766 block.nextBasicBlockInCodeOrder()) { 767 if (VERBOSE) { 768 System.out.print(" .... processing block # " + block.getNumber() + " ..."); 769 } 770 771 // This set will hold the live variables for the current 772 // instruction. It is initialized from the "In" set of the block's 773 // successors and updated during the walk up the basic block. 774 LiveSet local = new LiveSet(); 775 776 // The union of the IN sets of all exception blocks that can 777 // be reached (directly) from this block 778 LiveSet exceptionBlockSummary = new LiveSet(); 779 780 // Create the out set by unioning the successors' in sets. 781 // During this processing we should NOT include exception-catching 782 // blocks, but instead remember them for use at exception-raising 783 // statements in this block 784 for (Enumeration<BasicBlock> bbEnum = block.getOut(); bbEnum.hasMoreElements();) { 785 BasicBlock succ = bbEnum.nextElement(); 786 if (succ.isExceptionHandlerBasicBlock()) { 787 exceptionBlockSummary.add(bbLiveInfo[succ.getNumber()].getIn()); 788 } else { 789 local.add(bbLiveInfo[succ.getNumber()].getIn()); 790 } 791 } 792 if (VERBOSE) { 793 System.out.println(" Completed succ walk. exceptionBlockSummary: " + 794 exceptionBlockSummary + 795 "\n local: " + 796 local); 797 } 798 799 // initialize live range for this block 800 block.initializeLiveRange(); 801 802 // For each item in "local", create live interval info for this block. 803 LiveInterval.createEndLiveRange(local, block, null); 804 805 // Process the block, an instruction at a time. 806 for (Instruction inst = block.lastInstruction(); inst != block.firstInstruction(); inst = 807 inst.prevInstructionInCodeOrder()) { 808 if (VERBOSE) { 809 System.out.println("Processing: " + inst); 810 } 811 812 // If this instruction can raise an exception, then the catch 813 // block can be a direct successor to it 814 // To compensate this, we must first add in the live information 815 // for all such blocks, which we computed above and stored 816 // in "exceptionBlockSummary" 817 if (inst.isPEI()) { 818 local.add(exceptionBlockSummary); 819 820 // For each item in "exceptionBlockSummary", create live interval 821 // info for this block. 822 LiveInterval.createEndLiveRange(exceptionBlockSummary, block, inst); 823 } 824 825 // compute In set for this instruction & GC point info 826 // traverse from defs to uses, do "kill" then "gen" (backwards analysis) 827 // Def loop 828 for (Enumeration<Operand> defs = inst.getPureDefs(); defs.hasMoreElements();) { 829 Operand op = defs.nextElement(); 830 if (op instanceof RegisterOperand) { 831 RegisterOperand regOp = (RegisterOperand) op; 832 // Currently, clients of live information do not need to know 833 // about validation reges. (Reg Alloc cares about physical regs.) 834 if (isSkippableReg(regOp, ir)) { 835 continue; 836 } 837 if (regOp.getType() != null) { 838 // process the def as a kill 839 local.remove(regOp); 840 if (VERBOSE) { 841 System.out.println(" Killing: " + regOp + "\n local: " + local); 842 } 843 844 // mark this instruction as the start of the live range for reg 845 LiveInterval.setStartLiveRange(regOp.getRegister(), inst, block); 846 } 847 } // if operand is a Register 848 } // defs 849 850 // GC Map Code: 851 // 852 // Now that we have processed all of the defs, if any, we check 853 // if the instruction is a potential GC point, insert it into 854 // the map. 855 // We do this after processing the defs (remember, this is a backward 856 // analysis) because the GC will occur (at least in the case of calls) 857 // after the uses have occurred (in the forward sense). Thus, we 858 // don't yet factor in the uses for this instruction. 859 // For a statement like "x = y", we are capturing the program point 860 // "in the middle", i.e., during the execution, after the y has been 861 // fetched, but before the x has been defined. 862 863 // Above observation is not true for an OSR instruction. The current 864 // design of the OSR instruction requires the compiler build a GC map 865 // for variables used by the instruction. 866 // Otherwise, the compiler generates an empty gc map for the 867 // instruction. This results run away references if GC happens 868 // when a thread is being OSRed. 869 // 870 // TODO: better design of yieldpoint_osr instruction. 871 // -- Feng July 15, 2003 872 if (createGCMaps && !OsrPoint.conforms(inst) && inst.isGCPoint()) { 873 // make deep copy (and translate to regList) because we reuse 874 // local above. 875 // NOTE: this translation does some screening, see GCIRMap.java 876 List<RegSpillListElement> regList = map.createDU(local); 877 blockStack.push(new MapElement(inst, regList)); 878 if (VERBOSE) { System.out.println("SAVING GC Map"); } 879 } // is GC instruction, and map not already made 880 881 // now process the uses 882 for (Enumeration<Operand> uses = inst.getUses(); uses.hasMoreElements();) { 883 Operand op = uses.nextElement(); 884 if (op instanceof RegisterOperand) { 885 RegisterOperand regOp = (RegisterOperand) op; 886 // Do we care about this reg? 887 if (isSkippableReg(regOp, ir)) { 888 continue; 889 } 890 TypeReference regType = regOp.getType(); 891 // see Def loop comment about magics 892 if (regType != null) { 893 // process the use as a gen 894 local.add(regOp); 895 if (VERBOSE) { 896 System.out.println(" Gen-ing: " + regOp); 897 System.out.println("local: " + local); 898 } 899 // mark this instruction as the end of the live range for reg 900 LiveInterval.createEndLiveRange(regOp.getRegister(), block, inst); 901 } 902 } // if operand is a Register 903 } // uses 904 905 if (createGCMaps && OsrPoint.conforms(inst)) { 906 // delayed gc map generation for Osr instruction, 907 // see comments before processing uses -- Feng, July 15, 2003 908 List<RegSpillListElement> regList = map.createDU(local); 909 blockStack.push(new MapElement(inst, regList)); 910 911 // collect osr info using live set 912 collectOsrInfo(inst, local); 913 } 914 } // end instruction loop 915 916 // The register allocator prefers that any registers that are live 917 // on entry be listed first. This call makes it so. 918 LiveInterval.moveUpwardExposedRegsToFront(block); 919 if (createGCMaps) { 920 // empty the stack, insert the information into the map 921 while (!blockStack.isEmpty()) { 922 MapElement elem = blockStack.pop(); 923 map.insert(elem.getInst(), elem.getList()); 924 } 925 } 926 927 if (storeLiveAtHandlers && block.isExceptionHandlerBasicBlock()) { 928 ExceptionHandlerBasicBlock handlerBlock = (ExceptionHandlerBasicBlock) block; 929 930 // use local because we need to get a fresh one anyway. 931 handlerBlock.setLiveSet(local); 932 local = null; 933 } else { 934 935 // clear the local set for the next block 936 local.clear(); 937 } 938 } // end basic block for loop 939 if (DEBUG) { 940 System.out.println(" .... completed local propagation\n"); 941 } 942 } 943 944 /** 945 * Should this register be included in the liveness solution? 946 * 947 * @param regOp the register operand to consider skipping 948 * @param ir the governing ir 949 * @return whether the register should be skipped, i.e., not be 950 * present in the liveness solution 951 */ 952 private boolean isSkippableReg(RegisterOperand regOp, IR ir) { 953 // The old test would exclude all physical registers. However, 954 // register allocation needs to know about physical registers, except 955 // for the ones listed below. Such regs are inserted in the IR 956 // during call expansion. 957 return regOp.getRegister().isExcludedLiveA() || (regOp.getRegister().isValidation() && skipGuards); 958 } 959 960 /** 961 * Just a helper method to encapsulate the optional debugging info 962 * that is performed at the beginning of the perform method 963 * @param ir the IR 964 * @param createGCMaps are we creating GC maps? 965 * @param dumpFixedPointResults debug info 966 * @param dumpFinalMaps debug info 967 * @param dumpFinalLiveIntervals debug info 968 */ 969 private void debugBegining(IR ir, boolean createGCMaps, boolean dumpFixedPointResults, boolean dumpFinalMaps, boolean dumpFinalLiveIntervals) { 970 if (dumpFixedPointResults || dumpFinalMaps || dumpFinalLiveIntervals) { 971 System.out.print("\n ====> Performing liveness analysis "); 972 if (createGCMaps) { 973 System.out.print("and GC Maps "); 974 } 975 System.out.println("for method: " + ir.method.getName() + " in class: " + ir.method.getDeclaringClass() + "\n"); 976 System.out.println(" method has " + ir.cfg.numberOfNodes() + " basic blocks"); 977 } 978 if (dumpFinalMaps) { 979 System.out.println("**** START OF IR for method: " + 980 ir.method.getName() + 981 " in class: " + 982 ir.method.getDeclaringClass()); 983 ir.printInstructions(); 984 System.out.println("**** END OF IR INSTRUCTION DUMP ****"); 985 } 986 } 987 988 /** 989 * Just a helper method to encapsulate the optional debugging info 990 * that is performed after the global propagation step of "perform" 991 * 992 * @param ir the IR 993 * @param dumpFixedPointResults debug info 994 * @param dumpFinalMaps debug info 995 * @param dumpFinalLiveIntervals debug info 996 */ 997 private void debugPostGlobal(IR ir, boolean dumpFixedPointResults, boolean dumpFinalMaps, boolean dumpFinalLiveIntervals) { 998 if (DEBUG) { 999 System.out.println(" .... Completed global live computation ...."); 1000 if (VERBOSE) { 1001 // Print the basic blocks 1002 System.out.println(" .... CFG:"); 1003 System.out.println(ir.cfg); 1004 } 1005 } 1006 if (dumpFixedPointResults) { 1007 printFixedPointResults(ir); 1008 } 1009 } 1010 1011 /** 1012 * Prints the results of the fixed point computation. 1013 * (Use printFinalMaps for the final GC map) 1014 * @param ir the IR 1015 */ 1016 private void printFixedPointResults(IR ir) { 1017 System.out.println("\n ***** Fixed point results for IR-based GC Maps for " + 1018 ir.method.getDeclaringClass() + 1019 "." + 1020 ir.method.getName()); 1021 int length = bbLiveInfo.length; 1022 for (int i = 0; i < length; i++) { 1023 System.out.println("Live Info for Block #" + i); 1024 System.out.println(bbLiveInfo[i]); 1025 } 1026 } 1027 1028 /** 1029 * Prints the final maps 1030 * @param ir 1031 */ 1032 private void printFinalMaps(IR ir) { 1033 System.out.println("\n =-=-=-=-=- Final IR-based GC Maps for " + 1034 ir.method.getDeclaringClass() + 1035 "." + 1036 ir.method.getName()); 1037 map.dump(); 1038 System.out.println(" =-=-=-=-=- End Final IR-based GC Maps\n"); 1039 } 1040 1041 /** 1042 * Prints the Final Live Intervals 1043 * @param ir the IR 1044 */ 1045 private void printFinalLiveIntervals(IR ir) { 1046 ir.printInstructions(); 1047 System.out.println("\n *+*+*+*+*+ Final Live Intervals for " + 1048 ir.method.getDeclaringClass() + 1049 "." + 1050 ir.method.getName()); 1051 for (BasicBlock block = ir.firstBasicBlockInCodeOrder(); block != null; block = 1052 block.nextBasicBlockInCodeOrder()) { 1053 LiveInterval.printLiveIntervalList(block); 1054 } 1055 System.out.println(" *+*+*+*+*+ End Final Live Intervals\n"); 1056 } 1057 1058 /** 1059 * REturns the live information for a particular block 1060 * @param bb the basic block of interest 1061 * @return the live information for the block 1062 */ 1063 public BBLiveElement getLiveInfo(BasicBlock bb) { 1064 return bbLiveInfo[bb.getNumber()]; 1065 } 1066 1067 /** 1068 * Return the set of registers that are live on the control-flow edge 1069 * basic block bb1 to basic block bb2 1070 */ 1071 public HashSet<Register> getLiveRegistersOnEdge(BasicBlock bb1, BasicBlock bb2) { 1072 HashSet<Register> s1 = getLiveRegistersOnExit(bb1); 1073 HashSet<Register> s2 = getLiveRegistersOnEntry(bb2); 1074 s1.retainAll(s2); 1075 return s1; 1076 } 1077 1078 /** 1079 * Return the set of registers that are live across a basic block, and who 1080 * are live after the basic block exit. 1081 */ 1082 HashSet<Register> getLiveRegistersOnExit(BasicBlock bb) { 1083 HashSet<Register> result = new HashSet<Register>(10); 1084 for (Enumeration<LiveIntervalElement> e = bb.enumerateLiveIntervals(); e.hasMoreElements();) { 1085 LiveIntervalElement lie = e.nextElement(); 1086 Instruction end = lie.getEnd(); 1087 if (end == null) result.add(lie.getRegister()); 1088 } 1089 return result; 1090 } 1091 1092 /** 1093 * Return the set of registers that are live across a basic block, and who 1094 * are live before the basic block entry. 1095 */ 1096 HashSet<Register> getLiveRegistersOnEntry(BasicBlock bb) { 1097 HashSet<Register> result = new HashSet<Register>(10); 1098 for (Enumeration<LiveIntervalElement> e = bb.enumerateLiveIntervals(); e.hasMoreElements();) { 1099 LiveIntervalElement lie = e.nextElement(); 1100 Instruction begin = lie.getBegin(); 1101 if (begin == null) result.add(lie.getRegister()); 1102 } 1103 return result; 1104 } 1105 1106 // A simple class used to store live info 1107 public static final class BBLiveElement { 1108 private LiveSet gen; 1109 private LiveSet BBKillSet; 1110 private LiveSet firstPEIKillSet; 1111 private final LiveSet in; 1112 private boolean containsPEIWithHandler = false; 1113 1114 /** 1115 * The constructor 1116 */ 1117 BBLiveElement() { 1118 in = new LiveSet(); 1119 } 1120 1121 /** 1122 * Returns the kill set 1123 * @return the Kill set for this block 1124 */ 1125 public LiveSet BBKillSet() { 1126 return BBKillSet; 1127 } 1128 1129 /** 1130 * Returns the first PEI kill set, i.e., the Kill set up to the first PEI 1131 * @return the Kill set up to the first PEI 1132 */ 1133 public LiveSet firstPEIKillSet() { 1134 return firstPEIKillSet; 1135 } 1136 1137 /** 1138 * Returns the Gen set 1139 * @return the Gen set for this block 1140 */ 1141 public LiveSet getGen() { 1142 return gen; 1143 } 1144 1145 /** 1146 * Returns the In set 1147 * @return the In set for this block 1148 */ 1149 public LiveSet getIn() { 1150 return in; 1151 } 1152 1153 /** 1154 * Returns whether this block has a PEI with a handler in this method 1155 * @return whether this block has a PEI with a handler in this method 1156 */ 1157 public boolean getContainsPEIWithHandler() { 1158 return containsPEIWithHandler; 1159 } 1160 1161 /** 1162 * @param value whether this block has a PEI with a handler in this method 1163 */ 1164 public void setContainsPEIWithHandler(boolean value) { 1165 containsPEIWithHandler = value; 1166 } 1167 1168 /** 1169 * creates (allocates) the Gen and Kill Sets 1170 */ 1171 public void createKillAndGen() { 1172 BBKillSet = new LiveSet(); 1173 firstPEIKillSet = new LiveSet(); 1174 gen = new LiveSet(); 1175 } 1176 1177 /** 1178 * creates a string representation of this object 1179 * @return string representation of this object 1180 */ 1181 @Override 1182 public String toString() { 1183 StringBuilder buf = new StringBuilder(""); 1184 buf.append(" Gen: ").append(gen).append("\n"); 1185 buf.append(" BB Kill: ").append(BBKillSet).append("\n"); 1186 buf.append(" first PEI Kill: ").append(firstPEIKillSet).append("\n"); 1187 buf.append(" In: ").append(in).append("\n"); 1188 return buf.toString(); 1189 } 1190 1191 } 1192 1193 /** 1194 * A simple class used just in this file when creating GC maps 1195 */ 1196 static final class MapElement { 1197 1198 private final Instruction inst; 1199 private final List<RegSpillListElement> list; 1200 1201 /** 1202 * constructor 1203 * @param inst 1204 * @param list 1205 */ 1206 public MapElement(Instruction inst, List<RegSpillListElement> list) { 1207 this.inst = inst; 1208 this.list = list; 1209 } 1210 1211 /** 1212 * returns the instruction 1213 * @return the instruction 1214 */ 1215 public Instruction getInst() { 1216 return inst; 1217 } 1218 1219 /** 1220 * returns the list 1221 * @return the list 1222 */ 1223 public List<RegSpillListElement> getList() { 1224 return list; 1225 } 1226 } 1227 1228 /* collect osr info according to live information */ 1229 private void collectOsrInfo(Instruction inst, LiveSet lives) { 1230 // create an entry to the OSRIRMap, order: callee => caller 1231 LinkedList<MethodVariables> mvarList = new LinkedList<MethodVariables>(); 1232 1233 // get the type info for locals and stacks 1234 InlinedOsrTypeInfoOperand typeInfo = OsrPoint.getInlinedTypeInfo(inst); 1235 1236 /* iterator over type info and create LocalRegTuple 1237 * for each variable. 1238 * NOTE: we do not process LONG type register operand here, 1239 * which was splitted in BURS. 1240 */ 1241 byte[][] ltypes = typeInfo.localTypeCodes; 1242 byte[][] stypes = typeInfo.stackTypeCodes; 1243 1244 int nummeth = typeInfo.methodids.length; 1245 1246 int elm_idx = 0; 1247 int snd_long_idx = typeInfo.validOps; 1248 for (int midx = 0; midx < nummeth; midx++) { 1249 1250 LinkedList<LocalRegPair> tupleList = new LinkedList<LocalRegPair>(); 1251 1252 byte[] ls = ltypes[midx]; 1253 byte[] ss = stypes[midx]; 1254 1255 /* record maps for local variables, skip dead ones */ 1256 for (int i = 0, n = ls.length; i < n; i++) { 1257 if (ls[i] != VoidTypeCode) { 1258 // check liveness 1259 Operand op = OsrPoint.getElement(inst, elm_idx++); 1260 LocalRegPair tuple = new LocalRegPair(OSRConstants.LOCAL, i, ls[i], op); 1261 // put it in the list 1262 tupleList.add(tuple); 1263 1264 // get another half of a long type operand 1265 if (VM.BuildFor32Addr && (ls[i] == LongTypeCode)) { 1266 Operand other_op = OsrPoint.getElement(inst, snd_long_idx++); 1267 tuple._otherHalf = new LocalRegPair(OSRConstants.LOCAL, i, ls[i], other_op); 1268 1269 } 1270 } 1271 } 1272 1273 /* record maps for stack slots */ 1274 for (int i = 0, n = ss.length; i < n; i++) { 1275 if (ss[i] != VoidTypeCode) { 1276 LocalRegPair tuple = 1277 new LocalRegPair(OSRConstants.STACK, i, ss[i], OsrPoint.getElement(inst, elm_idx++)); 1278 1279 tupleList.add(tuple); 1280 1281 if (VM.BuildFor32Addr && (ss[i] == LongTypeCode)) { 1282 tuple._otherHalf = 1283 new LocalRegPair(OSRConstants.STACK, i, ss[i], OsrPoint.getElement(inst, snd_long_idx++)); 1284 } 1285 } 1286 } 1287 1288 // create MethodVariables 1289 MethodVariables mvar = new MethodVariables(typeInfo.methodids[midx], typeInfo.bcindexes[midx], tupleList); 1290 mvarList.add(mvar); 1291 } 1292 1293 // put the method variables for this OSR in the osrMap, encoding later. 1294 osrMap.insertFirst(inst, mvarList); 1295 } 1296 }