First, let's see what does exception handling do in C++.
Compares the type of exception object to that of catch blocks to find appropriate catch block.
Handles the exception.
Stack unwinding.
To achieve this:
Objects should be trackable for unwinding - a table storing objects (objects table)
Location of throw should be identifiable (location)
Catch blocks should be attached to corresponding try block (tryblock and catchblocks)
Because of call stack, objects for unwinding and exception handling objects should be linked for unwinding (exception handlers list)
Exception handler should associate tryblock and objects table (exption handler)
So the data structures should be:
//If the exception isnot handled, this list will be traversed to unwind all objects.
struct ExceptionHandlerList {
ExceptionList* prev;
ExceptionHandler* handler;
};
struct ExceptionHandler {
TryBlock* tryBlocks;
UnwindTable* unwind;
};
struct TryBlock {
Location* region;
CatchBlock* catchBlocks;
};
struck CatchBlock {
type_info* typeInfo;
Instruction* handler;
};
struct UnwindTable {
void* pObj;
void (*pDtor)(void* this);
intnext;
};
struct Exception {
void* pObj;// Actual exception object
void (*pDtor)(void*);// Dtor of actual exception object
type_info* typeInfo;// Type info of actual exception
Location* loc;
}
OK. Now let's check how these work together.
The throw statement will generate an object of Exception using the thrown exception
System call exception handling procedure, taking the object of Exception as argument, in which:
Current ExceptionHandlerList object will be retrieved to get the right TryBlock
Optional: if TryBlock object found, search the tryBlocks in current handler with the Location loc to get the CatchBlock list
Optional: if TryBlock object found, search the CatchBlock list with type of actual exception to get the actual handler
Optional: if CatchBlock found, execute the actual exception handler
Call Dtor to destroy all objects ready for unwinding
Optional: If no actual exception handler is executed, find previous ExceptionHandlerList object through the prev pointer (until none previous is found), passing the object of Exception to the handler, then repeat the handling procedure.
CallHandler(handler, e);// Destroy Exception object e
DestroyObjectsInTryBlock(cur->unwind, tryBlk);
handled =true;
}
}
if(!handled)
{
DestroyObjects(cur->unwind);
cur = cur->prev;
}
}
}
Note: Objects of UnwindTable, TryBlock, CatchBlock, ExceptionHandler are populated during compile time, while objects of Exception and list of ExceptionHandlerList are generated at runtime.