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.bc2ir;
014    
015    import java.util.Enumeration;
016    import java.util.HashSet;
017    import java.util.NoSuchElementException;
018    
019    import org.jikesrvm.VM;
020    import org.jikesrvm.classloader.BytecodeStream;
021    import org.jikesrvm.classloader.ExceptionHandlerMap;
022    import org.jikesrvm.classloader.TypeReference;
023    import org.jikesrvm.compilers.opt.OperationNotImplementedException;
024    import org.jikesrvm.compilers.opt.ir.BasicBlock;
025    import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
026    import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag;
027    import org.jikesrvm.compilers.opt.ir.IRTools;
028    import org.jikesrvm.compilers.opt.ir.Instruction;
029    import org.jikesrvm.compilers.opt.ir.Move;
030    import org.jikesrvm.compilers.opt.ir.operand.Operand;
031    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
032    import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
033    
034    /**
035     * A somewhat complex subtask of IR generation is to discover and maintain
036     * the set of basic blocks that are being generated.
037     * This class encapsulates that functionality.
038     * The backing data store is a red/black tree, but there are a number of
039     * very specialized operations that are performed during search/insertion
040     * so we roll our own instead of using one from the standard library.
041     */
042    final class BBSet implements IRGenOptions {
043      /** root of the backing red/black tree*/
044      private BasicBlockLE root;
045    
046      /**
047       * is it the case that we can ignore JSR processing because
048       * BC2IR has not yet generated a JSR bytecode in this method?
049       */
050      private boolean noJSR = true;
051    
052      /** entry block of the CFG */
053      private final BasicBlockLE entry;
054    
055      /** associated generation context */
056      private final GenerationContext gc;
057    
058      /** associated bytecodes */
059      private final BytecodeStream bcodes;
060    
061      // Fields to support generation/identification of catch blocks
062      /** Start bytecode index for each exception handler ranges */
063      private int[] startPCs;
064    
065      /** End bytecode index for each exception handler range */
066      private int[] endPCs;
067    
068      /** Start bytecode index of each the exception handler */
069      private int[] handlerPCs;
070    
071      /** Type of exception handled by each exception handler range. */
072      private TypeOperand[] exceptionTypes;
073    
074      /**
075       * Initialize the BBSet to handle basic block generation for the argument
076       * generation context and bytecode info.
077       * @param gc the generation context to generate blocks for
078       * @param bcodes the bytecodes of said generation context
079       * @param localState the state of the local variables for the block
080       *                   beginning at bytecode 0.
081       */
082      BBSet(GenerationContext gc, BytecodeStream bcodes, Operand[] localState) {
083        this.gc = gc;
084        this.bcodes = bcodes;
085    
086        // Set up internal data structures to deal with exception handlers
087        parseExceptionTables();
088    
089        // Create the entry block, setting root as a sideffect.
090        entry = _createBBLE(0, null, null, false);
091        entry.setStackKnown();
092        entry.copyIntoLocalState(localState);
093      }
094    
095      /** return the entry BBLE */
096      BasicBlockLE getEntry() { return entry; }
097    
098      /**
099       * Notify the BBSet that BC2IR has encountered a JSR bytecode.
100       * This enables more complex logic in getOrCreateBlock to drive
101       * the basic block specialization that is the key to JSR inlining.
102       */
103      void seenJSR() { noJSR = false; }
104    
105      /**
106       * Return a enumeration of the BasicBlockLE's currently in the BBSet.
107       */
108      Enumeration<BasicBlockLE> contents() {
109        return TreeEnumerator.enumFromRoot(root);
110      }
111    
112      /**
113       * Gets the bytecode index of the block in the set which has the
114       * next-higher bytecode index.
115       * Returns bcodes.length() if x is currently the block with the highest
116       * starting bytecode index.
117       * @param x basic block to start at.
118       */
119      int getNextBlockBytecodeIndex(BasicBlockLE x) {
120        BasicBlockLE nextBBLE = getSuccessor(x, x.low);
121        return nextBBLE == null ? bcodes.length() : nextBBLE.low;
122      }
123    
124      /**
125       * Finds the next ungenerated block, starting at the argument
126       * block and searching forward, wrapping around to the beginning.
127       * If all blocks are generated, it returns null.
128       * @param start the basic block at which to start looking.
129       */
130      BasicBlockLE getNextEmptyBlock(BasicBlockLE start) {
131        if (DBG_BBSET) db("getting the next empty block after " + start);
132    
133        // Look for an ungenerated block after start.
134        BBSet.TreeEnumerator e = TreeEnumerator.enumFromNode(start);
135        while (e.hasMoreElements()) {
136          BasicBlockLE block = e.next();
137          if (DBG_BBSET) {
138            db("Considering block " + block + " " + block.genState());
139          }
140          if (block.isReadyToGenerate()) {
141            if (DBG_BBSET) db("block " + block + " is not yet generated");
142            return block;
143          }
144        }
145    
146        // There were none. Start looking from the beginning.
147        if (DBG_BBSET) db("at end of bytecodes, restarting at beginning");
148        e = TreeEnumerator.enumFromRoot(root);
149        while (true) {
150          BasicBlockLE block = e.next();
151          if (block == start) {
152            if (DBG_BBSET) db("wrapped around, no more empty blocks");
153            return null;
154          }
155          if (DBG_BBSET) {
156            db("Considering block " + block + " " + block.genState());
157          }
158          if (block.isReadyToGenerate()) {
159            if (DBG_BBSET) db("block " + block + " is not yet generated");
160            return block;
161          }
162        }
163      }
164    
165      /**
166       * Get or create a block at the specified target.
167       * If simStack is non-null, rectifies stack state with target stack state.
168       * If simLocals is non-null, rectifies local state with target local state.
169       * Any instructions needed to rectify stack/local state are appended to
170       * from.
171       *
172       * @param target target index
173       * @param from the block from which control is being transfered
174       *                  and to which rectification instructions are added.
175       * @param simStack stack state to rectify, or null
176       * @param simLocals local state to rectify, or null
177       */
178      BasicBlockLE getOrCreateBlock(int target, BasicBlockLE from, OperandStack simStack, Operand[] simLocals) {
179        if (DBG_BB || BC2IR.DBG_SELECTED) {
180          db("getting block " +
181             target +
182             ", match stack: " +
183             (simStack != null) +
184             " match locals: " +
185             (simLocals != null));
186        }
187        return getOrCreateBlock(root, true, target, from, simStack, simLocals);
188      }
189    
190      /**
191       * Mark a previously generated block for regeneration.
192       * We define this method here so that in the future
193       * we can implement a more efficient getNextEmptyBlock that
194       * (1) avoids generating lots of blocks when a CFG predecessor has a
195       * pending regeneration and (2) avoids the scan through all blocks when
196       * there are no more blocks left to generate.
197       */
198      private void markBlockForRegeneration(BasicBlockLE p) {
199        if (DBG_REGEN) db("marking " + p + " for regeneration");
200        if (p.fallThrough != null && p.fallThrough instanceof InliningBlockLE) {
201          // if the fallthrough out edge of this block is an
202          // InlineMethodBasicBlock, then the inlined method must also be
203          // regenerated.  In preparation for this, we must delete all out
204          // edges from the inlined method to the caller.
205          // (These arise from thrown/caught exceptions.)
206          InliningBlockLE imbb = (InliningBlockLE) p.fallThrough;
207          imbb.deleteAllOutEdges();
208        }
209        // discard any "real" instructions in the block
210        if (!p.block.isEmpty()) {
211          p.block.discardInstructions();
212        }
213        p.setSelfRegen();
214        p.clearGenerated();
215        p.fallThrough = null;
216        // If p had a non-empty stack on entry, we need to go through it
217        // and copy all of its operands (they may point to instructions
218        // we just blew away, but then again they may not (may not be in p),
219        // so we can't simply null out the instruction field);
220        if (p.stackState != null) {
221          int i = p.stackState.getSize();
222          while (i-- > 0) {
223            Operand op = p.stackState.getFromTop(i);
224            p.stackState.replaceFromTop(i, op.copy());
225          }
226        }
227      }
228    
229      /**
230       * Rectify the given stack state with the state contained in the given
231       * BBLE, adding the necessary move instructions to the end of the given
232       * basic block to make register numbers agree and rectify mis-matched constants.
233       * <p>
234       * @param block basic block to append move instructions to
235       * @param stack stack to copy
236       * @param p BBLE to copy stack state into
237       */
238      void rectifyStacks(BasicBlock block, OperandStack stack, BasicBlockLE p) {
239        if (stack == null || stack.isEmpty()) {
240          if (VM.VerifyAssertions) VM._assert(p.stackState == null);
241          if (!p.isStackKnown()) {
242            p.setStackKnown();
243          }
244          if (DBG_STACK || BC2IR.DBG_SELECTED) {
245            db("Rectified empty expression stack into " + p + "(" + p.block + ")");
246          }
247          return;
248        }
249        boolean generated = p.isGenerated();
250        // (1) Rectify the stacks.
251        if (!p.isStackKnown()) {
252          // First time we reached p. Thus, its expression stack
253          // is implicitly top and the meet degenerates to a copy operation
254          // with possibly some register renaming.
255          // (We need to ensure that non-local registers appear at
256          // most once on each expression stack).
257          if (DBG_STACK || BC2IR.DBG_SELECTED) {
258            db("First stack rectifiction for " + p + "(" + p.block + ") simply saving");
259          }
260          if (VM.VerifyAssertions) VM._assert(p.stackState == null);
261          p.stackState = new OperandStack(stack.getCapacity());
262          for (int i = stack.getSize() - 1; i >= 0; i--) {
263            Operand op = stack.getFromTop(i);
264            if (op == BC2IR.DUMMY) {
265              p.stackState.push(BC2IR.DUMMY);
266            } else if (op instanceof RegisterOperand) {
267              RegisterOperand rop = op.asRegister();
268              if (rop.getRegister().isLocal()) {
269                RegisterOperand temp = gc.temps.makeTemp(rop);
270                temp.setInheritableFlags(rop);
271                BC2IR.setGuard(temp, BC2IR.getGuard(rop));
272                Instruction move = Move.create(IRTools.getMoveOp(rop.getType()), temp, rop.copyRO());
273                move.bcIndex = BC2IR.RECTIFY_BCI;
274                move.position = gc.inlineSequence;
275                block.appendInstructionRespectingTerminalBranch(move);
276                p.stackState.push(temp.copy());
277                if (DBG_STACK || BC2IR.DBG_SELECTED) {
278                  db("Inserted " + move + " into " + block + " to rename local");
279                }
280              } else {
281                p.stackState.push(rop.copy());
282              }
283            } else {
284              p.stackState.push(op.copy());
285            }
286          }
287          p.setStackKnown();
288        } else {
289          // A real rectification.
290          // We need to update mergedStack such that
291          // mergedStack[i] = meet(mergedStack[i], stack[i]).
292          if (DBG_STACK || BC2IR.DBG_SELECTED) db("rectifying stacks");
293          try {
294            if (VM.VerifyAssertions) {
295              VM._assert(stack.getSize() == p.stackState.getSize());
296            }
297          } catch (NullPointerException e) {
298            System.err.println("stack size " + stack.getSize());
299            System.err.println(stack);
300            System.err.println(p.stackState);
301            System.err.println(gc.method.toString());
302            block.printExtended();
303            p.block.printExtended();
304            throw e;
305          }
306          for (int i = 0; i < stack.getSize(); ++i) {
307            Operand sop = stack.getFromTop(i);
308            Operand mop = p.stackState.getFromTop(i);
309            if ((sop == BC2IR.DUMMY) || (sop instanceof ReturnAddressOperand)) {
310              if (VM.VerifyAssertions) VM._assert(mop.similar(sop));
311              continue;
312            } else if (sop.isConstant() || mop.isConstant()) {
313              if (mop.similar(sop)) {
314                continue; // constants are similar; so we don't have to do anything.
315              }
316              // sigh. Non-similar constants.
317              if (mop.isConstant()) {
318                // Insert move instructions in all predecessor
319                // blocks except 'block' to move mop into a register.
320                RegisterOperand mopTmp = gc.temps.makeTemp(mop);
321                if (DBG_STACK || BC2IR.DBG_SELECTED) db("Merged stack has constant operand " + mop);
322                for (Enumeration<BasicBlock> preds = p.block.getIn(); preds.hasMoreElements();) {
323                  BasicBlock pred = preds.nextElement();
324                  if (pred == block) continue;
325                  injectMove(pred, mopTmp.copyRO(), mop.copy());
326                }
327                p.stackState.replaceFromTop(i, mopTmp.copy());
328                if (generated) {
329                  if (DBG_STACK || BC2IR.DBG_SELECTED) {
330                    db("\t...forced to regenerate " + p + " (" + p.block + ") because of this");
331                  }
332                  markBlockForRegeneration(p);
333                  generated = false;
334                  p.block.deleteOut();
335                  if (DBG_CFG || BC2IR.DBG_SELECTED) db("Deleted all out edges of " + p.block);
336                }
337                mop = mopTmp;
338              }
339              if (sop.isConstant()) {
340                // Insert move instruction into block.
341                RegisterOperand sopTmp = gc.temps.makeTemp(sop);
342                if (DBG_STACK || BC2IR.DBG_SELECTED) db("incoming stack has constant operand " + sop);
343                injectMove(block, sopTmp, sop);
344                sop = sopTmp.copyRO();
345              }
346            }
347    
348            // sop and mop are RegisterOperands (either originally or because
349            // we forced them to be above due to incompatible constants.
350            RegisterOperand rsop = sop.asRegister();
351            RegisterOperand rmop = mop.asRegister();
352            if (rmop.getRegister() != rsop.getRegister()) {
353              // must insert move at end of block to get register #s to match
354              RegisterOperand temp = rsop.copyRO();
355              temp.setRegister(rmop.getRegister());
356              injectMove(block, temp, rsop.copyRO());
357            }
358            Operand meet = Operand.meet(rmop, rsop, rmop.getRegister());
359            if (DBG_STACK || BC2IR.DBG_SELECTED) db("Meet of " + rmop + " and " + rsop + " is " + meet);
360            if (meet != rmop) {
361              if (generated) {
362                if (DBG_STACK || BC2IR.DBG_SELECTED) {
363                  db("\t...forced to regenerate " + p + " (" + p.block + ") because of this");
364                }
365                markBlockForRegeneration(p);
366                generated = false;
367                p.block.deleteOut();
368                if (DBG_CFG || BC2IR.DBG_SELECTED) db("Deleted all out edges of " + p.block);
369              }
370              p.stackState.replaceFromTop(i, meet);
371            }
372          }
373        }
374      }
375    
376      private void injectMove(BasicBlock block, RegisterOperand res, Operand val) {
377        Instruction move = Move.create(IRTools.getMoveOp(res.getType()), res, val);
378        move.bcIndex = BC2IR.RECTIFY_BCI;
379        move.position = gc.inlineSequence;
380        block.appendInstructionRespectingTerminalBranch(move);
381        if (DBG_STACK || BC2IR.DBG_SELECTED) {
382          db("Inserted " + move + " into " + block);
383        }
384      }
385    
386      /**
387       * Rectify the given local variable state with the local variable state
388       * stored in the given BBLE.
389       *
390       * @param localState local variable state to rectify
391       * @param p target BBLE to rectify state to
392       */
393      void rectifyLocals(Operand[] localState, BasicBlockLE p) {
394        if (!p.isLocalKnown()) {
395          if (DBG_LOCAL || BC2IR.DBG_SELECTED) {
396            db("rectifying with heretofore unknown locals, changing to save");
397          }
398          p.copyIntoLocalState(localState);
399          return;
400        }
401        if (DBG_LOCAL || BC2IR.DBG_SELECTED) db("rectifying current local state with " + p);
402        boolean generated = p.isGenerated();
403        Operand[] incomingState = localState;
404        Operand[] presentState = p.localState;
405        if (VM.VerifyAssertions) {
406          VM._assert(incomingState.length == presentState.length);
407        }
408        for (int i = 0, n = incomingState.length; i < n; ++i) {
409          Operand pOP = presentState[i];
410          Operand iOP = incomingState[i];
411          if (pOP == iOP) {
412            if (DBG_LOCAL || BC2IR.DBG_SELECTED) {
413              db("local states have the exact same operand " + pOP + " for local " + i);
414            }
415          } else {
416            boolean untyped = (pOP == null || pOP == BC2IR.DUMMY || pOP instanceof ReturnAddressOperand);
417            Operand mOP = Operand.meet(pOP, iOP, untyped ? null : gc.localReg(i, pOP.getType()));
418            if (DBG_LOCAL || BC2IR.DBG_SELECTED) db("Meet of " + pOP + " and " + iOP + " is " + mOP);
419            if (mOP != pOP) {
420              if (generated) {
421                if (DBG_LOCAL || BC2IR.DBG_SELECTED) {
422                  db("\t...forced to regenerate " + p + " (" + p.block + ") because of this");
423                }
424                markBlockForRegeneration(p);
425                generated = false;
426                p.block.deleteOut();
427                if (DBG_CFG || BC2IR.DBG_SELECTED) db("Deleted all out edges of " + p.block);
428              }
429              presentState[i] = mOP;
430            }
431          }
432        }
433      }
434    
435      /**
436       * Do a final pass over the generated basic blocks to create
437       * the initial code ordering. All blocks generated for the method
438       * will be inserted after gc.prologue.<p>
439       *
440       * NOTE: Only some CFG edges are created here.....
441       * we're mainly just patching together a code linearization.
442       */
443      void finalPass(boolean inlinedSomething) {
444        BBSet.TreeEnumerator e = TreeEnumerator.enumFromRoot(root);
445        BasicBlock cop = gc.prologue;
446        BasicBlockLE curr = getEntry();
447        BasicBlockLE next = null;
448        top:
449        while (true) {
450          // Step 0: If curr is the first block in a catch block,
451          // inject synthetic entry block too.
452          if (curr instanceof HandlerBlockLE) {
453            // tell our caller that we actually put a handler in the final CFG.
454            gc.generatedExceptionHandlers = true;
455            HandlerBlockLE hcurr = (HandlerBlockLE) curr;
456            if (DBG_FLATTEN) {
457              db("injecting handler entry block " + hcurr.entryBlock + " before " + hcurr);
458            }
459            gc.cfg.insertAfterInCodeOrder(cop, hcurr.entryBlock);
460            cop = hcurr.entryBlock;
461          }
462          // Step 1: Insert curr in the code order (after cop, updating cop).
463          if (DBG_FLATTEN) db("flattening: " + curr + " (" + curr.block + ")");
464          curr.setInCodeOrder();
465          gc.cfg.insertAfterInCodeOrder(cop, curr.block);
466          cop = curr.block;
467          if (DBG_FLATTEN) {
468            db("Current Code order for " + gc.method + "\n");
469            for (BasicBlock bb = gc.prologue; bb != null; bb = (BasicBlock) bb.getNext()) {
470              VM.sysWrite(bb + "\n");
471            }
472          }
473          // Step 1.1 Sometimes (rarely) there will be an inscope
474          // exception handler that wasn't actually generated.  If this happens,
475          // make a new, filtered EHBBB to avoid later confusion.
476          if (curr.handlers != null) {
477            int notGenerated = 0;
478            for (HandlerBlockLE handler : curr.handlers) {
479              if (!handler.isGenerated()) {
480                if (DBG_EX || DBG_FLATTEN) {
481                  db("Will remove unreachable handler " + handler + " from " + curr);
482                }
483                notGenerated++;
484              }
485            }
486            if (notGenerated > 0) {
487              if (notGenerated == curr.handlers.length) {
488                if (DBG_EX || DBG_FLATTEN) {
489                  db("No (local) handlers were actually reachable for " + curr + "; setting to caller");
490                }
491                curr.block.exceptionHandlers = curr.block.exceptionHandlers.getCaller();
492              } else {
493                ExceptionHandlerBasicBlock[] nlh =
494                    new ExceptionHandlerBasicBlock[curr.handlers.length - notGenerated];
495                for (int i = 0, j = 0; i < curr.handlers.length; i++) {
496                  if (curr.handlers[i].isGenerated()) {
497                    nlh[j++] = curr.handlers[i].entryBlock;
498                  } else {
499                    if (VM.VerifyAssertions) {
500                      VM._assert(curr.handlers[i].entryBlock.hasZeroIn(), "Non-generated handler with CFG edges");
501                    }
502                  }
503                }
504                curr.block.exceptionHandlers =
505                    new ExceptionHandlerBasicBlockBag(nlh, curr.block.exceptionHandlers.getCaller());
506              }
507            }
508          }
509          // Step 2: Identify the next basic block to add to the code order.
510          // curr wants to fallthrough to an inlined method.
511          // Inject the entire inlined CFG in the code order.
512          // There's some fairly complicated coordination between this code,
513          // GenerationContext, and maybeInlineMethod.  Sorry, but you'll
514          // have to take a close look at all of these to see how it
515          // all fits together....--dave
516          if (curr.fallThrough != null && curr.fallThrough instanceof InliningBlockLE) {
517            InliningBlockLE icurr = (InliningBlockLE) curr.fallThrough;
518            BasicBlock forw = cop.nextBasicBlockInCodeOrder();
519            BasicBlock calleeEntry = icurr.gc.cfg.firstInCodeOrder();
520            BasicBlock calleeExit = icurr.gc.cfg.lastInCodeOrder();
521            gc.cfg.breakCodeOrder(cop, forw);
522            gc.cfg.linkInCodeOrder(cop, icurr.gc.cfg.firstInCodeOrder());
523            gc.cfg.linkInCodeOrder(icurr.gc.cfg.lastInCodeOrder(), forw);
524            if (DBG_CFG || BC2IR.DBG_SELECTED) {
525              db("Added CFG edge from " + cop + " to " + calleeEntry);
526            }
527            if (icurr.epilogueBBLE != null) {
528              if (DBG_FLATTEN) {
529                db("injected " + icurr + " between " + curr + " and " + icurr.epilogueBBLE.fallThrough);
530              }
531              if (VM.VerifyAssertions) {
532                VM._assert(icurr.epilogueBBLE.block == icurr.gc.cfg.lastInCodeOrder());
533              }
534              curr = icurr.epilogueBBLE;
535              cop = curr.block;
536            } else {
537              if (DBG_FLATTEN) db("injected " + icurr + " after " + curr);
538              curr = icurr;
539              cop = calleeExit;
540            }
541          }
542          next = curr.fallThrough;
543          if (DBG_FLATTEN && next == null) {
544            db(curr + " has no fallthrough case, getting next block");
545          }
546          if (next != null) {
547            if (DBG_CFG || BC2IR.DBG_SELECTED) {
548              db("Added CFG edge from " + curr.block + " to " + next.block);
549            }
550            if (next.isInCodeOrder()) {
551              if (DBG_FLATTEN) {
552                db("fallthrough " + next + " is already flattened, adding goto");
553              }
554              curr.block.appendInstruction(next.block.makeGOTO());
555              // set next to null to indicate no "real" fall through
556              next = null;
557            }
558          }
559          if (next == null) {
560            // Can't process fallthroughblock, so get next BBLE from enumeration
561            while (true) {
562              if (!e.hasMoreElements()) {
563                // all done.
564                if (DBG_FLATTEN) db("no more blocks! all done");
565                break top;
566              }
567              next = e.next();
568              if (DBG_FLATTEN) db("looking at " + next);
569              if (!next.isGenerated()) {
570                if (DBG_FLATTEN) db("block " + next + " was not generated");
571                continue;
572              }
573              if (!next.isInCodeOrder()) {
574                break;
575              }
576            }
577            if (DBG_FLATTEN) db("found unflattened block: " + next);
578          }
579          curr = next;
580        }
581        // If the epilogue was unreachable, remove it from the code order and cfg
582        // and set gc.epilogue to null.
583        boolean removedSomethingFromCodeOrdering = inlinedSomething;
584        if (gc.epilogue.hasZeroIn()) {
585          if (DBG_FLATTEN || DBG_CFG) {
586            db("Deleting unreachable epilogue " + gc.epilogue);
587          }
588          gc.cfg.removeFromCodeOrder(gc.epilogue);
589          removedSomethingFromCodeOrdering = true;
590    
591          // remove the node from the graph AND adjust its edge info
592          gc.epilogue.remove();
593          gc.epilogue.deleteIn();
594          gc.epilogue.deleteOut();
595          if (VM.VerifyAssertions) VM._assert(gc.epilogue.hasZeroOut());
596          gc.epilogue = null;
597        }
598        // if gc has an unlockAndRethrow block that was not used, then remove it
599        if (gc.unlockAndRethrow != null && gc.unlockAndRethrow.hasZeroIn()) {
600          gc.cfg.removeFromCFGAndCodeOrder(gc.unlockAndRethrow);
601          removedSomethingFromCodeOrdering = true;
602          gc.enclosingHandlers.remove(gc.unlockAndRethrow);
603        }
604        // if we removed a basic block then we should compact the node numbering
605        if (removedSomethingFromCodeOrdering) {
606          gc.cfg.compactNodeNumbering();
607        }
608    
609        if (DBG_FLATTEN) {
610          db("Current Code order for " + gc.method + "\n");
611          for (BasicBlock bb = gc.prologue; bb != null; bb = (BasicBlock) bb.getNext()) {
612            bb.printExtended();
613          }
614        }
615        if (DBG_FLATTEN) {
616          db("Final CFG for " + gc.method + "\n");
617          gc.cfg.printDepthFirst();
618        }
619      }
620    
621      //////////////////////////////////////////
622      // Gory implementation details of BBSet //
623      //////////////////////////////////////////
624    
625      /**
626       * Print a debug string to the sysWrite stream.
627       * @param val string to print
628       */
629      private void db(String val) {
630        VM.sysWrite("IRGEN " + bcodes.getDeclaringClass() + "." + gc.method.getName() + ":" + val + "\n");
631      }
632    
633      /**
634       * Initialize the global exception handler arrays for the method.<p>
635       */
636      private void parseExceptionTables() {
637        ExceptionHandlerMap eMap = gc.method.getExceptionHandlerMap();
638        if (DBG_EX) db("\texception handlers for " + gc.method + ": " + eMap);
639        if (eMap == null) return;  // method has no exception handling ranges.
640        startPCs = eMap.getStartPC();
641        endPCs = eMap.getEndPC();
642        handlerPCs = eMap.getHandlerPC();
643        int numExceptionHandlers = startPCs.length;
644        exceptionTypes = new TypeOperand[numExceptionHandlers];
645        for (int i = 0; i < numExceptionHandlers; i++) {
646          exceptionTypes[i] = new TypeOperand(eMap.getExceptionType(i));
647          if (DBG_EX) db("\t\t[" + startPCs[i] + "," + endPCs[i] + "] " + eMap.getExceptionType(i));
648        }
649      }
650    
651      /**
652       * Initialize bble's handlers array based on startPCs/endPCs.
653       * In the process, new HandlerBlockLE's may be created
654       * (by the call to getOrCreateBlock). <p>
655       * PRECONDITION: bble.low and bble.max have already been correctly
656       * set to reflect the invariant that a basic block is in exactly one
657       * "handler range."<p>
658       * Also initializes bble.block.exceptionHandlers.
659       */
660      private void initializeExceptionHandlers(BasicBlockLE bble, Operand[] simLocals) {
661        if (startPCs != null) {
662          HashSet<TypeReference> caughtTypes = new HashSet<TypeReference>();
663          for (int i = 0; i < startPCs.length; i++) {
664            TypeReference caughtType = exceptionTypes[i].getTypeRef();
665            if (bble.low >= startPCs[i] && bble.max <= endPCs[i] && !caughtTypes.contains(caughtType)) {
666              // bble's basic block is contained within this handler's range.
667              HandlerBlockLE eh = (HandlerBlockLE) getOrCreateBlock(handlerPCs[i], bble, null, simLocals);
668              if (DBG_EX) db("Adding handler " + eh + " to " + bble);
669              caughtTypes.add(caughtType);
670              bble.addHandler(eh);
671            }
672          }
673        }
674        if (bble.handlers != null) {
675          ExceptionHandlerBasicBlock[] ehbbs = new ExceptionHandlerBasicBlock[bble.handlers.length];
676          for (int i = 0; i < bble.handlers.length; i++) {
677            ehbbs[i] = bble.handlers[i].entryBlock;
678          }
679          bble.block.exceptionHandlers = new ExceptionHandlerBasicBlockBag(ehbbs, gc.enclosingHandlers);
680        } else {
681          bble.block.exceptionHandlers = gc.enclosingHandlers;
682        }
683      }
684    
685      /**
686       * Given a starting bytecode index, find the greatest bcIndex that
687       * is still has the same inscope exception handlers.
688       * @param bcIndex the start bytecode index
689       */
690      private int exceptionEndRange(int bcIndex) {
691        int max = bcodes.length();
692        if (startPCs != null) {
693          for (int spc : startPCs) {
694            if (bcIndex < spc && max > spc) {
695              max = spc;
696            }
697          }
698          for (int epc : endPCs) {
699            if (bcIndex < epc && max > epc) {
700              max = epc;
701            }
702          }
703        }
704        return max;
705      }
706    
707      /**
708       * We specialize basic blocks with respect to the return addresses
709       * they have on their expression stack and/or in their local variables
710       * on entry to the block. This has the effect of inlining the
711       * subroutine body at all of the JSR sites that invoke it.
712       * This is the key routine: it determines whether or not the
713       * argument simState (stack and locals) contains compatible
714       * return addresses as the candidate BasicBlockLE.
715       * <p>
716       * The main motivation for inlining away all JSR's is that it eliminates
717       * the "JSR problem" for type accurate GC.  It is also simpler to
718       * implement and arguably results in more efficient generated code
719       * (assuming that we don't get horrific code bloat).
720       * To deal with the code bloat, we detect excessive code duplication and
721       * stop IR generation (bail out to the baseline compiler).
722       *
723       * @param simStack  The expression stack to match
724       * @param simLocals The local variables to match
725       * @param candBBLE  The candidate BaseicBlockLE
726       */
727      private boolean matchingJSRcontext(OperandStack simStack, Operand[] simLocals, BasicBlockLE candBBLE) {
728        if (DBG_INLINE_JSR) {
729          db("Matching JSR context of argument stack/locals against " + candBBLE);
730        }
731    
732        int numRA = 0;
733        if (simStack != null && candBBLE.isStackKnown()) {
734          for (int i = simStack.getSize() - 1; i >= 0; i--) {
735            Operand op = simStack.getFromTop(i);
736            if (op instanceof ReturnAddressOperand) {
737              if (numRA++ > MAX_RETURN_ADDRESSES) {
738                throw new OperationNotImplementedException("Too many subroutines");
739              }
740              if (DBG_INLINE_JSR) db("simStack operand " + i + " is " + op);
741              Operand cop = candBBLE.stackState.getFromTop(i);
742              if (!Operand.conservativelyApproximates(cop, op)) {
743                if (DBG_INLINE_JSR) db("Not Matching: " + cop + " and " + op);
744                return false;
745              } else {
746                if (DBG_INLINE_JSR) db("operand " + cop + " is compatible with " + op);
747              }
748            }
749          }
750        }
751    
752        if (simLocals != null && candBBLE.isLocalKnown()) {
753          for (int i = 0; i < simLocals.length; i++) {
754            Operand op = simLocals[i];
755            if (op instanceof ReturnAddressOperand) {
756              if (numRA++ > MAX_RETURN_ADDRESSES) {
757                throw new OperationNotImplementedException("Too many subroutines");
758              }
759              if (DBG_INLINE_JSR) db("simLocal " + i + " is " + op);
760              Operand cop = candBBLE.localState[i];
761              if (!Operand.conservativelyApproximates(cop, op)) {
762                if (DBG_INLINE_JSR) db("Not Matching: " + cop + " and " + op);
763                return false;
764              } else {
765                if (DBG_INLINE_JSR) db("operand " + cop + " is compatible with " + op);
766              }
767            }
768          }
769        }
770    
771        if (DBG_INLINE_JSR) db("Found " + candBBLE + " to be compatible");
772        return true;
773      }
774    
775      /**
776       * Get or create a block at the specified target.
777       * If simStack is non-null, rectifies stack state with target stack state.
778       * If simLocals is non-null, rectifies local state with target local state.
779       * Any instructions needed to rectify stack/local state are appended to
780       * from.
781       * As blocks are created, they are added to the red/black tree below x.
782       *
783       * @param x starting node for search.
784       * @param shouldCreate should we create the block if we run off the tree?
785       * @param target target index
786       * @param from the block from which control is being transfered
787       *                  and to which rectification instructions are added.
788       * @param simStack stack state to rectify, or {@code null}
789       * @param simLocals local state to rectify, or {@code null}
790       */
791      private BasicBlockLE getOrCreateBlock(BasicBlockLE x, boolean shouldCreate, int target, BasicBlockLE from,
792                                            OperandStack simStack, Operand[] simLocals) {
793        if (target < x.low) {
794          if (x.left == null) {
795            return condCreateAndInit(x, shouldCreate, target, from, simStack, simLocals, true);
796          } else {
797            if (DBG_BBSET) db("following left branch from " + x + " to " + x.left);
798            return getOrCreateBlock(x.left, shouldCreate, target, from, simStack, simLocals);
799          }
800        } else if (target > x.low) {
801          if ((x.low < target) && (target <= x.high)) {
802            // the target points to the middle of x; mark x for regen
803            if (DBG_BBSET) db("target points to middle of " + x);
804            markBlockForRegeneration(x);
805            x.high = x.low;
806            x.block.deleteOut();
807            if (DBG_CFG || BC2IR.DBG_SELECTED) db("Deleted all out edges of " + x.block);
808          }
809          if (x.right == null) {
810            return condCreateAndInit(x, shouldCreate, target, from, simStack, simLocals, false);
811          } else {
812            if (DBG_BBSET) db("following right branch from " + x + " to " + x.right);
813            return getOrCreateBlock(x.right, shouldCreate, target, from, simStack, simLocals);
814          }
815        } else {
816          // found a basic block at the target bytecode index.
817          if (noJSR || matchingJSRcontext(simStack, simLocals, x)) {
818            if (DBG_BBSET) db("found block " + x + " (" + x.block + ")");
819            if (simStack != null) rectifyStacks(from.block, simStack, x);
820            if (simLocals != null) rectifyLocals(simLocals, x);
821            return x;
822          }
823          if (DBG_BBSET) db("found block " + x + ", but JSR context didn't match");
824          if (x.left == null) {
825            if (x.right == null) {
826              return condCreateAndInit(x, shouldCreate, target, from, simStack, simLocals, true);
827            } else {
828              if (DBG_BBSET) {
829                db(x + " has only right child, continuing down that branch");
830              }
831              return getOrCreateBlock(x.right, shouldCreate, target, from, simStack, simLocals);
832            }
833          } else {
834            if (x.right == null) {
835              if (DBG_BBSET) {
836                db(x + " has only left child, continuing down that branch");
837              }
838              return getOrCreateBlock(x.left, shouldCreate, target, from, simStack, simLocals);
839            } else {
840              if (DBG_BBSET) {
841                db(x + " has two children, searching left branch first");
842              }
843              BasicBlockLE bble = getOrCreateBlock(x.left, false, target, from, simStack, simLocals);
844              if (bble != null) {
845                return bble;
846              } else {
847                if (DBG_BBSET) {
848                  db("didn't find " + target + " on left branch, continuing down right branch");
849                }
850                return getOrCreateBlock(x.right, shouldCreate, target, from, simStack, simLocals);
851              }
852            }
853          }
854        }
855      }
856    
857      /**
858       * Conditionally create a block at the specified target as a child of x.
859       * If simStack is non-{@code null}, rectifies stack state with target stack state.
860       * If simLocals is non-{@code null}, rectifies local state with target local state.
861       * Any instructions needed to rectify stack/local state are appended to
862       * from.
863       *
864       * @param x starting node for search.
865       * @param shouldCreate should we create the block if we run off the tree?
866       * @param target target index
867       * @param from the block from which control is being transfered
868       *                  and to which rectification instructions are added.
869       * @param simStack stack state to rectify, or {@code null}
870       * @param simLocals local state to rectify, or {@code null}
871       * @param left are we creating a left child of parent?
872       * @return the newly created block, or {@code null} if !shouldCreate
873       */
874      private BasicBlockLE condCreateAndInit(BasicBlockLE x, boolean shouldCreate, int target, BasicBlockLE from,
875                                             OperandStack simStack, Operand[] simLocals, boolean left) {
876        BasicBlockLE bble = null;
877        if (shouldCreate) {
878          bble = _createBBLE(target, simLocals, x, left);
879          if (simStack != null) {
880            rectifyStacks(from.block, simStack, bble);
881          }
882          if (simLocals != null) {
883            bble.copyIntoLocalState(simLocals);
884          }
885        }
886        return bble;
887      }
888    
889      /**
890       * Allocate a new BBLE at the given bcIndex.
891       * If bcIndex is the start of an handler block,
892       * then a HandlerBlockLE is created.
893       * After the BBLE is created, its handlers data structure is initialized
894       * (which may cause other blocks to be created).
895       * @param bcIndex the bytecode index at which the block should be created.
896       * @param simLocals the localState to pass (via initializeExceptionHandler)to
897       *                  to getOrCreateBlock if we need to create BBLEs for
898       *                  exception handlers.  This is only actually used if
899       *                  !noJSR.  We don't need the expression stack, since
900       *                  the only thing on the expression stack on entry to
901       *                  a handler block is the exception object (and thus
902       *                  we can skip scanning the expression stack for
903       *                  return addresses when creating a handler block).
904       * @param parent parent in Red/Black tree
905       * @param left are we creating a left child of parent?
906       */
907      private BasicBlockLE _createBBLE(int bcIndex, Operand[] simLocals, BasicBlockLE parent, boolean left) {
908        BasicBlockLE newBBLE = null;
909        if (handlerPCs != null) {
910          for (int i = 0; i < handlerPCs.length; i++) {
911            if (handlerPCs[i] == bcIndex) {
912              if (newBBLE == null) {
913                newBBLE =
914                    new HandlerBlockLE(bcIndex,
915                                       gc.inlineSequence,
916                                       exceptionTypes[i],
917                                       gc.temps,
918                                       gc.method.getOperandWords(),
919                                       gc.cfg);
920                ((HandlerBlockLE) newBBLE).entryBlock.firstRealInstruction().
921                    position = gc.inlineSequence;
922              } else {
923                ((HandlerBlockLE) newBBLE).addCaughtException(exceptionTypes[i]);
924              }
925            }
926          }
927        }
928        if (newBBLE == null) {
929          newBBLE = new BasicBlockLE(bcIndex, gc.inlineSequence, gc.cfg);
930        }
931    
932        // Set newBBLE.max to encode exception ranges
933        newBBLE.max = exceptionEndRange(bcIndex);
934    
935        if (DBG_BBSET) db("Created " + newBBLE);
936    
937        // Now, insert newBBLE into our backing Red/Black tree before we call
938        // initializeExceptionHandlers.
939        // We must do it in this order because initExHand may in turn call
940        // _createBBLE to create new handler blocks, and our tree must contain
941        // newBBLE before we can correctly insert another block.
942        treeInsert(parent, newBBLE, left);
943    
944        initializeExceptionHandlers(newBBLE, simLocals);
945        return newBBLE;
946      }
947    
948      /**
949       * Returns the basic block which has the next-higher bytecode index.
950       * Returns {@code null} if x is the highest block.
951       * @param x basic block at which to start the search for a higher block
952       * @param value the contents of x.low (makes tail call elim work better
953       *              if we avoid the obvious 1 argument wrapper function)
954       */
955      private BasicBlockLE getSuccessor(BasicBlockLE x, int value) {
956        if (x.right != null) return minimumBB(x.right, value);
957        BasicBlockLE y = x.parent;
958        while ((y != null) && (x == y.right)) {
959          x = y;
960          y = x.parent;
961        }
962        // at this point either x is the root, or x is the left child of y
963        if ((y == null) || (y.low != value)) return y;
964        return getSuccessor(y, value);
965      }
966    
967      private BasicBlockLE minimumBB(BasicBlockLE x, int value) {
968        if (x.left != null) return minimumBB(x.left, value);
969        if (value == x.low) return getSuccessor(x, value);
970        return x;
971      }
972    
973      /**
974       * Insert <code>newBBLE</code> as a child of parent in our Red/Black tree.
975       * @param parent the parent node
976       * @param newBBLE  the new child node
977       * @param left   is the child the left or right child of parent?
978       */
979      private void treeInsert(BasicBlockLE parent, BasicBlockLE newBBLE, boolean left) {
980        if (parent == null) {
981          if (VM.VerifyAssertions) VM._assert(root == null);
982          root = newBBLE;
983          root.setBlack();
984          if (DBG_BBSET) db("inserted " + newBBLE + " as root of tree");
985        } else {
986          if (left) {
987            parent.left = newBBLE;
988          } else {
989            parent.right = newBBLE;
990          }
991          newBBLE.parent = parent;
992          if (DBG_BBSET) {
993            db("inserted new block " + newBBLE + " as " + (left ? "left" : "right") + " child of " + parent);
994          }
995          fixupBBSet(newBBLE);
996        }
997      }
998    
999      /**
1000       * Performs tree fixup (restore Red/Black invariants) after adding a
1001       * new node to the tree.
1002       * @param x node that was added.
1003       */
1004      private void fixupBBSet(BasicBlockLE x) {
1005        if (DBG_BBSET) db("fixing up tree after inserting " + x);
1006        x.setRed();
1007        while (x != root) {
1008          BasicBlockLE xp = x.parent;
1009          if (xp.isBlack()) {
1010            break;
1011          }
1012          if (DBG_BBSET) db(x + " and its parent " + xp + " are both red");
1013          BasicBlockLE xpp = xp.parent;
1014          if (DBG_BBSET) db(xp + "'s parent is " + xpp);
1015          if (xp == xpp.left) {
1016            BasicBlockLE y = xpp.right;
1017            if ((y != null) && y.isRed()) {
1018              xp.setBlack();
1019              y.setBlack();
1020              xpp.setRed();
1021              x = xpp;
1022            } else {
1023              if (x == xp.right) {
1024                x = xp;
1025                leftRotateBBSet(xp);
1026                xp = x.parent;
1027                xpp = xp.parent;
1028              }
1029              xp.setBlack();
1030              xpp.setRed();
1031              rightRotateBBSet(xpp);
1032            }
1033          } else {
1034            BasicBlockLE y = xpp.left;
1035            if ((y != null) && y.isRed()) {
1036              xp.setBlack();
1037              y.setBlack();
1038              xpp.setRed();
1039              x = xpp;
1040            } else {
1041              if (x == xp.left) {
1042                x = xp;
1043                rightRotateBBSet(xp);
1044                xp = x.parent;
1045                xpp = xp.parent;
1046              }
1047              xp.setBlack();
1048              xpp.setRed();
1049              leftRotateBBSet(xpp);
1050            }
1051          }
1052        }
1053        root.setBlack();
1054        // verifyTree();
1055      }
1056    
1057      private void leftRotateBBSet(BasicBlockLE x) {
1058        if (DBG_BBSET) db("performing left tree rotation");
1059        BasicBlockLE y = x.right;
1060        BasicBlockLE yl = y.left;
1061        x.right = yl;
1062        if (yl != null) {
1063          yl.parent = x;
1064        }
1065        BasicBlockLE xp = x.parent;
1066        y.parent = xp;
1067        if (xp == null) {
1068          root = y;
1069        } else if (x == xp.left) {
1070          xp.left = y;
1071        } else {
1072          xp.right = y;
1073        }
1074        y.left = x;
1075        x.parent = y;
1076      }
1077    
1078      private void rightRotateBBSet(BasicBlockLE x) {
1079        if (DBG_BBSET) db("performing right tree rotation");
1080        BasicBlockLE y = x.left;
1081        BasicBlockLE yr = y.right;
1082        x.left = yr;
1083        if (yr != null) {
1084          yr.parent = x;
1085        }
1086        BasicBlockLE xp = x.parent;
1087        y.parent = xp;
1088        if (xp == null) {
1089          root = y;
1090        } else if (x == xp.right) {
1091          xp.right = y;
1092        } else {
1093          xp.left = y;
1094        }
1095        y.right = x;
1096        x.parent = y;
1097      }
1098    
1099      @SuppressWarnings("unused")
1100      // here for debugging
1101      private void verifyTree() {
1102        if (VM.VerifyAssertions) {
1103          VM._assert(root.isBlack());
1104          verifyTree(root, -1, bcodes.length());
1105          countBlack(root);
1106        }
1107      }
1108    
1109      private void verifyTree(BasicBlockLE node, int min, int max) {
1110        if (VM.VerifyAssertions) {
1111          VM._assert(node.low >= min);
1112          VM._assert(node.low <= max);
1113          if (node.left != null) {
1114            VM._assert(node.isBlack() || node.left.isBlack());
1115            VM._assert(node.left.parent == node);
1116            verifyTree(node.left, min, node.low);
1117          }
1118          if (node.right != null) {
1119            VM._assert(node.isBlack() || node.right.isBlack());
1120            VM._assert(node.right.parent == node);
1121            verifyTree(node.right, node.low, max);
1122          }
1123        }
1124      }
1125    
1126      private int countBlack(BasicBlockLE node) {
1127        if (node == null) return 1;
1128        int left = countBlack(node.left);
1129        int right = countBlack(node.right);
1130        if (VM.VerifyAssertions) VM._assert(left == right);
1131        if (node.isBlack()) {
1132          left++;
1133        }
1134        return left;
1135      }
1136    
1137      private static final class TreeEnumerator implements Enumeration<BasicBlockLE> {
1138        BasicBlockLE node;
1139    
1140        static BBSet.TreeEnumerator enumFromRoot(BasicBlockLE root) {
1141          if (root.left != null) {
1142            do {
1143              root = root.left;
1144            } while (root.left != null);
1145          }
1146          return new TreeEnumerator(root);
1147        }
1148    
1149        static BBSet.TreeEnumerator enumFromNode(BasicBlockLE node) {
1150          return new TreeEnumerator(node);
1151        }
1152    
1153        private TreeEnumerator(BasicBlockLE node) {
1154          this.node = node;
1155        }
1156    
1157        @Override
1158        public boolean hasMoreElements() {
1159          return (node != null);
1160        }
1161    
1162        public BasicBlockLE next() {
1163          BasicBlockLE retVal = node;
1164          if (retVal == null) {
1165            throw new NoSuchElementException();
1166          }
1167          if (retVal.right != null) {
1168            node = retVal.right;
1169            while (node.left != null) {
1170              node = node.left;
1171            }
1172          } else {
1173            BasicBlockLE x = retVal;
1174            node = x.parent;
1175            while ((node != null) && (node.right == x)) {
1176              x = node;
1177              node = x.parent;
1178            }
1179          }
1180          return retVal;
1181        }
1182    
1183        @Override
1184        public BasicBlockLE nextElement() {
1185          return next();
1186        }
1187      }
1188    }