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 }