Reserve a global (or thread-local) variable to store a pointer to the current exception. Analyze to determine if a function can throw an exception:
Set can_throw = false initially (true if there is a throw statement)
Compute can_throw for child functions
If a child can throw, set can_throw = false
Use an enum: can_throw = true | false | undef
If a function can_throw, then generate an if block after the call to check if current_exception is non-null. If it is, then cleanup, and jump to the finally or catch if there is one; otherwise, return garbage to rax and leave current_exception set.
Justification for this plan (vs. a table-driven exception handling scheme like C++ has):
C interoperability
Performance during exception throw/stack unwind (GCC has to do a binary search to find EH)
Cost slight code performance loss from error-checking if blocks (just 1 extra instruction)
To start, do not support try/throw/catch. Just mark yield as 'can_throw', and then perform can_throw analysis and add error-checking if blocks.
Reserve a global (or thread-local) variable to store a pointer to the current exception. Analyze to determine if a function can throw an exception:
can_throw = false
initially (true
if there is a throw statement)can_throw
for child functionscan_throw = false
can_throw = true | false | undef
If a function
can_throw
, then generate anif
block after the call to check ifcurrent_exception
is non-null. If it is, then cleanup, and jump to thefinally
orcatch
if there is one; otherwise, return garbage torax
and leavecurrent_exception
set.Justification for this plan (vs. a table-driven exception handling scheme like C++ has):
if
blocks (just 1 extra instruction)To start, do not support try/throw/catch. Just mark
yield
as 'can_throw', and then performcan_throw
analysis and add error-checkingif
blocks.