Exception mechanism internals


Overview

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.