except.c revision 52284
1194246Smarius/* Implements exception handling. 2194246Smarius Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc. 3194246Smarius Contributed by Mike Stump <mrs@cygnus.com>. 4194246Smarius 5194246SmariusThis file is part of GNU CC. 6194246Smarius 7194246SmariusGNU CC is free software; you can redistribute it and/or modify 8194246Smariusit under the terms of the GNU General Public License as published by 9194246Smariusthe Free Software Foundation; either version 2, or (at your option) 10194246Smariusany later version. 11194246Smarius 12194246SmariusGNU CC is distributed in the hope that it will be useful, 13194246Smariusbut WITHOUT ANY WARRANTY; without even the implied warranty of 14194246SmariusMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15194246SmariusGNU General Public License for more details. 16194246Smarius 17194246SmariusYou should have received a copy of the GNU General Public License 18194246Smariusalong with GNU CC; see the file COPYING. If not, write to 19194246Smariusthe Free Software Foundation, 59 Temple Place - Suite 330, 20194246SmariusBoston, MA 02111-1307, USA. */ 21194246Smarius 22194246Smarius 23194246Smarius/* An exception is an event that can be signaled from within a 24194246Smarius function. This event can then be "caught" or "trapped" by the 25194246Smarius callers of this function. This potentially allows program flow to 26194246Smarius be transferred to any arbitrary code associated with a function call 27194246Smarius several levels up the stack. 28194246Smarius 29194246Smarius The intended use for this mechanism is for signaling "exceptional 30194246Smarius events" in an out-of-band fashion, hence its name. The C++ language 31194246Smarius (and many other OO-styled or functional languages) practically 32194246Smarius requires such a mechanism, as otherwise it becomes very difficult 33194246Smarius or even impossible to signal failure conditions in complex 34194246Smarius situations. The traditional C++ example is when an error occurs in 35194246Smarius the process of constructing an object; without such a mechanism, it 36194246Smarius is impossible to signal that the error occurs without adding global 37194246Smarius state variables and error checks around every object construction. 38194246Smarius 39194246Smarius The act of causing this event to occur is referred to as "throwing 40194246Smarius an exception". (Alternate terms include "raising an exception" or 41194246Smarius "signaling an exception".) The term "throw" is used because control 42194246Smarius is returned to the callers of the function that is signaling the 43194246Smarius exception, and thus there is the concept of "throwing" the 44194246Smarius exception up the call stack. 45194246Smarius 46194246Smarius There are two major codegen options for exception handling. The 47194246Smarius flag -fsjlj-exceptions can be used to select the setjmp/longjmp 48194246Smarius approach, which is the default. -fno-sjlj-exceptions can be used to 49194246Smarius get the PC range table approach. While this is a compile time 50194246Smarius flag, an entire application must be compiled with the same codegen 51194246Smarius option. The first is a PC range table approach, the second is a 52194246Smarius setjmp/longjmp based scheme. We will first discuss the PC range 53194246Smarius table approach, after that, we will discuss the setjmp/longjmp 54194246Smarius based approach. 55194246Smarius 56194246Smarius It is appropriate to speak of the "context of a throw". This 57194246Smarius context refers to the address where the exception is thrown from, 58194246Smarius and is used to determine which exception region will handle the 59194246Smarius exception. 60194904Smarius 61194246Smarius Regions of code within a function can be marked such that if it 62194246Smarius contains the context of a throw, control will be passed to a 63194246Smarius designated "exception handler". These areas are known as "exception 64194246Smarius regions". Exception regions cannot overlap, but they can be nested 65194246Smarius to any arbitrary depth. Also, exception regions cannot cross 66194246Smarius function boundaries. 67194246Smarius 68194246Smarius Exception handlers can either be specified by the user (which we 69194246Smarius will call a "user-defined handler") or generated by the compiler 70194246Smarius (which we will designate as a "cleanup"). Cleanups are used to 71194246Smarius perform tasks such as destruction of objects allocated on the 72194246Smarius stack. 73194246Smarius 74194246Smarius In the current implementation, cleanups are handled by allocating an 75194246Smarius exception region for the area that the cleanup is designated for, 76194246Smarius and the handler for the region performs the cleanup and then 77194246Smarius rethrows the exception to the outer exception region. From the 78194246Smarius standpoint of the current implementation, there is little 79207585Smarius distinction made between a cleanup and a user-defined handler, and 80194246Smarius the phrase "exception handler" can be used to refer to either one 81194246Smarius equally well. (The section "Future Directions" below discusses how 82194246Smarius this will change). 83194246Smarius 84194246Smarius Each object file that is compiled with exception handling contains 85194246Smarius a static array of exception handlers named __EXCEPTION_TABLE__. 86194246Smarius Each entry contains the starting and ending addresses of the 87194246Smarius exception region, and the address of the handler designated for 88194246Smarius that region. 89194246Smarius 90194246Smarius If the target does not use the DWARF 2 frame unwind information, at 91194246Smarius program startup each object file invokes a function named 92194246Smarius __register_exceptions with the address of its local 93194246Smarius __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and 94194246Smarius is responsible for recording all of the exception regions into one list 95194246Smarius (which is kept in a static variable named exception_table_list). 96194246Smarius 97194246Smarius On targets that support crtstuff.c, the unwind information 98194246Smarius is stored in a section named .eh_frame and the information for the 99194246Smarius entire shared object or program is registered with a call to 100194246Smarius __register_frame_info. On other targets, the information for each 101194246Smarius translation unit is registered from the file generated by collect2. 102194246Smarius __register_frame_info is defined in frame.c, and is responsible for 103194246Smarius recording all of the unwind regions into one list (which is kept in a 104194246Smarius static variable named unwind_table_list). 105194246Smarius 106194246Smarius The function __throw is actually responsible for doing the 107194246Smarius throw. On machines that have unwind info support, __throw is generated 108194246Smarius by code in libgcc2.c, otherwise __throw is generated on a 109194246Smarius per-object-file basis for each source file compiled with 110194246Smarius -fexceptions by the C++ frontend. Before __throw is invoked, 111194246Smarius the current context of the throw needs to be placed in the global 112194246Smarius variable __eh_pc. 113194246Smarius 114194246Smarius __throw attempts to find the appropriate exception handler for the 115194246Smarius PC value stored in __eh_pc by calling __find_first_exception_table_match 116194246Smarius (which is defined in libgcc2.c). If __find_first_exception_table_match 117194246Smarius finds a relevant handler, __throw transfers control directly to it. 118194246Smarius 119194246Smarius If a handler for the context being thrown from can't be found, __throw 120194246Smarius walks (see Walking the stack below) the stack up the dynamic call chain to 121194246Smarius continue searching for an appropriate exception handler based upon the 122194246Smarius caller of the function it last sought a exception handler for. It stops 123194246Smarius then either an exception handler is found, or when the top of the 124194246Smarius call chain is reached. 125194246Smarius 126194246Smarius If no handler is found, an external library function named 127194246Smarius __terminate is called. If a handler is found, then we restart 128194246Smarius our search for a handler at the end of the call chain, and repeat 129194246Smarius the search process, but instead of just walking up the call chain, 130194246Smarius we unwind the call chain as we walk up it. 131194246Smarius 132194246Smarius Internal implementation details: 133194246Smarius 134194246Smarius To associate a user-defined handler with a block of statements, the 135194246Smarius function expand_start_try_stmts is used to mark the start of the 136194246Smarius block of statements with which the handler is to be associated 137194246Smarius (which is known as a "try block"). All statements that appear 138194246Smarius afterwards will be associated with the try block. 139194904Smarius 140194904Smarius A call to expand_start_all_catch marks the end of the try block, 141194246Smarius and also marks the start of the "catch block" (the user-defined 142194246Smarius handler) associated with the try block. 143194246Smarius 144194246Smarius This user-defined handler will be invoked for *every* exception 145194246Smarius thrown with the context of the try block. It is up to the handler 146194246Smarius to decide whether or not it wishes to handle any given exception, 147194246Smarius as there is currently no mechanism in this implementation for doing 148194246Smarius this. (There are plans for conditionally processing an exception 149194246Smarius based on its "type", which will provide a language-independent 150194246Smarius mechanism). 151194246Smarius 152194246Smarius If the handler chooses not to process the exception (perhaps by 153194246Smarius looking at an "exception type" or some other additional data 154194246Smarius supplied with the exception), it can fall through to the end of the 155194246Smarius handler. expand_end_all_catch and expand_leftover_cleanups 156194246Smarius add additional code to the end of each handler to take care of 157194246Smarius rethrowing to the outer exception handler. 158194246Smarius 159194246Smarius The handler also has the option to continue with "normal flow of 160194246Smarius code", or in other words to resume executing at the statement 161194246Smarius immediately after the end of the exception region. The variable 162194246Smarius caught_return_label_stack contains a stack of labels, and jumping 163194246Smarius to the topmost entry's label via expand_goto will resume normal 164194246Smarius flow to the statement immediately after the end of the exception 165194246Smarius region. If the handler falls through to the end, the exception will 166194246Smarius be rethrown to the outer exception region. 167194246Smarius 168194904Smarius The instructions for the catch block are kept as a separate 169194246Smarius sequence, and will be emitted at the end of the function along with 170194904Smarius the handlers specified via expand_eh_region_end. The end of the 171194246Smarius catch block is marked with expand_end_all_catch. 172194246Smarius 173194246Smarius Any data associated with the exception must currently be handled by 174194246Smarius some external mechanism maintained in the frontend. For example, 175194246Smarius the C++ exception mechanism passes an arbitrary value along with 176194246Smarius the exception, and this is handled in the C++ frontend by using a 177194246Smarius global variable to hold the value. (This will be changing in the 178194246Smarius future.) 179210334Sattilio 180194246Smarius The mechanism in C++ for handling data associated with the 181194246Smarius exception is clearly not thread-safe. For a thread-based 182194246Smarius environment, another mechanism must be used (possibly using a 183194246Smarius per-thread allocation mechanism if the size of the area that needs 184194246Smarius to be allocated isn't known at compile time.) 185194246Smarius 186194246Smarius Internally-generated exception regions (cleanups) are marked by 187194246Smarius calling expand_eh_region_start to mark the start of the region, 188194246Smarius and expand_eh_region_end (handler) is used to both designate the 189194246Smarius end of the region and to associate a specified handler/cleanup with 190194246Smarius the region. The rtl code in HANDLER will be invoked whenever an 191194246Smarius exception occurs in the region between the calls to 192194246Smarius expand_eh_region_start and expand_eh_region_end. After HANDLER is 193194246Smarius executed, additional code is emitted to handle rethrowing the 194194246Smarius exception to the outer exception handler. The code for HANDLER will 195194246Smarius be emitted at the end of the function. 196194246Smarius 197194246Smarius TARGET_EXPRs can also be used to designate exception regions. A 198194246Smarius TARGET_EXPR gives an unwind-protect style interface commonly used 199194246Smarius in functional languages such as LISP. The associated expression is 200194246Smarius evaluated, and whether or not it (or any of the functions that it 201194246Smarius calls) throws an exception, the protect expression is always 202194246Smarius invoked. This implementation takes care of the details of 203194246Smarius associating an exception table entry with the expression and 204194246Smarius generating the necessary code (it actually emits the protect 205194246Smarius expression twice, once for normal flow and once for the exception 206223986Smarius case). As for the other handlers, the code for the exception case 207194904Smarius will be emitted at the end of the function. 208194904Smarius 209194904Smarius Cleanups can also be specified by using add_partial_entry (handler) 210194904Smarius and end_protect_partials. add_partial_entry creates the start of 211194904Smarius a new exception region; HANDLER will be invoked if an exception is 212194904Smarius thrown with the context of the region between the calls to 213194904Smarius add_partial_entry and end_protect_partials. end_protect_partials is 214194904Smarius used to mark the end of these regions. add_partial_entry can be 215194904Smarius called as many times as needed before calling end_protect_partials. 216194904Smarius However, end_protect_partials should only be invoked once for each 217245923Smarius group of calls to add_partial_entry as the entries are queued 218194904Smarius and all of the outstanding entries are processed simultaneously 219245923Smarius when end_protect_partials is invoked. Similarly to the other 220245923Smarius handlers, the code for HANDLER will be emitted at the end of the 221245923Smarius function. 222245923Smarius 223194246Smarius The generated RTL for an exception region includes 224194246Smarius NOTE_INSN_EH_REGION_BEG and NOTE_INSN_EH_REGION_END notes that mark 225194246Smarius the start and end of the exception region. A unique label is also 226194246Smarius generated at the start of the exception region, which is available 227194246Smarius by looking at the ehstack variable. The topmost entry corresponds 228194246Smarius to the current region. 229194246Smarius 230194246Smarius In the current implementation, an exception can only be thrown from 231194246Smarius a function call (since the mechanism used to actually throw an 232194904Smarius exception involves calling __throw). If an exception region is 233194246Smarius created but no function calls occur within that region, the region 234194246Smarius can be safely optimized away (along with its exception handlers) 235194246Smarius since no exceptions can ever be caught in that region. This 236194246Smarius optimization is performed unless -fasynchronous-exceptions is 237194246Smarius given. If the user wishes to throw from a signal handler, or other 238194246Smarius asynchronous place, -fasynchronous-exceptions should be used when 239194246Smarius compiling for maximally correct code, at the cost of additional 240194246Smarius exception regions. Using -fasynchronous-exceptions only produces 241194246Smarius code that is reasonably safe in such situations, but a correct 242194246Smarius program cannot rely upon this working. It can be used in failsafe 243194246Smarius code, where trying to continue on, and proceeding with potentially 244194246Smarius incorrect results is better than halting the program. 245194246Smarius 246194246Smarius 247194246Smarius Walking the stack: 248194246Smarius 249194246Smarius The stack is walked by starting with a pointer to the current 250194246Smarius frame, and finding the pointer to the callers frame. The unwind info 251194246Smarius tells __throw how to find it. 252194246Smarius 253194246Smarius Unwinding the stack: 254194246Smarius 255194246Smarius When we use the term unwinding the stack, we mean undoing the 256194246Smarius effects of the function prologue in a controlled fashion so that we 257194246Smarius still have the flow of control. Otherwise, we could just return 258194246Smarius (jump to the normal end of function epilogue). 259194246Smarius 260194246Smarius This is done in __throw in libgcc2.c when we know that a handler exists 261194246Smarius in a frame higher up the call stack than its immediate caller. 262194246Smarius 263194246Smarius To unwind, we find the unwind data associated with the frame, if any. 264194246Smarius If we don't find any, we call the library routine __terminate. If we do 265194246Smarius find it, we use the information to copy the saved register values from 266194246Smarius that frame into the register save area in the frame for __throw, return 267194246Smarius into a stub which updates the stack pointer, and jump to the handler. 268194246Smarius The normal function epilogue for __throw handles restoring the saved 269194246Smarius values into registers. 270194246Smarius 271194246Smarius When unwinding, we use this method if we know it will 272194246Smarius work (if DWARF2_UNWIND_INFO is defined). Otherwise, we know that 273194246Smarius an inline unwinder will have been emitted for any function that 274194246Smarius __unwind_function cannot unwind. The inline unwinder appears as a 275194246Smarius normal exception handler for the entire function, for any function 276194246Smarius that we know cannot be unwound by __unwind_function. We inform the 277194246Smarius compiler of whether a function can be unwound with 278194246Smarius __unwind_function by having DOESNT_NEED_UNWINDER evaluate to true 279194246Smarius when the unwinder isn't needed. __unwind_function is used as an 280194246Smarius action of last resort. If no other method can be used for 281194246Smarius unwinding, __unwind_function is used. If it cannot unwind, it 282194246Smarius should call __terminate. 283194246Smarius 284194246Smarius By default, if the target-specific backend doesn't supply a definition 285194246Smarius for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined 286194246Smarius unwinders will be used instead. The main tradeoff here is in text space 287194246Smarius utilization. Obviously, if inline unwinders have to be generated 288194246Smarius repeatedly, this uses much more space than if a single routine is used. 289194246Smarius 290194246Smarius However, it is simply not possible on some platforms to write a 291194246Smarius generalized routine for doing stack unwinding without having some 292194246Smarius form of additional data associated with each function. The current 293194246Smarius implementation can encode this data in the form of additional 294194246Smarius machine instructions or as static data in tabular form. The later 295194246Smarius is called the unwind data. 296194246Smarius 297194246Smarius The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether 298194246Smarius or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is 299194246Smarius defined and has a non-zero value, a per-function unwinder is not emitted 300194246Smarius for the current function. If the static unwind data is supported, then 301194246Smarius a per-function unwinder is not emitted. 302194246Smarius 303194246Smarius On some platforms it is possible that neither __unwind_function 304194246Smarius nor inlined unwinders are available. For these platforms it is not 305194246Smarius possible to throw through a function call, and abort will be 306194246Smarius invoked instead of performing the throw. 307194246Smarius 308194246Smarius The reason the unwind data may be needed is that on some platforms 309194246Smarius the order and types of data stored on the stack can vary depending 310194246Smarius on the type of function, its arguments and returned values, and the 311194246Smarius compilation options used (optimization versus non-optimization, 312194246Smarius -fomit-frame-pointer, processor variations, etc). 313194246Smarius 314194246Smarius Unfortunately, this also means that throwing through functions that 315194246Smarius aren't compiled with exception handling support will still not be 316194246Smarius possible on some platforms. This problem is currently being 317194246Smarius investigated, but no solutions have been found that do not imply 318194246Smarius some unacceptable performance penalties. 319194246Smarius 320194246Smarius Future directions: 321194246Smarius 322194246Smarius Currently __throw makes no differentiation between cleanups and 323194246Smarius user-defined exception regions. While this makes the implementation 324194246Smarius simple, it also implies that it is impossible to determine if a 325194246Smarius user-defined exception handler exists for a given exception without 326194246Smarius completely unwinding the stack in the process. This is undesirable 327194246Smarius from the standpoint of debugging, as ideally it would be possible 328194246Smarius to trap unhandled exceptions in the debugger before the process of 329207585Smarius unwinding has even started. 330207585Smarius 331207585Smarius This problem can be solved by marking user-defined handlers in a 332207585Smarius special way (probably by adding additional bits to exception_table_list). 333207585Smarius A two-pass scheme could then be used by __throw to iterate 334207585Smarius through the table. The first pass would search for a relevant 335207585Smarius user-defined handler for the current context of the throw, and if 336207585Smarius one is found, the second pass would then invoke all needed cleanups 337207585Smarius before jumping to the user-defined handler. 338207585Smarius 339207585Smarius Many languages (including C++ and Ada) make execution of a 340207585Smarius user-defined handler conditional on the "type" of the exception 341207585Smarius thrown. (The type of the exception is actually the type of the data 342207585Smarius that is thrown with the exception.) It will thus be necessary for 343207585Smarius __throw to be able to determine if a given user-defined 344207585Smarius exception handler will actually be executed, given the type of 345207585Smarius exception. 346245923Smarius 347245923Smarius One scheme is to add additional information to exception_table_list 348245923Smarius as to the types of exceptions accepted by each handler. __throw 349207585Smarius can do the type comparisons and then determine if the handler is 350207585Smarius actually going to be executed. 351207585Smarius 352245923Smarius There is currently no significant level of debugging support 353207585Smarius available, other than to place a breakpoint on __throw. While 354213893Smarius this is sufficient in most cases, it would be helpful to be able to 355213893Smarius know where a given exception was going to be thrown to before it is 356215721Smarius actually thrown, and to be able to choose between stopping before 357194246Smarius every exception region (including cleanups), or just user-defined 358207585Smarius exception regions. This should be possible to do in the two-pass 359207585Smarius scheme by adding additional labels to __throw for appropriate 360207585Smarius breakpoints, and additional debugger commands could be added to 361207585Smarius query various state variables to determine what actions are to be 362207585Smarius performed next. 363207585Smarius 364207585Smarius Another major problem that is being worked on is the issue with stack 365207585Smarius unwinding on various platforms. Currently the only platforms that have 366207585Smarius support for the generation of a generic unwinder are the SPARC and MIPS. 367207585Smarius All other ports require per-function unwinders, which produce large 368207585Smarius amounts of code bloat. 369245923Smarius 370207585Smarius For setjmp/longjmp based exception handling, some of the details 371207585Smarius are as above, but there are some additional details. This section 372207585Smarius discusses the details. 373207585Smarius 374245923Smarius We don't use NOTE_INSN_EH_REGION_{BEG,END} pairs. We don't 375207585Smarius optimize EH regions yet. We don't have to worry about machine 376213893Smarius specific issues with unwinding the stack, as we rely upon longjmp 377213893Smarius for all the machine specific details. There is no variable context 378215721Smarius of a throw, just the one implied by the dynamic handler stack 379194246Smarius pointed to by the dynamic handler chain. There is no exception 380207585Smarius table, and no calls to __register_exceptions. __sjthrow is used 381207585Smarius instead of __throw, and it works by using the dynamic handler 382207585Smarius chain, and longjmp. -fasynchronous-exceptions has no effect, as 383207585Smarius the elimination of trivial exception regions is not yet performed. 384194246Smarius 385207585Smarius A frontend can set protect_cleanup_actions_with_terminate when all 386207585Smarius the cleanup actions should be protected with an EH region that 387207585Smarius calls terminate when an unhandled exception is throw. C++ does 388207585Smarius this, Ada does not. */ 389207585Smarius 390207585Smarius 391207585Smarius#include "config.h" 392194246Smarius#include "defaults.h" 393207585Smarius#include "eh-common.h" 394207585Smarius#include "system.h" 395207585Smarius#include "rtl.h" 396207585Smarius#include "tree.h" 397207585Smarius#include "flags.h" 398213893Smarius#include "except.h" 399213893Smarius#include "function.h" 400215721Smarius#include "insn-flags.h" 401194246Smarius#include "expr.h" 402194246Smarius#include "insn-codes.h" 403213893Smarius#include "regs.h" 404194246Smarius#include "hard-reg-set.h" 405194246Smarius#include "insn-config.h" 406194246Smarius#include "recog.h" 407194246Smarius#include "output.h" 408194246Smarius#include "toplev.h" 409194246Smarius#include "intl.h" 410194246Smarius#include "obstack.h" 411194246Smarius 412194246Smarius/* One to use setjmp/longjmp method of generating code for exception 413194246Smarius handling. */ 414194246Smarius 415194246Smariusint exceptions_via_longjmp = 2; 416194246Smarius 417194246Smarius/* One to enable asynchronous exception support. */ 418194246Smarius 419194246Smariusint asynchronous_exceptions = 0; 420194246Smarius 421194246Smarius/* One to protect cleanup actions with a handler that calls 422194246Smarius __terminate, zero otherwise. */ 423194246Smarius 424194246Smariusint protect_cleanup_actions_with_terminate; 425194246Smarius 426194246Smarius/* A list of labels used for exception handlers. Created by 427194246Smarius find_exception_handler_labels for the optimization passes. */ 428194246Smarius 429194246Smariusrtx exception_handler_labels; 430194246Smarius 431194246Smarius/* The EH context. Nonzero if the function has already 432194246Smarius fetched a pointer to the EH context for exception handling. */ 433194246Smarius 434194246Smariusrtx current_function_ehc; 435194246Smarius 436194246Smarius/* A stack used for keeping track of the currently active exception 437194246Smarius handling region. As each exception region is started, an entry 438194246Smarius describing the region is pushed onto this stack. The current 439194246Smarius region can be found by looking at the top of the stack, and as we 440194246Smarius exit regions, the corresponding entries are popped. 441194246Smarius 442194246Smarius Entries cannot overlap; they can be nested. So there is only one 443194246Smarius entry at most that corresponds to the current instruction, and that 444194246Smarius is the entry on the top of the stack. */ 445194246Smarius 446194246Smariusstatic struct eh_stack ehstack; 447194246Smarius 448194246Smarius 449194246Smarius/* This stack is used to represent what the current eh region is 450194246Smarius for the catch blocks beings processed */ 451194246Smarius 452194246Smariusstatic struct eh_stack catchstack; 453194246Smarius 454194246Smarius/* A queue used for tracking which exception regions have closed but 455194246Smarius whose handlers have not yet been expanded. Regions are emitted in 456194246Smarius groups in an attempt to improve paging performance. 457194246Smarius 458194246Smarius As we exit a region, we enqueue a new entry. The entries are then 459194246Smarius dequeued during expand_leftover_cleanups and expand_start_all_catch, 460194246Smarius 461194246Smarius We should redo things so that we either take RTL for the handler, 462194246Smarius or we expand the handler expressed as a tree immediately at region 463194246Smarius end time. */ 464194246Smarius 465194246Smariusstatic struct eh_queue ehqueue; 466194246Smarius 467194904Smarius/* Insns for all of the exception handlers for the current function. 468194904Smarius They are currently emitted by the frontend code. */ 469194246Smarius 470194246Smariusrtx catch_clauses; 471194246Smarius 472194246Smarius/* A TREE_CHAINed list of handlers for regions that are not yet 473194246Smarius closed. The TREE_VALUE of each entry contains the handler for the 474194246Smarius corresponding entry on the ehstack. */ 475194246Smarius 476194246Smariusstatic tree protect_list; 477194246Smarius 478194246Smarius/* Stacks to keep track of various labels. */ 479194246Smarius 480194904Smarius/* Keeps track of the label to resume to should one want to resume 481194246Smarius normal control flow out of a handler (instead of, say, returning to 482194246Smarius the caller of the current function or exiting the program). */ 483194246Smarius 484194246Smariusstruct label_node *caught_return_label_stack = NULL; 485194246Smarius 486194904Smarius/* Keeps track of the label used as the context of a throw to rethrow an 487194904Smarius exception to the outer exception region. */ 488194246Smarius 489194904Smariusstruct label_node *outer_context_label_stack = NULL; 490194246Smarius 491194246Smarius/* A random data area for the front end's own use. */ 492194246Smarius 493194246Smariusstruct label_node *false_label_stack = NULL; 494194246Smarius 495194246Smarius/* Pseudos used to hold exception return data in the interim between 496194246Smarius __builtin_eh_return and the end of the function. */ 497194246Smarius 498194246Smariusstatic rtx eh_return_context; 499194246Smariusstatic rtx eh_return_stack_adjust; 500194246Smariusstatic rtx eh_return_handler; 501194246Smarius 502194246Smarius/* Used to mark the eh return stub for flow, so that the Right Thing 503194246Smarius happens with the values for the hardregs therin. */ 504194246Smarius 505194246Smariusrtx eh_return_stub_label; 506194246Smarius 507194246Smarius/* This is used for targets which can call rethrow with an offset instead 508194246Smarius of an address. This is subtracted from the rethrow label we are 509194246Smarius interested in. */ 510194246Smarius 511194246Smariusstatic rtx first_rethrow_symbol = NULL_RTX; 512194246Smariusstatic rtx final_rethrow = NULL_RTX; 513194246Smariusstatic rtx last_rethrow_symbol = NULL_RTX; 514194246Smarius 515194246Smarius 516194246Smarius/* Prototypes for local functions. */ 517194246Smarius 518194246Smariusstatic void push_eh_entry PROTO((struct eh_stack *)); 519194246Smariusstatic struct eh_entry * pop_eh_entry PROTO((struct eh_stack *)); 520194246Smariusstatic void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *)); 521194246Smariusstatic struct eh_entry * dequeue_eh_entry PROTO((struct eh_queue *)); 522194246Smariusstatic rtx call_get_eh_context PROTO((void)); 523194246Smariusstatic void start_dynamic_cleanup PROTO((tree, tree)); 524194246Smariusstatic void start_dynamic_handler PROTO((void)); 525194246Smariusstatic void expand_rethrow PROTO((rtx)); 526194246Smariusstatic void output_exception_table_entry PROTO((FILE *, int)); 527194246Smariusstatic int can_throw PROTO((rtx)); 528194246Smariusstatic rtx scan_region PROTO((rtx, int, int *)); 529194246Smariusstatic void eh_regs PROTO((rtx *, rtx *, rtx *, int)); 530194246Smariusstatic void set_insn_eh_region PROTO((rtx *, int)); 531194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP 532194246Smariusstatic void jumpif_rtx PROTO((rtx, rtx)); 533194246Smarius#endif 534194246Smarius 535194246Smariusrtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); 536194246Smarius 537194246Smarius/* Various support routines to manipulate the various data structures 538194246Smarius used by the exception handling code. */ 539194246Smarius 540194246Smariusextern struct obstack permanent_obstack; 541194246Smarius 542194246Smarius/* Generate a SYMBOL_REF for rethrow to use */ 543194246Smariusstatic rtx 544194246Smariuscreate_rethrow_ref (region_num) 545194246Smarius int region_num; 546194246Smarius{ 547194246Smarius rtx def; 548194246Smarius char *ptr; 549194246Smarius char buf[60]; 550194246Smarius 551194246Smarius push_obstacks_nochange (); 552194246Smarius end_temporary_allocation (); 553194246Smarius 554194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num); 555194246Smarius ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf)); 556194246Smarius def = gen_rtx_SYMBOL_REF (Pmode, ptr); 557194246Smarius SYMBOL_REF_NEED_ADJUST (def) = 1; 558194246Smarius 559194246Smarius pop_obstacks (); 560194246Smarius return def; 561194246Smarius} 562194246Smarius 563194246Smarius/* Push a label entry onto the given STACK. */ 564194246Smarius 565194246Smariusvoid 566194246Smariuspush_label_entry (stack, rlabel, tlabel) 567194246Smarius struct label_node **stack; 568194246Smarius rtx rlabel; 569194246Smarius tree tlabel; 570194246Smarius{ 571194246Smarius struct label_node *newnode 572194246Smarius = (struct label_node *) xmalloc (sizeof (struct label_node)); 573194246Smarius 574194246Smarius if (rlabel) 575194246Smarius newnode->u.rlabel = rlabel; 576194246Smarius else 577194246Smarius newnode->u.tlabel = tlabel; 578194246Smarius newnode->chain = *stack; 579194246Smarius *stack = newnode; 580194246Smarius} 581194246Smarius 582194246Smarius/* Pop a label entry from the given STACK. */ 583194246Smarius 584194246Smariusrtx 585194246Smariuspop_label_entry (stack) 586194246Smarius struct label_node **stack; 587194246Smarius{ 588194246Smarius rtx label; 589194246Smarius struct label_node *tempnode; 590194246Smarius 591194246Smarius if (! *stack) 592194246Smarius return NULL_RTX; 593194246Smarius 594194246Smarius tempnode = *stack; 595194246Smarius label = tempnode->u.rlabel; 596194246Smarius *stack = (*stack)->chain; 597194246Smarius free (tempnode); 598194246Smarius 599194246Smarius return label; 600194246Smarius} 601194246Smarius 602194246Smarius/* Return the top element of the given STACK. */ 603194246Smarius 604194246Smariustree 605194246Smariustop_label_entry (stack) 606194246Smarius struct label_node **stack; 607194246Smarius{ 608194246Smarius if (! *stack) 609194246Smarius return NULL_TREE; 610194246Smarius 611194246Smarius return (*stack)->u.tlabel; 612194246Smarius} 613194246Smarius 614194246Smarius/* get an exception label. These must be on the permanent obstack */ 615194246Smarius 616194246Smariusrtx 617194246Smariusgen_exception_label () 618194246Smarius{ 619194246Smarius rtx lab; 620194246Smarius lab = gen_label_rtx (); 621194246Smarius return lab; 622194246Smarius} 623194246Smarius 624194246Smarius/* Push a new eh_node entry onto STACK. */ 625194246Smarius 626194246Smariusstatic void 627194246Smariuspush_eh_entry (stack) 628194246Smarius struct eh_stack *stack; 629194246Smarius{ 630194246Smarius struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node)); 631194246Smarius struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry)); 632194246Smarius 633194246Smarius rtx rlab = gen_exception_label (); 634194246Smarius entry->finalization = NULL_TREE; 635194246Smarius entry->label_used = 0; 636194904Smarius entry->exception_handler_label = rlab; 637194246Smarius entry->false_label = NULL_RTX; 638194246Smarius if (! flag_new_exceptions) 639194246Smarius entry->outer_context = gen_label_rtx (); 640194246Smarius else 641194246Smarius entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab)); 642194246Smarius entry->rethrow_label = entry->outer_context; 643194246Smarius 644194246Smarius node->entry = entry; 645194246Smarius node->chain = stack->top; 646194246Smarius stack->top = node; 647194246Smarius} 648194246Smarius 649194246Smarius/* push an existing entry onto a stack. */ 650194246Smariusstatic void 651194246Smariuspush_entry (stack, entry) 652194246Smarius struct eh_stack *stack; 653194246Smarius struct eh_entry *entry; 654194246Smarius{ 655194246Smarius struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node)); 656194246Smarius node->entry = entry; 657194246Smarius node->chain = stack->top; 658194246Smarius stack->top = node; 659194246Smarius} 660194246Smarius 661194246Smarius/* Pop an entry from the given STACK. */ 662194246Smarius 663194246Smariusstatic struct eh_entry * 664194246Smariuspop_eh_entry (stack) 665194246Smarius struct eh_stack *stack; 666194246Smarius{ 667194246Smarius struct eh_node *tempnode; 668194246Smarius struct eh_entry *tempentry; 669194246Smarius 670194246Smarius tempnode = stack->top; 671194904Smarius tempentry = tempnode->entry; 672194904Smarius stack->top = stack->top->chain; 673194246Smarius free (tempnode); 674194904Smarius 675194904Smarius return tempentry; 676194246Smarius} 677194246Smarius 678194246Smarius/* Enqueue an ENTRY onto the given QUEUE. */ 679194246Smarius 680194246Smariusstatic void 681194246Smariusenqueue_eh_entry (queue, entry) 682194246Smarius struct eh_queue *queue; 683194246Smarius struct eh_entry *entry; 684194246Smarius{ 685194246Smarius struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node)); 686194246Smarius 687194246Smarius node->entry = entry; 688194246Smarius node->chain = NULL; 689194246Smarius 690194246Smarius if (queue->head == NULL) 691194246Smarius { 692194246Smarius queue->head = node; 693194246Smarius } 694194246Smarius else 695194246Smarius { 696194246Smarius queue->tail->chain = node; 697194246Smarius } 698194246Smarius queue->tail = node; 699194246Smarius} 700194246Smarius 701194246Smarius/* Dequeue an entry from the given QUEUE. */ 702194246Smarius 703194246Smariusstatic struct eh_entry * 704194246Smariusdequeue_eh_entry (queue) 705194246Smarius struct eh_queue *queue; 706194246Smarius{ 707194246Smarius struct eh_node *tempnode; 708194246Smarius struct eh_entry *tempentry; 709194246Smarius 710194246Smarius if (queue->head == NULL) 711194246Smarius return NULL; 712194246Smarius 713194246Smarius tempnode = queue->head; 714194246Smarius queue->head = queue->head->chain; 715194246Smarius 716194246Smarius tempentry = tempnode->entry; 717194246Smarius free (tempnode); 718194246Smarius 719194246Smarius return tempentry; 720194246Smarius} 721194246Smarius 722194246Smariusstatic void 723194246Smariusreceive_exception_label (handler_label) 724194246Smarius rtx handler_label; 725194246Smarius{ 726194246Smarius emit_label (handler_label); 727194246Smarius 728194246Smarius#ifdef HAVE_exception_receiver 729194246Smarius if (! exceptions_via_longjmp) 730194246Smarius if (HAVE_exception_receiver) 731194246Smarius emit_insn (gen_exception_receiver ()); 732194246Smarius#endif 733194246Smarius 734194246Smarius#ifdef HAVE_nonlocal_goto_receiver 735194246Smarius if (! exceptions_via_longjmp) 736194246Smarius if (HAVE_nonlocal_goto_receiver) 737194246Smarius emit_insn (gen_nonlocal_goto_receiver ()); 738194246Smarius#endif 739194246Smarius} 740194246Smarius 741194246Smarius 742194246Smariusstruct func_eh_entry 743194246Smarius{ 744194246Smarius int range_number; /* EH region number from EH NOTE insn's */ 745194246Smarius rtx rethrow_label; /* Label for rethrow */ 746194246Smarius struct handler_info *handlers; 747194246Smarius}; 748194246Smarius 749194246Smarius 750194246Smarius/* table of function eh regions */ 751194246Smariusstatic struct func_eh_entry *function_eh_regions = NULL; 752194246Smariusstatic int num_func_eh_entries = 0; 753194246Smariusstatic int current_func_eh_entry = 0; 754194246Smarius 755194246Smarius#define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X) 756194246Smarius 757194246Smarius/* Add a new eh_entry for this function, and base it off of the information 758194246Smarius in the EH_ENTRY parameter. A NULL parameter is invalid. 759194246Smarius OUTER_CONTEXT is a label which is used for rethrowing. The number 760194246Smarius returned is an number which uniquely identifies this exception range. */ 761194246Smarius 762194246Smariusstatic int 763194246Smariusnew_eh_region_entry (note_eh_region, rethrow) 764194246Smarius int note_eh_region; 765194246Smarius rtx rethrow; 766194246Smarius{ 767194246Smarius if (current_func_eh_entry == num_func_eh_entries) 768194246Smarius { 769194246Smarius if (num_func_eh_entries == 0) 770194246Smarius { 771223951Smarius function_eh_regions = 772194246Smarius (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50)); 773194246Smarius num_func_eh_entries = 50; 774194246Smarius } 775194246Smarius else 776194246Smarius { 777194246Smarius num_func_eh_entries = num_func_eh_entries * 3 / 2; 778194246Smarius function_eh_regions = (struct func_eh_entry *) 779194246Smarius realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries)); 780194246Smarius } 781194246Smarius } 782194246Smarius function_eh_regions[current_func_eh_entry].range_number = note_eh_region; 783223951Smarius if (rethrow == NULL_RTX) 784194246Smarius function_eh_regions[current_func_eh_entry].rethrow_label = 785194246Smarius create_rethrow_ref (note_eh_region); 786194246Smarius else 787194246Smarius function_eh_regions[current_func_eh_entry].rethrow_label = rethrow; 788194246Smarius function_eh_regions[current_func_eh_entry].handlers = NULL; 789194246Smarius 790194246Smarius return current_func_eh_entry++; 791194246Smarius} 792194246Smarius 793194246Smarius/* Add new handler information to an exception range. The first parameter 794194246Smarius specifies the range number (returned from new_eh_entry()). The second 795194246Smarius parameter specifies the handler. By default the handler is inserted at 796194246Smarius the end of the list. A handler list may contain only ONE NULL_TREE 797194246Smarius typeinfo entry. Regardless where it is positioned, a NULL_TREE entry 798223951Smarius is always output as the LAST handler in the exception table for a region. */ 799194246Smarius 800194246Smariusvoid 801194246Smariusadd_new_handler (region, newhandler) 802194246Smarius int region; 803194246Smarius struct handler_info *newhandler; 804194246Smarius{ 805194246Smarius struct handler_info *last; 806194246Smarius 807194246Smarius newhandler->next = NULL; 808194246Smarius last = function_eh_regions[region].handlers; 809194246Smarius if (last == NULL) 810223951Smarius function_eh_regions[region].handlers = newhandler; 811194246Smarius else 812194246Smarius { 813194246Smarius for ( ; ; last = last->next) 814194246Smarius { 815194246Smarius if (last->type_info == CATCH_ALL_TYPE) 816194246Smarius pedwarn ("additional handler after ..."); 817194246Smarius if (last->next == NULL) 818194246Smarius break; 819194246Smarius } 820194246Smarius last->next = newhandler; 821194246Smarius } 822194246Smarius} 823194246Smarius 824194246Smarius/* Remove a handler label. The handler label is being deleted, so all 825223951Smarius regions which reference this handler should have it removed from their 826223951Smarius list of possible handlers. Any region which has the final handler 827247579Smarius removed can be deleted. */ 828247579Smarius 829223951Smariusvoid remove_handler (removing_label) 830194246Smarius rtx removing_label; 831194246Smarius{ 832194246Smarius struct handler_info *handler, *last; 833194246Smarius int x; 834194246Smarius for (x = 0 ; x < current_func_eh_entry; ++x) 835194246Smarius { 836194246Smarius last = NULL; 837194246Smarius handler = function_eh_regions[x].handlers; 838194246Smarius for ( ; handler; last = handler, handler = handler->next) 839194246Smarius if (handler->handler_label == removing_label) 840223951Smarius { 841223951Smarius if (last) 842247579Smarius { 843247579Smarius last->next = handler->next; 844223951Smarius handler = last; 845194246Smarius } 846194246Smarius else 847194246Smarius function_eh_regions[x].handlers = handler->next; 848194246Smarius } 849194246Smarius } 850194246Smarius} 851194246Smarius 852194246Smarius/* This function will return a malloc'd pointer to an array of 853194246Smarius void pointer representing the runtime match values that 854194246Smarius currently exist in all regions. */ 855194246Smarius 856194246Smariusint 857194246Smariusfind_all_handler_type_matches (array) 858194246Smarius void ***array; 859194246Smarius{ 860194246Smarius struct handler_info *handler, *last; 861194246Smarius int x,y; 862194246Smarius void *val; 863194246Smarius void **ptr; 864194246Smarius int max_ptr; 865194246Smarius int n_ptr = 0; 866194246Smarius 867194246Smarius *array = NULL; 868194246Smarius 869194246Smarius if (!doing_eh (0) || ! flag_new_exceptions) 870194246Smarius return 0; 871194246Smarius 872194246Smarius max_ptr = 100; 873194246Smarius ptr = (void **)malloc (max_ptr * sizeof (void *)); 874194246Smarius 875194246Smarius if (ptr == NULL) 876194246Smarius return 0; 877194246Smarius 878194246Smarius for (x = 0 ; x < current_func_eh_entry; x++) 879194246Smarius { 880194246Smarius last = NULL; 881194246Smarius handler = function_eh_regions[x].handlers; 882194246Smarius for ( ; handler; last = handler, handler = handler->next) 883194246Smarius { 884194246Smarius val = handler->type_info; 885194246Smarius if (val != NULL && val != CATCH_ALL_TYPE) 886194246Smarius { 887194246Smarius /* See if this match value has already been found. */ 888194246Smarius for (y = 0; y < n_ptr; y++) 889194246Smarius if (ptr[y] == val) 890194246Smarius break; 891194246Smarius 892194246Smarius /* If we break early, we already found this value. */ 893194246Smarius if (y < n_ptr) 894194246Smarius continue; 895194246Smarius 896194246Smarius /* Do we need to allocate more space? */ 897194246Smarius if (n_ptr >= max_ptr) 898194246Smarius { 899194246Smarius max_ptr += max_ptr / 2; 900194246Smarius ptr = (void **)realloc (ptr, max_ptr * sizeof (void *)); 901194246Smarius if (ptr == NULL) 902194246Smarius return 0; 903194246Smarius } 904194246Smarius ptr[n_ptr] = val; 905194246Smarius n_ptr++; 906194246Smarius } 907194246Smarius } 908194246Smarius } 909194246Smarius *array = ptr; 910194246Smarius return n_ptr; 911194246Smarius} 912194246Smarius 913194246Smarius/* Create a new handler structure initialized with the handler label and 914194246Smarius typeinfo fields passed in. */ 915194246Smarius 916194246Smariusstruct handler_info * 917194246Smariusget_new_handler (handler, typeinfo) 918194246Smarius rtx handler; 919194246Smarius void *typeinfo; 920194246Smarius{ 921194246Smarius struct handler_info* ptr; 922194246Smarius ptr = (struct handler_info *) malloc (sizeof (struct handler_info)); 923194246Smarius ptr->handler_label = handler; 924194246Smarius ptr->handler_number = CODE_LABEL_NUMBER (handler); 925194246Smarius ptr->type_info = typeinfo; 926194246Smarius ptr->next = NULL; 927194246Smarius 928194246Smarius return ptr; 929194246Smarius} 930194246Smarius 931194246Smarius 932194246Smarius 933194246Smarius/* Find the index in function_eh_regions associated with a NOTE region. If 934194246Smarius the region cannot be found, a -1 is returned. This should never happen! */ 935194246Smarius 936194246Smariusint 937194246Smariusfind_func_region (insn_region) 938194246Smarius int insn_region; 939194246Smarius{ 940194246Smarius int x; 941194246Smarius for (x = 0; x < current_func_eh_entry; x++) 942194246Smarius if (function_eh_regions[x].range_number == insn_region) 943194246Smarius return x; 944194246Smarius 945194246Smarius return -1; 946194246Smarius} 947194246Smarius 948194246Smarius/* Get a pointer to the first handler in an exception region's list. */ 949194246Smarius 950194246Smariusstruct handler_info * 951194246Smariusget_first_handler (region) 952194246Smarius int region; 953194246Smarius{ 954194246Smarius return function_eh_regions[find_func_region (region)].handlers; 955194246Smarius} 956194246Smarius 957194246Smarius/* Clean out the function_eh_region table and free all memory */ 958194246Smarius 959194246Smariusstatic void 960194246Smariusclear_function_eh_region () 961194246Smarius{ 962194246Smarius int x; 963194246Smarius struct handler_info *ptr, *next; 964194246Smarius for (x = 0; x < current_func_eh_entry; x++) 965194246Smarius for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next) 966194246Smarius { 967194246Smarius next = ptr->next; 968194246Smarius free (ptr); 969194246Smarius } 970194246Smarius free (function_eh_regions); 971194246Smarius num_func_eh_entries = 0; 972194246Smarius current_func_eh_entry = 0; 973194246Smarius} 974194904Smarius 975194904Smarius/* Make a duplicate of an exception region by copying all the handlers 976194904Smarius for an exception region. Return the new handler index. The final 977194246Smarius parameter is a routine which maps old labels to new ones. */ 978194246Smarius 979194246Smariusint 980194246Smariusduplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map) 981194246Smarius int old_note_eh_region, new_note_eh_region; 982194246Smarius rtx (*map) PARAMS ((rtx)); 983194246Smarius{ 984194246Smarius struct handler_info *ptr, *new_ptr; 985194246Smarius int new_region, region; 986194246Smarius 987194246Smarius region = find_func_region (old_note_eh_region); 988194246Smarius if (region == -1) 989194246Smarius fatal ("Cannot duplicate non-existant exception region."); 990194246Smarius 991194246Smarius /* duplicate_eh_handlers may have been called during a symbol remap. */ 992194246Smarius new_region = find_func_region (new_note_eh_region); 993194246Smarius if (new_region != -1) 994194246Smarius return (new_region); 995194246Smarius 996207585Smarius new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX); 997207585Smarius 998207585Smarius ptr = function_eh_regions[region].handlers; 999194246Smarius 1000194246Smarius for ( ; ptr; ptr = ptr->next) 1001194246Smarius { 1002194246Smarius new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info); 1003194246Smarius add_new_handler (new_region, new_ptr); 1004194246Smarius } 1005194246Smarius 1006194246Smarius return new_region; 1007194246Smarius} 1008194246Smarius 1009194246Smarius 1010194246Smarius/* Given a rethrow symbol, find the EH region number this is for. */ 1011194246Smariusint 1012194246Smariuseh_region_from_symbol (sym) 1013194246Smarius rtx sym; 1014194246Smarius{ 1015194246Smarius int x; 1016194246Smarius if (sym == last_rethrow_symbol) 1017194246Smarius return 1; 1018194246Smarius for (x = 0; x < current_func_eh_entry; x++) 1019194246Smarius if (function_eh_regions[x].rethrow_label == sym) 1020194246Smarius return function_eh_regions[x].range_number; 1021194246Smarius return -1; 1022194246Smarius} 1023194246Smarius 1024194246Smarius 1025194246Smarius/* When inlining/unrolling, we have to map the symbols passed to 1026194246Smarius __rethrow as well. This performs the remap. If a symbol isn't foiund, 1027194246Smarius the original one is returned. This is not an efficient routine, 1028194246Smarius so don't call it on everything!! */ 1029194246Smariusrtx 1030194246Smariusrethrow_symbol_map (sym, map) 1031194246Smarius rtx sym; 1032194246Smarius rtx (*map) PARAMS ((rtx)); 1033194246Smarius{ 1034194246Smarius int x, y; 1035194246Smarius for (x = 0; x < current_func_eh_entry; x++) 1036194246Smarius if (function_eh_regions[x].rethrow_label == sym) 1037194246Smarius { 1038194246Smarius /* We've found the original region, now lets determine which region 1039194246Smarius this now maps to. */ 1040194246Smarius rtx l1 = function_eh_regions[x].handlers->handler_label; 1041194246Smarius rtx l2 = map (l1); 1042194246Smarius y = CODE_LABEL_NUMBER (l2); /* This is the new region number */ 1043194246Smarius x = find_func_region (y); /* Get the new permanent region */ 1044194246Smarius if (x == -1) /* Hmm, Doesn't exist yet */ 1045194246Smarius { 1046247579Smarius x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map); 1047247579Smarius /* Since we're mapping it, it must be used. */ 1048194246Smarius SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1; 1049194246Smarius } 1050194246Smarius return function_eh_regions[x].rethrow_label; 1051194246Smarius } 1052194246Smarius return sym; 1053194246Smarius} 1054194246Smarius 1055194246Smariusint 1056194246Smariusrethrow_used (region) 1057194904Smarius int region; 1058194246Smarius{ 1059194246Smarius if (flag_new_exceptions) 1060194246Smarius { 1061194246Smarius rtx lab = function_eh_regions[find_func_region (region)].rethrow_label; 1062194246Smarius return (SYMBOL_REF_USED (lab)); 1063194246Smarius } 1064194246Smarius return 0; 1065194246Smarius} 1066194904Smarius 1067194904Smarius 1068194246Smarius/* Routine to see if exception handling is turned on. 1069194246Smarius DO_WARN is non-zero if we want to inform the user that exception 1070194246Smarius handling is turned off. 1071194246Smarius 1072194246Smarius This is used to ensure that -fexceptions has been specified if the 1073194246Smarius compiler tries to use any exception-specific functions. */ 1074194246Smarius 1075194246Smariusint 1076194246Smariusdoing_eh (do_warn) 1077194246Smarius int do_warn; 1078194246Smarius{ 1079194246Smarius if (! flag_exceptions) 1080194246Smarius { 1081194246Smarius static int warned = 0; 1082194246Smarius if (! warned && do_warn) 1083194246Smarius { 1084194246Smarius error ("exception handling disabled, use -fexceptions to enable"); 1085194246Smarius warned = 1; 1086194246Smarius } 1087194246Smarius return 0; 1088194246Smarius } 1089194246Smarius return 1; 1090194246Smarius} 1091194246Smarius 1092194246Smarius/* Given a return address in ADDR, determine the address we should use 1093194246Smarius to find the corresponding EH region. */ 1094194246Smarius 1095194246Smariusrtx 1096194246Smariuseh_outer_context (addr) 1097194246Smarius rtx addr; 1098194246Smarius{ 1099194246Smarius /* First mask out any unwanted bits. */ 1100194246Smarius#ifdef MASK_RETURN_ADDR 1101194246Smarius expand_and (addr, MASK_RETURN_ADDR, addr); 1102194246Smarius#endif 1103194246Smarius 1104194246Smarius /* Then adjust to find the real return address. */ 1105194246Smarius#if defined (RETURN_ADDR_OFFSET) 1106194246Smarius addr = plus_constant (addr, RETURN_ADDR_OFFSET); 1107194246Smarius#endif 1108194246Smarius 1109194246Smarius return addr; 1110194246Smarius} 1111194246Smarius 1112194246Smarius/* Start a new exception region for a region of code that has a 1113215721Smarius cleanup action and push the HANDLER for the region onto 1114194246Smarius protect_list. All of the regions created with add_partial_entry 1115194246Smarius will be ended when end_protect_partials is invoked. */ 1116194246Smarius 1117194246Smariusvoid 1118194246Smariusadd_partial_entry (handler) 1119194246Smarius tree handler; 1120194246Smarius{ 1121194246Smarius expand_eh_region_start (); 1122194246Smarius 1123194246Smarius /* Make sure the entry is on the correct obstack. */ 1124194246Smarius push_obstacks_nochange (); 1125194246Smarius resume_temporary_allocation (); 1126194246Smarius 1127194246Smarius /* Because this is a cleanup action, we may have to protect the handler 1128194246Smarius with __terminate. */ 1129194246Smarius handler = protect_with_terminate (handler); 1130194246Smarius 1131194246Smarius protect_list = tree_cons (NULL_TREE, handler, protect_list); 1132194246Smarius pop_obstacks (); 1133194246Smarius} 1134194246Smarius 1135194246Smarius/* Emit code to get EH context to current function. */ 1136194246Smarius 1137194246Smariusstatic rtx 1138194246Smariuscall_get_eh_context () 1139194246Smarius{ 1140194246Smarius static tree fn; 1141194246Smarius tree expr; 1142194246Smarius 1143194246Smarius if (fn == NULL_TREE) 1144194246Smarius { 1145194246Smarius tree fntype; 1146194246Smarius fn = get_identifier ("__get_eh_context"); 1147194246Smarius push_obstacks_nochange (); 1148194246Smarius end_temporary_allocation (); 1149194246Smarius fntype = build_pointer_type (build_pointer_type 1150194246Smarius (build_pointer_type (void_type_node))); 1151194246Smarius fntype = build_function_type (fntype, NULL_TREE); 1152223951Smarius fn = build_decl (FUNCTION_DECL, fn, fntype); 1153223951Smarius DECL_EXTERNAL (fn) = 1; 1154223951Smarius TREE_PUBLIC (fn) = 1; 1155223951Smarius DECL_ARTIFICIAL (fn) = 1; 1156223951Smarius TREE_READONLY (fn) = 1; 1157223951Smarius make_decl_rtl (fn, NULL_PTR, 1); 1158223951Smarius assemble_external (fn); 1159223951Smarius pop_obstacks (); 1160223951Smarius } 1161194246Smarius 1162194246Smarius expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); 1163194246Smarius expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), 1164194246Smarius expr, NULL_TREE, NULL_TREE); 1165223951Smarius TREE_SIDE_EFFECTS (expr) = 1; 1166194246Smarius 1167194246Smarius return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0)); 1168194246Smarius} 1169194246Smarius 1170220943Smarius/* Get a reference to the EH context. 1171194246Smarius We will only generate a register for the current function EH context here, 1172194246Smarius and emit a USE insn to mark that this is a EH context register. 1173194246Smarius 1174194246Smarius Later, emit_eh_context will emit needed call to __get_eh_context 1175194246Smarius in libgcc2, and copy the value to the register we have generated. */ 1176194246Smarius 1177194246Smariusrtx 1178194246Smariusget_eh_context () 1179194246Smarius{ 1180194246Smarius if (current_function_ehc == 0) 1181194246Smarius { 1182194246Smarius rtx insn; 1183194246Smarius 1184194246Smarius current_function_ehc = gen_reg_rtx (Pmode); 1185194246Smarius 1186194246Smarius insn = gen_rtx_USE (GET_MODE (current_function_ehc), 1187194246Smarius current_function_ehc); 1188194246Smarius insn = emit_insn_before (insn, get_first_nonparm_insn ()); 1189194246Smarius 1190194246Smarius REG_NOTES (insn) 1191194246Smarius = gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc, 1192194246Smarius REG_NOTES (insn)); 1193194246Smarius } 1194194246Smarius return current_function_ehc; 1195194246Smarius} 1196194246Smarius 1197194246Smarius/* Get a reference to the dynamic handler chain. It points to the 1198194246Smarius pointer to the next element in the dynamic handler chain. It ends 1199194246Smarius when there are no more elements in the dynamic handler chain, when 1200194246Smarius the value is &top_elt from libgcc2.c. Immediately after the 1201194246Smarius pointer, is an area suitable for setjmp/longjmp when 1202194246Smarius DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for 1203194246Smarius __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP 1204194246Smarius isn't defined. */ 1205194246Smarius 1206194246Smariusrtx 1207243857Sglebiusget_dynamic_handler_chain () 1208194246Smarius{ 1209194246Smarius rtx ehc, dhc, result; 1210194246Smarius 1211194246Smarius ehc = get_eh_context (); 1212194246Smarius 1213194246Smarius /* This is the offset of dynamic_handler_chain in the eh_context struct 1214194246Smarius declared in eh-common.h. If its location is change, change this offset */ 1215194246Smarius dhc = plus_constant (ehc, POINTER_SIZE / BITS_PER_UNIT); 1216194246Smarius 1217194246Smarius result = copy_to_reg (dhc); 1218194246Smarius 1219194246Smarius /* We don't want a copy of the dcc, but rather, the single dcc. */ 1220194246Smarius return gen_rtx_MEM (Pmode, result); 1221194246Smarius} 1222194246Smarius 1223194246Smarius/* Get a reference to the dynamic cleanup chain. It points to the 1224194246Smarius pointer to the next element in the dynamic cleanup chain. 1225194246Smarius Immediately after the pointer, are two Pmode variables, one for a 1226194246Smarius pointer to a function that performs the cleanup action, and the 1227194246Smarius second, the argument to pass to that function. */ 1228194246Smarius 1229194246Smariusrtx 1230243857Sglebiusget_dynamic_cleanup_chain () 1231194246Smarius{ 1232194246Smarius rtx dhc, dcc, result; 1233194246Smarius 1234194246Smarius dhc = get_dynamic_handler_chain (); 1235194246Smarius dcc = plus_constant (dhc, POINTER_SIZE / BITS_PER_UNIT); 1236194246Smarius 1237194246Smarius result = copy_to_reg (dcc); 1238194246Smarius 1239194246Smarius /* We don't want a copy of the dcc, but rather, the single dcc. */ 1240194246Smarius return gen_rtx_MEM (Pmode, result); 1241194246Smarius} 1242194246Smarius 1243194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP 1244194246Smarius/* Generate code to evaluate X and jump to LABEL if the value is nonzero. 1245194246Smarius LABEL is an rtx of code CODE_LABEL, in this function. */ 1246194246Smarius 1247194246Smariusstatic void 1248194246Smariusjumpif_rtx (x, label) 1249194246Smarius rtx x; 1250194246Smarius rtx label; 1251194246Smarius{ 1252194246Smarius jumpif (make_tree (type_for_mode (GET_MODE (x), 0), x), label); 1253194246Smarius} 1254194246Smarius#endif 1255194246Smarius 1256194246Smarius/* Start a dynamic cleanup on the EH runtime dynamic cleanup stack. 1257194246Smarius We just need to create an element for the cleanup list, and push it 1258194246Smarius into the chain. 1259194246Smarius 1260194246Smarius A dynamic cleanup is a cleanup action implied by the presence of an 1261194246Smarius element on the EH runtime dynamic cleanup stack that is to be 1262194246Smarius performed when an exception is thrown. The cleanup action is 1263194246Smarius performed by __sjthrow when an exception is thrown. Only certain 1264194246Smarius actions can be optimized into dynamic cleanup actions. For the 1265194246Smarius restrictions on what actions can be performed using this routine, 1266194246Smarius see expand_eh_region_start_tree. */ 1267194246Smarius 1268194246Smariusstatic void 1269194246Smariusstart_dynamic_cleanup (func, arg) 1270194246Smarius tree func; 1271194246Smarius tree arg; 1272194246Smarius{ 1273194246Smarius rtx dcc; 1274194246Smarius rtx new_func, new_arg; 1275194246Smarius rtx x, buf; 1276194246Smarius int size; 1277194246Smarius 1278194246Smarius /* We allocate enough room for a pointer to the function, and 1279194246Smarius one argument. */ 1280194246Smarius size = 2; 1281194246Smarius 1282194246Smarius /* XXX, FIXME: The stack space allocated this way is too long lived, 1283194246Smarius but there is no allocation routine that allocates at the level of 1284194246Smarius the last binding contour. */ 1285194246Smarius buf = assign_stack_local (BLKmode, 1286194246Smarius GET_MODE_SIZE (Pmode)*(size+1), 1287194246Smarius 0); 1288194246Smarius 1289194246Smarius buf = change_address (buf, Pmode, NULL_RTX); 1290194246Smarius 1291194246Smarius /* Store dcc into the first word of the newly allocated buffer. */ 1292194246Smarius 1293194246Smarius dcc = get_dynamic_cleanup_chain (); 1294194246Smarius emit_move_insn (buf, dcc); 1295194246Smarius 1296194246Smarius /* Store func and arg into the cleanup list element. */ 1297194246Smarius 1298194246Smarius new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0), 1299194246Smarius GET_MODE_SIZE (Pmode))); 1300194246Smarius new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0), 1301194904Smarius GET_MODE_SIZE (Pmode)*2)); 1302194246Smarius x = expand_expr (func, new_func, Pmode, 0); 1303194246Smarius if (x != new_func) 1304194246Smarius emit_move_insn (new_func, x); 1305194246Smarius 1306194246Smarius x = expand_expr (arg, new_arg, Pmode, 0); 1307194246Smarius if (x != new_arg) 1308194246Smarius emit_move_insn (new_arg, x); 1309194246Smarius 1310194246Smarius /* Update the cleanup chain. */ 1311194246Smarius 1312194246Smarius emit_move_insn (dcc, XEXP (buf, 0)); 1313194246Smarius} 1314194246Smarius 1315194246Smarius/* Emit RTL to start a dynamic handler on the EH runtime dynamic 1316194246Smarius handler stack. This should only be used by expand_eh_region_start 1317194246Smarius or expand_eh_region_start_tree. */ 1318194246Smarius 1319194246Smariusstatic void 1320194246Smariusstart_dynamic_handler () 1321194246Smarius{ 1322194246Smarius rtx dhc, dcc; 1323194246Smarius rtx x, arg, buf; 1324194246Smarius int size; 1325194246Smarius 1326194246Smarius#ifndef DONT_USE_BUILTIN_SETJMP 1327194246Smarius /* The number of Pmode words for the setjmp buffer, when using the 1328194246Smarius builtin setjmp/longjmp, see expand_builtin, case 1329194246Smarius BUILT_IN_LONGJMP. */ 1330194246Smarius size = 5; 1331194246Smarius#else 1332194246Smarius#ifdef JMP_BUF_SIZE 1333194246Smarius size = JMP_BUF_SIZE; 1334194246Smarius#else 1335194246Smarius /* Should be large enough for most systems, if it is not, 1336194246Smarius JMP_BUF_SIZE should be defined with the proper value. It will 1337194246Smarius also tend to be larger than necessary for most systems, a more 1338194246Smarius optimal port will define JMP_BUF_SIZE. */ 1339194246Smarius size = FIRST_PSEUDO_REGISTER+2; 1340194246Smarius#endif 1341194246Smarius#endif 1342194246Smarius /* XXX, FIXME: The stack space allocated this way is too long lived, 1343194246Smarius but there is no allocation routine that allocates at the level of 1344194246Smarius the last binding contour. */ 1345194246Smarius arg = assign_stack_local (BLKmode, 1346194246Smarius GET_MODE_SIZE (Pmode)*(size+1), 1347194246Smarius 0); 1348194246Smarius 1349194246Smarius arg = change_address (arg, Pmode, NULL_RTX); 1350194246Smarius 1351194246Smarius /* Store dhc into the first word of the newly allocated buffer. */ 1352194246Smarius 1353194246Smarius dhc = get_dynamic_handler_chain (); 1354194246Smarius dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0), 1355215721Smarius GET_MODE_SIZE (Pmode))); 1356194246Smarius emit_move_insn (arg, dhc); 1357194246Smarius 1358194246Smarius /* Zero out the start of the cleanup chain. */ 1359194246Smarius emit_move_insn (dcc, const0_rtx); 1360194246Smarius 1361194246Smarius /* The jmpbuf starts two words into the area allocated. */ 1362194246Smarius buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2); 1363194246Smarius 1364194246Smarius#ifdef DONT_USE_BUILTIN_SETJMP 1365194246Smarius x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1, 1366194246Smarius buf, Pmode); 1367194246Smarius /* If we come back here for a catch, transfer control to the handler. */ 1368194246Smarius jumpif_rtx (x, ehstack.top->entry->exception_handler_label); 1369194246Smarius#else 1370194246Smarius { 1371194246Smarius /* A label to continue execution for the no exception case. */ 1372194246Smarius rtx noex = gen_label_rtx(); 1373194246Smarius x = expand_builtin_setjmp (buf, NULL_RTX, noex, 1374194246Smarius ehstack.top->entry->exception_handler_label); 1375194246Smarius emit_label (noex); 1376194246Smarius } 1377194246Smarius#endif 1378194246Smarius 1379194246Smarius /* We are committed to this, so update the handler chain. */ 1380194246Smarius 1381194246Smarius emit_move_insn (dhc, force_operand (XEXP (arg, 0), NULL_RTX)); 1382194246Smarius} 1383194246Smarius 1384194246Smarius/* Start an exception handling region for the given cleanup action. 1385194246Smarius All instructions emitted after this point are considered to be part 1386194246Smarius of the region until expand_eh_region_end is invoked. CLEANUP is 1387194246Smarius the cleanup action to perform. The return value is true if the 1388194246Smarius exception region was optimized away. If that case, 1389194246Smarius expand_eh_region_end does not need to be called for this cleanup, 1390194246Smarius nor should it be. 1391194246Smarius 1392194246Smarius This routine notices one particular common case in C++ code 1393194246Smarius generation, and optimizes it so as to not need the exception 1394194246Smarius region. It works by creating a dynamic cleanup action, instead of 1395194246Smarius a using an exception region. */ 1396194246Smarius 1397194246Smariusint 1398194246Smariusexpand_eh_region_start_tree (decl, cleanup) 1399194246Smarius tree decl; 1400194246Smarius tree cleanup; 1401194246Smarius{ 1402194246Smarius /* This is the old code. */ 1403194246Smarius if (! doing_eh (0)) 1404194246Smarius return 0; 1405194246Smarius 1406194246Smarius /* The optimization only applies to actions protected with 1407194246Smarius terminate, and only applies if we are using the setjmp/longjmp 1408194246Smarius codegen method. */ 1409194246Smarius if (exceptions_via_longjmp 1410194246Smarius && protect_cleanup_actions_with_terminate) 1411194246Smarius { 1412194904Smarius tree func, arg; 1413194246Smarius tree args; 1414194904Smarius 1415194246Smarius /* Ignore any UNSAVE_EXPR. */ 1416194904Smarius if (TREE_CODE (cleanup) == UNSAVE_EXPR) 1417194904Smarius cleanup = TREE_OPERAND (cleanup, 0); 1418194246Smarius 1419194246Smarius /* Further, it only applies if the action is a call, if there 1420194246Smarius are 2 arguments, and if the second argument is 2. */ 1421194246Smarius 1422194246Smarius if (TREE_CODE (cleanup) == CALL_EXPR 1423194246Smarius && (args = TREE_OPERAND (cleanup, 1)) 1424194246Smarius && (func = TREE_OPERAND (cleanup, 0)) 1425194246Smarius && (arg = TREE_VALUE (args)) 1426194246Smarius && (args = TREE_CHAIN (args)) 1427194246Smarius 1428194246Smarius /* is the second argument 2? */ 1429194246Smarius && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST 1430194246Smarius && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2 1431194246Smarius && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0 1432194246Smarius 1433194246Smarius /* Make sure there are no other arguments. */ 1434194246Smarius && TREE_CHAIN (args) == NULL_TREE) 1435194246Smarius { 1436194246Smarius /* Arrange for returns and gotos to pop the entry we make on the 1437194246Smarius dynamic cleanup stack. */ 1438194246Smarius expand_dcc_cleanup (decl); 1439194904Smarius start_dynamic_cleanup (func, arg); 1440194246Smarius return 1; 1441194246Smarius } 1442194246Smarius } 1443194246Smarius 1444194246Smarius expand_eh_region_start_for_decl (decl); 1445194904Smarius ehstack.top->entry->finalization = cleanup; 1446194246Smarius 1447194246Smarius return 0; 1448194904Smarius} 1449194904Smarius 1450194246Smarius/* Just like expand_eh_region_start, except if a cleanup action is 1451194904Smarius entered on the cleanup chain, the TREE_PURPOSE of the element put 1452194246Smarius on the chain is DECL. DECL should be the associated VAR_DECL, if 1453194904Smarius any, otherwise it should be NULL_TREE. */ 1454194904Smarius 1455194904Smariusvoid 1456194246Smariusexpand_eh_region_start_for_decl (decl) 1457194246Smarius tree decl; 1458194246Smarius{ 1459194246Smarius rtx note; 1460194246Smarius 1461194246Smarius /* This is the old code. */ 1462194246Smarius if (! doing_eh (0)) 1463194246Smarius return; 1464194246Smarius 1465194246Smarius if (exceptions_via_longjmp) 1466194246Smarius { 1467194246Smarius /* We need a new block to record the start and end of the 1468194246Smarius dynamic handler chain. We could always do this, but we 1469194246Smarius really want to permit jumping into such a block, and we want 1470194246Smarius to avoid any errors or performance impact in the SJ EH code 1471194246Smarius for now. */ 1472194246Smarius expand_start_bindings (0); 1473194246Smarius 1474194246Smarius /* But we don't need or want a new temporary level. */ 1475194246Smarius pop_temp_slots (); 1476194246Smarius 1477194246Smarius /* Mark this block as created by expand_eh_region_start. This 1478194246Smarius is so that we can pop the block with expand_end_bindings 1479194246Smarius automatically. */ 1480194246Smarius mark_block_as_eh_region (); 1481194246Smarius 1482194246Smarius /* Arrange for returns and gotos to pop the entry we make on the 1483194246Smarius dynamic handler stack. */ 1484194246Smarius expand_dhc_cleanup (decl); 1485194246Smarius } 1486194246Smarius 1487194246Smarius push_eh_entry (&ehstack); 1488194246Smarius note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG); 1489194246Smarius NOTE_BLOCK_NUMBER (note) 1490194246Smarius = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label); 1491194246Smarius if (exceptions_via_longjmp) 1492194246Smarius start_dynamic_handler (); 1493194246Smarius} 1494194246Smarius 1495194246Smarius/* Start an exception handling region. All instructions emitted after 1496194246Smarius this point are considered to be part of the region until 1497194246Smarius expand_eh_region_end is invoked. */ 1498194246Smarius 1499194904Smariusvoid 1500194904Smariusexpand_eh_region_start () 1501194246Smarius{ 1502194246Smarius expand_eh_region_start_for_decl (NULL_TREE); 1503194246Smarius} 1504194246Smarius 1505194246Smarius/* End an exception handling region. The information about the region 1506194246Smarius is found on the top of ehstack. 1507194246Smarius 1508194246Smarius HANDLER is either the cleanup for the exception region, or if we're 1509194246Smarius marking the end of a try block, HANDLER is integer_zero_node. 1510194246Smarius 1511194246Smarius HANDLER will be transformed to rtl when expand_leftover_cleanups 1512194246Smarius is invoked. */ 1513194246Smarius 1514194246Smariusvoid 1515194246Smariusexpand_eh_region_end (handler) 1516194246Smarius tree handler; 1517194246Smarius{ 1518194246Smarius struct eh_entry *entry; 1519194246Smarius rtx note; 1520194246Smarius int ret, r; 1521194246Smarius 1522194246Smarius if (! doing_eh (0)) 1523194246Smarius return; 1524194246Smarius 1525194246Smarius entry = pop_eh_entry (&ehstack); 1526194246Smarius 1527194246Smarius note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END); 1528194246Smarius ret = NOTE_BLOCK_NUMBER (note) 1529194246Smarius = CODE_LABEL_NUMBER (entry->exception_handler_label); 1530194246Smarius if (exceptions_via_longjmp == 0 && ! flag_new_exceptions 1531194246Smarius /* We share outer_context between regions; only emit it once. */ 1532194246Smarius && INSN_UID (entry->outer_context) == 0) 1533194246Smarius { 1534194246Smarius rtx label; 1535194246Smarius 1536194246Smarius label = gen_label_rtx (); 1537194246Smarius emit_jump (label); 1538194246Smarius 1539194246Smarius /* Emit a label marking the end of this exception region that 1540194246Smarius is used for rethrowing into the outer context. */ 1541194246Smarius emit_label (entry->outer_context); 1542194246Smarius expand_internal_throw (); 1543194246Smarius 1544194246Smarius emit_label (label); 1545194246Smarius } 1546194246Smarius 1547194246Smarius entry->finalization = handler; 1548194246Smarius 1549194246Smarius /* create region entry in final exception table */ 1550194246Smarius r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label); 1551194246Smarius 1552194246Smarius enqueue_eh_entry (&ehqueue, entry); 1553194246Smarius 1554194246Smarius /* If we have already started ending the bindings, don't recurse. 1555194246Smarius This only happens when exceptions_via_longjmp is true. */ 1556194246Smarius if (is_eh_region ()) 1557194246Smarius { 1558194246Smarius /* Because we don't need or want a new temporary level and 1559194246Smarius because we didn't create one in expand_eh_region_start, 1560194246Smarius create a fake one now to avoid removing one in 1561194246Smarius expand_end_bindings. */ 1562194246Smarius push_temp_slots (); 1563194246Smarius 1564194246Smarius mark_block_as_not_eh_region (); 1565194246Smarius 1566194246Smarius /* Maybe do this to prevent jumping in and so on... */ 1567194246Smarius expand_end_bindings (NULL_TREE, 0, 0); 1568194246Smarius } 1569194246Smarius} 1570194246Smarius 1571194246Smarius/* End the EH region for a goto fixup. We only need them in the region-based 1572194246Smarius EH scheme. */ 1573194246Smarius 1574194246Smariusvoid 1575194246Smariusexpand_fixup_region_start () 1576194246Smarius{ 1577194246Smarius if (! doing_eh (0) || exceptions_via_longjmp) 1578194246Smarius return; 1579194246Smarius 1580194246Smarius expand_eh_region_start (); 1581194246Smarius} 1582194246Smarius 1583194246Smarius/* End the EH region for a goto fixup. CLEANUP is the cleanup we just 1584194246Smarius expanded; to avoid running it twice if it throws, we look through the 1585194246Smarius ehqueue for a matching region and rethrow from its outer_context. */ 1586194246Smarius 1587194246Smariusvoid 1588215721Smariusexpand_fixup_region_end (cleanup) 1589194246Smarius tree cleanup; 1590215721Smarius{ 1591215721Smarius struct eh_node *node; 1592215721Smarius int dont_issue; 1593194246Smarius 1594194246Smarius if (! doing_eh (0) || exceptions_via_longjmp) 1595194246Smarius return; 1596194246Smarius 1597194904Smarius for (node = ehstack.top; node && node->entry->finalization != cleanup; ) 1598194246Smarius node = node->chain; 1599194246Smarius if (node == 0) 1600194246Smarius for (node = ehqueue.head; node && node->entry->finalization != cleanup; ) 1601194246Smarius node = node->chain; 1602194246Smarius if (node == 0) 1603194246Smarius abort (); 1604194246Smarius 1605194246Smarius /* If the outer context label has not been issued yet, we don't want 1606194246Smarius to issue it as a part of this region, unless this is the 1607194246Smarius correct region for the outer context. If we did, then the label for 1608194246Smarius the outer context will be WITHIN the begin/end labels, 1609194246Smarius and we could get an infinte loop when it tried to rethrow, or just 1610194246Smarius generally incorrect execution following a throw. */ 1611194246Smarius 1612194246Smarius dont_issue = ((INSN_UID (node->entry->outer_context) == 0) 1613194246Smarius && (ehstack.top->entry != node->entry)); 1614223986Smarius 1615194246Smarius ehstack.top->entry->outer_context = node->entry->outer_context; 1616194246Smarius 1617194246Smarius /* Since we are rethrowing to the OUTER region, we know we don't need 1618194246Smarius a jump around sequence for this region, so we'll pretend the outer 1619194246Smarius context label has been issued by setting INSN_UID to 1, then clearing 1620194246Smarius it again afterwards. */ 1621194246Smarius 1622194246Smarius if (dont_issue) 1623194246Smarius INSN_UID (node->entry->outer_context) = 1; 1624194246Smarius 1625194246Smarius /* Just rethrow. size_zero_node is just a NOP. */ 1626194246Smarius expand_eh_region_end (size_zero_node); 1627194246Smarius 1628194246Smarius if (dont_issue) 1629223986Smarius INSN_UID (node->entry->outer_context) = 0; 1630194246Smarius} 1631194246Smarius 1632194246Smarius/* If we are using the setjmp/longjmp EH codegen method, we emit a 1633194246Smarius call to __sjthrow. 1634194246Smarius 1635194246Smarius Otherwise, we emit a call to __throw and note that we threw 1636194246Smarius something, so we know we need to generate the necessary code for 1637194246Smarius __throw. 1638194246Smarius 1639194246Smarius Before invoking throw, the __eh_pc variable must have been set up 1640194246Smarius to contain the PC being thrown from. This address is used by 1641194246Smarius __throw to determine which exception region (if any) is 1642194246Smarius responsible for handling the exception. */ 1643194246Smarius 1644194246Smariusvoid 1645194246Smariusemit_throw () 1646194246Smarius{ 1647194246Smarius if (exceptions_via_longjmp) 1648194246Smarius { 1649194246Smarius emit_library_call (sjthrow_libfunc, 0, VOIDmode, 0); 1650194246Smarius } 1651194246Smarius else 1652194246Smarius { 1653194246Smarius#ifdef JUMP_TO_THROW 1654215721Smarius emit_indirect_jump (throw_libfunc); 1655194246Smarius#else 1656194246Smarius emit_library_call (throw_libfunc, 0, VOIDmode, 0); 1657194246Smarius#endif 1658194246Smarius } 1659194246Smarius emit_barrier (); 1660194246Smarius} 1661194246Smarius 1662194246Smarius/* Throw the current exception. If appropriate, this is done by jumping 1663194246Smarius to the next handler. */ 1664194246Smarius 1665194246Smariusvoid 1666194246Smariusexpand_internal_throw () 1667194246Smarius{ 1668194246Smarius emit_throw (); 1669194246Smarius} 1670194246Smarius 1671194246Smarius/* Called from expand_exception_blocks and expand_end_catch_block to 1672194246Smarius emit any pending handlers/cleanups queued from expand_eh_region_end. */ 1673194246Smarius 1674194246Smariusvoid 1675194246Smariusexpand_leftover_cleanups () 1676194246Smarius{ 1677194246Smarius struct eh_entry *entry; 1678194246Smarius 1679194246Smarius while ((entry = dequeue_eh_entry (&ehqueue)) != 0) 1680194246Smarius { 1681194246Smarius rtx prev; 1682194246Smarius 1683194246Smarius /* A leftover try block. Shouldn't be one here. */ 1684194246Smarius if (entry->finalization == integer_zero_node) 1685194246Smarius abort (); 1686194246Smarius 1687194246Smarius /* Output the label for the start of the exception handler. */ 1688194246Smarius 1689194246Smarius receive_exception_label (entry->exception_handler_label); 1690194246Smarius 1691194246Smarius /* register a handler for this cleanup region */ 1692194246Smarius add_new_handler ( 1693194246Smarius find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 1694194246Smarius get_new_handler (entry->exception_handler_label, NULL)); 1695194246Smarius 1696194246Smarius /* And now generate the insns for the handler. */ 1697194246Smarius expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 1698194246Smarius 1699194246Smarius prev = get_last_insn (); 1700194246Smarius if (prev == NULL || GET_CODE (prev) != BARRIER) 1701194246Smarius /* Emit code to throw to the outer context if we fall off 1702194246Smarius the end of the handler. */ 1703194246Smarius expand_rethrow (entry->outer_context); 1704194246Smarius 1705194246Smarius do_pending_stack_adjust (); 1706194246Smarius free (entry); 1707194246Smarius } 1708194246Smarius} 1709194246Smarius 1710194246Smarius/* Called at the start of a block of try statements. */ 1711194246Smariusvoid 1712194246Smariusexpand_start_try_stmts () 1713194246Smarius{ 1714194246Smarius if (! doing_eh (1)) 1715194246Smarius return; 1716194246Smarius 1717194246Smarius expand_eh_region_start (); 1718194246Smarius} 1719194246Smarius 1720194246Smarius/* Called to begin a catch clause. The parameter is the object which 1721194246Smarius will be passed to the runtime type check routine. */ 1722194246Smariusvoid 1723194246Smariusstart_catch_handler (rtime) 1724194246Smarius tree rtime; 1725194246Smarius{ 1726194246Smarius rtx handler_label; 1727194246Smarius int insn_region_num; 1728194246Smarius int eh_region_entry; 1729243857Sglebius 1730194246Smarius if (! doing_eh (1)) 1731194246Smarius return; 1732194246Smarius 1733194246Smarius handler_label = catchstack.top->entry->exception_handler_label; 1734194973Smarius insn_region_num = CODE_LABEL_NUMBER (handler_label); 1735194246Smarius eh_region_entry = find_func_region (insn_region_num); 1736194246Smarius 1737194973Smarius /* If we've already issued this label, pick a new one */ 1738194246Smarius if (catchstack.top->entry->label_used) 1739194973Smarius handler_label = gen_exception_label (); 1740194973Smarius else 1741194246Smarius catchstack.top->entry->label_used = 1; 1742194973Smarius 1743194246Smarius receive_exception_label (handler_label); 1744194246Smarius 1745194246Smarius add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime)); 1746194246Smarius 1747194246Smarius if (flag_new_exceptions && ! exceptions_via_longjmp) 1748194246Smarius return; 1749194246Smarius 1750194246Smarius /* Under the old mechanism, as well as setjmp/longjmp, we need to 1751194246Smarius issue code to compare 'rtime' to the value in eh_info, via the 1752194246Smarius matching function in eh_info. If its is false, we branch around 1753194246Smarius the handler we are about to issue. */ 1754194246Smarius 1755194246Smarius if (rtime != NULL_TREE && rtime != CATCH_ALL_TYPE) 1756194246Smarius { 1757223986Smarius rtx call_rtx, rtime_address; 1758194246Smarius 1759223986Smarius if (catchstack.top->entry->false_label != NULL_RTX) 1760194246Smarius fatal ("Compiler Bug: Never issued previous false_label"); 1761223951Smarius catchstack.top->entry->false_label = gen_exception_label (); 1762194246Smarius 1763194246Smarius rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER); 1764194246Smarius#ifdef POINTERS_EXTEND_UNSIGNED 1765194246Smarius rtime_address = convert_memory_address (Pmode, rtime_address); 1766194246Smarius#endif 1767194246Smarius rtime_address = force_reg (Pmode, rtime_address); 1768194246Smarius 1769194246Smarius /* Now issue the call, and branch around handler if needed */ 1770194246Smarius call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, 1771194246Smarius 0, SImode, 1, rtime_address, Pmode); 1772194246Smarius 1773194246Smarius /* Did the function return true? */ 1774243857Sglebius emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX, 1775194246Smarius GET_MODE (call_rtx), 0, 0, 1776194246Smarius catchstack.top->entry->false_label); 1777194246Smarius } 1778194246Smarius} 1779194246Smarius 1780194246Smarius/* Called to end a catch clause. If we aren't using the new exception 1781194973Smarius model tabel mechanism, we need to issue the branch-around label 1782194246Smarius for the end of the catch block. */ 1783194973Smarius 1784194973Smariusvoid 1785194246Smariusend_catch_handler () 1786194973Smarius{ 1787194973Smarius if (! doing_eh (1)) 1788194973Smarius return; 1789194973Smarius 1790194246Smarius if (flag_new_exceptions && ! exceptions_via_longjmp) 1791194246Smarius { 1792194246Smarius emit_barrier (); 1793194246Smarius return; 1794194246Smarius } 1795194246Smarius 1796194246Smarius /* A NULL label implies the catch clause was a catch all or cleanup */ 1797208776Smarius if (catchstack.top->entry->false_label == NULL_RTX) 1798194246Smarius return; 1799194246Smarius 1800194246Smarius emit_label (catchstack.top->entry->false_label); 1801194246Smarius catchstack.top->entry->false_label = NULL_RTX; 1802194246Smarius} 1803194246Smarius 1804194246Smarius/* Generate RTL for the start of a group of catch clauses. 1805194246Smarius 1806194246Smarius It is responsible for starting a new instruction sequence for the 1807194246Smarius instructions in the catch block, and expanding the handlers for the 1808194246Smarius internally-generated exception regions nested within the try block 1809194246Smarius corresponding to this catch block. */ 1810208776Smarius 1811243857Sglebiusvoid 1812208776Smariusexpand_start_all_catch () 1813208776Smarius{ 1814208776Smarius struct eh_entry *entry; 1815208776Smarius tree label; 1816208776Smarius rtx outer_context; 1817208776Smarius 1818208776Smarius if (! doing_eh (1)) 1819208776Smarius return; 1820194973Smarius 1821208776Smarius outer_context = ehstack.top->entry->outer_context; 1822208776Smarius 1823208776Smarius /* End the try block. */ 1824208776Smarius expand_eh_region_end (integer_zero_node); 1825208776Smarius 1826194973Smarius emit_line_note (input_filename, lineno); 1827208776Smarius label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); 1828208776Smarius 1829208776Smarius /* The label for the exception handling block that we will save. 1830208776Smarius This is Lresume in the documentation. */ 1831208776Smarius expand_label (label); 1832194246Smarius 1833208776Smarius /* Push the label that points to where normal flow is resumed onto 1834208776Smarius the top of the label stack. */ 1835208776Smarius push_label_entry (&caught_return_label_stack, NULL_RTX, label); 1836208776Smarius 1837208776Smarius /* Start a new sequence for all the catch blocks. We will add this 1838194246Smarius to the global sequence catch_clauses when we have completed all 1839194246Smarius the handlers in this handler-seq. */ 1840194246Smarius start_sequence (); 1841194246Smarius 1842208776Smarius entry = dequeue_eh_entry (&ehqueue); 1843194246Smarius for ( ; entry->finalization != integer_zero_node; 1844194246Smarius entry = dequeue_eh_entry (&ehqueue)) 1845194246Smarius { 1846194246Smarius rtx prev; 1847194246Smarius 1848194246Smarius /* Emit the label for the cleanup handler for this region, and 1849194246Smarius expand the code for the handler. 1850194246Smarius 1851194246Smarius Note that a catch region is handled as a side-effect here; 1852194246Smarius for a try block, entry->finalization will contain 1853194246Smarius integer_zero_node, so no code will be generated in the 1854194246Smarius expand_expr call below. But, the label for the handler will 1855223986Smarius still be emitted, so any code emitted after this point will 1856194246Smarius end up being the handler. */ 1857223986Smarius 1858194246Smarius receive_exception_label (entry->exception_handler_label); 1859223951Smarius 1860194246Smarius /* register a handler for this cleanup region */ 1861194246Smarius add_new_handler ( 1862194246Smarius find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 1863194246Smarius get_new_handler (entry->exception_handler_label, NULL)); 1864194246Smarius 1865194246Smarius /* And now generate the insns for the cleanup handler. */ 1866194246Smarius expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); 1867194246Smarius 1868194246Smarius prev = get_last_insn (); 1869194246Smarius if (prev == NULL || GET_CODE (prev) != BARRIER) 1870194246Smarius /* Code to throw out to outer context when we fall off end 1871194246Smarius of the handler. We can't do this here for catch blocks, 1872194246Smarius so it's done in expand_end_all_catch instead. */ 1873194904Smarius expand_rethrow (entry->outer_context); 1874194904Smarius 1875194246Smarius do_pending_stack_adjust (); 1876194246Smarius free (entry); 1877194246Smarius } 1878194246Smarius 1879194246Smarius /* At this point, all the cleanups are done, and the ehqueue now has 1880194246Smarius the current exception region at its head. We dequeue it, and put it 1881194246Smarius on the catch stack. */ 1882194246Smarius 1883194246Smarius push_entry (&catchstack, entry); 1884194246Smarius 1885215721Smarius /* If we are not doing setjmp/longjmp EH, because we are reordered 1886194246Smarius out of line, we arrange to rethrow in the outer context. We need to 1887194246Smarius do this because we are not physically within the region, if any, that 1888194246Smarius logically contains this catch block. */ 1889194246Smarius if (! exceptions_via_longjmp) 1890194246Smarius { 1891194246Smarius expand_eh_region_start (); 1892194246Smarius ehstack.top->entry->outer_context = outer_context; 1893194246Smarius } 1894194246Smarius 1895223986Smarius} 1896194246Smarius 1897194246Smarius/* Finish up the catch block. At this point all the insns for the 1898194246Smarius catch clauses have already been generated, so we only have to add 1899194246Smarius them to the catch_clauses list. We also want to make sure that if 1900194246Smarius we fall off the end of the catch clauses that we rethrow to the 1901194246Smarius outer EH region. */ 1902194246Smarius 1903194246Smariusvoid 1904194246Smariusexpand_end_all_catch () 1905194246Smarius{ 1906194246Smarius rtx new_catch_clause; 1907194246Smarius struct eh_entry *entry; 1908194246Smarius 1909194246Smarius if (! doing_eh (1)) 1910194246Smarius return; 1911194246Smarius 1912194246Smarius /* Dequeue the current catch clause region. */ 1913223986Smarius entry = pop_eh_entry (&catchstack); 1914223986Smarius free (entry); 1915194246Smarius 1916223986Smarius if (! exceptions_via_longjmp) 1917223986Smarius { 1918194246Smarius rtx outer_context = ehstack.top->entry->outer_context; 1919194246Smarius 1920194246Smarius /* Finish the rethrow region. size_zero_node is just a NOP. */ 1921194246Smarius expand_eh_region_end (size_zero_node); 1922194246Smarius /* New exceptions handling models will never have a fall through 1923194246Smarius of a catch clause */ 1924223986Smarius if (!flag_new_exceptions) 1925194246Smarius expand_rethrow (outer_context); 1926194246Smarius } 1927194246Smarius else 1928194246Smarius expand_rethrow (NULL_RTX); 1929194246Smarius 1930194246Smarius /* Code to throw out to outer context, if we fall off end of catch 1931194246Smarius handlers. This is rethrow (Lresume, same id, same obj) in the 1932194246Smarius documentation. We use Lresume because we know that it will throw 1933194246Smarius to the correct context. 1934194246Smarius 1935194246Smarius In other words, if the catch handler doesn't exit or return, we 1936194246Smarius do a "throw" (using the address of Lresume as the point being 1937194246Smarius thrown from) so that the outer EH region can then try to process 1938194246Smarius the exception. */ 1939194246Smarius 1940194246Smarius /* Now we have the complete catch sequence. */ 1941194246Smarius new_catch_clause = get_insns (); 1942194246Smarius end_sequence (); 1943194246Smarius 1944194246Smarius /* This level of catch blocks is done, so set up the successful 1945194246Smarius catch jump label for the next layer of catch blocks. */ 1946194246Smarius pop_label_entry (&caught_return_label_stack); 1947194904Smarius pop_label_entry (&outer_context_label_stack); 1948194246Smarius 1949223986Smarius /* Add the new sequence of catches to the main one for this function. */ 1950194246Smarius push_to_sequence (catch_clauses); 1951194904Smarius emit_insns (new_catch_clause); 1952194904Smarius catch_clauses = get_insns (); 1953194246Smarius end_sequence (); 1954194246Smarius 1955194246Smarius /* Here we fall through into the continuation code. */ 1956194246Smarius} 1957194246Smarius 1958194246Smarius/* Rethrow from the outer context LABEL. */ 1959194246Smarius 1960194246Smariusstatic void 1961194246Smariusexpand_rethrow (label) 1962194246Smarius rtx label; 1963194246Smarius{ 1964194246Smarius if (exceptions_via_longjmp) 1965194904Smarius emit_throw (); 1966223986Smarius else 1967194904Smarius if (flag_new_exceptions) 1968194904Smarius { 1969194246Smarius rtx insn, val; 1970194246Smarius if (label == NULL_RTX) 1971194904Smarius label = last_rethrow_symbol; 1972194246Smarius emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode); 1973194246Smarius SYMBOL_REF_USED (label) = 1; 1974194246Smarius 1975194904Smarius /* Search backwards for the actual call insn. */ 1976194904Smarius insn = get_last_insn (); 1977194904Smarius while (GET_CODE (insn) != CALL_INSN) 1978194904Smarius insn = PREV_INSN (insn); 1979194904Smarius delete_insns_since (insn); 1980194904Smarius 1981194904Smarius /* Mark the label/symbol on the call. */ 1982194904Smarius val = GEN_INT (eh_region_from_symbol (label)); 1983194904Smarius REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val, 1984194904Smarius REG_NOTES (insn)); 1985194904Smarius emit_barrier (); 1986194904Smarius } 1987194904Smarius else 1988194904Smarius emit_jump (label); 1989194904Smarius} 1990194904Smarius 1991194904Smarius/* End all the pending exception regions on protect_list. The handlers 1992194246Smarius will be emitted when expand_leftover_cleanups is invoked. */ 1993194246Smarius 1994194904Smariusvoid 1995194904Smariusend_protect_partials () 1996194904Smarius{ 1997194904Smarius while (protect_list) 1998194904Smarius { 1999194246Smarius expand_eh_region_end (TREE_VALUE (protect_list)); 2000194246Smarius protect_list = TREE_CHAIN (protect_list); 2001194904Smarius } 2002194246Smarius} 2003223986Smarius 2004194246Smarius/* Arrange for __terminate to be called if there is an unhandled throw 2005194246Smarius from within E. */ 2006194246Smarius 2007215721Smariustree 2008194246Smariusprotect_with_terminate (e) 2009194246Smarius tree e; 2010194246Smarius{ 2011194246Smarius /* We only need to do this when using setjmp/longjmp EH and the 2012194246Smarius language requires it, as otherwise we protect all of the handlers 2013194246Smarius at once, if we need to. */ 2014194246Smarius if (exceptions_via_longjmp && protect_cleanup_actions_with_terminate) 2015194246Smarius { 2016194246Smarius tree handler, result; 2017194246Smarius 2018194246Smarius /* All cleanups must be on the function_obstack. */ 2019194246Smarius push_obstacks_nochange (); 2020194246Smarius resume_temporary_allocation (); 2021194246Smarius 2022194246Smarius handler = make_node (RTL_EXPR); 2023194246Smarius TREE_TYPE (handler) = void_type_node; 2024194246Smarius RTL_EXPR_RTL (handler) = const0_rtx; 2025194246Smarius TREE_SIDE_EFFECTS (handler) = 1; 2026194246Smarius start_sequence_for_rtl_expr (handler); 2027194246Smarius 2028194246Smarius emit_library_call (terminate_libfunc, 0, VOIDmode, 0); 2029194246Smarius emit_barrier (); 2030194246Smarius 2031194246Smarius RTL_EXPR_SEQUENCE (handler) = get_insns (); 2032194246Smarius end_sequence (); 2033194246Smarius 2034194246Smarius result = build (TRY_CATCH_EXPR, TREE_TYPE (e), e, handler); 2035194246Smarius TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e); 2036194246Smarius TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e); 2037194246Smarius TREE_READONLY (result) = TREE_READONLY (e); 2038194246Smarius 2039194246Smarius pop_obstacks (); 2040194246Smarius 2041194246Smarius e = result; 2042194246Smarius } 2043223986Smarius 2044194246Smarius return e; 2045194246Smarius} 2046194246Smarius 2047194246Smarius/* The exception table that we build that is used for looking up and 2048194246Smarius dispatching exceptions, the current number of entries, and its 2049194246Smarius maximum size before we have to extend it. 2050194246Smarius 2051223986Smarius The number in eh_table is the code label number of the exception 2052194246Smarius handler for the region. This is added by add_eh_table_entry and 2053194246Smarius used by output_exception_table_entry. */ 2054194246Smarius 2055194246Smariusstatic int *eh_table = NULL; 2056194246Smariusstatic int eh_table_size = 0; 2057194246Smariusstatic int eh_table_max_size = 0; 2058194246Smarius 2059194246Smarius/* Note the need for an exception table entry for region N. If we 2060223986Smarius don't need to output an explicit exception table, avoid all of the 2061194246Smarius extra work. 2062194246Smarius 2063194246Smarius Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen. 2064194246Smarius (Or NOTE_INSN_EH_REGION_END sometimes) 2065194246Smarius N is the NOTE_BLOCK_NUMBER of the note, which comes from the code 2066194246Smarius label number of the exception handler for the region. */ 2067194246Smarius 2068194246Smariusvoid 2069194246Smariusadd_eh_table_entry (n) 2070194904Smarius int n; 2071194246Smarius{ 2072194246Smarius#ifndef OMIT_EH_TABLE 2073194246Smarius if (eh_table_size >= eh_table_max_size) 2074194246Smarius { 2075194246Smarius if (eh_table) 2076194904Smarius { 2077194246Smarius eh_table_max_size += eh_table_max_size>>1; 2078194246Smarius 2079194246Smarius if (eh_table_max_size < 0) 2080223986Smarius abort (); 2081194246Smarius 2082223986Smarius eh_table = (int *) xrealloc (eh_table, 2083223986Smarius eh_table_max_size * sizeof (int)); 2084194904Smarius } 2085194904Smarius else 2086223986Smarius { 2087194904Smarius eh_table_max_size = 252; 2088223986Smarius eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int)); 2089194904Smarius } 2090194904Smarius } 2091194904Smarius eh_table[eh_table_size++] = n; 2092194904Smarius#endif 2093194904Smarius} 2094194904Smarius 2095194904Smarius/* Return a non-zero value if we need to output an exception table. 2096194904Smarius 2097194904Smarius On some platforms, we don't have to output a table explicitly. 2098194904Smarius This routine doesn't mean we don't have one. */ 2099194904Smarius 2100194904Smariusint 2101194904Smariusexception_table_p () 2102194904Smarius{ 2103194904Smarius if (eh_table) 2104194904Smarius return 1; 2105194904Smarius 2106194904Smarius return 0; 2107194904Smarius} 2108194246Smarius 2109194246Smarius/* Output the entry of the exception table corresponding to the 2110194904Smarius exception region numbered N to file FILE. 2111194246Smarius 2112194246Smarius N is the code label number corresponding to the handler of the 2113194246Smarius region. */ 2114194246Smarius 2115194246Smariusstatic void 2116194246Smariusoutput_exception_table_entry (file, n) 2117194246Smarius FILE *file; 2118194246Smarius int n; 2119215721Smarius{ 2120215721Smarius char buf[256]; 2121194246Smarius rtx sym; 2122215721Smarius struct handler_info *handler = get_first_handler (n); 2123194246Smarius int index = find_func_region (n); 2124215721Smarius rtx rethrow; 2125215721Smarius 2126194246Smarius /* form and emit the rethrow label, if needed */ 2127215721Smarius rethrow = function_eh_regions[index].rethrow_label; 2128194246Smarius if (rethrow != NULL_RTX && !flag_new_exceptions) 2129194246Smarius rethrow = NULL_RTX; 2130194246Smarius if (rethrow != NULL_RTX && handler == NULL) 2131194904Smarius if (! SYMBOL_REF_USED (rethrow)) 2132194246Smarius rethrow = NULL_RTX; 2133194246Smarius 2134194246Smarius 2135194246Smarius for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next) 2136194246Smarius { 2137194246Smarius /* rethrow label should indicate the LAST entry for a region */ 2138194246Smarius if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL)) 2139194246Smarius { 2140194904Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n); 2141194246Smarius assemble_label(buf); 2142194904Smarius rethrow = NULL_RTX; 2143194904Smarius } 2144194246Smarius 2145194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n); 2146194246Smarius sym = gen_rtx_SYMBOL_REF (Pmode, buf); 2147194246Smarius assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); 2148194246Smarius 2149194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n); 2150194246Smarius sym = gen_rtx_SYMBOL_REF (Pmode, buf); 2151194246Smarius assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); 2152194246Smarius 2153207585Smarius if (handler == NULL) 2154207585Smarius assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1); 2155194246Smarius else 2156194246Smarius { 2157194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number); 2158194246Smarius sym = gen_rtx_SYMBOL_REF (Pmode, buf); 2159194246Smarius assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); 2160194246Smarius } 2161194246Smarius 2162194246Smarius if (flag_new_exceptions) 2163194246Smarius { 2164194246Smarius if (handler == NULL || handler->type_info == NULL) 2165194246Smarius assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); 2166194246Smarius else 2167194246Smarius if (handler->type_info == CATCH_ALL_TYPE) 2168194246Smarius assemble_integer (GEN_INT (CATCH_ALL_TYPE), 2169194246Smarius POINTER_SIZE / BITS_PER_UNIT, 1); 2170194246Smarius else 2171194246Smarius output_constant ((tree)(handler->type_info), 2172194246Smarius POINTER_SIZE / BITS_PER_UNIT); 2173194246Smarius } 2174194246Smarius putc ('\n', file); /* blank line */ 2175194246Smarius /* We only output the first label under the old scheme */ 2176194246Smarius if (! flag_new_exceptions || handler == NULL) 2177194246Smarius break; 2178194246Smarius } 2179194246Smarius} 2180194246Smarius 2181194246Smarius/* Output the exception table if we have and need one. */ 2182194246Smarius 2183194246Smariusstatic short language_code = 0; 2184194246Smariusstatic short version_code = 0; 2185194246Smarius 2186194246Smarius/* This routine will set the language code for exceptions. */ 2187194246Smariusvoid 2188194246Smariusset_exception_lang_code (code) 2189194246Smarius int code; 2190194246Smarius{ 2191194246Smarius language_code = code; 2192194246Smarius} 2193194246Smarius 2194194246Smarius/* This routine will set the language version code for exceptions. */ 2195194246Smariusvoid 2196194246Smariusset_exception_version_code (code) 2197194246Smarius int code; 2198194246Smarius{ 2199194246Smarius version_code = code; 2200194246Smarius} 2201194246Smarius 2202194246Smarius 2203194246Smariusvoid 2204194246Smariusoutput_exception_table () 2205194246Smarius{ 2206194246Smarius int i; 2207194246Smarius char buf[256]; 2208194246Smarius extern FILE *asm_out_file; 2209194246Smarius 2210194246Smarius if (! doing_eh (0) || ! eh_table) 2211194246Smarius return; 2212194246Smarius 2213194246Smarius exception_section (); 2214194246Smarius 2215194246Smarius /* Beginning marker for table. */ 2216194246Smarius assemble_align (GET_MODE_ALIGNMENT (ptr_mode)); 2217194246Smarius assemble_label ("__EXCEPTION_TABLE__"); 2218194246Smarius 2219194246Smarius if (flag_new_exceptions) 2220194246Smarius { 2221194246Smarius assemble_integer (GEN_INT (NEW_EH_RUNTIME), 2222194246Smarius POINTER_SIZE / BITS_PER_UNIT, 1); 2223194246Smarius assemble_integer (GEN_INT (language_code), 2 , 1); 2224194246Smarius assemble_integer (GEN_INT (version_code), 2 , 1); 2225194246Smarius 2226194246Smarius /* Add enough padding to make sure table aligns on a pointer boundry. */ 2227194246Smarius i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4; 2228194246Smarius for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT) 2229194246Smarius ; 2230194246Smarius if (i != 0) 2231194246Smarius assemble_integer (const0_rtx, i , 1); 2232194246Smarius 2233194246Smarius /* Generate the label for offset calculations on rethrows */ 2234194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0); 2235194246Smarius assemble_label(buf); 2236194246Smarius } 2237194246Smarius 2238194246Smarius for (i = 0; i < eh_table_size; ++i) 2239194246Smarius output_exception_table_entry (asm_out_file, eh_table[i]); 2240194246Smarius 2241194246Smarius free (eh_table); 2242194246Smarius clear_function_eh_region (); 2243194246Smarius 2244194246Smarius /* Ending marker for table. */ 2245194246Smarius /* Generate the label for end of table. */ 2246194246Smarius ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow)); 2247194246Smarius assemble_label(buf); 2248194246Smarius assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); 2249194246Smarius 2250194246Smarius /* for binary compatability, the old __throw checked the second 2251194246Smarius position for a -1, so we should output at least 2 -1's */ 2252194246Smarius if (! flag_new_exceptions) 2253194246Smarius assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); 2254194246Smarius 2255194246Smarius putc ('\n', asm_out_file); /* blank line */ 2256194246Smarius} 2257194246Smarius 2258194246Smarius/* Emit code to get EH context. 2259194246Smarius 2260194246Smarius We have to scan thru the code to find possible EH context registers. 2261194246Smarius Inlined functions may use it too, and thus we'll have to be able 2262194246Smarius to change them too. 2263207585Smarius 2264207585Smarius This is done only if using exceptions_via_longjmp. */ 2265194246Smarius 2266194246Smariusvoid 2267207585Smariusemit_eh_context () 2268207585Smarius{ 2269194246Smarius rtx insn; 2270194246Smarius rtx ehc = 0; 2271207585Smarius 2272207585Smarius if (! doing_eh (0)) 2273194246Smarius return; 2274194246Smarius 2275194246Smarius for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 2276194246Smarius if (GET_CODE (insn) == INSN 2277194246Smarius && GET_CODE (PATTERN (insn)) == USE) 2278194246Smarius { 2279194246Smarius rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0); 2280194246Smarius if (reg) 2281194246Smarius { 2282194246Smarius rtx insns; 2283207585Smarius 2284207585Smarius start_sequence (); 2285194246Smarius 2286194246Smarius /* If this is the first use insn, emit the call here. This 2287194246Smarius will always be at the top of our function, because if 2288194246Smarius expand_inline_function notices a REG_EH_CONTEXT note, it 2289194246Smarius adds a use insn to this function as well. */ 2290194246Smarius if (ehc == 0) 2291194246Smarius ehc = call_get_eh_context (); 2292194246Smarius 2293194246Smarius emit_move_insn (XEXP (reg, 0), ehc); 2294194246Smarius insns = get_insns (); 2295194246Smarius end_sequence (); 2296194246Smarius 2297194246Smarius emit_insns_before (insns, insn); 2298194246Smarius 2299194246Smarius /* At -O0, we must make the context register stay alive so 2300194246Smarius that the stupid.c register allocator doesn't get confused. */ 2301194246Smarius if (obey_regdecls != 0) 2302194246Smarius { 2303194246Smarius insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0)); 2304194246Smarius emit_insn_before (insns, get_last_insn ()); 2305194246Smarius } 2306194246Smarius } 2307194246Smarius } 2308194246Smarius} 2309194246Smarius 2310194246Smarius/* Scan the current insns and build a list of handler labels. The 2311194246Smarius resulting list is placed in the global variable exception_handler_labels. 2312194246Smarius 2313194246Smarius It is called after the last exception handling region is added to 2314194246Smarius the current function (when the rtl is almost all built for the 2315194246Smarius current function) and before the jump optimization pass. */ 2316194246Smarius 2317194246Smariusvoid 2318194246Smariusfind_exception_handler_labels () 2319194246Smarius{ 2320194246Smarius rtx insn; 2321194246Smarius 2322194246Smarius exception_handler_labels = NULL_RTX; 2323213893Smarius 2324194246Smarius /* If we aren't doing exception handling, there isn't much to check. */ 2325194246Smarius if (! doing_eh (0)) 2326194246Smarius return; 2327194246Smarius 2328194246Smarius /* For each start of a region, add its label to the list. */ 2329194246Smarius 2330194246Smarius for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 2331194246Smarius { 2332194246Smarius struct handler_info* ptr; 2333194246Smarius if (GET_CODE (insn) == NOTE 2334194246Smarius && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) 2335194246Smarius { 2336194246Smarius ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn)); 2337194246Smarius for ( ; ptr; ptr = ptr->next) 2338194246Smarius { 2339194246Smarius /* make sure label isn't in the list already */ 2340194246Smarius rtx x; 2341194246Smarius for (x = exception_handler_labels; x; x = XEXP (x, 1)) 2342194246Smarius if (XEXP (x, 0) == ptr->handler_label) 2343194246Smarius break; 2344194246Smarius if (! x) 2345194246Smarius exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode, 2346194246Smarius ptr->handler_label, exception_handler_labels); 2347194246Smarius } 2348194246Smarius } 2349194246Smarius } 2350223951Smarius} 2351223951Smarius 2352194246Smarius/* Return a value of 1 if the parameter label number is an exception handler 2353194246Smarius label. Return 0 otherwise. */ 2354194246Smarius 2355194246Smariusint 2356194246Smariusis_exception_handler_label (lab) 2357194246Smarius int lab; 2358194246Smarius{ 2359194246Smarius rtx x; 2360223951Smarius for (x = exception_handler_labels ; x ; x = XEXP (x, 1)) 2361194246Smarius if (lab == CODE_LABEL_NUMBER (XEXP (x, 0))) 2362223951Smarius return 1; 2363194246Smarius return 0; 2364194246Smarius} 2365194246Smarius 2366194246Smarius/* Perform sanity checking on the exception_handler_labels list. 2367194246Smarius 2368194246Smarius Can be called after find_exception_handler_labels is called to 2369194246Smarius build the list of exception handlers for the current function and 2370194246Smarius before we finish processing the current function. */ 2371194246Smarius 2372194246Smariusvoid 2373194246Smariuscheck_exception_handler_labels () 2374194246Smarius{ 2375194246Smarius rtx insn, insn2; 2376194246Smarius 2377194246Smarius /* If we aren't doing exception handling, there isn't much to check. */ 2378194246Smarius if (! doing_eh (0)) 2379194246Smarius return; 2380194246Smarius 2381194246Smarius /* Make sure there is no more than 1 copy of a label */ 2382194246Smarius for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1)) 2383194246Smarius { 2384194246Smarius int count = 0; 2385194246Smarius for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1)) 2386194246Smarius if (XEXP (insn, 0) == XEXP (insn2, 0)) 2387194246Smarius count++; 2388194246Smarius if (count != 1) 2389194246Smarius warning ("Counted %d copies of EH region %d in list.\n", count, 2390194246Smarius CODE_LABEL_NUMBER (insn)); 2391194246Smarius } 2392194246Smarius 2393194246Smarius} 2394194246Smarius 2395194246Smarius/* This group of functions initializes the exception handling data 2396194246Smarius structures at the start of the compilation, initializes the data 2397194246Smarius structures at the start of a function, and saves and restores the 2398194246Smarius exception handling data structures for the start/end of a nested 2399194246Smarius function. */ 2400194246Smarius 2401194246Smarius/* Toplevel initialization for EH things. */ 2402194246Smarius 2403194246Smariusvoid 2404194246Smariusinit_eh () 2405194246Smarius{ 2406194246Smarius first_rethrow_symbol = create_rethrow_ref (0); 2407194246Smarius final_rethrow = gen_exception_label (); 2408194246Smarius last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow)); 2409194246Smarius} 2410194246Smarius 2411194246Smarius/* Initialize the per-function EH information. */ 2412194246Smarius 2413194246Smariusvoid 2414194246Smariusinit_eh_for_function () 2415194246Smarius{ 2416194246Smarius ehstack.top = 0; 2417194246Smarius catchstack.top = 0; 2418194246Smarius ehqueue.head = ehqueue.tail = 0; 2419194246Smarius catch_clauses = NULL_RTX; 2420223951Smarius false_label_stack = 0; 2421223986Smarius caught_return_label_stack = 0; 2422194246Smarius protect_list = NULL_TREE; 2423194246Smarius current_function_ehc = NULL_RTX; 2424194246Smarius eh_return_context = NULL_RTX; 2425194246Smarius eh_return_stack_adjust = NULL_RTX; 2426194246Smarius eh_return_handler = NULL_RTX; 2427194246Smarius eh_return_stub_label = NULL_RTX; 2428194246Smarius} 2429194246Smarius 2430194246Smarius/* Save some of the per-function EH info into the save area denoted by 2431194246Smarius P. 2432194246Smarius 2433194246Smarius This is currently called from save_stmt_status. */ 2434194246Smarius 2435194246Smariusvoid 2436194246Smariussave_eh_status (p) 2437194246Smarius struct function *p; 2438194246Smarius{ 2439194246Smarius if (p == NULL) 2440194246Smarius abort (); 2441194246Smarius 2442194246Smarius p->ehstack = ehstack; 2443194246Smarius p->catchstack = catchstack; 2444194246Smarius p->ehqueue = ehqueue; 2445194246Smarius p->catch_clauses = catch_clauses; 2446194246Smarius p->false_label_stack = false_label_stack; 2447194246Smarius p->caught_return_label_stack = caught_return_label_stack; 2448194246Smarius p->protect_list = protect_list; 2449194246Smarius p->ehc = current_function_ehc; 2450194246Smarius p->eh_return_stub_label = eh_return_stub_label; 2451194246Smarius 2452194246Smarius init_eh_for_function (); 2453194246Smarius} 2454194246Smarius 2455194246Smarius/* Restore the per-function EH info saved into the area denoted by P. 2456194246Smarius 2457194246Smarius This is currently called from restore_stmt_status. */ 2458194246Smarius 2459194246Smariusvoid 2460194246Smariusrestore_eh_status (p) 2461194246Smarius struct function *p; 2462194246Smarius{ 2463194246Smarius if (p == NULL) 2464194246Smarius abort (); 2465194246Smarius 2466194246Smarius protect_list = p->protect_list; 2467194246Smarius caught_return_label_stack = p->caught_return_label_stack; 2468194246Smarius false_label_stack = p->false_label_stack; 2469194246Smarius catch_clauses = p->catch_clauses; 2470194246Smarius ehqueue = p->ehqueue; 2471194246Smarius ehstack = p->ehstack; 2472194246Smarius catchstack = p->catchstack; 2473194246Smarius current_function_ehc = p->ehc; 2474194246Smarius eh_return_stub_label = p->eh_return_stub_label; 2475194246Smarius} 2476194246Smarius 2477194246Smarius/* This section is for the exception handling specific optimization 2478194246Smarius pass. First are the internal routines, and then the main 2479194246Smarius optimization pass. */ 2480194246Smarius 2481194246Smarius/* Determine if the given INSN can throw an exception. */ 2482194246Smarius 2483194246Smariusstatic int 2484194246Smariuscan_throw (insn) 2485194246Smarius rtx insn; 2486194246Smarius{ 2487194246Smarius /* Calls can always potentially throw exceptions. */ 2488194246Smarius if (GET_CODE (insn) == CALL_INSN) 2489194246Smarius return 1; 2490194246Smarius 2491194246Smarius if (asynchronous_exceptions) 2492194246Smarius { 2493194246Smarius /* If we wanted asynchronous exceptions, then everything but NOTEs 2494194246Smarius and CODE_LABELs could throw. */ 2495194246Smarius if (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL) 2496194246Smarius return 1; 2497194246Smarius } 2498194246Smarius 2499194246Smarius return 0; 2500194246Smarius} 2501194904Smarius 2502194904Smarius/* Scan a exception region looking for the matching end and then 2503194246Smarius remove it if possible. INSN is the start of the region, N is the 2504194246Smarius region number, and DELETE_OUTER is to note if anything in this 2505194246Smarius region can throw. 2506194246Smarius 2507194246Smarius Regions are removed if they cannot possibly catch an exception. 2508194246Smarius This is determined by invoking can_throw on each insn within the 2509194246Smarius region; if can_throw returns true for any of the instructions, the 2510194246Smarius region can catch an exception, since there is an insn within the 2511194246Smarius region that is capable of throwing an exception. 2512194246Smarius 2513194246Smarius Returns the NOTE_INSN_EH_REGION_END corresponding to this region, or 2514194246Smarius calls abort if it can't find one. 2515194246Smarius 2516194246Smarius Can abort if INSN is not a NOTE_INSN_EH_REGION_BEGIN, or if N doesn't 2517194246Smarius correspond to the region number, or if DELETE_OUTER is NULL. */ 2518194246Smarius 2519194246Smariusstatic rtx 2520194246Smariusscan_region (insn, n, delete_outer) 2521194246Smarius rtx insn; 2522194246Smarius int n; 2523194246Smarius int *delete_outer; 2524194246Smarius{ 2525194246Smarius rtx start = insn; 2526194246Smarius 2527194246Smarius /* Assume we can delete the region. */ 2528194246Smarius int delete = 1; 2529194246Smarius 2530194246Smarius int r = find_func_region (n); 2531194246Smarius /* Can't delete something which is rethrown to. */ 2532194246Smarius if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label))) 2533194246Smarius delete = 0; 2534194246Smarius 2535194246Smarius if (insn == NULL_RTX 2536223951Smarius || GET_CODE (insn) != NOTE 2537223951Smarius || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG 2538194246Smarius || NOTE_BLOCK_NUMBER (insn) != n 2539223951Smarius || delete_outer == NULL) 2540223951Smarius abort (); 2541194246Smarius 2542194246Smarius insn = NEXT_INSN (insn); 2543194246Smarius 2544223951Smarius /* Look for the matching end. */ 2545223951Smarius while (! (GET_CODE (insn) == NOTE 2546223951Smarius && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) 2547223951Smarius { 2548194246Smarius /* If anything can throw, we can't remove the region. */ 2549223951Smarius if (delete && can_throw (insn)) 2550194246Smarius { 2551194246Smarius delete = 0; 2552194246Smarius } 2553194246Smarius 2554194246Smarius /* Watch out for and handle nested regions. */ 2555194246Smarius if (GET_CODE (insn) == NOTE 2556194246Smarius && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) 2557194246Smarius { 2558194246Smarius insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete); 2559194246Smarius } 2560194246Smarius 2561194246Smarius insn = NEXT_INSN (insn); 2562194246Smarius } 2563194246Smarius 2564194246Smarius /* The _BEG/_END NOTEs must match and nest. */ 2565194246Smarius if (NOTE_BLOCK_NUMBER (insn) != n) 2566194246Smarius abort (); 2567194246Smarius 2568194246Smarius /* If anything in this exception region can throw, we can throw. */ 2569194246Smarius if (! delete) 2570194246Smarius *delete_outer = 0; 2571195049Srwatson else 2572194246Smarius { 2573194246Smarius /* Delete the start and end of the region. */ 2574194246Smarius delete_insn (start); 2575194246Smarius delete_insn (insn); 2576194246Smarius 2577194246Smarius/* We no longer removed labels here, since flow will now remove any 2578194246Smarius handler which cannot be called any more. */ 2579194246Smarius 2580194246Smarius#if 0 2581194246Smarius /* Only do this part if we have built the exception handler 2582194246Smarius labels. */ 2583194246Smarius if (exception_handler_labels) 2584195049Srwatson { 2585194246Smarius rtx x, *prev = &exception_handler_labels; 2586194246Smarius 2587194246Smarius /* Find it in the list of handlers. */ 2588194246Smarius for (x = exception_handler_labels; x; x = XEXP (x, 1)) 2589194246Smarius { 2590194246Smarius rtx label = XEXP (x, 0); 2591194246Smarius if (CODE_LABEL_NUMBER (label) == n) 2592194246Smarius { 2593194246Smarius /* If we are the last reference to the handler, 2594194246Smarius delete it. */ 2595223951Smarius if (--LABEL_NUSES (label) == 0) 2596223951Smarius delete_insn (label); 2597194246Smarius 2598194246Smarius if (optimize) 2599194246Smarius { 2600194246Smarius /* Remove it from the list of exception handler 2601194246Smarius labels, if we are optimizing. If we are not, then 2602194246Smarius leave it in the list, as we are not really going to 2603194246Smarius remove the region. */ 2604194246Smarius *prev = XEXP (x, 1); 2605194246Smarius XEXP (x, 1) = 0; 2606194246Smarius XEXP (x, 0) = 0; 2607194246Smarius } 2608194246Smarius 2609194246Smarius break; 2610194246Smarius } 2611194246Smarius prev = &XEXP (x, 1); 2612194246Smarius } 2613194246Smarius } 2614194246Smarius#endif 2615194246Smarius } 2616194246Smarius return insn; 2617194246Smarius} 2618194246Smarius 2619194246Smarius/* Perform various interesting optimizations for exception handling 2620227843Smarius code. 2621194246Smarius 2622194246Smarius We look for empty exception regions and make them go (away). The 2623194246Smarius jump optimization code will remove the handler if nothing else uses 2624194246Smarius it. */ 2625194246Smarius 2626194246Smariusvoid 2627194246Smariusexception_optimize () 2628194246Smarius{ 2629194246Smarius rtx insn; 2630194246Smarius int n; 2631194246Smarius 2632194246Smarius /* Remove empty regions. */ 2633194246Smarius for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 2634194246Smarius { 2635194246Smarius if (GET_CODE (insn) == NOTE 2636194246Smarius && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) 2637194246Smarius { 2638242625Sdim /* Since scan_region will return the NOTE_INSN_EH_REGION_END 2639194246Smarius insn, we will indirectly skip through all the insns 2640194246Smarius inbetween. We are also guaranteed that the value of insn 2641194246Smarius returned will be valid, as otherwise scan_region won't 2642194246Smarius return. */ 2643194246Smarius insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n); 2644194246Smarius } 2645194246Smarius } 2646194246Smarius} 2647194246Smarius 2648194246Smarius/* Various hooks for the DWARF 2 __throw routine. */ 2649194246Smarius 2650194246Smarius/* Do any necessary initialization to access arbitrary stack frames. 2651194246Smarius On the SPARC, this means flushing the register windows. */ 2652194246Smarius 2653194246Smariusvoid 2654194246Smariusexpand_builtin_unwind_init () 2655194246Smarius{ 2656194246Smarius /* Set this so all the registers get saved in our frame; we need to be 2657194246Smarius able to copy the saved values for any registers from frames we unwind. */ 2658194246Smarius current_function_has_nonlocal_label = 1; 2659194246Smarius 2660194246Smarius#ifdef SETUP_FRAME_ADDRESSES 2661194246Smarius SETUP_FRAME_ADDRESSES (); 2662194246Smarius#endif 2663194246Smarius} 2664194246Smarius 2665194246Smarius/* Given a value extracted from the return address register or stack slot, 2666194246Smarius return the actual address encoded in that value. */ 2667207585Smarius 2668207585Smariusrtx 2669207585Smariusexpand_builtin_extract_return_addr (addr_tree) 2670207585Smarius tree addr_tree; 2671207585Smarius{ 2672194246Smarius rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); 2673194246Smarius return eh_outer_context (addr); 2674194246Smarius} 2675207585Smarius 2676194246Smarius/* Given an actual address in addr_tree, do any necessary encoding 2677194246Smarius and return the value to be stored in the return address register or 2678194246Smarius stack slot so the epilogue will return to that address. */ 2679194246Smarius 2680207585Smariusrtx 2681194246Smariusexpand_builtin_frob_return_addr (addr_tree) 2682194246Smarius tree addr_tree; 2683194246Smarius{ 2684194246Smarius rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); 2685194246Smarius#ifdef RETURN_ADDR_OFFSET 2686194246Smarius addr = plus_constant (addr, -RETURN_ADDR_OFFSET); 2687194246Smarius#endif 2688194246Smarius return addr; 2689194246Smarius} 2690194246Smarius 2691194246Smarius/* Choose three registers for communication between the main body of 2692194246Smarius __throw and the epilogue (or eh stub) and the exception handler. 2693194246Smarius We must do this with hard registers because the epilogue itself 2694194246Smarius will be generated after reload, at which point we may not reference 2695194246Smarius pseudos at all. 2696194246Smarius 2697247579Smarius The first passes the exception context to the handler. For this 2698247579Smarius we use the return value register for a void*. 2699247579Smarius 2700247579Smarius The second holds the stack pointer value to be restored. For 2701194246Smarius this we use the static chain register if it exists and is different 2702194246Smarius from the previous, otherwise some arbitrary call-clobbered register. 2703194246Smarius 2704194246Smarius The third holds the address of the handler itself. Here we use 2705194246Smarius some arbitrary call-clobbered register. */ 2706194246Smarius 2707194246Smariusstatic void 2708194246Smariuseh_regs (pcontext, psp, pra, outgoing) 2709194246Smarius rtx *pcontext, *psp, *pra; 2710194246Smarius int outgoing; 2711194246Smarius{ 2712194246Smarius rtx rcontext, rsp, rra; 2713194246Smarius int i; 2714194246Smarius 2715194246Smarius#ifdef FUNCTION_OUTGOING_VALUE 2716194246Smarius if (outgoing) 2717194246Smarius rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node), 2718194246Smarius current_function_decl); 2719194246Smarius else 2720194246Smarius#endif 2721194246Smarius rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node), 2722194246Smarius current_function_decl); 2723194246Smarius 2724207585Smarius#ifdef STATIC_CHAIN_REGNUM 2725207585Smarius if (outgoing) 2726207585Smarius rsp = static_chain_incoming_rtx; 2727207585Smarius else 2728207585Smarius rsp = static_chain_rtx; 2729207585Smarius if (REGNO (rsp) == REGNO (rcontext)) 2730207585Smarius#endif /* STATIC_CHAIN_REGNUM */ 2731194246Smarius rsp = NULL_RTX; 2732194246Smarius 2733207585Smarius if (rsp == NULL_RTX) 2734207585Smarius { 2735207585Smarius for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 2736207585Smarius if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext)) 2737207585Smarius break; 2738194246Smarius if (i == FIRST_PSEUDO_REGISTER) 2739194246Smarius abort(); 2740194246Smarius 2741194246Smarius rsp = gen_rtx_REG (Pmode, i); 2742194246Smarius } 2743194246Smarius 2744194246Smarius for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) 2745194246Smarius if (call_used_regs[i] && ! fixed_regs[i] 2746194246Smarius && i != REGNO (rcontext) && i != REGNO (rsp)) 2747194246Smarius break; 2748194246Smarius if (i == FIRST_PSEUDO_REGISTER) 2749194246Smarius abort(); 2750194246Smarius 2751194246Smarius rra = gen_rtx_REG (Pmode, i); 2752194246Smarius 2753194246Smarius *pcontext = rcontext; 2754194246Smarius *psp = rsp; 2755194246Smarius *pra = rra; 2756194246Smarius} 2757194246Smarius 2758194246Smarius/* Retrieve the register which contains the pointer to the eh_context 2759194246Smarius structure set the __throw. */ 2760194246Smarius 2761194246Smariusrtx 2762194246Smariusget_reg_for_handler () 2763194246Smarius{ 2764194246Smarius rtx reg1; 2765194246Smarius reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node), 2766194246Smarius current_function_decl); 2767194246Smarius return reg1; 2768194246Smarius} 2769194246Smarius 2770194246Smarius/* Set up the epilogue with the magic bits we'll need to return to the 2771207585Smarius exception handler. */ 2772207585Smarius 2773207585Smariusvoid 2774207585Smariusexpand_builtin_eh_return (context, stack, handler) 2775194246Smarius tree context, stack, handler; 2776194246Smarius{ 2777194246Smarius if (eh_return_context) 2778194246Smarius error("Duplicate call to __builtin_eh_return"); 2779194246Smarius 2780194246Smarius eh_return_context 2781194246Smarius = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0)); 2782194246Smarius eh_return_stack_adjust 2783194246Smarius = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0)); 2784194246Smarius eh_return_handler 2785194246Smarius = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0)); 2786194246Smarius} 2787194246Smarius 2788194246Smariusvoid 2789194246Smariusexpand_eh_return () 2790194246Smarius{ 2791194246Smarius rtx reg1, reg2, reg3; 2792194246Smarius rtx stub_start, after_stub; 2793194246Smarius rtx ra, tmp; 2794194246Smarius 2795194246Smarius if (!eh_return_context) 2796194246Smarius return; 2797194246Smarius 2798194246Smarius current_function_cannot_inline = N_("function uses __builtin_eh_return"); 2799194246Smarius 2800194246Smarius eh_regs (®1, ®2, ®3, 1); 2801194246Smarius#ifdef POINTERS_EXTEND_UNSIGNED 2802194246Smarius eh_return_context = convert_memory_address (Pmode, eh_return_context); 2803194246Smarius eh_return_stack_adjust = 2804194246Smarius convert_memory_address (Pmode, eh_return_stack_adjust); 2805194246Smarius eh_return_handler = convert_memory_address (Pmode, eh_return_handler); 2806194246Smarius#endif 2807194246Smarius emit_move_insn (reg1, eh_return_context); 2808194246Smarius emit_move_insn (reg2, eh_return_stack_adjust); 2809194246Smarius emit_move_insn (reg3, eh_return_handler); 2810194246Smarius 2811194246Smarius /* Talk directly to the target's epilogue code when possible. */ 2812194246Smarius 2813194246Smarius#ifdef HAVE_eh_epilogue 2814194246Smarius if (HAVE_eh_epilogue) 2815194246Smarius { 2816194246Smarius emit_insn (gen_eh_epilogue (reg1, reg2, reg3)); 2817194246Smarius return; 2818194246Smarius } 2819194246Smarius#endif 2820194246Smarius 2821194246Smarius /* Otherwise, use the same stub technique we had before. */ 2822194246Smarius 2823207585Smarius eh_return_stub_label = stub_start = gen_label_rtx (); 2824207585Smarius after_stub = gen_label_rtx (); 2825207585Smarius 2826207585Smarius /* Set the return address to the stub label. */ 2827207585Smarius 2828207585Smarius ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 2829207585Smarius 0, hard_frame_pointer_rtx); 2830207585Smarius if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER) 2831207585Smarius abort(); 2832207585Smarius 2833207585Smarius tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start)); 2834207585Smarius#ifdef RETURN_ADDR_OFFSET 2835207585Smarius tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET); 2836207585Smarius#endif 2837207585Smarius tmp = force_operand (tmp, ra); 2838207585Smarius if (tmp != ra) 2839207585Smarius emit_move_insn (ra, tmp); 2840207585Smarius 2841207585Smarius /* Indicate that the registers are in fact used. */ 2842207585Smarius emit_insn (gen_rtx_USE (VOIDmode, reg1)); 2843207585Smarius emit_insn (gen_rtx_USE (VOIDmode, reg2)); 2844207585Smarius emit_insn (gen_rtx_USE (VOIDmode, reg3)); 2845207585Smarius if (GET_CODE (ra) == REG) 2846207585Smarius emit_insn (gen_rtx_USE (VOIDmode, ra)); 2847207585Smarius 2848207585Smarius /* Generate the stub. */ 2849207585Smarius 2850207585Smarius emit_jump (after_stub); 2851207585Smarius emit_label (stub_start); 2852207585Smarius 2853207585Smarius eh_regs (®1, ®2, ®3, 0); 2854207585Smarius adjust_stack (reg2); 2855207585Smarius emit_indirect_jump (reg3); 2856207585Smarius 2857207585Smarius emit_label (after_stub); 2858207585Smarius} 2859207585Smarius 2860207585Smarius 2861207585Smarius/* This contains the code required to verify whether arbitrary instructions 2862207585Smarius are in the same exception region. */ 2863207585Smarius 2864207585Smariusstatic int *insn_eh_region = (int *)0; 2865207585Smariusstatic int maximum_uid; 2866207585Smarius 2867207585Smariusstatic void 2868194246Smariusset_insn_eh_region (first, region_num) 2869194246Smarius rtx *first; 2870194246Smarius int region_num; 2871194246Smarius{ 2872194246Smarius rtx insn; 2873194246Smarius int rnum; 2874194246Smarius 2875194246Smarius for (insn = *first; insn; insn = NEXT_INSN (insn)) 2876194246Smarius { 2877194246Smarius if ((GET_CODE (insn) == NOTE) && 2878207585Smarius (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)) 2879194246Smarius { 2880194246Smarius rnum = NOTE_BLOCK_NUMBER (insn); 2881194246Smarius insn_eh_region[INSN_UID (insn)] = rnum; 2882194246Smarius insn = NEXT_INSN (insn); 2883245923Smarius set_insn_eh_region (&insn, rnum); 2884194246Smarius /* Upon return, insn points to the EH_REGION_END of nested region */ 2885194246Smarius continue; 2886207585Smarius } 2887207585Smarius insn_eh_region[INSN_UID (insn)] = region_num; 2888207585Smarius if ((GET_CODE (insn) == NOTE) && 2889207585Smarius (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) 2890207585Smarius break; 2891207585Smarius } 2892245923Smarius *first = insn; 2893207585Smarius} 2894207585Smarius 2895207585Smarius/* Free the insn table, an make sure it cannot be used again. */ 2896194246Smarius 2897194246Smariusvoid 2898194246Smariusfree_insn_eh_region () 2899194246Smarius{ 2900194246Smarius if (!doing_eh (0)) 2901194246Smarius return; 2902194246Smarius 2903194246Smarius if (insn_eh_region) 2904194904Smarius { 2905194246Smarius free (insn_eh_region); 2906194246Smarius insn_eh_region = (int *)0; 2907194246Smarius } 2908194246Smarius} 2909194246Smarius 2910194246Smarius/* Initialize the table. max_uid must be calculated and handed into 2911194246Smarius this routine. If it is unavailable, passing a value of 0 will 2912194246Smarius cause this routine to calculate it as well. */ 2913194246Smarius 2914194246Smariusvoid 2915194246Smariusinit_insn_eh_region (first, max_uid) 2916194246Smarius rtx first; 2917194246Smarius int max_uid; 2918194246Smarius{ 2919194246Smarius rtx insn; 2920194246Smarius 2921194246Smarius if (!doing_eh (0)) 2922194246Smarius return; 2923194246Smarius 2924194246Smarius if (insn_eh_region) 2925194246Smarius free_insn_eh_region(); 2926194246Smarius 2927194246Smarius if (max_uid == 0) 2928194246Smarius for (insn = first; insn; insn = NEXT_INSN (insn)) 2929194246Smarius if (INSN_UID (insn) > max_uid) /* find largest UID */ 2930194246Smarius max_uid = INSN_UID (insn); 2931194246Smarius 2932194246Smarius maximum_uid = max_uid; 2933194246Smarius insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int)); 2934194246Smarius insn = first; 2935194246Smarius set_insn_eh_region (&insn, 0); 2936194246Smarius} 2937194246Smarius 2938194246Smarius 2939194246Smarius/* Check whether 2 instructions are within the same region. */ 2940194246Smarius 2941194246Smariusint 2942194246Smariusin_same_eh_region (insn1, insn2) 2943194246Smarius rtx insn1, insn2; 2944194246Smarius{ 2945 int ret, uid1, uid2; 2946 2947 /* If no exceptions, instructions are always in same region. */ 2948 if (!doing_eh (0)) 2949 return 1; 2950 2951 /* If the table isn't allocated, assume the worst. */ 2952 if (!insn_eh_region) 2953 return 0; 2954 2955 uid1 = INSN_UID (insn1); 2956 uid2 = INSN_UID (insn2); 2957 2958 /* if instructions have been allocated beyond the end, either 2959 the table is out of date, or this is a late addition, or 2960 something... Assume the worst. */ 2961 if (uid1 > maximum_uid || uid2 > maximum_uid) 2962 return 0; 2963 2964 ret = (insn_eh_region[uid1] == insn_eh_region[uid2]); 2965 return ret; 2966} 2967 2968