private List<Object[]> buildJVMExceptionTable() {
    List<Object[]> etEntries = new ArrayList<Object[]>();
    for (BasicBlock b : linearizedBBList) {
      // We need handlers for:
      // - Unrescuable    (handled by ensures),
      // - Throwable      (handled by rescues)
      // in that order since Throwable < Unrescuable
      BasicBlock rBB = cfg().getRescuerBBFor(b);
      BasicBlock eBB = cfg().getEnsurerBBFor(b);
      if ((eBB != null) && (rBB == eBB || rBB == null)) {
        // 1. same rescue and ensure handler ==> just spit out one entry with a Throwable class
        // 2. only ensure handler            ==> just spit out one entry with a Throwable class

        etEntries.add(new Object[] {b.getLabel(), eBB.getLabel(), Throwable.class});
      } else if (rBB != null) {
        // Unrescuable comes before Throwable
        if (eBB != null)
          etEntries.add(new Object[] {b.getLabel(), eBB.getLabel(), Unrescuable.class});
        etEntries.add(new Object[] {b.getLabel(), rBB.getLabel(), Throwable.class});
      }
    }

    // SSS FIXME: This could be optimized by compressing entries for adjacent BBs that have
    // identical handlers
    // This could be optimized either during generation or as another pass over the table.  But, if
    // the JVM
    // does that already, do we need to bother with it?
    return etEntries;
  }
  private Instr[] prepareInstructionsForInterpretation() {
    checkRelinearization();

    if (linearizedInstrArray != null) return linearizedInstrArray; // Already prepared

    try {
      buildLinearization(); // FIXME: compiler passes should have done this
      depends(linearization());
    } catch (RuntimeException e) {
      LOG.error("Error linearizing cfg: ", e);
      CFG c = cfg();
      LOG.error("\nGraph:\n" + c.toStringGraph());
      LOG.error("\nInstructions:\n" + c.toStringInstrs());
      throw e;
    }

    // Set up IPCs
    HashMap<Label, Integer> labelIPCMap = new HashMap<Label, Integer>();
    List<Instr> newInstrs = new ArrayList<Instr>();
    int ipc = 0;
    for (BasicBlock b : linearizedBBList) {
      labelIPCMap.put(b.getLabel(), ipc);
      List<Instr> bbInstrs = b.getInstrs();
      int bbInstrsLength = bbInstrs.size();
      for (int i = 0; i < bbInstrsLength; i++) {
        Instr instr = bbInstrs.get(i);

        if (instr instanceof Specializeable) {
          instr = ((Specializeable) instr).specializeForInterpretation();
          bbInstrs.set(i, instr);
        }

        if (!(instr instanceof ReceiveSelfInstr)) {
          newInstrs.add(instr);
          ipc++;
        }
      }
    }

    // Set up label PCs
    setupLabelPCs(labelIPCMap);

    // Exit BB ipc
    cfg().getExitBB().getLabel().setTargetPC(ipc + 1);

    linearizedInstrArray = newInstrs.toArray(new Instr[newInstrs.size()]);
    return linearizedInstrArray;
  }
  // SSS FIXME: Extremely inefficient
  public int getEnsurerPC(Instr excInstr) {
    depends(cfg());

    for (BasicBlock b : linearizedBBList) {
      for (Instr i : b.getInstrs()) {
        if (i == excInstr) {
          BasicBlock ensurerBB = cfg.getEnsurerBBFor(b);
          return (ensurerBB == null) ? -1 : ensurerBB.getLabel().getTargetPC();
        }
      }
    }

    // SSS FIXME: Cannot happen! Throw runtime exception
    LOG.error("Fell through looking for ensurer ipc for " + excInstr);
    return -1;
  }
  /** Run any necessary passes to get the IR ready for compilation */
  public Tuple<Instr[], Map<Integer, Label[]>> prepareForCompilation() {
    // Build CFG and run compiler passes, if necessary
    if (getCFG() == null) runCompilerPasses();

    // Add this always since we dont re-JIT a previously
    // JIT-ted closure.  But, check if there are other
    // smarts available to us and eliminate adding this
    // code to every closure there is.
    //
    // Add a global ensure block to catch uncaught breaks
    // and throw a LocalJumpError.
    if (this instanceof IRClosure && ((IRClosure) this).addGEBForUncaughtBreaks()) {
      this.relinearizeCFG = true;
    }

    try {
      buildLinearization(); // FIXME: compiler passes should have done this
      depends(linearization());
    } catch (RuntimeException e) {
      LOG.error("Error linearizing cfg: ", e);
      CFG c = cfg();
      LOG.error("\nGraph:\n" + c.toStringGraph());
      LOG.error("\nInstructions:\n" + c.toStringInstrs());
      throw e;
    }

    // Set up IPCs
    // FIXME: Would be nice to collapse duplicate labels; for now, using Label[]
    HashMap<Integer, Label[]> ipcLabelMap = new HashMap<Integer, Label[]>();
    List<Instr> newInstrs = new ArrayList<Instr>();
    int ipc = 0;
    for (BasicBlock b : linearizedBBList) {
      Label l = b.getLabel();
      ipcLabelMap.put(ipc, catLabels(ipcLabelMap.get(ipc), l));
      for (Instr i : b.getInstrs()) {
        if (!(i instanceof ReceiveSelfInstr)) {
          newInstrs.add(i);
          ipc++;
        }
      }
    }

    return new Tuple<Instr[], Map<Integer, Label[]>>(
        newInstrs.toArray(new Instr[newInstrs.size()]), ipcLabelMap);
  }
 private void setupLabelPCs(HashMap<Label, Integer> labelIPCMap) {
   for (BasicBlock b : linearizedBBList) {
     Label l = b.getLabel();
     l.setTargetPC(labelIPCMap.get(l));
   }
 }