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.baseline; 014 015 import org.jikesrvm.VM; 016 import org.jikesrvm.classloader.BytecodeConstants; 017 import org.jikesrvm.classloader.BytecodeStream; 018 import org.jikesrvm.classloader.ExceptionHandlerMap; 019 import org.jikesrvm.classloader.NormalMethod; 020 021 /** 022 * Analyze the byte codes and determine the boundaries of the 023 * basic blocks. Used for building the reference maps for a 024 * method. 025 */ 026 final class BuildBB implements BytecodeConstants, BBConstants { 027 028 // ---------------- Static Class Fields -------------------- 029 030 /** Types of Instructions */ 031 private static enum InstructionType { 032 NONBRANCH, CONDITIONAL_BRANCH, BRANCH 033 }; 034 035 //***************************************************************************// 036 // // 037 // Once the method determineTheBasicBlocks is complete, these 4 items // 038 // basicBlocks, byteToBlockMap, numJsrs and gcPointCount will be // 039 // appropriately filled in. They will be accessed by BuildReferenceMaps // 040 // BuildLiveRefMaps, so that the reference maps can be built. // 041 // // 042 //***************************************************************************// 043 044 /** 045 * basic blocks of the byte code 046 */ 047 public BasicBlockFactory bbf; 048 public BasicBlock[] basicBlocks; 049 050 /** 051 * identify which block a byte is part of 052 */ 053 public short[] byteToBlockMap; 054 055 /** 056 * Number of unique jsr targets processed 057 */ 058 public int numJsrs; 059 060 /** 061 * Number of GC points found 062 */ 063 public int gcPointCount; 064 065 // This variable is used in multiple methods of this class, make it accessible 066 int bytelength; 067 068 /** 069 * Analyze the bytecodes and build the basic blocks with their predecessors. 070 * The results will be used by BuildReferenceMaps 071 */ 072 public void determineTheBasicBlocks(NormalMethod method) { 073 ExceptionHandlerMap exceptions; // Used to get a hold of the try Start, End and Handler lists 074 int[] retList; // List of basic block numbers that end with a "ret" instruction. 075 BytecodeStream bcodes; // The bytecodes being analyzed. 076 BasicBlock currentBB; // current basic block being processed 077 InstructionType lastInstrType;// type of the last instruction 078 int lastInstrStart;// byte index where last instruction started 079 080 // 081 // Initialization 082 // 083 int nextRetList = 0; 084 numJsrs = 0; 085 gcPointCount = 1; // All methods have the possible thread switch in prologue 086 087 bcodes = method.getBytecodes(); 088 bytelength = bcodes.length(); 089 090 byteToBlockMap = new short[bytelength]; 091 basicBlocks = new BasicBlock[2]; // many methods only have one block (+1 for EXIT) 092 093 bbf = new BasicBlockFactory(); 094 095 exceptions = method.getExceptionHandlerMap(); 096 097 retList = null; 098 099 // 100 // Set up the EXIT basic block 101 // 102 basicBlocks[BasicBlock.EXITBLOCK] = new BasicBlock(bytelength, bytelength, BasicBlock.EXITBLOCK); 103 104 // 105 // Get the first basic block 106 // 107 currentBB = bbf.newBlock(0); 108 addBasicBlock(currentBB); 109 currentBB.setState(BasicBlock.METHODENTRY); 110 lastInstrType = InstructionType.NONBRANCH; 111 lastInstrStart = 0; 112 113 if (exceptions != null) { 114 // Get blocks for any handlers, which tend to not be a clear block boundaries 115 // 116 setupHandlerBBs(exceptions); 117 118 // Set up blocks for start of try block, which tend not be to at clear 119 // block boundaries 120 // 121 setupTryStartBBs(exceptions); 122 } 123 124 // 125 // Scan the bytecodes for this method 126 // 127 while (bcodes.hasMoreBytecodes()) { 128 // Determine if we are at a block boundary 129 // We are at a block boundary if: 130 // 1) non-branch instruction followed by a known block 131 // 2) last instruction was a conditional branch 132 // 3) last instruction was a branch 133 // Note that forward branches mean that the byteToBlockMap will have 134 // a basic block value prior to us examining that destination byte code 135 // 136 if (lastInstrType == InstructionType.NONBRANCH) { 137 if (byteToBlockMap[bcodes.index()] == BasicBlock.NOTBLOCK) { 138 // Not a new block 139 // Make note of current block 140 byteToBlockMap[bcodes.index()] = (short) currentBB.getBlockNumber(); 141 } else { 142 // Earlier forward branch must have started this block 143 currentBB.setEnd(lastInstrStart); 144 basicBlocks[byteToBlockMap[bcodes.index()]].addPredecessor(currentBB); 145 currentBB = basicBlocks[byteToBlockMap[bcodes.index()]]; 146 } 147 } else { // we are at a block boundary, last instr was some type of branch 148 if (lastInstrType == InstructionType.CONDITIONAL_BRANCH) { 149 currentBB.setEnd(lastInstrStart); 150 // See if we need a new block 151 if (byteToBlockMap[bcodes.index()] == BasicBlock.NOTBLOCK) { 152 BasicBlock newBB = bbf.newBlock(bcodes.index()); 153 addBasicBlock(newBB); 154 newBB.addPredecessor(currentBB); 155 currentBB = newBB; 156 // Make note of current block 157 byteToBlockMap[bcodes.index()] = (short) currentBB.getBlockNumber(); 158 } else { 159 // From an earlier forward branch 160 basicBlocks[byteToBlockMap[bcodes.index()]].addPredecessor(currentBB); 161 currentBB = basicBlocks[byteToBlockMap[bcodes.index()]]; 162 } 163 } else { 164 if (lastInstrType == InstructionType.BRANCH) { 165 currentBB.setEnd(lastInstrStart); 166 // See if we need a new block 167 if (byteToBlockMap[bcodes.index()] == BasicBlock.NOTBLOCK) { 168 BasicBlock newBB = bbf.newBlock(bcodes.index()); 169 addBasicBlock(newBB); 170 currentBB = newBB; 171 // Make note of current block 172 byteToBlockMap[bcodes.index()] = (short) currentBB.getBlockNumber(); 173 } else { 174 // From an earlier forward branch 175 currentBB = basicBlocks[byteToBlockMap[bcodes.index()]]; 176 } 177 } 178 } 179 } 180 // end of determining if at block boundary 181 182 // Now examine this instruction 183 lastInstrStart = bcodes.index(); // Instruction starts here 184 lastInstrType = InstructionType.NONBRANCH; // assume it will be a non-branch 185 switch (bcodes.nextInstruction()) { 186 case JBC_ifeq: 187 case JBC_ifne: 188 case JBC_iflt: 189 case JBC_ifge: 190 case JBC_ifgt: 191 case JBC_ifle: 192 case JBC_if_icmpeq: 193 case JBC_if_icmpne: 194 case JBC_if_icmplt: 195 case JBC_if_icmpge: 196 case JBC_if_icmpgt: 197 case JBC_if_icmple: 198 case JBC_if_acmpeq: 199 case JBC_if_acmpne: 200 case JBC_ifnull: 201 case JBC_ifnonnull: { 202 lastInstrType = InstructionType.CONDITIONAL_BRANCH; 203 int offset = bcodes.getBranchOffset(); 204 if (offset <= 0) gcPointCount++; // gc map required if backward edge 205 int branchtarget = lastInstrStart + offset; 206 processBranchTarget(lastInstrStart, branchtarget); 207 break; 208 } 209 210 case JBC_jsr: { 211 lastInstrType = InstructionType.BRANCH; 212 int offset = bcodes.getBranchOffset(); 213 int branchtarget = lastInstrStart + offset; 214 processBranchTarget(lastInstrStart, branchtarget); 215 int jsrentryBBNum = byteToBlockMap[branchtarget]; 216 BasicBlock bb = basicBlocks[jsrentryBBNum]; 217 if ((bb.getState() & BasicBlock.JSRENTRY) == 0) numJsrs++; 218 bb.setState(BasicBlock.JSRENTRY); 219 gcPointCount = gcPointCount + 1; 220 break; 221 } 222 223 case JBC_jsr_w: { 224 lastInstrType = InstructionType.BRANCH; 225 int offset = bcodes.getWideBranchOffset(); 226 int branchtarget = lastInstrStart + offset; 227 processBranchTarget(lastInstrStart, branchtarget); 228 int jsrentryBBNum = byteToBlockMap[branchtarget]; 229 BasicBlock bb = basicBlocks[jsrentryBBNum]; 230 if ((bb.getState() & BasicBlock.JSRENTRY) == 0) numJsrs++; 231 bb.setState(BasicBlock.JSRENTRY); 232 gcPointCount = gcPointCount + 1; 233 break; 234 } 235 236 case JBC_goto: { 237 lastInstrType = InstructionType.BRANCH; 238 int offset = bcodes.getBranchOffset(); 239 if (offset <= 0) gcPointCount++; // gc map required if backward edge 240 int branchtarget = lastInstrStart + offset; 241 processBranchTarget(lastInstrStart, branchtarget); 242 break; 243 } 244 245 case JBC_goto_w: { 246 lastInstrType = InstructionType.BRANCH; 247 int offset = bcodes.getWideBranchOffset(); 248 if (offset <= 0) gcPointCount++; // gc map required if backward edge 249 int branchtarget = lastInstrStart + offset; 250 processBranchTarget(lastInstrStart, branchtarget); 251 break; 252 } 253 254 case JBC_tableswitch: { 255 lastInstrType = InstructionType.BRANCH; 256 bcodes.alignSwitch(); 257 int def = bcodes.getDefaultSwitchOffset(); 258 processBranchTarget(lastInstrStart, lastInstrStart + def); 259 int low = bcodes.getLowSwitchValue(); 260 int high = bcodes.getHighSwitchValue(); 261 int n = high - low + 1; // n = number of normal cases (0..n-1) 262 263 // generate labels for offsets 264 for (int i = 0; i < n; i++) { 265 int offset = bcodes.getTableSwitchOffset(i); 266 processBranchTarget(lastInstrStart, lastInstrStart + offset); 267 } 268 bcodes.skipTableSwitchOffsets(n); 269 break; 270 } 271 272 case JBC_lookupswitch: { 273 lastInstrType = InstructionType.BRANCH; 274 bcodes.alignSwitch(); 275 int def = bcodes.getDefaultSwitchOffset(); 276 int npairs = bcodes.getSwitchLength(); 277 processBranchTarget(lastInstrStart, lastInstrStart + def); 278 279 // generate label for each offset in table 280 for (int i = 0; i < npairs; i++) { 281 int offset = bcodes.getLookupSwitchOffset(i); 282 processBranchTarget(lastInstrStart, lastInstrStart + offset); 283 } 284 bcodes.skipLookupSwitchPairs(npairs); 285 break; 286 } 287 288 case JBC_ireturn: 289 case JBC_lreturn: 290 case JBC_freturn: 291 case JBC_dreturn: 292 case JBC_areturn: 293 case JBC_return: { 294 lastInstrType = InstructionType.BRANCH; 295 basicBlocks[BasicBlock.EXITBLOCK].addPredecessor(currentBB); 296 if (method.isSynchronized() || VM.UseEpilogueYieldPoints) { 297 gcPointCount++; 298 } 299 break; 300 } 301 302 case JBC_ret: { 303 lastInstrType = InstructionType.BRANCH; 304 bcodes.getLocalNumber(); // index 305 int blocknum = currentBB.getBlockNumber(); 306 basicBlocks[blocknum].setState(BasicBlock.JSREXIT); 307 308 // Worry about growing retListarray 309 if (retList == null) retList = new int[10]; 310 if (nextRetList >= retList.length) { 311 int[] biggerRetList = new int[nextRetList + 10]; 312 for (int i = 0; i < nextRetList; i++) { 313 biggerRetList[i] = retList[i]; 314 } 315 retList = biggerRetList; 316 biggerRetList = null; 317 } 318 retList[nextRetList++] = blocknum; 319 break; 320 } 321 322 case JBC_wide: { 323 int widecode = bcodes.getWideOpcode(); 324 bcodes.getWideLocalNumber(); // index 325 if (widecode == JBC_ret) { 326 lastInstrType = InstructionType.BRANCH; 327 int blocknum = currentBB.getBlockNumber(); 328 basicBlocks[blocknum].setState(BasicBlock.JSREXIT); 329 330 // Worry about growing retListarray 331 if (retList == null) retList = new int[10]; 332 if (nextRetList >= retList.length) { 333 int[] biggerRetList = new int[nextRetList + 10]; 334 for (int i = 0; i < nextRetList; i++) { 335 biggerRetList[i] = retList[i]; 336 } 337 retList = biggerRetList; 338 biggerRetList = null; 339 } 340 retList[nextRetList++] = blocknum; 341 } else if (widecode == JBC_iinc) { 342 bcodes.getWideIncrement(); 343 } else { 344 // nothing more to do 345 } 346 break; 347 } 348 349 case JBC_athrow: { 350 lastInstrType = InstructionType.BRANCH; 351 processAthrow(exceptions, lastInstrStart); 352 gcPointCount++; 353 break; 354 } 355 356 case JBC_aaload: 357 case JBC_iaload: 358 case JBC_faload: 359 case JBC_baload: 360 case JBC_caload: 361 case JBC_saload: 362 case JBC_laload: 363 case JBC_daload: 364 case JBC_lastore: 365 case JBC_dastore: 366 case JBC_iastore: 367 case JBC_fastore: 368 case JBC_aastore: 369 case JBC_bastore: 370 case JBC_castore: 371 case JBC_sastore: 372 case JBC_putfield: 373 case JBC_getfield: 374 case JBC_getstatic: 375 case JBC_putstatic: 376 case JBC_irem: 377 case JBC_idiv: 378 case JBC_lrem: 379 case JBC_ldiv: 380 case JBC_invokevirtual: 381 case JBC_invokespecial: 382 case JBC_invokestatic: 383 case JBC_invokeinterface: 384 case JBC_instanceof: 385 case JBC_checkcast: 386 case JBC_monitorenter: 387 case JBC_monitorexit: 388 case JBC_new: 389 case JBC_newarray: 390 case JBC_anewarray: 391 case JBC_multianewarray: { 392 bcodes.skipInstruction(); 393 byteToBlockMap[lastInstrStart] = (short) currentBB.getBlockNumber(); 394 gcPointCount = gcPointCount + 1; 395 break; 396 } 397 398 default: { 399 bcodes.skipInstruction(); 400 byteToBlockMap[lastInstrStart] = (short) currentBB.getBlockNumber(); 401 break; 402 } 403 } // switch (opcode) 404 } // while (bcodes.hasMoreBytecodes) 405 406 currentBB.setEnd(lastInstrStart); // close off last block 407 408 // process try and catch blocks 409 if (exceptions != null) { 410 // process catch blocks 411 processExceptionHandlers(exceptions); 412 // mark all blocks in try sections as being part of a try 413 markTryBlocks(exceptions); 414 } 415 416 // process ret instructions as last step 417 if (retList != null) { 418 processRetList(retList, nextRetList); 419 } 420 421 // can not support jsrs with unboxed types at the moment 422 if (VM.VerifyAssertions && !VM.BuildForHarmony) VM._assert(VM.runningVM || numJsrs == 0); 423 } 424 425 /********************************/ 426 /* */ 427 /* Routines for Branches */ 428 /* */ 429 /********************************/ 430 431 /** 432 * Processing a branch that appears at location index in the byte code and has a 433 * target index of branchtarget in the byte code. The target of a branch must 434 * start a basic block. So if the byteToBlockMap doesn't already show a basic 435 * block at the target, make one start there. If a basic block is already set 436 * up and this is a branch forward then only need to adjust predecessor list 437 * (we know it is not a branch into the middle of a block as only starts are 438 * marked in byte code beyond "index"). If the basic block is already set up and 439 * this is a backward branch then we must check if the block needs splitting, 440 * branching to the middle of a block is not allowed. 441 */ 442 private void processBranchTarget(int index, int branchtarget) { 443 444 BasicBlock newBB, currentBB; 445 if (byteToBlockMap[branchtarget] == BasicBlock.NOTBLOCK) { 446 newBB = bbf.newBlock(branchtarget); 447 addBasicBlock(newBB); 448 byteToBlockMap[branchtarget] = (short) newBB.getBlockNumber(); 449 currentBB = basicBlocks[byteToBlockMap[index]]; 450 newBB.addPredecessor(currentBB); 451 } else if (index > branchtarget) { 452 // This is a backwards branch 453 processBackwardBranch(index, branchtarget); 454 } else { 455 // This is a forward branch to an existing block, need to register 456 // the predecessor 457 currentBB = basicBlocks[byteToBlockMap[index]]; 458 basicBlocks[byteToBlockMap[branchtarget]].addPredecessor(currentBB); 459 } 460 } 461 462 /** 463 * A backwards branch has been found from the byte code at location "index" 464 * to a target location of "branchtarget". Need to make sure that the 465 * branchtarget location is the start of a block (and if not, then split the 466 * existing block into two) Need to register the block that ends at "index" 467 * as a predecessor of the block that starts at branchtarget. 468 */ 469 private void processBackwardBranch(int index, int branchtarget) { 470 BasicBlock existingBB, currentBB, newBB; 471 int newBlockNum, i, newBlockEnd; 472 473 existingBB = basicBlocks[byteToBlockMap[branchtarget]]; 474 if (existingBB.getStart() != branchtarget) { 475 // Need to split the existing block in two, by ending the existing block 476 // at the previous instruction and starting a new block at the branchtarget. 477 // Need to split the existing block in two. It is best to set up the new 478 // block to end at the instruction before the target and the existing 479 // block to start at the target. That way the tail stays the same. 480 481 newBB = bbf.newBlock(existingBB.getStart()); 482 addBasicBlock(newBB); 483 newBlockNum = newBB.getBlockNumber(); 484 existingBB.setStart(branchtarget); 485 486 // Find the last instruction prior to the branch target; 487 // that's the end of the new block 488 // 489 for (i = branchtarget - 1; byteToBlockMap[i] == BasicBlock.NOTBLOCK; i--) {} 490 491 newBlockEnd = i; 492 newBB.setEnd(i); 493 494 // Going forwards, mark the start of each instruction with the new block 495 // number 496 // 497 for (i = newBB.getStart(); i <= newBlockEnd; i++) { 498 if (byteToBlockMap[i] != BasicBlock.NOTBLOCK) { 499 byteToBlockMap[i] = (short) newBlockNum; 500 } 501 } 502 503 BasicBlock.transferPredecessors(existingBB, newBB); 504 505 // The new block is a predecessor of the existing block 506 existingBB.addPredecessor(newBB); 507 } else { 508 // Nice coincidence, the existing block starts at "branchtarget" 509 } 510 511 // Now mark the "current" block (the one that ends at "index") as a predecessor 512 // of the target block (which is either the existing block or a newly made 513 // block) 514 // 515 currentBB = basicBlocks[byteToBlockMap[index]]; 516 existingBB.addPredecessor(currentBB); 517 } 518 519 /********************************/ 520 /* */ 521 /* Routines for JSR/Ret */ 522 /* */ 523 /********************************/ 524 525 /** 526 * process the effect of the ret instructions on the precedance table 527 */ 528 private void processRetList(int[] retList, int nextRetList) { 529 // block 0 not used 530 int otherRetCount; 531 for (int i = 0; i < nextRetList; i++) { 532 int retBlockNum = retList[i]; 533 BasicBlock retBB = basicBlocks[retBlockNum]; 534 boolean[] seenAlready = new boolean[bbf.getNumberofBlocks() + 1]; 535 otherRetCount = 0; 536 findAndSetJSRCallSite(retBlockNum, retBB, otherRetCount, seenAlready); 537 } 538 } 539 540 /** 541 * scan back from ret instruction to jsr call sites 542 */ 543 private void findAndSetJSRCallSite(int pred, BasicBlock retBB, int otherRetCount, boolean[] seenAlready) { 544 seenAlready[pred] = true; 545 BasicBlock jsrBB = basicBlocks[pred]; 546 jsrBB.setState(BasicBlock.INJSR); 547 548 if (basicBlocks[pred].isJSRExit() && pred != retBB.getBlockNumber()) { 549 otherRetCount++; 550 } 551 552 if (basicBlocks[pred].isJSREntry()) { 553 if (otherRetCount == 0) { 554 // setup call site 555 setupJSRCallSite(basicBlocks[pred], retBB); 556 return; 557 } else { 558 otherRetCount--; 559 } 560 } 561 int[] predecessors = basicBlocks[pred].getPredecessors(); 562 for (int predecessor : predecessors) { 563 if (!seenAlready[predecessor]) { 564 findAndSetJSRCallSite(predecessor, retBB, otherRetCount, seenAlready); 565 } 566 } 567 } 568 569 /** 570 * setup jsr call site 571 */ 572 private void setupJSRCallSite(BasicBlock entryBB, BasicBlock retBB) { 573 int newBB; 574 int[] callsites = entryBB.getPredecessors(); 575 int callLength = callsites.length; 576 for (int i = 0; i < callLength; i++) { 577 int callsite = callsites[i]; 578 int blockend = basicBlocks[callsite].getEnd(); 579 for (newBB = blockend + 1; byteToBlockMap[newBB] == BasicBlock.NOTBLOCK; newBB++) ; 580 int nextBlock = byteToBlockMap[newBB]; 581 basicBlocks[nextBlock].addPredecessor(retBB); 582 } 583 } 584 585 /********************************/ 586 /* */ 587 /* Routines for Try/catch */ 588 /* */ 589 /********************************/ 590 591 /** 592 * For every handler, make a block that starts with the handler PC 593 * Only called when exceptions is not null. 594 */ 595 private void setupHandlerBBs(ExceptionHandlerMap exceptions) { 596 int[] tryHandlerPC = exceptions.getHandlerPC(); 597 int tryLength = tryHandlerPC.length; 598 for (int i = 0; i < tryLength; i++) { 599 if (byteToBlockMap[tryHandlerPC[i]] == BasicBlock.NOTBLOCK) { 600 BasicBlock handlerBB = bbf.newBlock(tryHandlerPC[i]); 601 handlerBB.setState(BasicBlock.TRYHANDLERSTART); 602 addBasicBlock(handlerBB); 603 byteToBlockMap[tryHandlerPC[i]] = (short) handlerBB.getBlockNumber(); 604 } 605 } 606 } 607 608 /** 609 * For every try start, make a block that starts with the Try start, 610 * mark it as a try start. Only called when exceptions is not null. 611 */ 612 private void setupTryStartBBs(ExceptionHandlerMap exceptions) { 613 int[] tryStartPC = exceptions.getStartPC(); 614 int tryLength = tryStartPC.length; 615 for (int i = 0; i < tryLength; i++) { 616 if (byteToBlockMap[tryStartPC[i]] == BasicBlock.NOTBLOCK) { 617 BasicBlock tryStartBB = bbf.newBlock(tryStartPC[i]); 618 addBasicBlock(tryStartBB); 619 byteToBlockMap[tryStartPC[i]] = (short) tryStartBB.getBlockNumber(); 620 tryStartBB.setState(BasicBlock.TRYSTART); 621 } 622 } 623 } 624 625 /** 626 * For every handler, mark the blocks in its try block as its predecessors. 627 * Only called when exceptions is not null. 628 */ 629 private void processExceptionHandlers(ExceptionHandlerMap exceptions) { 630 int[] tryStartPC = exceptions.getStartPC(); 631 int[] tryEndPC = exceptions.getEndPC(); 632 int[] tryHandlerPC = exceptions.getHandlerPC(); 633 int tryLength = tryHandlerPC.length; 634 for (int i = 0; i < tryLength; i++) { 635 int handlerBBNum = byteToBlockMap[tryHandlerPC[i]]; 636 BasicBlock tryHandlerBB = basicBlocks[handlerBBNum]; 637 int throwBBNum = 0; 638 for (int k = tryStartPC[i]; k < tryEndPC[i]; k++) { 639 if (byteToBlockMap[k] == BasicBlock.NOTBLOCK) continue; 640 641 if (byteToBlockMap[k] != throwBBNum) { 642 throwBBNum = byteToBlockMap[k]; 643 BasicBlock throwBB = basicBlocks[throwBBNum]; 644 tryHandlerBB.addUniquePredecessor(throwBB); 645 } 646 } 647 } 648 } 649 650 /** 651 * Mark all the blocks within try range as being Try blocks 652 * used for determining the stack maps for Handler blocks 653 * Only called when exceptions is not null. 654 */ 655 private void markTryBlocks(ExceptionHandlerMap exceptions) { 656 int[] tryStartPC = exceptions.getStartPC(); 657 int[] tryEndPC = exceptions.getEndPC(); 658 int tryLength = tryStartPC.length; 659 int tryBlockNum = 0; 660 for (int i = 0; i < tryLength; i++) { 661 for (int j = tryStartPC[i]; j < tryEndPC[i]; j++) { 662 if (byteToBlockMap[j] != BasicBlock.NOTBLOCK) { 663 if (tryBlockNum != byteToBlockMap[j]) { 664 tryBlockNum = byteToBlockMap[j]; 665 basicBlocks[tryBlockNum].setState(BasicBlock.TRYBLOCK); 666 } 667 } 668 } 669 } 670 } 671 672 /** 673 * Check if an athrow is within a try block, if it is, then handlers have this 674 * block as their predecessor; which is registered in "processExceptionHandlers" 675 * Otherwise, the athrow acts as a branch to the exit and that should be marked 676 * here. Note exceptions may be null. 677 */ 678 private void processAthrow(ExceptionHandlerMap exceptions, int athrowIndex) { 679 if (exceptions != null) { 680 int[] tryStartPC = exceptions.getStartPC(); 681 int[] tryEndPC = exceptions.getEndPC(); 682 int tryLength = tryStartPC.length; 683 // Check if this athrow index is within any of the try blocks 684 for (int i = 0; i < tryLength; i++) { 685 if (tryStartPC[i] <= athrowIndex && athrowIndex < tryEndPC[i]) { 686 return; // found it 687 } 688 } 689 } 690 691 BasicBlock athrowBB = basicBlocks[byteToBlockMap[athrowIndex]]; 692 basicBlocks[BasicBlock.EXITBLOCK].addPredecessor(athrowBB); 693 } 694 695 /********************************/ 696 /* */ 697 /* Misc routines */ 698 /* */ 699 /********************************/ 700 701 /** 702 * add a basic block to the list 703 */ 704 private void addBasicBlock(BasicBlock newBB) { 705 // Check whether basicBlock array must be grown. 706 // 707 int blocknum = newBB.getBlockNumber(); 708 if (blocknum >= basicBlocks.length) { 709 int currentSize = basicBlocks.length; 710 int newSize = 15; 711 if (currentSize != 2) { 712 if (currentSize == 15) { 713 newSize = bytelength >> 4; // assume 16 bytecodes per basic block 714 } else { 715 newSize = currentSize + currentSize >> 3; // increase by 12.5% 716 } 717 if (newSize <= blocknum) { 718 newSize = blocknum + 20; 719 } 720 } 721 BasicBlock[] biggerBlocks = new BasicBlock[newSize]; 722 for (int i = 0; i < currentSize; i++) { 723 biggerBlocks[i] = basicBlocks[i]; 724 } 725 basicBlocks = biggerBlocks; 726 } 727 728 // Go ahead and add block 729 basicBlocks[blocknum] = newBB; 730 } 731 }