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