📄 gxxint.texi
字号:
We don't call delete on new expressions that die because the ctor threwan exception. See except/18 for a test case.15.2 para 13: The exception being handled should be rethrown if controlreaches the end of a handler of the function-try-block of a constructoror destructor, right now, it is not.15.2 para 12: If a return statement appears in a handler offunction-try-block of a constructor, the program is ill-formed, but thisisn't diagnosed.15.2 para 11: If the handlers of a function-try-block contain a jumpinto the body of a constructor or destructor, the program is ill-formed,but this isn't diagnosed.15.2 para 9: Check that the fully constructed base classes and membersof an object are destroyed before entering the handler of afunction-try-block of a constructor or destructor for that object.build_exception_variant should sort the incoming list, so that itimplements set compares, not exact list equality. Type smashing shouldsmash exception specifications using set union.Thrown objects are usually allocated on the heap, in the usual way. Ifone runs out of heap space, throwing an object will probably never work.This could be relaxed some by passing an __in_chrg parameter to trackwho has control over the exception object. Thrown objects are notallocated on the heap when they are pointer to object types. We shouldextend it so that all small (<4*sizeof(void*)) objects are storeddirectly, instead of allocated on the heap.When the backend returns a value, it can create new exception regionsthat need protecting. The new region should rethrow the object incontext of the last associated cleanup that ran to completion.The structure of the code that is generated for C++ exception handlingcode is shown below:@exampleLn: throw value; copy value onto heap jump throw (Ln, id, address of copy of value on heap) try @{+Lstart: the start of the main EH region|... ...+Lend: the end of the main EH region @} catch (T o) @{ ...1 @}Lresume: nop used to make sure there is something before the next region ends, if there is one... ... jump Ldone[Lmainhandler: handler for the region Lstart-Lend cleanup] zero or more, depending upon automatic vars with dtors+Lpartial:| jump Lover+Lhere: rethrow (Lhere, same id, same obj);Lterm: handler for the region Lpartial-Lhere call terminateLover:[ [ call throw_type_match if (eq) @{ ] these lines disappear when there is no catch condition+Lsregion2:| ...1| jump Lresume|Lhandler: handler for the region Lsregion2-Leregion2| rethrow (Lresume, same id, same obj);+Leregion2 @}] there are zero or more of these sections, depending upon how many catch clauses there are----------------------------- expand_end_all_catch -------------------------- here we have fallen off the end of all catch clauses, so we rethrow to outer rethrow (Lresume, same id, same obj);----------------------------- expand_end_all_catch --------------------------[L1: maybe throw routine] depending upon if we have expanded it or notLdone: retstart_all_catch emits labels: Lresume, @end exampleThe __unwind_function takes a pointer to the throw handler, and isexpected to pop the stack frame that was built to call it, as well asthe frame underneath and then jump to the throw handler. It mustrestore all registers to their proper values as well as all othermachine state as determined by the context in which we are unwindinginto. The way I normally start is to compile: void *g; foo(void* a) @{ g = a; @}with -S, and change the thing that alters the PC (return, or retusually) to not alter the PC, making sure to leave all other semantics(like adjusting the stack pointer, or frame pointers) in. After that,replicate the prologue once more at the end, again, changing the PCaltering instructions, and finally, at the very end, jump to `g'.It takes about a week to write this routine, if someone wants tovolunteer to write this routine for any architecture, exception supportfor that architecture will be added to g++. Please send in those codedonations. One other thing that needs to be done, is to double checkthat __builtin_return_address (0) works.@subsection Specific TargetsFor the alpha, the __unwind_function will be something resembling:@examplevoid__unwind_function(void *ptr)@{ /* First frame */ asm ("ldq $15, 8($30)"); /* get the saved frame ptr; 15 is fp, 30 is sp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Second frame */ asm ("ldq $15, 8($30)"); /* fp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Return */ asm ("ret $31, ($16), 1"); /* return to PTR, stored in a0 */@}@end example@noindentHowever, there are a few problems preventing it from working. First ofall, the gcc-internal function @code{__builtin_return_address} needs towork given an argument of 0 for the alpha. As it stands as of August30th, 1995, the code for @code{BUILT_IN_RETURN_ADDRESS} in @file{expr.c}will definitely not work on the alpha. Instead, we need to definethe macros @code{DYNAMIC_CHAIN_ADDRESS} (maybe),@code{RETURN_ADDR_IN_PREVIOUS_FRAME}, and definitely need a newdefinition for @code{RETURN_ADDR_RTX}.In addition (and more importantly), we need a way to reliably find theframe pointer on the alpha. The use of the value 8 above to restore theframe pointer (register 15) is incorrect. On many systems, the framepointer is consistently offset to a specific point on the stack. On thealpha, however, the frame pointer is pushed last. First the returnaddress is stored, then any other registers are saved (e.g., @code{s0}),and finally the frame pointer is put in place. So @code{fp} could havean offset of 8, but if the calling function saved any registers at all,they add to the offset.The only places the frame size is noted are with the @samp{.frame}directive, for use by the debugger and the OSF exception handling model(useless to us), and in the initial computation of the new value for@code{sp}, the stack pointer. For example, the function may start with:@examplelda $30,-32($30).frame $15,32,$26,0@end example @noindentThe 32 above is exactly the value we need. With this, we can be surethat the frame pointer is stored 8 bytes less---in this case, at 24(sp)).The drawback is that there is no way that I (Brendan) have found to letus discover the size of a previous frame @emph{inside} the definitionof @code{__unwind_function}.So to accomplish exception handling support on the alpha, we need twothings: first, a way to figure out where the frame pointer was stored,and second, a functional @code{__builtin_return_address} implementationfor except.c to be able to use it.Or just support DWARF 2 unwind info.@subsection New Backend Exception SupportThis subsection discusses various aspects of the design of thedata-driven model being implemented for the exception handling backend.The goal is to generate enough data during the compilation of user code,such that we can dynamically unwind through functions at run time with asingle routine (@code{__throw}) that lives in libgcc.a, built by thecompiler, and dispatch into associated exception handlers.This information is generated by the DWARF 2 debugging backend, andincludes all of the information __throw needs to unwind an arbitraryframe. It specifies where all of the saved registers and the returnaddress can be found at any point in the function.Major disadvantages when enabling exceptions are:@itemize @bullet@itemCode that uses caller saved registers, can't, when flow can betransferred into that code from an exception handler. In high performancecode this should not usually be true, so the effects should be minimal.@end itemize@subsection Backend Exception SupportThe backend must be extended to fully support exceptions. Right nowthere are a few hooks into the alpha exception handling backend thatresides in the C++ frontend from that backend that allows exceptionhandling to work in g++. An exception region is a segment of generatedcode that has a handler associated with it. The exception regions aredenoted in the generated code as address ranges denoted by a starting PCvalue and an ending PC value of the region. Some of the limitationswith this scheme are:@itemize @bullet@itemThe backend replicates insns for such things as loop unrolling andfunction inlining. Right now, there are no hooks into the frontend'sexception handling backend to handle the replication of insns. Whenreplication happens, a new exception region descriptor needs to begenerated for the new region.@itemThe backend expects to be able to rearrange code, for things like jumpoptimization. Any rearranging of the code needs have exception regiondescriptors updated appropriately.@itemThe backend can eliminate dead code. Any associated exception regiondescriptor that refers to fully contained code that has been eliminatedshould also be removed, although not doing this is harmless in terms ofsemantics.@end itemizeThe above is not meant to be exhaustive, but does include all things Ihave thought of so far. I am sure other limitations exist.Below are some notes on the migration of the exception handling codebackend from the C++ frontend to the backend.NOTEs are to be used to denote the start of an exception region, and theend of the region. I presume that the interface used to generate thesenotes in the backend would be two functions, start_exception_region andend_exception_region (or something like that). The frontends arerequired to call them in pairs. When marking the end of a region, anargument can be passed to indicate the handler for the marked region.This can be passed in many ways, currently a tree is used. Anotherpossibility would be insns for the handler, or a label that denotes ahandler. I have a feeling insns might be the best way to pass it.Semantics are, if an exception is thrown inside the region, control istransferred unconditionally to the handler. If control passes throughthe handler, then the backend is to rethrow the exception, in thecontext of the end of the original region. The handler is protected bythe conventional mechanisms; it is the frontend's responsibility toprotect the handler, if special semantics are required.This is a very low level view, and it would be nice is the backendsupported a somewhat higher level view in addition to this view. Thishigher level could include source line number, name of the source file,name of the language that threw the exception and possibly the name ofthe exception. Kenner may want to rope you into doing more than justthe basics required by C++. You will have to resolve this. He may wantyou to do support for non-local gotos, first scan for exception handler,if none is found, allow the debugger to be entered, without any cleanupsbeing done. To do this, the backend would have to know the differencebetween a cleanup-rethrower, and a real handler, if would also have tohave a way to know if a handler `matches' a thrown exception, and thisis frontend specific.The stack unwinder is one of the hardest parts to do. It is highlymachine dependent. The form that kenner seems to like was a couple ofmacros, that would do the machine dependent grunt work. One preexistingfunction that might be of some use is __builtin_return_address (). Onemacro he seemed to want was __builtin_return_address, and the otherwould do the hard work of fixing up the registers, adjusting the stackpointer, frame pointer, arg pointer and so on.@node Free Store, Mangling, Exception Handling, Top@section Free Store@code{operator new []} adds a magic cookie to the beginning of arraysfor which the number of elements will be needed by @code{operator delete[]}. These are arrays of objects with destructors and arrays of objectsthat define @code{operator delete []} with the optional size_t argument.This cookie can be examined from a program as follows:@exampletypedef unsigned long size_t;extern "C" int printf (const char *, ...);size_t nelts (void *p)@{ struct cookie @{ size_t nelts __attribute__ ((aligned (sizeof (double)))); @}; cookie *cp = (cookie *)p; --cp; return cp->nelts;@}struct A @{ ~A() @{ @}@};main()@{ A *ap = new A[3]; printf ("%ld\n", nelts (ap));@}@end example@section LinkageThe linkage code in g++ is horribly twisted in order to meet two design goals:1) Avoid unnecessary emission of inlines and vtables.2) Support pedantic assemblers like the one in AIX.To meet the first goal, we defer emission of inlines and vtables untilthe end of the translation unit, where we can decide whether or not theyare needed, and how to emit them if they are. @node Mangling, Vtables, Free Store, Top@section Function name mangling for C++ and JavaBoth C++ and Jave provide overloaded function and methods,which are methods with the same types but different parameter lists.Selecting the correct version is done at compile time.Though the overloaded functions have the same name in the source code,they need to be translated into different assembler-level names,since typical assemblers and linkers cannot handle overloading.This process of encoding the parameter types with the method nameinto a unique name is called @dfn{name mangling}. The inverseprocess is called @dfn{demangling}.It is convenient that C++ and Java use compatible mangling schemes,since the makes life easier for tools such as gdb, and it easesintegration between C++ and Java.Note there is also a standard "Jave Native Interface" (JNI) whichimplements a different calling convention, and uses a differentmangling scheme. The JNI is a rather abstract ABI so Java can call methodswritten in C or C++; we are concerned here about a lower-level interface primarilyintended for methods written in Java, but that can also be used for C++(and less easily C).Note that on systems that follow BSD tradition, a C identifier @code{var}would get "mangled" into the assembler name @samp{_var}. On suchsystems, all other mangled names are also prefixed by a @samp{_}which is not shown in the following examples.@subsection Method name manglingC++ mangles a method by emitting the function name, followed by @code{__},followed by encodings of any method qualifiers (such as @code{const}),followed by the mangling of the method's class,followed by the mangling of the parameters, in order.For example @code{Foo::bar(int, long) const} is mangledas @samp{bar__C3Fooil}.For a constructor, the method name is left out.That is @code{Foo::Foo(int, long) const} is mangled as @samp{__C3Fooil}.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -