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.ir; 014 015 import static org.jikesrvm.compilers.opt.ir.Operators.ATHROW_opcode; 016 import static org.jikesrvm.compilers.opt.ir.Operators.BBEND_opcode; 017 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_IFCMP_opcode; 018 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_IFCMP_opcode; 019 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO_opcode; 020 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2_opcode; 021 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP_opcode; 022 import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE; 023 import static org.jikesrvm.compilers.opt.ir.Operators.LABEL; 024 import static org.jikesrvm.compilers.opt.ir.Operators.LABEL_opcode; 025 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_IFCMP_opcode; 026 import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH_opcode; 027 import static org.jikesrvm.compilers.opt.ir.Operators.LOWTABLESWITCH; 028 import static org.jikesrvm.compilers.opt.ir.Operators.PHI_opcode; 029 import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP_opcode; 030 import static org.jikesrvm.compilers.opt.ir.Operators.RETURN_opcode; 031 import static org.jikesrvm.compilers.opt.ir.Operators.TABLESWITCH_opcode; 032 033 import java.util.ArrayList; 034 import java.util.Enumeration; 035 import java.util.HashSet; 036 import java.util.Stack; 037 038 import org.jikesrvm.VM; 039 import org.jikesrvm.ArchitectureSpecificOpt.RegisterPool; 040 import org.jikesrvm.ArchitectureSpecificOpt.StackManager; 041 import org.jikesrvm.classloader.NormalMethod; 042 import org.jikesrvm.classloader.TypeReference; 043 import org.jikesrvm.compilers.common.CompiledMethod; 044 import org.jikesrvm.compilers.common.CompiledMethods; 045 import org.jikesrvm.compilers.opt.DefUse; 046 import org.jikesrvm.compilers.opt.OptOptions; 047 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 048 import org.jikesrvm.compilers.opt.bc2ir.GenerationContext; 049 import org.jikesrvm.compilers.opt.driver.CompilationPlan; 050 import org.jikesrvm.compilers.opt.driver.CompilerPhase; 051 import org.jikesrvm.compilers.opt.driver.InstrumentationPlan; 052 import org.jikesrvm.compilers.opt.inlining.InlineOracle; 053 import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand; 054 import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand; 055 import org.jikesrvm.compilers.opt.ir.operand.HeapOperand; 056 import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand; 057 import org.jikesrvm.compilers.opt.ir.operand.Operand; 058 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 059 import org.jikesrvm.compilers.opt.regalloc.GenericStackManager; 060 import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; 061 import org.jikesrvm.compilers.opt.ssa.HeapVariable; 062 import org.jikesrvm.compilers.opt.ssa.SSAOptions; 063 import org.jikesrvm.util.BitVector; 064 import org.vmmagic.pragma.NoInline; 065 066 /** 067 * An <code>IR</code> object (IR is short for Intermediate Representation) 068 * contains all the per-compilation information associated with 069 * a method that is being compiled. 070 * <p> 071 * <code>IR</code> objects are intended to be transitory. 072 * They are created to compile a particular method under a 073 * given {@link CompilationPlan compilation plan} 074 * and are discarded once the compilation plan has been completed. 075 * <p> 076 * The primary component of the IR is the 077 * {@link ControlFlowGraph <em>FCFG</em>} (factored control flow graph) 078 * The FCFG contains 079 * {@link Instruction intermediate language instructions} 080 * grouped into {@link BasicBlock factored basic blocks}. 081 * In addition to the FCFG, an <code>IR</code> object also 082 * contains a variety of other supporting and derived data structures. 083 * <p> 084 * 085 * @see ControlFlowGraph 086 * @see BasicBlock 087 * @see Instruction 088 * @see Operator 089 * @see Operand 090 */ 091 public final class IR { 092 093 /** 094 * Control for (dynamic) IR invariant checking. 095 * By default, SANITY_CHECK == {@link VM#VerifyAssertions}. 096 * When SANITY_CHECK is <code>true</code>, critical invariants 097 * are checked by complex routines that depend on them, 098 * and {@link #verify(String) verify} is invoked several times 099 * during compilation. 100 */ 101 public static final boolean SANITY_CHECK = VM.VerifyAssertions; 102 103 /** 104 * Control for (dynamic) IR invariant checking. 105 * By default PARANOID is <code>false</code>. 106 * PARANOID must not be true unless {@link VM#VerifyAssertions} 107 * is also <code>true</code>. 108 * When PARANOID is <code>true</code> many IR utility functions 109 * check the invariants on which they depend, and 110 * {@link #verify(String,boolean)} is invoked as each 111 * compilation phase is 112 * {@link CompilerPhase#performPhase(IR) performed}. 113 */ 114 public static final boolean PARANOID = false && SANITY_CHECK; 115 116 /** Part of an enumerated type used to encode IR Level */ 117 public static final byte UNFORMED = 0; 118 /** Part of an enumerated type used to encode IR Level */ 119 public static final byte HIR = 1; 120 /** Part of an enumerated type used to encode IR Level */ 121 public static final byte LIR = 2; 122 /** Part of an enumerated type used to encode IR Level */ 123 public static final byte MIR = 3; 124 125 /** 126 * The {@link NormalMethod} object corresponding to the 127 * method being compiled. Other methods may have been inlined into 128 * the IR during compilation, so method really only represents the 129 * primary or outermost method being compiled. 130 */ 131 public final NormalMethod method; 132 133 /** 134 * The specialized parameters to be used in place of those defined 135 * in the NormalMethod. 136 */ 137 public final TypeReference[] params; 138 139 /** 140 * @return The {@link NormalMethod} object corresponding to the 141 * method being compiled. Other methods may have been inlined into 142 * the IR during compilation, so method really only represents the 143 * primary or outermost method being compiled. 144 */ 145 public NormalMethod getMethod() { 146 return method; 147 } 148 149 /** 150 * The compiled method created to hold the result of this compilation. 151 */ 152 public final OptCompiledMethod compiledMethod; 153 154 /** 155 * The compiler {@link OptOptions options} that apply 156 * to the current compilation. 157 */ 158 public final OptOptions options; 159 160 /** 161 * {@link SSAOptions Options} that define the SSA properties 162 * desired the next time we enter SSA form. 163 */ 164 public SSAOptions desiredSSAOptions; 165 166 /** 167 * {@link SSAOptions Options} that define the SSA properties 168 * currently carried by the IR. Compiler phases that are invoked 169 * on SSA form should update this object to reflect transformations 170 * on SSA form. 171 */ 172 public SSAOptions actualSSAOptions; 173 174 /** 175 * Are we in SSA form? 176 */ 177 public boolean inSSAForm() { 178 return (actualSSAOptions != null) && actualSSAOptions.getScalarValid(); 179 } 180 181 /** 182 * Are we in SSA form that's broken awaiting re-entry? 183 */ 184 public boolean inSSAFormAwaitingReEntry() { 185 return (actualSSAOptions != null) && !actualSSAOptions.getScalarValid(); 186 } 187 188 /** 189 * The root {@link GenerationContext generation context} 190 * for the current compilation. 191 */ 192 public GenerationContext gc; 193 194 /** 195 * The {@link InlineOracle inlining oracle} to be used for the 196 * current compilation. 197 * TODO: It would make more sense to have the inlining oracle be 198 * a component of the generation context, but as things currently 199 * stand the IR is created before the generation context. We might be 200 * able to restructure things such that the generation context is 201 * created in the IR constructor and then eliminate this field, 202 * replacing all uses with gc.inlinePlan instead. 203 */ 204 public final InlineOracle inlinePlan; 205 206 /** 207 * Information specifying what instrumentation should be performed 208 * during compilation of this method. 209 */ 210 public final InstrumentationPlan instrumentationPlan; 211 212 /** 213 * The {@link ControlFlowGraph FCFG} (Factored Control Flow Graph) 214 */ 215 public ControlFlowGraph cfg; 216 217 /** 218 * The {@link RegisterPool Register pool} 219 */ 220 public RegisterPool regpool; 221 222 /** 223 * The {@link GenericStackManager stack manager}. 224 */ 225 public final GenericStackManager stackManager = new StackManager(); 226 227 /** 228 * The IR is tagged to identify its level (stage). 229 * As compilation continues, the level monotonically 230 * increases from {@link #UNFORMED} to {@link #HIR} 231 * to {@link #LIR} to {@link #MIR}. 232 */ 233 public byte IRStage = UNFORMED; 234 235 /** 236 * Was liveness for handlers computed? 237 */ 238 private boolean handlerLivenessComputed = false; 239 240 /** 241 * Pointer to the HIRInfo for this method. 242 * Valid only if {@link #IRStage}>=HIR 243 */ 244 public HIRInfo HIRInfo; 245 246 /** 247 * Pointer to the LIRInfo for this method. 248 * Valid only if {@link #IRStage}>=LIR. 249 */ 250 public LIRInfo LIRInfo; 251 252 /** 253 * Pointer to the MIRInfo for this method. 254 * Valid only if {@link #IRStage}>=MIR. 255 */ 256 public MIRInfo MIRInfo; 257 258 /** 259 * Backing store for {@link #getBasicBlock(int)}. 260 */ 261 private BasicBlock[] basicBlockMap; 262 263 /** 264 * Does this IR include a syscall? 265 * Initialized during lir to mir conversion; 266 */ 267 private boolean hasSysCall = false; 268 269 public boolean hasSysCall() { return hasSysCall; } 270 271 public void setHasSysCall(boolean b) { hasSysCall = b; } 272 273 /** 274 * @param m The method to compile 275 * @param ip The inlining oracle to use for the compilation 276 * @param opts The options to use for the compilation 277 */ 278 public IR(NormalMethod m, InlineOracle ip, OptOptions opts) { 279 method = m; 280 params = null; 281 options = opts; 282 inlinePlan = ip; 283 instrumentationPlan = null; 284 compiledMethod = (OptCompiledMethod) CompiledMethods.createCompiledMethod(method, CompiledMethod.OPT); 285 } 286 287 /** 288 * @param m The method to compile 289 * @param cp The compilation plan to execute 290 */ 291 public IR(NormalMethod m, CompilationPlan cp) { 292 method = m; 293 params = cp.params; 294 options = cp.options; 295 inlinePlan = cp.inlinePlan; 296 instrumentationPlan = cp.instrumentationPlan; 297 compiledMethod = (OptCompiledMethod) CompiledMethods.createCompiledMethod(method, CompiledMethod.OPT); 298 } 299 300 /** 301 * Print the instructions in this IR to System.out. 302 */ 303 public void printInstructions() { 304 for (Enumeration<Instruction> e = forwardInstrEnumerator(); e.hasMoreElements();) { 305 Instruction i = e.nextElement(); 306 System.out.print(i.bcIndex + "\t" + i); 307 308 // Print block frequency with the label instruction 309 if (i.operator() == LABEL) { 310 BasicBlock bb = i.getBasicBlock(); 311 System.out.print(" Frequency: " + bb.getExecutionFrequency()); 312 } 313 314 System.out.println(); 315 } 316 } 317 318 /** 319 * Should strictfp be adhered to for the given instructions? 320 */ 321 public boolean strictFP(Instruction... is) { 322 for (Instruction i : is) { 323 if (i.position.method.isStrictFP()) { 324 return true; 325 } 326 } 327 return false; 328 } 329 330 /** 331 * Return the first instruction with respect to 332 * the current code linearization order. 333 * 334 * @return the first instruction in the code order 335 */ 336 public Instruction firstInstructionInCodeOrder() { 337 return firstBasicBlockInCodeOrder().firstInstruction(); 338 } 339 340 /** 341 * Return the last instruction with respect to 342 * the current code linearization order. 343 * 344 * @return the last instruction in the code order 345 */ 346 public Instruction lastInstructionInCodeOrder() { 347 return lastBasicBlockInCodeOrder().lastInstruction(); 348 } 349 350 /** 351 * Return the first basic block with respect to 352 * the current code linearization order. 353 * 354 * @return the first basic block in the code order 355 */ 356 public BasicBlock firstBasicBlockInCodeOrder() { 357 return cfg.firstInCodeOrder(); 358 } 359 360 /** 361 * Return the last basic block with respect to 362 * the current code linearization order. 363 * 364 * @return the last basic block in the code order 365 */ 366 public BasicBlock lastBasicBlockInCodeOrder() { 367 return cfg.lastInCodeOrder(); 368 } 369 370 /** 371 * Forward (with respect to the current code linearization order) 372 * iteration over all the instructions in this IR. 373 * The IR must <em>not</em> be modified during the iteration. 374 * 375 * @return an enumeration that enumerates the 376 * instructions in forward code order. 377 */ 378 public Enumeration<Instruction> forwardInstrEnumerator() { 379 return IREnumeration.forwardGlobalIE(this); 380 } 381 382 /** 383 * Reverse (with respect to the current code linearization order) 384 * iteration over all the instructions in this IR. 385 * The IR must <em>not</em> be modified during the iteration. 386 * 387 * @return an enumeration that enumerates the 388 * instructions in reverse code order. 389 */ 390 public Enumeration<Instruction> reverseInstrEnumerator() { 391 return IREnumeration.reverseGlobalIE(this); 392 } 393 394 /** 395 * Enumerate the basic blocks in the IR in an arbitrary order. 396 * 397 * @return an enumeration of {@link BasicBlock}s that enumerates the 398 * basic blocks in an arbitrary order. 399 */ 400 public Enumeration<BasicBlock> getBasicBlocks() { 401 return IREnumeration.forwardBE(this); 402 } 403 404 /** 405 * Forward (with respect to the current code linearization order) 406 * iteration overal all the basic blocks in the IR. 407 * 408 * @return an enumeration of {@link BasicBlock}s that enumerates the 409 * basic blocks in forward code order. 410 */ 411 public Enumeration<BasicBlock> forwardBlockEnumerator() { 412 return IREnumeration.forwardBE(this); 413 } 414 415 /** 416 * Reverse (with respect to the current code linearization order) 417 * iteration overal all the basic blocks in the IR. 418 * 419 * @return an enumeration of {@link BasicBlock}s that enumerates the 420 * basic blocks in reverse code order. 421 */ 422 public Enumeration<BasicBlock> reverseBlockEnumerator() { 423 return IREnumeration.reverseBE(this); 424 } 425 426 /** 427 * Return an enumeration of the parameters to the IR 428 * Warning: Only valid before register allocation (see CallingConvention) 429 * 430 * @return the parameters of the IR. 431 */ 432 public Enumeration<Operand> getParameters() { 433 for (Instruction s = firstInstructionInCodeOrder(); true; s = s.nextInstructionInCodeOrder()) { 434 if (s.operator() == IR_PROLOGUE) { 435 return s.getDefs(); 436 } 437 } 438 } 439 440 /** 441 * Is the operand a parameter of the IR? 442 * Warning: Only valid before register allocation (see CallingConvention) 443 * 444 * @param op the operand to check 445 * @return {@code true} if the op is a parameter to the IR, {@code false} otherwise 446 */ 447 public boolean isParameter(Operand op) { 448 for (Enumeration<Operand> e = getParameters(); e.hasMoreElements();) { 449 if (e.nextElement().similar(op)) return true; 450 } 451 return false; 452 } 453 454 /** 455 * How many bytes of parameters does this method take? 456 */ 457 public int incomingParameterBytes() { 458 int nWords = method.getParameterWords(); 459 // getParameterWords() does not include the implicit 'this' parameter. 460 if (!method.isStatic()) nWords++; 461 return nWords << 2; 462 } 463 464 /** 465 * Recompute the basic block map, so can use getBasicBlock(int) 466 * to index into the basic blocks quickly. 467 * TODO: think about possibly keeping the basic block map up-to-date 468 * automatically (Use a hashtable, perhaps?). 469 */ 470 public void resetBasicBlockMap() { 471 basicBlockMap = new BasicBlock[getMaxBasicBlockNumber() + 1]; 472 for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) { 473 BasicBlock block = bbEnum.nextElement(); 474 basicBlockMap[block.getNumber()] = block; 475 } 476 } 477 478 /** 479 * Get the basic block with a given number. 480 * PRECONDITION: {@link #resetBasicBlockMap} has been called 481 * before calling this function, but after making any changes to 482 * the set of basic blocks in the IR. 483 * 484 * @param number the number of the basic block to retrieve 485 * @return that requested block 486 */ 487 public BasicBlock getBasicBlock(int number) { 488 if (VM.VerifyAssertions) VM._assert(basicBlockMap != null); 489 return basicBlockMap[number]; 490 } 491 492 /** 493 * Get an enumeration of all the basic blocks whose numbers 494 * appear in the given BitSet. 495 * PRECONDITION: {@link #resetBasicBlockMap} has been called 496 * before calling this function, but after making any changes to 497 * the set of basic blocks in the IR. 498 * 499 * @param bits The BitSet that defines which basic blocks to 500 * enumerate. 501 * @return an enumeration of said blocks. 502 */ 503 public Enumeration<BasicBlock> getBasicBlocks(BitVector bits) { 504 return new BitSetBBEnum(this, bits); 505 } 506 507 // TODO: It would be easy to avoid creating the Stack if we switch to 508 // the "advance" pattern used in BasicBlock.BBEnum. 509 // TODO: Make this an anonymous local class. 510 private static final class BitSetBBEnum implements Enumeration<BasicBlock> { 511 private final Stack<BasicBlock> stack; 512 513 BitSetBBEnum(IR ir, BitVector bits) { 514 stack = new Stack<BasicBlock>(); 515 int size = bits.length(); 516 Enumeration<BasicBlock> bbEnum = ir.getBasicBlocks(); 517 while (bbEnum.hasMoreElements()) { 518 BasicBlock block = bbEnum.nextElement(); 519 int number = block.getNumber(); 520 if (number < size && bits.get(number)) stack.push(block); 521 } 522 } 523 524 @Override 525 public boolean hasMoreElements() { return !stack.empty(); } 526 527 @Override 528 public BasicBlock nextElement() { return stack.pop(); } 529 } 530 531 /** 532 * Densely number all the instructions currently in this IR 533 * from 0...numInstr-1. 534 * Returns the number of instructions in the IR. 535 * Intended style of use: 536 * <pre> 537 * passInfo = new passInfoObjects[ir.numberInstructions()]; 538 * ...do analysis using passInfo as a look aside 539 * array holding pass specific info... 540 * </pre> 541 * 542 * @return the number of instructions 543 */ 544 public int numberInstructions() { 545 int num = 0; 546 for (Instruction instr = firstInstructionInCodeOrder(); instr != null; instr = 547 instr.nextInstructionInCodeOrder(), num++) { 548 instr.scratch = num; 549 } 550 return num; 551 } 552 553 /** 554 * Set the scratch word on all instructions currently in this 555 * IR to a given value. 556 * 557 * @param value value to store in all instruction scratch words 558 */ 559 public void setInstructionScratchWord(int value) { 560 for (Instruction instr = firstInstructionInCodeOrder(); instr != null; instr = 561 instr.nextInstructionInCodeOrder()) { 562 instr.scratch = value; 563 } 564 } 565 566 /** 567 * Clear (set to zero) the scratch word on all 568 * instructions currently in this IR. 569 */ 570 public void clearInstructionScratchWord() { 571 setInstructionScratchWord(0); 572 } 573 574 /** 575 * Clear (set to {@code null}) the scratch object on 576 * all instructions currently in this IR. 577 */ 578 public void clearInstructionScratchObject() { 579 for (Instruction instr = firstInstructionInCodeOrder(); instr != null; instr = 580 instr.nextInstructionInCodeOrder()) { 581 instr.scratchObject = null; 582 } 583 } 584 585 /** 586 * Clear (set to {@code null}) the scratch object on 587 * all basic blocks currently in this IR. 588 */ 589 public void clearBasicBlockScratchObject() { 590 Enumeration<BasicBlock> e = getBasicBlocks(); 591 while (e.hasMoreElements()) { 592 e.nextElement().scratchObject = null; 593 } 594 } 595 596 /** 597 * Return the number of symbolic registers for this IR 598 */ 599 public int getNumberOfSymbolicRegisters() { 600 return regpool.getNumberOfSymbolicRegisters(); 601 } 602 603 /** 604 * @return the largest basic block number assigned to 605 * a block in the IR. Will return -1 if no 606 * block numbers have been assigned. 607 */ 608 public int getMaxBasicBlockNumber() { 609 if (cfg == null) { 610 return -1; 611 } else { 612 return cfg.numberOfNodes(); 613 } 614 } 615 616 /** 617 * Prune the exceptional out edges for each basic block in the IR. 618 */ 619 public void pruneExceptionalOut() { 620 if (hasReachableExceptionHandlers()) { 621 for (Enumeration<BasicBlock> e = getBasicBlocks(); e.hasMoreElements();) { 622 BasicBlock bb = e.nextElement(); 623 bb.pruneExceptionalOut(this); 624 } 625 } 626 } 627 628 /** 629 * @return <code>true</code> if it is possible that the IR contains 630 * an exception handler, <code>false</code> if it is not. 631 * Note this method may conservatively return <code>true</code> 632 * even if the IR does not actually contain a reachable 633 * exception handler. 634 */ 635 public boolean hasReachableExceptionHandlers() { 636 return gc.generatedExceptionHandlers; 637 } 638 639 /** 640 * Partially convert the FCFG into a more traditional 641 * CFG by splitting all nodes that contain PEIs and that 642 * have reachable exception handlers into multiple basic 643 * blocks such that the instructions in the block have 644 * the expected post-dominance relationship. Note, we do 645 * not bother to unfactor basic blocks that do not have reachable 646 * exception handlers because the fact that the post-dominance 647 * relationship between instructions does not hold in these blocks 648 * does not matter (at least for intraprocedural analyses). 649 * For more information {@link BasicBlock see}. 650 */ 651 public void unfactor() { 652 Enumeration<BasicBlock> e = getBasicBlocks(); 653 while (e.hasMoreElements()) { 654 BasicBlock b = e.nextElement(); 655 b.unfactor(this); 656 } 657 } 658 659 /** 660 * States whether liveness for handlers is available 661 & @return whether liveness for handlers is available 662 */ 663 public boolean getHandlerLivenessComputed() { 664 return handlerLivenessComputed; 665 } 666 667 /** 668 * Record whether or not liveness information for handlers is available 669 */ 670 public void setHandlerLivenessComputed(boolean value) { 671 handlerLivenessComputed = value; 672 } 673 674 /** 675 * Verify that the IR is well-formed.<p> 676 * NB: this is expensive -- be sure to guard invocations with 677 * debugging flags. 678 * 679 * @param where phrase identifying invoking compilation phase 680 */ 681 public void verify(String where) { 682 verify(where, true); 683 } 684 685 /** 686 * Verify that the IR is well-formed.<p> 687 * NB: this is expensive -- be sure to guard invocations with 688 * debugging flags. 689 * 690 * @param where phrase identifying invoking compilation phase 691 * @param checkCFG should the CFG invariants be checked 692 * (they can become invalid in "late" MIR). 693 */ 694 public void verify(String where, boolean checkCFG) { 695 // Check basic block and the containing instruction construction 696 verifyBBConstruction(where); 697 698 if (checkCFG) { 699 // Check CFG invariants 700 verifyCFG(where); 701 } 702 703 if (IRStage < MIR) { 704 // In HIR or LIR: 705 // Simple def-use tests 706 if (VM.BuildForPowerPC) { 707 // only on PPC as def use doesn't consider def-use 708 verifyRegisterDefs(where); 709 } 710 711 // Verify registers aren't in use for 2 different types 712 verifyRegisterTypes(where); 713 } 714 715 if (PARANOID) { 716 // Follow CFG checking use follows def (ultra-expensive) 717 verifyUseFollowsDef(where); 718 719 // Simple sanity checks on instructions 720 verifyInstructions(where); 721 } 722 723 // Make sure CFG is in fit state for dominators 724 // TODO: Enable this check; currently finds some broken IR 725 // that we need to fix. 726 // verifyAllBlocksAreReachable(where); 727 } 728 729 /** 730 * Verify basic block construction from the basic block and 731 * instruction information. 732 * 733 * @param where phrase identifying invoking compilation phase 734 */ 735 private void verifyBBConstruction(String where) { 736 // First, verify that the basic blocks are properly chained together 737 // and that each basic block's instruction list is properly constructed. 738 BasicBlock cur = cfg.firstInCodeOrder(); 739 BasicBlock prev = null; 740 while (cur != null) { 741 if (cur.getPrev() != prev) { 742 verror(where, "Prev link of " + cur + " does not point to " + prev); 743 } 744 745 // Verify cur's start and end instructions 746 Instruction s = cur.start; 747 Instruction e = cur.end; 748 if (s == null) { 749 verror(where, "Bblock " + cur + " has null start instruction"); 750 } 751 if (e == null) { 752 verror(where, "Bblock " + cur + " has null end instruction"); 753 } 754 755 // cur has start and end instructions, 756 // make sure that they are locally ok. 757 if (!s.isBbFirst()) { 758 verror(where, "Instr " + s + " is first instr of " + cur + " but is not BB_FIRST"); 759 } 760 if (s.getBasicBlock() != cur) { 761 verror(where, "Instr " + s + " is first instr of " + cur + " but points to BBlock " + s.getBasicBlock()); 762 } 763 if (!e.isBbLast()) { 764 verror(where, "Instr " + e + " is last instr of " + cur + " but is not BB_LAST"); 765 } 766 if (e.getBasicBlock() != cur) { 767 verror(where, "Instr " + e + " is last instr of " + cur + " but points to BBlock " + e.getBasicBlock()); 768 } 769 770 // Now check the integrity of the block's instruction list 771 if (s.getPrev() != null) { 772 verror(where, "Instr " + s + " is the first instr of " + cur + " but has a predecessor " + s.getPrev()); 773 } 774 if (e.getNext() != null) { 775 verror(where, "Instr " + s + " is the last instr of " + cur + " but has a successor " + e.getNext()); 776 } 777 Instruction pp = s; 778 Instruction p = s.getNext(); 779 boolean foundBranch = false; 780 while (p != e) { 781 if (p == null) { 782 verror(where, "Fell off the instruction list in " + cur + " before finding " + e); 783 } 784 if (p.getPrev() != pp) { 785 verror(where, "Instr " + pp + " has next " + p + " but " + p + " has prev " + p.getPrev()); 786 } 787 if (!p.isBbInside()) { 788 verror(where, "Instr " + p + " should be inside " + cur + " but is not BBInside"); 789 } 790 if (foundBranch && !p.isBranch()) { 791 printInstructions(); 792 verror(where, "Non branch " + p + " after branch " + pp + " in " + cur); 793 } 794 if (p.isBranch() && p.operator() != LOWTABLESWITCH) { 795 foundBranch = true; 796 if (p.isUnconditionalBranch() && p.getNext() != e) { 797 printInstructions(); 798 verror(where, "Unconditional branch " + p + " does not end its basic block " + cur); 799 } 800 } 801 pp = p; 802 p = p.getNext(); 803 } 804 if (p.getPrev() != pp) { 805 verror(where, "Instr " + pp + " has next " + p + " but " + p + " has prev " + p.getPrev()); 806 } 807 808 // initialize the mark bit for the bblist test below 809 cur.scratch = 0; 810 811 prev = cur; 812 cur = (BasicBlock) cur.getNext(); 813 } 814 } 815 816 /** 817 * Verify control flow graph construction 818 * 819 * @param where phrase identifying invoking compilation phase 820 */ 821 private void verifyCFG(String where) { 822 // Check that the CFG links are well formed 823 final int inBBListMarker = 999; // actual number is insignificant 824 final boolean VERIFY_CFG_EDGES = false; 825 HashSet<BasicBlock> origOutSet = null; 826 if (VERIFY_CFG_EDGES) origOutSet = new HashSet<BasicBlock>(); 827 828 for (BasicBlock cur = cfg.firstInCodeOrder(); cur != null; cur = (BasicBlock) cur.getNext()) { 829 830 // Check incoming edges 831 for (Enumeration<BasicBlock> e = cur.getIn(); e.hasMoreElements();) { 832 BasicBlock pred = e.nextElement(); 833 if (!pred.pointsOut(cur)) { 834 verror(where, pred + " is an inEdge of " + cur + " but " + cur + " is not an outEdge of " + pred); 835 } 836 } 837 838 // Check outgoing edges 839 for (Enumeration<BasicBlock> e = cur.getOut(); e.hasMoreElements();) { 840 BasicBlock succ = e.nextElement(); 841 if (!succ.pointsIn(cur)) { 842 verror(where, succ + " is an outEdge of " + cur + " but " + cur + " is not an inEdge of " + succ); 843 } 844 // Remember the original out edges for CFG edge verification 845 if (VERIFY_CFG_EDGES && IRStage <= LIR) origOutSet.add(succ); 846 } 847 848 if (VERIFY_CFG_EDGES && IRStage <= LIR) { 849 // Next, check that the CFG links are semantically correct 850 // (ie that the CFG links and branch instructions agree) 851 // This done by calling recomputeNormalOut() and confirming 852 // that nothing changes. 853 cur.recomputeNormalOut(this); 854 855 // Confirm outgoing edges didn't change 856 for (Enumeration<BasicBlock> e = cur.getOut(); e.hasMoreElements();) { 857 BasicBlock succ = e.nextElement(); 858 if (!origOutSet.contains(succ) && !succ.isExit() // Sometimes recomput is conservative in adding edge to exit 859 // because it relies soley on the mayThrowUncaughtException 860 // flag. 861 ) { 862 cur.printExtended(); 863 verror(where, 864 "An edge in the cfg was incorrect. " + 865 succ + 866 " was not originally an out edge of " + 867 cur + 868 " but it was after calling recomputeNormalOut()"); 869 } 870 origOutSet.remove(succ); // we saw it, so remove it 871 } 872 // See if there were any edges that we didn't see the second 873 // time around 874 if (!origOutSet.isEmpty()) { 875 BasicBlock missing = origOutSet.iterator().next(); 876 877 cur.printExtended(); 878 verror(where, 879 "An edge in the cfg was incorrect. " + 880 missing + 881 " was originally an out edge of " + 882 cur + 883 " but not after calling recomputeNormalOut()"); 884 } 885 } 886 887 // mark this block because it is the bblist 888 cur.scratch = inBBListMarker; 889 } 890 891 // Check to make sure that all blocks connected 892 // (via a CFG edge) to a block 893 // that is in the bblist are also in the bblist 894 for (BasicBlock cur = cfg.firstInCodeOrder(); cur != null; cur = (BasicBlock) cur.getNext()) { 895 for (Enumeration<BasicBlock> e = cur.getIn(); e.hasMoreElements();) { 896 BasicBlock pred = e.nextElement(); 897 if (pred.scratch != inBBListMarker) { 898 verror(where, 899 "In Method " + 900 method.getName() + 901 ", " + 902 pred + 903 " is an inEdge of " + 904 cur + 905 " but it is not in the CFG!"); 906 } 907 } 908 for (Enumeration<BasicBlock> e = cur.getOut(); e.hasMoreElements();) { 909 BasicBlock succ = e.nextElement(); 910 if (succ.scratch != inBBListMarker) { 911 // the EXIT block is never in the BB list 912 if (succ != cfg.exit()) { 913 verror(where, 914 "In Method " + 915 method.getName() + 916 ", " + 917 succ + 918 " is an outEdge of " + 919 cur + 920 " but it is not in the CFG!"); 921 } 922 } 923 } 924 } 925 } 926 927 /** 928 * Verify that every instruction: 929 * <ul> 930 * <li>1) has operands that back reference it</li> 931 * <li>2) is valid for its position in the basic block</li> 932 * <li>3) if we are MIR, has no guard operands</li> 933 * </ul> 934 * 935 * @param where phrase identifying invoking compilation phase 936 */ 937 private void verifyInstructions(String where) { 938 Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); 939 while (bbEnum.hasMoreElements()) { 940 BasicBlock block = bbEnum.nextElement(); 941 IREnumeration.AllInstructionsEnum instructions = new IREnumeration.AllInstructionsEnum(this, block); 942 boolean startingInstructionsPassed = false; 943 while (instructions.hasMoreElements()) { 944 Instruction instruction = instructions.nextElement(); 945 // Perform (1) and (3) 946 IREnumeration.AllUsesEnum useOperands = new IREnumeration.AllUsesEnum(this, instruction); 947 while (useOperands.hasMoreElements()) { 948 Operand use = useOperands.nextElement(); 949 if (use.instruction != instruction) { 950 verror(where, 951 "In block " + 952 block + 953 " for instruction " + 954 instruction + 955 " the back link in the use of operand " + 956 use + 957 " is invalid and references " + 958 use 959 .instruction); 960 } 961 if ((IRStage >= MIR) && (use.isRegister()) && (use.asRegister().getRegister().isValidation())) { 962 verror(where, 963 "In block " + 964 block + 965 " for instruction " + 966 instruction + 967 " the use operand " + 968 use + 969 " is invalid as it is a validation register and this IR is in MIR form"); 970 } 971 } 972 IREnumeration.AllDefsEnum defOperands = new IREnumeration.AllDefsEnum(this, instruction); 973 while (defOperands.hasMoreElements()) { 974 Operand def = defOperands.nextElement(); 975 if (def.instruction != instruction) { 976 verror(where, 977 "In block " + 978 block + 979 " for instruction " + 980 instruction + 981 " the back link in the def of operand " + 982 def + 983 " is invalid and references " + 984 def 985 .instruction); 986 } 987 if ((IRStage >= MIR) && (def.isRegister()) && (def.asRegister().getRegister().isValidation())) { 988 verror(where, 989 "In block " + 990 block + 991 " for instruction " + 992 instruction + 993 " the def operand " + 994 def + 995 " is invalid as it is a validation register and this IR is in MIR form"); 996 } 997 } 998 // Perform (2) 999 // test for starting instructions 1000 if (!startingInstructionsPassed) { 1001 if (Label.conforms(instruction)) { 1002 continue; 1003 } 1004 if (Phi.conforms(instruction)) { 1005 if ((!inSSAForm()) && (!inSSAFormAwaitingReEntry())) { 1006 verror(where, "Phi node encountered but SSA not computed"); 1007 } 1008 continue; 1009 } 1010 startingInstructionsPassed = true; 1011 } 1012 // main instruction location test 1013 switch (instruction.operator().opcode) { 1014 // Label and phi nodes must be at the start of a BB 1015 case PHI_opcode: 1016 case LABEL_opcode: 1017 verror(where, "Unexpected instruction in the middle of a basic block " + instruction); 1018 // BBend, Goto, IfCmp, TableSwitch, Return, Trap and Athrow 1019 // must all appear at the end of a basic block 1020 case INT_IFCMP_opcode: 1021 case INT_IFCMP2_opcode: 1022 case LONG_IFCMP_opcode: 1023 case FLOAT_IFCMP_opcode: 1024 case DOUBLE_IFCMP_opcode: 1025 case REF_IFCMP_opcode: 1026 instruction = instructions.nextElement(); 1027 if (!Goto.conforms(instruction) && !BBend.conforms(instruction) && !MIR_Branch.conforms(instruction)) { 1028 verror(where, "Unexpected instruction after IFCMP " + instruction); 1029 } 1030 if (Goto.conforms(instruction) || MIR_Branch.conforms(instruction)) { 1031 instruction = instructions.nextElement(); 1032 if (!BBend.conforms(instruction)) { 1033 verror(where, "Unexpected instruction after GOTO/MIR_BRANCH " + instruction); 1034 } 1035 } 1036 if (instructions.hasMoreElements()) { 1037 verror(where, "Unexpected instructions after BBEND " + instructions.nextElement()); 1038 } 1039 break; 1040 case TABLESWITCH_opcode: 1041 case LOOKUPSWITCH_opcode: 1042 case ATHROW_opcode: 1043 case RETURN_opcode: 1044 // TODO: Traps should be at the end of basic blocks but 1045 // Simplify reduces instructions to traps not respecting 1046 // this. Uses of Simplify should eliminate unreachable 1047 // instructions when an instruction not at the end of a 1048 // basic block is reduced into a trap. When this happens 1049 // please uncomment the next line: 1050 //case TRAP_opcode: 1051 case GOTO_opcode: 1052 Instruction next = instructions.nextElement(); 1053 if (!BBend.conforms(next)) { 1054 verror(where, "Unexpected instruction after " + instruction + "\n" + next); 1055 } 1056 if (instructions.hasMoreElements()) { 1057 verror(where, "Unexpected instructions after BBEND " + instructions.nextElement()); 1058 } 1059 break; 1060 case BBEND_opcode: 1061 if (instructions.hasMoreElements()) { 1062 verror(where, "Unexpected instructions after BBEND " + instructions.nextElement()); 1063 } 1064 break; 1065 default: 1066 } 1067 } 1068 } 1069 } 1070 1071 /** 1072 * Verify that every block in the CFG is reachable as failing to do 1073 * so will cause EnterSSA.insertPhiFunctions to possibly access 1074 * elements in DominanceFrontier.getIteratedDominanceFrontier 1075 * and then DominanceFrontier.getDominanceFrontier that aren't 1076 * defined. Also verify that blocks reached over an exception out 1077 * edge are not also reachable on normal out edges as this will 1078 * confuse liveness analysis. 1079 * 1080 * @param where phrase identifying invoking compilation phase 1081 */ 1082 @SuppressWarnings("unused") 1083 // used when needed for debugging 1084 private void verifyAllBlocksAreReachable(String where) { 1085 BitVector reachableNormalBlocks = new BitVector(cfg.numberOfNodes()); 1086 BitVector reachableExceptionBlocks = new BitVector(cfg.numberOfNodes()); 1087 resetBasicBlockMap(); 1088 verifyAllBlocksAreReachable(where, cfg.entry(), reachableNormalBlocks, reachableExceptionBlocks, false); 1089 boolean hasUnreachableBlocks = false; 1090 StringBuffer unreachablesString = new StringBuffer(); 1091 for (int j = 0; j < cfg.numberOfNodes(); j++) { 1092 if (!reachableNormalBlocks.get(j) && !reachableExceptionBlocks.get(j)) { 1093 hasUnreachableBlocks = true; 1094 if (basicBlockMap[j] != null) { 1095 basicBlockMap[j].printExtended(); 1096 } 1097 unreachablesString.append(" BB").append(j); 1098 } 1099 } 1100 if (hasUnreachableBlocks) { 1101 verror(where, "Unreachable blocks in the CFG which will confuse dominators:" + unreachablesString); 1102 } 1103 } 1104 1105 /** 1106 * Verify that every block in the CFG is reachable as failing to do 1107 * so will cause EnterSSA.insertPhiFunctions to possibly access 1108 * elements in DominanceFrontier.getIteratedDominanceFrontier 1109 * and then DominanceFrontier.getDominanceFrontier that aren't 1110 * defined. Also verify that blocks reached over an exception out 1111 * edge are not also reachable on normal out edges as this will 1112 * confuse liveness analysis. 1113 * 1114 * @param where location of verify in compilation 1115 * @param curBB the current BB to work on 1116 * @param visitedNormalBBs the blocks already visited (to avoid cycles) on normal out edges 1117 * @param visitedExceptionalBBs the blocks already visited (to avoid cycles) on exceptional out edges 1118 * @param fromExceptionEdge should paths from exceptions be validated? 1119 */ 1120 private void verifyAllBlocksAreReachable(String where, BasicBlock curBB, BitVector visitedNormalBBs, 1121 BitVector visitedExceptionalBBs, boolean fromExceptionEdge) { 1122 // Set visited information 1123 if (fromExceptionEdge) { 1124 visitedExceptionalBBs.set(curBB.getNumber()); 1125 } else { 1126 visitedNormalBBs.set(curBB.getNumber()); 1127 } 1128 1129 // Recurse to next BBs 1130 Enumeration<BasicBlock> outBlocks = curBB.getNormalOut(); 1131 while (outBlocks.hasMoreElements()) { 1132 BasicBlock out = outBlocks.nextElement(); 1133 if (!visitedNormalBBs.get(out.getNumber())) { 1134 verifyAllBlocksAreReachable(where, out, visitedNormalBBs, visitedExceptionalBBs, false); 1135 } 1136 } 1137 outBlocks = curBB.getExceptionalOut(); 1138 while (outBlocks.hasMoreElements()) { 1139 BasicBlock out = outBlocks.nextElement(); 1140 if (!visitedExceptionalBBs.get(out.getNumber())) { 1141 verifyAllBlocksAreReachable(where, out, visitedNormalBBs, visitedExceptionalBBs, true); 1142 } 1143 if (visitedNormalBBs.get(out.getNumber())) { 1144 curBB.printExtended(); 1145 out.printExtended(); 1146 verror(where, 1147 "Basic block " + 1148 curBB + 1149 " reaches " + 1150 out + 1151 " by normal and exceptional out edges thereby breaking a liveness analysis assumption."); 1152 } 1153 } 1154 if (curBB.mayThrowUncaughtException()) { 1155 visitedExceptionalBBs.set(cfg.exit().getNumber()); 1156 if (!cfg.exit().isExit()) { 1157 cfg.exit().printExtended(); 1158 verror(where, "The exit block is reachable by an exception edge and contains instructions."); 1159 } 1160 } 1161 } 1162 1163 /** 1164 * Verify that every non-physical, non-parameter symbolic register 1165 * that has a use also has at least one def 1166 * 1167 * @param where phrase identifying invoking compilation phase 1168 */ 1169 private void verifyRegisterDefs(String where) { 1170 DefUse.computeDU(this); 1171 //TODO: (SJF)I hate the register list interface. Re-do it. 1172 for (Register r = regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) { 1173 if (r.isPhysical()) continue; 1174 if (r.useList != null) { 1175 if (r.defList == null) { 1176 printInstructions(); 1177 verror(where, "verifyRegisterDefs: " + r + " has use but no defs"); 1178 } 1179 } 1180 } 1181 } 1182 1183 /** 1184 * Verify that no register is used as a long type and an int type 1185 * PRECONDITION: register lists computed 1186 * 1187 * @param where phrase identifying invoking compilation phase 1188 */ 1189 private void verifyRegisterTypes(String where) { 1190 for (Register r = regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) { 1191 // don't worry about physical registers 1192 if (r.isPhysical()) continue; 1193 1194 int types = 0; 1195 if (r.isLong()) types++; 1196 if (r.isDouble()) types++; 1197 if (r.isInteger()) types++; 1198 if (r.isAddress()) types++; 1199 if (r.isFloat()) types++; 1200 if (types > 1) { 1201 verror(where, "Register " + r + " has incompatible types."); 1202 } 1203 } 1204 } 1205 1206 /** 1207 * Check whether uses follow definitions and that in SSA form 1208 * variables aren't multiply defined 1209 */ 1210 private void verifyUseFollowsDef(String where) { 1211 // Create set of defined variables and add registers that will be 1212 // defined before entry to the IR 1213 HashSet<Object> definedVariables = new HashSet<Object>(); 1214 // NB the last two args determine how thorough we're going to test 1215 // things 1216 verifyUseFollowsDef(where, 1217 definedVariables, 1218 cfg.entry(), 1219 new BitVector(cfg.numberOfNodes()), 1220 new ArrayList<BasicBlock>(), 1221 5, 1222 // <-- maximum number of basic blocks followed 1223 true 1224 // <-- follow exception as well as normal out edges? 1225 ); 1226 } 1227 1228 /** 1229 * Check whether uses follow definitions and in SSA form that 1230 * variables aren't multiply defined 1231 * 1232 * @param where location of verify in compilation 1233 * @param definedVariables variables already defined on this path 1234 * @param curBB the current BB to work on 1235 * @param visitedBBs the blocks already visited (to avoid cycles) 1236 * @param path a record of the path taken to reach this basic block 1237 * @param traceExceptionEdges should paths from exceptions be validated? 1238 */ 1239 private void verifyUseFollowsDef(String where, HashSet<Object> definedVariables, BasicBlock curBB, 1240 BitVector visitedBBs, ArrayList<BasicBlock> path, int maxPathLength, 1241 boolean traceExceptionEdges) { 1242 if (path.size() > maxPathLength) { 1243 return; 1244 } 1245 path.add(curBB); 1246 // Process instructions in block 1247 IREnumeration.AllInstructionsEnum instructions = new IREnumeration.AllInstructionsEnum(this, curBB); 1248 while (instructions.hasMoreElements()) { 1249 Instruction instruction = instructions.nextElement(); 1250 // Special phi handling case 1251 if (Phi.conforms(instruction)) { 1252 if ((!inSSAForm()) && (!inSSAFormAwaitingReEntry())) { 1253 verror(where, "Phi node encountered but SSA not computed"); 1254 } 1255 // Find predecessors that we have already visited 1256 for (int i = 0; i < Phi.getNumberOfPreds(instruction); i++) { 1257 BasicBlock phi_pred = Phi.getPred(instruction, i).block; 1258 if (phi_pred.getNumber() > basicBlockMap.length) { 1259 verror(where, "Phi predecessor not a valid basic block " + phi_pred); 1260 } 1261 if ((curBB != phi_pred) && path.contains(phi_pred)) { 1262 // This predecessor has been visited on this path so the 1263 // variable should be defined 1264 Object variable = getVariableUse(where, Phi.getValue(instruction, i)); 1265 if ((variable != null) && (!definedVariables.contains(variable))) { 1266 StringBuffer pathString = new StringBuffer(); 1267 for (int j = 0; j < path.size(); j++) { 1268 pathString.append(path.get(j).getNumber()); 1269 if (j < (path.size() - 1)) { 1270 pathString.append("->"); 1271 } 1272 } 1273 verror(where, "Use of " + variable + " before definition: " + instruction + "\npath: " + pathString); 1274 } 1275 } 1276 } 1277 } else { 1278 // General use follows def test 1279 IREnumeration.AllUsesEnum useOperands = new IREnumeration.AllUsesEnum(this, instruction); 1280 while (useOperands.hasMoreElements()) { 1281 Object variable = getVariableUse(where, useOperands.nextElement()); 1282 if ((variable != null) && (!definedVariables.contains(variable))) { 1283 if (instruction.operator.toString().indexOf("xor") != -1) 1284 continue; 1285 StringBuffer pathString = new StringBuffer(); 1286 for (int i = 0; i < path.size(); i++) { 1287 pathString.append(path.get(i).getNumber()); 1288 if (i < (path.size() - 1)) { 1289 pathString.append("->"); 1290 } 1291 } 1292 verror(where, "Use of " + variable + " before definition: " + instruction + "\npath: " + pathString); 1293 } 1294 } 1295 } 1296 // Add definitions to defined variables 1297 IREnumeration.AllDefsEnum defOperands = new IREnumeration.AllDefsEnum(this, instruction); 1298 while (defOperands.hasMoreElements()) { 1299 Object variable = getVariableDef(where, defOperands.nextElement()); 1300 // Check that a variable isn't defined twice when we believe we're in SSA form 1301 if (variable != null) { 1302 if ((inSSAForm()) && (!inSSAFormAwaitingReEntry())) { 1303 if (definedVariables.contains(variable)) { 1304 verror(where, "Single assignment broken - multiple definitions of " + variable); 1305 } 1306 } 1307 definedVariables.add(variable); 1308 } 1309 } 1310 } 1311 // Recurse to next BBs 1312 visitedBBs.set(curBB.getNumber()); 1313 Enumeration<BasicBlock> outBlocks; 1314 if (traceExceptionEdges) { 1315 outBlocks = curBB.getOut(); // <-- very slow 1316 } else { 1317 outBlocks = curBB.getNormalOut(); 1318 } 1319 while (outBlocks.hasMoreElements()) { 1320 BasicBlock out = outBlocks.nextElement(); 1321 if (!visitedBBs.get(out.getNumber())) { 1322 verifyUseFollowsDef(where, 1323 new HashSet<Object>(definedVariables), 1324 out, 1325 new BitVector(visitedBBs), 1326 new ArrayList<BasicBlock>(path), 1327 maxPathLength, 1328 traceExceptionEdges); 1329 visitedBBs.set(out.getNumber()); 1330 } 1331 } 1332 } 1333 1334 /** 1335 * Get the variable used by this operand 1336 * 1337 * @param where the verification location 1338 * @param operand the operand to pull a variable from 1339 * @return {@code null} if the variable should be ignored otherwise the variable 1340 */ 1341 private Object getVariableUse(String where, Operand operand) { 1342 if (operand.isConstant() || 1343 (operand instanceof ConditionOperand) || 1344 operand.isStringConstant() || 1345 operand.isType() || 1346 operand.isMethod() || 1347 operand.isBranch() || 1348 (operand instanceof BranchProfileOperand) || 1349 operand.isLocation() || 1350 operand.isStackLocation() || 1351 operand.isMemory() || 1352 (operand instanceof TrapCodeOperand) || 1353 (operand instanceof InlinedOsrTypeInfoOperand) || 1354 (Operators.helper.isConditionOperand(operand)) || 1355 (VM.BuildForIA32 && Operators.helper.isBURSManagedFPROperand(operand)) || 1356 (VM.BuildForPowerPC && Operators.helper.isPowerPCTrapOperand(operand))) { 1357 return null; 1358 } else if (operand.isRegister()) { 1359 Register register = operand.asRegister().getRegister(); 1360 // ignore physical registers 1361 return (register.isPhysical()) ? null : register; 1362 } else if (operand.isBlock()) { 1363 Enumeration<BasicBlock> blocks = cfg.basicBlocks(); 1364 while (blocks.hasMoreElements()) { 1365 if (operand.asBlock().block == blocks.nextElement()) { 1366 return null; 1367 } 1368 } 1369 verror(where, "Basic block not found in CFG for BasicBlockOperand: " + operand); 1370 return null; // keep jikes quiet 1371 } else if (operand instanceof HeapOperand) { 1372 if (!actualSSAOptions.getHeapValid()) { 1373 return null; 1374 } 1375 HeapVariable<?> variable = ((HeapOperand<?>) operand).getHeapVariable(); 1376 if (variable.getNumber() > 0) { 1377 return variable; 1378 } else { 1379 // definition 0 comes in from outside the IR 1380 return null; 1381 } 1382 } else { 1383 verror(where, "Unknown variable of " + operand.getClass() + " with operand: " + operand); 1384 return null; // keep jikes quiet 1385 } 1386 } 1387 1388 /** 1389 * Get the variable defined by this operand 1390 * 1391 * @param where the verification location 1392 * @param operand the operand to pull a variable from 1393 * @return {@code null} if the variable should be ignored otherwise the variable 1394 */ 1395 private Object getVariableDef(String where, Operand operand) { 1396 if (operand.isRegister()) { 1397 Register register = operand.asRegister().getRegister(); 1398 // ignore physical registers 1399 return (register.isPhysical()) ? null : register; 1400 } else if (operand instanceof HeapOperand) { 1401 if (!actualSSAOptions.getHeapValid()) { 1402 return null; 1403 } 1404 return ((HeapOperand<?>) operand).getHeapVariable(); 1405 } else if (VM.BuildForIA32 && Operators.helper.isBURSManagedFPROperand(operand)) { 1406 return Operators.helper.getBURSManagedFPRValue(operand); 1407 } else if (operand.isStackLocation() || operand.isMemory()) { 1408 // it would be nice to handle these but they have multiple 1409 // constituent parts :-( 1410 return null; 1411 } else { 1412 verror(where, "Unknown variable of " + operand.getClass() + " with operand: " + operand); 1413 return null; // keep jikes quiet 1414 } 1415 } 1416 1417 /** 1418 * Generate error 1419 * 1420 * @param where phrase identifying invoking compilation phase 1421 * @param msg error message 1422 */ 1423 @NoInline 1424 private void verror(String where, String msg) { 1425 CompilerPhase.dumpIR(this, "Verify: " + where + ": " + method, true); 1426 VM.sysWriteln("VERIFY: " + where + " " + msg); 1427 throw new OptimizingCompilerException("VERIFY: " + where, msg); 1428 } 1429 }