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    }