private void compileTryStatement(
     MethodVisitor mv, Label tryStart, Label tryEnd, Label tryCatchEnd) {
   mv.visitLabel(tryStart);
   IRBytecodeCompiler.compileIRStatement(_stmt().getTryBody(), _context);
   inlineLocalFinallyStmt(_stmt().getTryBody(), tryCatchEnd);
   mv.visitLabel(tryEnd);
 }
  private void inlineLocalFinallyStmt(IRStatement tryOrCatchStmt, Label labelEnd) {
    MethodVisitor mv = _context.getMv();

    if (tryOrCatchStmt.getLeastSignificantTerminalStatement() == null) {
      if (hasFinally()) {
        _finallyPartitioner.inlineFinally();
        NamedLabel endLabel =
            new NamedLabel("EndFinally" + _finallyPartitioner.getFinallyEnds().size());
        _context.visitLabel(endLabel);
        _finallyPartitioner.endInlineFinally(endLabel);
      }

      // Also jump to end of finally
      mv.visitJumpInsn(Opcodes.GOTO, labelEnd);
    }
  }
  private void compileFinallyStatement(MethodVisitor mv, Label tryStart) {
    Label finallyStart = new NamedLabel("Finally Start ");
    mv.visitLabel(finallyStart);
    declareCatchExtents(
        mv, tryStart, finallyStart, finallyStart, JavaClassIRType.get(Throwable.class));
    int iExceptionIndex =
        _context
            .getLocalVar(
                new IRSymbol("**temp**throwable**", JavaClassIRType.get(Throwable.class), true))
            .getIndex();
    mv.visitVarInsn(Opcodes.ASTORE, iExceptionIndex);

    IRBytecodeCompiler.compileIRStatement(_stmt().getFinallyBody(), _context);

    if (_stmt().getFinallyBody().getLeastSignificantTerminalStatement() == null) {
      mv.visitVarInsn(Opcodes.ALOAD, iExceptionIndex);
      mv.visitInsn(Opcodes.ATHROW);
    }
  }
 private void insertTryCatchBlock(
     MethodVisitor mv, Label handlerStart, IRType type, Label start, Label end) {
   if (start.getOffset() > end.getOffset()) {
     throw new IllegalStateException("start label must precede the end label");
   } else if (start.getOffset()
       != end
           .getOffset()) { // If start == end, then we want to ignore it and not generate any
                           // exception table entry
     mv.visitTryCatchBlock(start, end, handlerStart, type.getSlashName());
   }
 }
  public static void compile(IRIfStatement statement, IRBytecodeContext context) {
    MethodVisitor mv = context.getMv();

    IRBytecodeCompiler.compileIRExpression(statement.getExpression(), context);

    Label afterIf = new Label();
    mv.visitJumpInsn(Opcodes.IFEQ, afterIf);
    IRBytecodeCompiler.compileIRStatement(statement.getIfStatement(), context);
    if (statement.getElseStatement() != null) {
      Label afterElse = new Label();
      boolean bTerminal = statement.getLeastSignificantTerminalStatement() != null;
      if (!bTerminal) {
        mv.visitJumpInsn(Opcodes.GOTO, afterElse);
      }
      mv.visitLabel(afterIf);

      IRBytecodeCompiler.compileIRStatement(statement.getElseStatement(), context);

      if (!bTerminal) {
        mv.visitLabel(afterElse);
      }
    } else {
      mv.visitLabel(afterIf);
    }
  }
  public static void compile(IRTernaryExpression expression, IRBytecodeContext context) {
    // TODO - Gosu Perf - We could make this more efficient by inspecting the conditional expression
    // for common
    // patterns like equality expressions or other comparisons
    MethodVisitor mv = context.getMv();

    Label trueLabel = new Label();
    if (isComparisonToNull(expression.getTest())) {
      IRBytecodeCompiler.compileIRExpression(
          getNonNullEqualityOperand(expression.getTest()), context);
      mv.visitJumpInsn(
          getNullOpCode(expression.getTest()),
          trueLabel); // i.e. jump to trueLabel if the expression is equal to null
    } else {
      IRBytecodeCompiler.compileIRExpression(expression.getTest(), context);
      mv.visitJumpInsn(
          Opcodes.IFNE,
          trueLabel); // i.e. jump to trueLabel if the expression returned true and thus left a
                      // non-zero value on the stack
    }

    IRBytecodeCompiler.compileIRExpression(expression.getFalseValue(), context);
    Label falseLabel = new Label();
    mv.visitJumpInsn(Opcodes.GOTO, falseLabel);
    mv.visitLabel(trueLabel);
    IRBytecodeCompiler.compileIRExpression(expression.getTrueValue(), context);
    mv.visitLabel(falseLabel);
  }
  private void compile() {
    MethodVisitor mv = _context.getMv();

    Label tryStart = new NamedLabel("TryStart");
    Label tryEnd = new NamedLabel("TryEnd");
    Label tryCatchFinallyEnd = new NamedLabel("TryCatchFinallyEnd");
    List<IRCatchClause> catchStmts = _stmt().getCatchStatements();

    _finallyPartitioner = pushFinallyStmt();
    try {
      compileTryStatement(mv, tryStart, tryEnd, tryCatchFinallyEnd);

      if (catchStmts != null && !catchStmts.isEmpty()) {
        compileCatchStatements(mv, tryStart, tryEnd, tryCatchFinallyEnd, catchStmts);
      }
      if (hasFinally()) {
        compileFinallyStatement(mv, tryStart);
      }
      mv.visitLabel(tryCatchFinallyEnd);
    } finally {
      popFinallyStmt(_finallyPartitioner);
    }
  }
 private void assignExceptionParam(MethodVisitor mv, IRSymbol exceptionSym) {
   IRCompilerLocalVar exceptionVar = _context.getLocalVar(exceptionSym);
   mv.visitVarInsn(Opcodes.ASTORE, exceptionVar.getIndex());
 }