Label rBeginLabel = m.getNewLabel();
Label rEndLabel = ebi.end;
List<Label> rescueLabels = new ArrayList<Label>() { };
// Start of region
m.addInstr(new LABEL_Instr(rBeginLabel));
m.addInstr(new ExceptionRegionStartMarkerInstr(rBeginLabel, rEndLabel, rescueLabels));
// Generate IR for Code being protected
Operand rv = (bodyNode instanceof RescueNode) ? buildRescueInternal(bodyNode, m, rBeginLabel) : build(bodyNode, m);
// End of protected region
m.addInstr(new ExceptionRegionEndMarkerInstr());
// Jump to start of ensure block -- dont bother if we had a return in the protected body
if (rv != U_NIL)
m.addInstr(new SET_RETADDR_Instr(ebi.returnAddr, rEndLabel));
// Pop the current ensure block info node *BEFORE* generating the ensure code for this block itself!
_ensureBlockStack.pop();
// Generate the ensure block now
m.addInstr(new LABEL_Instr(ebi.start));
// Two cases:
// 1. Ensure block has no explicit return => the result of the entire ensure expression is the result of the protected body.
// 2. Ensure block has an explicit return => the result of the protected body is ignored.
Operand ensureRetVal = (ensureNode.getEnsureNode() == null) ? Nil.NIL : build(ensureNode.getEnsureNode(), m);
if (ensureRetVal == null) // null => there was a return from within the ensure block!
rv = null;
m.addInstr(new JUMP_INDIRECT_Instr(ebi.returnAddr));
// Now build the dummy rescue block that:
// * catches all exceptions thrown by the body
// * jumps to the ensure block code
// * returns back (via set_retaddr instr)
// * rethrows the caught exception
Label dummyRescueBlockLabel = m.getNewLabel();
Label rethrowExcLabel = m.getNewLabel();
rescueLabels.add(dummyRescueBlockLabel);
Variable exc = m.getNewTemporaryVariable();
m.addInstr(new LABEL_Instr(dummyRescueBlockLabel));
m.addInstr(new RECV_EXCEPTION_Instr(exc));
m.addInstr(new SET_RETADDR_Instr(ebi.returnAddr, rethrowExcLabel));
m.addInstr(new JumpInstr(ebi.start));
m.addInstr(new LABEL_Instr(rethrowExcLabel));
m.addInstr(new THROW_EXCEPTION_Instr(exc));
// End label for the exception region
m.addInstr(new LABEL_Instr(rEndLabel));
return rv;
}