autodtor.txt
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 文本 代码 · 共 239 行
TXT
239 行
Automatic Destruction of Stuff and Error Handling
=================================================
92/07/20 -- J.W.Welch -- initial writing
A) Introduction
------------
- stuff is data to be destructed and includes:
- automatic and static variables
- significant sub-objects of an object being destructed or constructed
- scheme must:
- integrate with exception handling
- handle asynchronous exceptions
- support multiple threads of execution
B) Data Structure Overview
-----------------------
- data structures are found in CPPLIB.H; any communication between run-
and compile-time is found in WCPP.H
- as a thread of execution progresses, control blocks are linked and
unlinked in stack fashion to maintain a execution description for:
- each active block containing autos to be DTOR'd
- each initialized module containing statics to be DTOR'd
- each try-catch activation
- each object being DTOR'd or CTOR'd
- arrays of objects being DTOR'd or CTOR'd are handled by the run-time
support for array DTOR/CTOR
- five data structures are found in the linked list for a thread:
- auto variables in a block
- sub-objects of an object being DTOR'd or CTOR'd
- static variables in a module
- an array being DTOR'd or CTOR'd
- try/catch specification
- each has a unique R/O block and unique routines to process these blocks
- a common header is used to distinguish the R/O blocks
- each R/W block has a common header:
- pointer to R/O block
- pointer to previous R/W block
- all structures use RW_DTOR_BLK as a base:
- autos, objects, and module-initializations have flags to indicate
that the n-th item needs to be DTOR'd
- objects also contain the object address
- array block contains the count and address of the array
- catch blocks contain the address of the JMPBUF used to implement
catches
- except for statics, the R/W block is allocated on the stack
C) R/O Data Structure for items to be DTOR'd
-----------------------------------------
- each such block is located from the RW_DTOR_BLOCK
- block is created at compilation time
- RW_DTOR_BLK located on stack and is initialized by a run-time
routine
- R/O block is:
- count of number of items
- vector of item descriptors
- item descriptor is
- address/offset of item to be DTOR'd
- is offset from RW_DTOR_BLK for autos
- is address for static variables in a module
- is offset from start of object for CTOR/DTOR sub-objects
- address of DTOR function
D) Mechanism for Automatic DTOR
----------------------------
- various routines are invoked to:
- DTOR part of a block
- DTOR entire block
- DTOR current + some number of blocks
- DTOR all blocks until a block is encountered
- try/catch blocks are ignored
- otherwise, data structure contains enough information to compute the
address of each item to be DTOR'd
- error if exception thrown while DTOR'ing during exception processing
E) Impact on DTOR
--------------
- DTOR epilogue must set up block to record DTOR'ing of sub-objects
- DTOR epilogue can be a run-time routine which DTOR's the top-level
block (set all flags to 1); alternatively, existing code can turn
off flags as sub-objects are DTOR'd
- the DTOR epilogue can be implemented as call to:
cpp_dtor_epi( void *element // - element to be DTOR'd
, unsigned flags // - flags passed to DTOR
, RO_DTOR_DEFN *def // - definition for R/T routine
, RW_DTOR_BLK *blk // - R/W block for element
);
- the RW_DTOR_BLK could be allocated dymnamically by cpp_dtor_epi
if more code-space saving is desired
- one of two routines could be used, depending on the optimization
level
- the RO_DTOR_DEFN block supplies information for the run-time DTOR
routine (cpp_dtor_epi):
struct RO_DTOR_DEFN
{ RO_DTOR_BLK *blk; // - RO_DTOR_BLK for a class element
void *(*dtor) // - DTOR for class element
( void *element // - - element to be DTOR'd
; unsigned flags ); // - - flags for DTOR routine
void (*opdel) // - operator delete to be used
( void *element ); // - - element to be deleted
unsigned virtuals; // - number of virtual bases
};
- pseudo code for cpp_dtor_epi( element, flags, def, blk ):
if array-dtor,
(0) call cpp_array_dtor
else
(1) set '11', non-virtual flags
(2) if required to dtor virtuals, set flags for virtuals
(3) set up rest of R/W block, link it to R/W dtor chain
(4) call cpp_block_close
(5) if required to delete
endif
return addr. of element
F) Impact on CTOR
--------------
- CTOR prologue must set up block to record CTOR'ing of sub-objects
- CTOR prologue must turn on flags as sub-objects are CTOR'd
- could set up a R/O block to be passed to a run-time routine for
CTOR routines without initializers
G) Try/Catch R/O block
-------------------
- assume there is a "signature" for each possible type to be considered
- this can be the address of a unique 1-byte variable (COMDAT) for
each type
- at try: R/O block indicates the type for each catch block
- count of number of catches
- signature of type for each catch, in order of appearance
- compiled code for try/catch is:
auto jmpbuf;
cpp_try( jmpbuf, rw_blk, ro_blk );
switch( setjmp( jmpbuf ) ) {
case 0:
- code for try
case 1:
- code for catch[1]
...
case n:
- code for catch[n]
}
- cpp_try( jmpbuf, rw_blk, ro_blk ) sets up rw_blk using jmpbuf, ro_blk
- it cannot contain the setjmp without tricky system-dependent
coding since the routine containing a setjmp must remain active
for a subsequent longjmp to work
- at throw: R/O throw block is constructed
- COMDAT data named by the type of the throw expression
- used to enumerate all possible conversions, for exception purposes,
of the throw expression
- contains:
- count of # of target conversions
- vector of conversion entries; each entry contains
- signature of target type
- address of conversion routine
- exception handling overview:
- search the try/catch blocks for the thread; for each block
- look for a signature match between a signature in the block
and a signature in the throw data structure
- abandon search at first match, and:
- convert (using the corresponding routine in the throw block) the
throw expression to target object (unique to the thread)
- DTOR items in all intervening blocks
- call cpp_catch
- when no matches, call terminate()
- cpp_catch( jmpbuf, int retn ) is a run-time routine:
jmpbuf -- saved by cpp_try
retn -- is base-1 index of catch block to be executed
implemented as: longjmp( jmpbuf, retn )
- details: incorporate proper control for terminate(), unexpected(),
set_terminate(), and set_unexpected()
H) Unknowns
--------
- what happens when exceptions are thrown during static initialization
or static completion ?
- initialization -- will either be caught by in an active routine or
no try blocks will be active and unexpected() will be called
- completion :
-- terminate() not called:
-- caught in an active routine (ok)
-- no try block active ==> call unexpected()
-- terminate() called
-- error condition (15.6.1)
I) Other details
-------------
- latest draft of standard has dictated a number of compilation conditions
that need to be detected (for example, "..." must be specified only in
last catch block.
- see description for unexpected(), terminate(), etc. for more details
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?