private void updateUnboxedVarsInfo(
      Instr i, UnboxState state, Variable dst, boolean hasRescuer, boolean isDFBarrier) {
    HashSet<Variable> varsToBox = new HashSet<Variable>();
    // Special treatment for instructions that can raise exceptions
    if (i.canRaiseException()) {
      if (hasRescuer) {
        // If we are going to be rescued,
        // box all unboxed dirty vars before we execute the instr.
        state.unboxedDirtyVars.clear();
      } else {
        // We are going to exit if an exception is raised.
        // So, only need to bother with dirty live local vars for closures
        if (problem.getScope() instanceof IRClosure) {
          markLocalVariables(varsToBox, state.unboxedDirtyVars);
        }
      }
    }

    if (isDFBarrier) {
      // All dirty unboxed local vars will get reboxed.
      markLocalVariables(varsToBox, state.unboxedDirtyVars);

      // We have to re-unbox local variables as necessary since we don't
      // know how they are going to change once we get past this instruction.
      List<Variable> lvs = new ArrayList<Variable>();
      markLocalVariables(lvs, state.unboxedVars.keySet());

      state.unboxedVars.keySet().removeAll(lvs);
    }

    // Update set of unboxed dirty vars
    state.unboxedDirtyVars.removeAll(varsToBox);

    // FIXME: Also global variables .. see LVA / StoreLocalVar analysis.

    // B_TRUE and B_FALSE have unboxed forms and their operands
    // needn't get boxed back.
    Operation op = i.getOperation();
    if (op != Operation.B_TRUE && op != Operation.B_FALSE) {
      // Vars used by this instruction that only exist in unboxed form
      // will have to get boxed before it is executed
      state.unboxedDirtyVars.removeAll(i.getUsedVariables());
    }

    // If the instruction writes into 'dst', it will be in boxed form.
    if (dst != null) {
      state.unboxedVars.remove(dst);
      state.unboxedDirtyVars.remove(dst);
    }
  }
  private void boxRequiredVars(
      Instr i,
      UnboxState state,
      Map<Variable, TemporaryLocalVariable> unboxMap,
      Variable dst,
      boolean hasRescuer,
      boolean isDFBarrier,
      List<Instr> newInstrs) {
    // Special treatment for instructions that can raise exceptions
    boolean isClosure = problem.getScope() instanceof IRClosure;
    HashSet<Variable> varsToBox = new HashSet<Variable>();
    if (i.canRaiseException()) {
      if (hasRescuer) {
        // If we are going to be rescued,
        // box all unboxed dirty vars before we execute the instr
        varsToBox.addAll(state.unboxedDirtyVars);
      } else if (isClosure) {
        // We are going to exit if an exception is raised.
        // So, only need to bother with dirty live local vars for closures
        markLocalVariables(varsToBox, state.unboxedDirtyVars);
      }
    }

    if (isClosure && (i instanceof ReturnInstr || i instanceof BreakInstr)) {
      markLocalVariables(varsToBox, state.unboxedDirtyVars);
    }

    if (isDFBarrier) {
      // All dirty unboxed (local) vars will get reboxed.
      markLocalVariables(varsToBox, state.unboxedDirtyVars);

      // We have to re-unbox local variables as necessary since we don't
      // know how they are going to change once we get past this instruction.
      List<Variable> lvs = new ArrayList<Variable>();
      markLocalVariables(lvs, state.unboxedVars.keySet());

      state.unboxedVars.keySet().removeAll(lvs);
    }

    // B_TRUE and B_FALSE have unboxed forms and their operands
    // needn't get boxed back.
    Operation op = i.getOperation();
    boolean isBranch = op == Operation.B_TRUE || op == Operation.B_FALSE;
    if (!isBranch) {
      // Vars used by this instruction that only exist in unboxed form
      // will have to get boxed before it is executed
      for (Variable v : i.getUsedVariables()) {
        if (state.unboxedDirtyVars.contains(v)) {
          varsToBox.add(v);
        }
      }
    }

    // Add boxing instrs.
    for (Variable v : varsToBox) {
      boxVar(state, state.unboxedVars.get(v), unboxMap, v, newInstrs);
    }

    // Add 'i' itself
    if (isBranch) {
      OneOperandBranchInstr bi = (OneOperandBranchInstr) i;
      Operand a = bi.getArg1();
      Operand ua = getUnboxedOperand(state, unboxMap, a);
      if (ua == a) {
        newInstrs.add(i);
      } else if (op == Operation.B_TRUE) {
        newInstrs.add(new BTrueInstr(Operation.B_TRUE, ua, bi.getJumpTarget()));
      } else {
        newInstrs.add(new BFalseInstr(Operation.B_FALSE, ua, bi.getJumpTarget()));
      }
    } else {
      newInstrs.add(i);
    }

    // If the instruction writes into 'dst', it will be in boxed form.
    if (dst != null) {
      state.unboxedVars.remove(dst);
      state.unboxedDirtyVars.remove(dst);
    }
  }