Exception mechanism internals
This article documents exception handling mechanisms at implementation level, including runtime and code generation.
Typical execution/trace stack operation in a routine
Once or routine with old variable is slightly different. See following pseudocode:
-- entry new_exset do -- eif_stack: Create a new vector EX_CALL on eif_stack. end if not setjmp then -- Routine body else exresc do -- eif_trace: Check the stack of eif_trace top element must be EN_FAIL or EN_RES -- eif_trace: Mark top node as rescued -- eif_trace: Create new EN_ILVL item on eif_trace, indicating entering a new level -- eif_stack: Create new EX_RESC vector on eif_stack. end Rescue_body -- If there is retry clause, it calls exret do -- eif_stack: Check top vector of eif_stack is EX_RESC -- eif_stack: Override top item of eif_stack with the vector of current routine (saved as local). Change the type of the vector to EX_RETY -- eif_trace: Pop off eif_trace, which must be EN_ILVL item -- eif_trace: unwind_trace, pop items from eif_trace until EN_ILVL item is found. Restore `exdata' at previous level. end -- If no retry is called, call at the end: exfail do -- eif_stack: pop EX_RESC from eif_stack -- eif_trace: pop EN_ILVL from eif_trace, leaving call failures created by `draise' on stack. -- create last_exception (ROUTINE_FAILURE) -- eif_stack: call `backtrack' which will pop eif_stack until find the top most jmpbuf. -- Call longjmp with the found jmpbuf. end end exok do -- eif_stack: Pop eif_stack until a EX_CALL, EX_RESC, EX_RETY or EX_OSTK is found and popped. -- eif_trace: unwind_trace, pop item from eif_trace until we find EN_ILVL item. Restore `exdata' at previous level. end
Raise an exception (draise, eraise, com_raise, )
- Create a new item on eif_trace, with the type the exception.
- Pop and push back eif_stack in order to get information. Fill those information into `exdata'.
- Setup information for top node in eif_trace.
- In make_exception, when building trace, traverse eif_stack, and push corresponding items into eif_trace, until jmp pointer is found. In the meantime, if the item is EX_RESC, we change it to EN_OLVL and put into eif_trace.
- Continue buidling trace from the rest element of eif_stack until root node is reached.
- Call `back_track' to really pop off items in eif_stack and call longjmp when the first jmp pointer is found.
System signal handler
- Push an EN_ILVL item on eif_trace
- Push an EX_HDLR item on eif_stack and setup a jmpbuf
- Call exception handler and be ready to longjmp back and call eraise to populate the exception.