Mail Archives: djgpp/1998/05/20/23:11:13
Josh Rubin wrote in message <35620fc6 DOT 4685212 AT news1 DOT bway DOT net>...
>Suppose an assembly language routine calls a C++ function.
>Does the new exception handling mechanism require that
>the assembly language routine do anything special for
>stack unwinding in case an exception is thrown?
This might help. Its from the file except.c in gcc/cp directory
Andy
/* ======================================================================
Briefly the algorithm works like this:
When a constructor or start of a try block is encountered,
push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
new entry in the unwind protection stack and returns a label to
output to start the protection for that block.
When a destructor or end try block is encountered, pop_eh_entry
(&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
created when push_eh_entry () was called. The eh_entry structure
contains three things at this point. The start protect label,
the end protect label, and the exception handler label. The end
protect label should be output before the call to the destructor
(if any). If it was a destructor, then its parse tree is stored
in the finalization variable in the eh_entry structure. Otherwise
the finalization variable is set to NULL to reflect the fact that
it is the end of a try block. Next, this modified eh_entry node
is enqueued in the finalizations queue by calling
enqueue_eh_entry (&queue,entry).
+---------------------------------------------------------------+
|XXX: Will need modification to deal with partially |
| constructed arrays of objects |
| |
| Basically, this consists of keeping track of how many |
| of the objects have been constructed already (this |
| should be in a register though, so that shouldn't be a |
| problem. |
+---------------------------------------------------------------+
When a catch block is encountered, there is a lot of work to be
done.
Since we don't want to generate the catch block inline with the
regular flow of the function, we need to have some way of doing
so. Luckily, we can use sequences to defer the catch sections.
When the start of a catch block is encountered, we start the
sequence. After the catch block is generated, we end the
sequence.
Next we must insure that when the catch block is executed, all
finalizations for the matching try block have been completed. If
any of those finalizations throw an exception, we must call
terminate according to the ARM (section r.15.6.1). What this
means is that we need to dequeue and emit finalizations for each
entry in the eh_queue until we get to an entry with a NULL
finalization field. For any of the finalization entries, if it
is not a call to terminate (), we must protect it by giving it
another start label, end label, and exception handler label,
setting its finalization tree to be a call to terminate (), and
enqueue'ing this new eh_entry to be output at an outer level.
Finally, after all that is done, we can get around to outputting
the catch block which basically wraps all the "catch (...) {...}"
statements in a big if/then/else construct that matches the
correct block to call.
- Raw text -