1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann <tiemann@cygnus.com>
4 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5 initial re-implementation courtesy Tad Hunt.
7 This file is part of GNU CC.
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING. If not, write to
21 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 /* High-level class interface. */
34 extern void (*interim_eh_hook
) PROTO((tree
));
36 /* holds the fndecl for __builtin_return_address () */
37 tree builtin_return_address_fndecl
;
39 /* Define at your own risk! */
56 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined (__arm) || defined (__alpha)
66 static int warned
= 0;
69 sorry ("exception handling not supported");
75 expand_exception_blocks ()
85 end_protect (finalization
)
91 expand_start_try_stmts ()
97 expand_end_try_stmts ()
102 expand_start_all_catch ()
107 expand_end_all_catch ()
112 expand_start_catch_block (declspecs
, declarator
)
113 tree declspecs
, declarator
;
118 expand_end_catch_block ()
123 init_exception_processing ()
136 /* Make 'label' the first numbered label of the current function */
138 make_first_label(label
)
141 if (CODE_LABEL_NUMBER(label
) < get_first_label_num())
142 set_new_first_and_last_label_num (CODE_LABEL_NUMBER(label
),
150 if (! flag_handle_exceptions
)
152 static int warned
= 0;
153 if (! warned
&& do_warn
)
155 error ("exception handling disabled, use -fhandle-exceptions to enable.");
165 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
166 to supporting exception handling as per Stroustrup's 2nd edition.
167 It is a complete rewrite of all the EH stuff that was here before
169 1. The type of the throw and catch must still match
170 exactly (no support yet for matching base classes)
171 2. Throw specifications of functions still doesnt't work.
173 1. Destructors are called properly :-)
174 2. No overhead for the non-exception thrown case.
175 3. Fixing shortcomings 1 and 2 is simple.
176 -Tad Hunt (tad@mail.csh.rit.edu)
180 /* A couple of backend routines from m88k.c */
182 /* used to cache a call to __builtin_return_address () */
183 static tree BuiltinReturnAddress
;
191 /* XXX - Tad: for EH */
192 /* output an exception table entry */
195 output_exception_table_entry (file
, start_label
, end_label
, eh_label
)
197 rtx start_label
, end_label
, eh_label
;
201 assemble_integer (start_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
202 assemble_integer (end_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
203 assemble_integer (eh_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
204 putc ('\n', file
); /* blank line */
208 easy_expand_asm (str
)
211 expand_asm (build_string (strlen (str
)+1, str
));
216 /* This is the startup, and finish stuff per exception table. */
218 /* XXX - Tad: exception handling section */
219 #ifndef EXCEPT_SECTION_ASM_OP
220 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
223 #ifdef EXCEPT_SECTION_ASM_OP
227 void *exception_handler
;
229 #endif /* EXCEPT_SECTION_ASM_OP */
231 #ifdef EXCEPT_SECTION_ASM_OP
233 /* on machines which support it, the exception table lives in another section,
234 but it needs a label so we can reference it... This sets up that
236 asm (EXCEPT_SECTION_ASM_OP
);
237 exception_table __EXCEPTION_TABLE__
[1] = { (void*)0, (void*)0, (void*)0 };
238 asm (TEXT_SECTION_ASM_OP
);
240 #endif /* EXCEPT_SECTION_ASM_OP */
242 #ifdef EXCEPT_SECTION_ASM_OP
244 /* we need to know where the end of the exception table is... so this
247 asm (EXCEPT_SECTION_ASM_OP
);
248 exception_table __EXCEPTION_END__
[1] = { (void*)-1, (void*)-1, (void*)-1 };
249 asm (TEXT_SECTION_ASM_OP
);
251 #endif /* EXCEPT_SECTION_ASM_OP */
258 #ifdef ASM_OUTPUT_SECTION_NAME
259 named_section (NULL_TREE
, ".gcc_except_table");
264 #if defined(__rs6000)
267 readonly_data_section ();
275 /* from: my-cp-except.c */
277 /* VI: ":set ts=4" */
279 #include <stdio.h> */
289 #include "insn-flags.h"
295 /* ======================================================================
296 Briefly the algorithm works like this:
298 When a constructor or start of a try block is encountered,
299 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
300 new entry in the unwind protection stack and returns a label to
301 output to start the protection for that block.
303 When a destructor or end try block is encountered, pop_eh_entry
304 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
305 created when push_eh_entry () was called. The ehEntry structure
306 contains three things at this point. The start protect label,
307 the end protect label, and the exception handler label. The end
308 protect label should be output before the call to the destructor
309 (if any). If it was a destructor, then its parse tree is stored
310 in the finalization variable in the ehEntry structure. Otherwise
311 the finalization variable is set to NULL to reflect the fact that
312 is the the end of a try block. Next, this modified ehEntry node
313 is enqueued in the finalizations queue by calling
314 enqueue_eh_entry (&queue,entry).
316 +---------------------------------------------------------------+
317 |XXX: Will need modification to deal with partially |
318 | constructed arrays of objects |
320 | Basically, this consists of keeping track of how many |
321 | of the objects have been constructed already (this |
322 | should be in a register though, so that shouldn't be a |
324 +---------------------------------------------------------------+
326 When a catch block is encountered, there is a lot of work to be
329 Since we don't want to generate the catch block inline with the
330 regular flow of the function, we need to have some way of doing
331 so. Luckily, we have a couple of routines "get_last_insn ()" and
332 "set_last_insn ()" provided. When the start of a catch block is
333 encountered, we save a pointer to the last insn generated. After
334 the catch block is generated, we save a pointer to the first
335 catch block insn and the last catch block insn with the routines
336 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
337 to be the last insn generated before the catch block, and set the
338 NEXT_INSN (last_insn) to zero.
340 Since catch blocks might be nested inside other catch blocks, and
341 we munge the chain of generated insns after the catch block is
342 generated, we need to store the pointers to the last insn
343 generated in a stack, so that when the end of a catch block is
344 encountered, the last insn before the current catch block can be
345 popped and set to be the last insn, and the first and last insns
346 of the catch block just generated can be enqueue'd for output at
349 Next we must insure that when the catch block is executed, all
350 finalizations for the matching try block have been completed. If
351 any of those finalizations throw an exception, we must call
352 terminate according to the ARM (section r.15.6.1). What this
353 means is that we need to dequeue and emit finalizations for each
354 entry in the ehQueue until we get to an entry with a NULL
355 finalization field. For any of the finalization entries, if it
356 is not a call to terminate (), we must protect it by giving it
357 another start label, end label, and exception handler label,
358 setting its finalization tree to be a call to terminate (), and
359 enqueue'ing this new ehEntry to be output at an outer level.
360 Finally, after all that is done, we can get around to outputting
361 the catch block which basically wraps all the "catch (...) {...}"
362 statements in a big if/then/else construct that matches the
363 correct block to call.
365 ===================================================================== */
367 extern rtx emit_insn
PROTO((rtx
));
368 extern rtx gen_nop
PROTO(());
370 /* local globals for function calls
371 ====================================================================== */
373 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
374 "set_unexpected ()" after default_conversion. (lib-except.c) */
375 static tree Terminate
, Unexpected
, SetTerminate
, SetUnexpected
, CatchMatch
;
377 /* used to cache __find_first_exception_table_match ()
378 for throw (lib-except.c) */
379 static tree FirstExceptionMatch
;
381 /* used to cache a call to __unwind_function () (lib-except.c) */
384 /* holds a ready to emit call to "terminate ()". */
385 static tree TerminateFunctionCall
;
387 /* ====================================================================== */
391 /* data structures for my various quick and dirty stacks and queues
392 Eventually, most of this should go away, because I think it can be
393 integrated with stuff already built into the compiler. */
395 /* =================================================================== */
399 struct labelNode
*chain
;
403 /* this is the most important structure here. Basically this is how I store
404 an exception table entry internally. */
408 rtx exception_handler_label
;
415 struct ehEntry
*entry
;
416 struct ehNode
*chain
;
432 struct exceptNode
*chain
;
436 struct exceptNode
*top
;
438 /* ========================================================================= */
442 /* local globals - these local globals are for storing data necessary for
443 generating the exception table and code in the correct order.
445 ========================================================================= */
447 /* Holds the pc for doing "throw" */
449 /* Holds the type of the thing being thrown. */
450 rtx saved_throw_type
;
451 /* Holds the value being thrown. */
452 rtx saved_throw_value
;
456 static struct ehStack ehstack
;
457 static struct ehQueue ehqueue
;
458 static struct ehQueue eh_table_output_queue
;
459 static struct exceptStack exceptstack
;
460 static struct labelNode
*false_label_stack
= NULL
;
461 static struct labelNode
*caught_return_label_stack
= NULL
;
462 /* ========================================================================= */
464 /* function prototypes */
465 static struct ehEntry
*pop_eh_entry
PROTO((struct ehStack
*stack
));
466 static void enqueue_eh_entry
PROTO((struct ehQueue
*queue
, struct ehEntry
*entry
));
467 static void push_except_stmts
PROTO((struct exceptStack
*exceptstack
,
468 rtx catchstart
, rtx catchend
));
469 static int pop_except_stmts
PROTO((struct exceptStack
*exceptstack
,
470 rtx
*catchstart
, rtx
*catchend
));
471 static rtx push_eh_entry
PROTO((struct ehStack
*stack
));
472 static struct ehEntry
*dequeue_eh_entry
PROTO((struct ehQueue
*queue
));
473 static void new_eh_queue
PROTO((struct ehQueue
*queue
));
474 static void new_eh_stack
PROTO((struct ehStack
*stack
));
475 static void new_except_stack
PROTO((struct exceptStack
*queue
));
476 static void push_last_insn
PROTO(());
477 static rtx pop_last_insn
PROTO(());
478 static void push_label_entry
PROTO((struct labelNode
**labelstack
, rtx label
));
479 static rtx pop_label_entry
PROTO((struct labelNode
**labelstack
));
480 static rtx top_label_entry
PROTO((struct labelNode
**labelstack
));
481 static struct ehEntry
*copy_eh_entry
PROTO((struct ehEntry
*entry
));
485 /* All my cheesy stack/queue/misc data structure handling routines
487 ========================================================================= */
490 push_label_entry (labelstack
, label
)
491 struct labelNode
**labelstack
;
494 struct labelNode
*newnode
=(struct labelNode
*)xmalloc (sizeof (struct labelNode
));
496 newnode
->label
= label
;
497 newnode
->chain
= *labelstack
;
498 *labelstack
= newnode
;
502 pop_label_entry (labelstack
)
503 struct labelNode
**labelstack
;
506 struct labelNode
*tempnode
;
508 if (! *labelstack
) return NULL_RTX
;
510 tempnode
= *labelstack
;
511 label
= tempnode
->label
;
512 *labelstack
= (*labelstack
)->chain
;
519 top_label_entry (labelstack
)
520 struct labelNode
**labelstack
;
522 if (! *labelstack
) return NULL_RTX
;
524 return (*labelstack
)->label
;
528 push_except_stmts (exceptstack
, catchstart
, catchend
)
529 struct exceptStack
*exceptstack
;
530 rtx catchstart
, catchend
;
532 struct exceptNode
*newnode
= (struct exceptNode
*)
533 xmalloc (sizeof (struct exceptNode
));
535 newnode
->catchstart
= catchstart
;
536 newnode
->catchend
= catchend
;
537 newnode
->chain
= exceptstack
->top
;
539 exceptstack
->top
= newnode
;
543 pop_except_stmts (exceptstack
, catchstart
, catchend
)
544 struct exceptStack
*exceptstack
;
545 rtx
*catchstart
, *catchend
;
547 struct exceptNode
*tempnode
;
549 if (!exceptstack
->top
) {
550 *catchstart
= *catchend
= NULL_RTX
;
554 tempnode
= exceptstack
->top
;
555 exceptstack
->top
= exceptstack
->top
->chain
;
557 *catchstart
= tempnode
->catchstart
;
558 *catchend
= tempnode
->catchend
;
564 /* Push to permanent obstack for rtl generation.
566 static struct obstack
*saved_rtl_obstack
;
570 extern struct obstack permanent_obstack
;
571 extern struct obstack
*rtl_obstack
;
573 saved_rtl_obstack
= rtl_obstack
;
574 rtl_obstack
= &permanent_obstack
;
577 /* Pop back to normal rtl handling. */
581 extern struct obstack permanent_obstack
;
582 extern struct obstack
*rtl_obstack
;
584 rtl_obstack
= saved_rtl_obstack
;
588 push_eh_entry (stack
)
589 struct ehStack
*stack
;
591 struct ehNode
*node
= (struct ehNode
*)xmalloc (sizeof (struct ehNode
));
592 struct ehEntry
*entry
= (struct ehEntry
*)xmalloc (sizeof (struct ehEntry
));
600 /* These are saved for the exception table. */
602 entry
->start_label
= gen_label_rtx ();
603 entry
->end_label
= gen_label_rtx ();
604 entry
->exception_handler_label
= gen_label_rtx ();
605 pop_rtl_from_perm ();
607 LABEL_PRESERVE_P (entry
->start_label
) = 1;
608 LABEL_PRESERVE_P (entry
->end_label
) = 1;
609 LABEL_PRESERVE_P (entry
->exception_handler_label
) = 1;
611 entry
->finalization
= NULL_TREE
;
612 entry
->context
= current_function_decl
;
615 node
->chain
= stack
->top
;
618 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (entry
));
620 return entry
->start_label
;
623 static struct ehEntry
*
625 struct ehStack
*stack
;
627 struct ehNode
*tempnode
;
628 struct ehEntry
*tempentry
;
630 if (stack
&& (tempnode
= stack
->top
)) {
631 tempentry
= tempnode
->entry
;
632 stack
->top
= stack
->top
->chain
;
641 static struct ehEntry
*
642 copy_eh_entry (entry
)
643 struct ehEntry
*entry
;
645 struct ehEntry
*newentry
;
647 newentry
= (struct ehEntry
*)xmalloc (sizeof (struct ehEntry
));
648 memcpy ((void*)newentry
, (void*)entry
, sizeof (struct ehEntry
));
654 enqueue_eh_entry (queue
, entry
)
655 struct ehQueue
*queue
;
656 struct ehEntry
*entry
;
658 struct ehNode
*node
= (struct ehNode
*)xmalloc (sizeof (struct ehNode
));
663 if (queue
->head
== NULL
)
669 queue
->tail
->chain
= node
;
674 static struct ehEntry
*
675 dequeue_eh_entry (queue
)
676 struct ehQueue
*queue
;
678 struct ehNode
*tempnode
;
679 struct ehEntry
*tempentry
;
681 if (queue
->head
== NULL
)
684 tempnode
= queue
->head
;
685 queue
->head
= queue
->head
->chain
;
687 tempentry
= tempnode
->entry
;
695 struct ehQueue
*queue
;
697 queue
->head
= queue
->tail
= NULL
;
702 struct ehStack
*stack
;
708 new_except_stack (stack
)
709 struct exceptStack
*stack
;
713 /* ========================================================================= */
716 lang_interim_eh (finalization
)
720 end_protect (finalization
);
725 extern tree auto_function
PROTO((tree
, tree
, enum built_in_function
));
727 /* sets up all the global eh stuff that needs to be initialized at the
728 start of compilation.
731 - Setting up all the function call trees
732 - Initializing the ehqueue
733 - Initializing the eh_table_output_queue
734 - Initializing the ehstack
735 - Initializing the exceptstack
739 init_exception_processing ()
741 extern tree
define_function ();
742 tree unexpected_fndecl
, terminate_fndecl
;
743 tree set_unexpected_fndecl
, set_terminate_fndecl
;
744 tree catch_match_fndecl
;
745 tree find_first_exception_match_fndecl
;
749 tree PFV
= build_pointer_type (build_function_type
750 (void_type_node
, void_list_node
));
752 /* arg list for the build_function_type call for set_terminate () and
754 tree pfvlist
= tree_cons (NULL_TREE
, PFV
, void_list_node
);
756 /* void (*pfvtype (void (*) ()))() */
757 tree pfvtype
= build_function_type (PFV
, pfvlist
);
760 tree vtype
= build_function_type (void_type_node
, void_list_node
);
762 set_terminate_fndecl
= auto_function (get_identifier ("set_terminate"),
763 pfvtype
, NOT_BUILT_IN
);
764 set_unexpected_fndecl
= auto_function (get_identifier ("set_unexpected"),
765 pfvtype
, NOT_BUILT_IN
);
766 unexpected_fndecl
= auto_function (get_identifier ("unexpected"),
767 vtype
, NOT_BUILT_IN
);
768 terminate_fndecl
= auto_function (get_identifier ("terminate"),
769 vtype
, NOT_BUILT_IN
);
771 interim_eh_hook
= lang_interim_eh
;
773 push_lang_context (lang_name_c
);
776 define_function ("__throw_type_match",
777 build_function_type (integer_type_node
,
778 tree_cons (NULL_TREE
, string_type_node
, tree_cons (NULL_TREE
, ptr_type_node
, void_list_node
))),
782 find_first_exception_match_fndecl
=
783 define_function ("__find_first_exception_table_match",
784 build_function_type (ptr_type_node
,
785 tree_cons (NULL_TREE
, ptr_type_node
,
791 define_function ("__unwind_function",
792 build_function_type (void_type_node
,
793 tree_cons (NULL_TREE
, ptr_type_node
, void_list_node
)),
798 Unexpected
= default_conversion (unexpected_fndecl
);
799 Terminate
= default_conversion (terminate_fndecl
);
800 SetTerminate
= default_conversion (set_terminate_fndecl
);
801 SetUnexpected
= default_conversion (set_unexpected_fndecl
);
802 CatchMatch
= default_conversion (catch_match_fndecl
);
803 FirstExceptionMatch
= default_conversion (find_first_exception_match_fndecl
);
804 Unwind
= default_conversion (unwind_fndecl
);
805 BuiltinReturnAddress
= default_conversion (builtin_return_address_fndecl
);
807 TerminateFunctionCall
= build_function_call (Terminate
, NULL_TREE
);
810 throw_label
= gen_label_rtx ();
812 saved_pc
= gen_rtx (REG
, Pmode
, 16);
813 saved_throw_type
= gen_rtx (REG
, Pmode
, 17);
814 saved_throw_value
= gen_rtx (REG
, Pmode
, 18);
817 saved_pc
= gen_rtx (REG
, Pmode
, 3);
818 saved_throw_type
= gen_rtx (REG
, Pmode
, 4);
819 saved_throw_value
= gen_rtx (REG
, Pmode
, 5);
822 saved_pc
= gen_rtx (REG
, Pmode
, 13);
823 saved_throw_type
= gen_rtx (REG
, Pmode
, 14);
824 saved_throw_value
= gen_rtx (REG
, Pmode
, 15);
827 saved_pc
= gen_rtx (REG
, Pmode
, 5);
828 saved_throw_type
= gen_rtx (REG
, Pmode
, 6);
829 saved_throw_value
= gen_rtx (REG
, Pmode
, 7);
832 saved_pc
= gen_rtx (REG
, Pmode
, 10);
833 saved_throw_type
= gen_rtx (REG
, Pmode
, 11);
834 saved_throw_value
= gen_rtx (REG
, Pmode
, 12);
837 saved_pc
= gen_rtx (REG
, Pmode
, 16);
838 saved_throw_type
= gen_rtx (REG
, Pmode
, 17);
839 saved_throw_value
= gen_rtx (REG
, Pmode
, 18);
842 saved_pc
= gen_rtx (REG
, Pmode
, 7);
843 saved_throw_type
= gen_rtx (REG
, Pmode
, 8);
844 saved_throw_value
= gen_rtx (REG
, Pmode
, 9);
847 saved_pc
= gen_rtx (REG
, Pmode
, 9);
848 saved_throw_type
= gen_rtx (REG
, Pmode
, 10);
849 saved_throw_value
= gen_rtx (REG
, Pmode
, 11);
851 new_eh_queue (&ehqueue
);
852 new_eh_queue (&eh_table_output_queue
);
853 new_eh_stack (&ehstack
);
854 new_except_stack (&exceptstack
);
857 /* call this to begin a block of unwind protection (ie: when an object is
864 emit_label (push_eh_entry (&ehstack
));
868 /* call this to end a block of unwind protection. the finalization tree is
869 the finalization which needs to be run in order to cleanly unwind through
870 this level of protection. (ie: call this when a scope is exited)*/
872 end_protect (finalization
)
875 struct ehEntry
*entry
= pop_eh_entry (&ehstack
);
880 emit_label (entry
->end_label
);
882 entry
->finalization
= finalization
;
884 enqueue_eh_entry (&ehqueue
, entry
);
887 /* call this on start of a try block. */
889 expand_start_try_stmts ()
898 expand_end_try_stmts ()
900 end_protect (integer_zero_node
);
903 struct insn_save_node
{
905 struct insn_save_node
*chain
;
908 static struct insn_save_node
*InsnSave
= NULL
;
911 /* Used to keep track of where the catch blocks start. */
915 struct insn_save_node
*newnode
= (struct insn_save_node
*)
916 xmalloc (sizeof (struct insn_save_node
));
918 newnode
->last
= get_last_insn ();
919 newnode
->chain
= InsnSave
;
923 /* Use to keep track of where the catch blocks start. */
927 struct insn_save_node
*tempnode
;
930 if (!InsnSave
) return NULL_RTX
;
933 temprtx
= tempnode
->last
;
934 InsnSave
= InsnSave
->chain
;
941 /* call this to start processing of all the catch blocks. */
943 expand_start_all_catch ()
945 struct ehEntry
*entry
;
951 emit_line_note (input_filename
, lineno
);
952 label
= gen_label_rtx ();
953 /* The label for the exception handling block we will save. */
956 push_label_entry (&caught_return_label_stack
, label
);
958 /* Remember where we started. */
961 emit_insn (gen_nop ());
963 /* Will this help us not stomp on it? */
964 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
965 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
969 entry
= dequeue_eh_entry (&ehqueue
);
970 emit_label (entry
->exception_handler_label
);
972 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
974 /* When we get down to the matching entry, stop. */
975 if (entry
->finalization
== integer_zero_node
)
981 /* This goes when the below moves out of our way. */
983 label
= gen_label_rtx ();
987 /* All this should be out of line, and saved back in the exception handler
990 entry
->start_label
= entry
->exception_handler_label
;
991 /* These are saved for the exception table. */
993 entry
->end_label
= gen_label_rtx ();
994 entry
->exception_handler_label
= gen_label_rtx ();
995 entry
->finalization
= TerminateFunctionCall
;
996 entry
->context
= current_function_decl
;
997 assemble_external (TREE_OPERAND (Terminate
, 0));
998 pop_rtl_from_perm ();
1000 LABEL_PRESERVE_P (entry
->start_label
) = 1;
1001 LABEL_PRESERVE_P (entry
->end_label
) = 1;
1002 LABEL_PRESERVE_P (entry
->exception_handler_label
) = 1;
1004 emit_label (entry
->end_label
);
1006 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (entry
));
1008 /* After running the finalization, continue on out to the next
1009 cleanup, if we have nothing better to do. */
1010 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, entry
->end_label
));
1011 /* Will this help us not stomp on it? */
1012 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1013 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1014 make_first_label(throw_label
);
1015 emit_jump (throw_label
);
1016 emit_label (entry
->exception_handler_label
);
1017 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
1023 /* call this to end processing of all the catch blocks. */
1025 expand_end_all_catch ()
1027 rtx catchstart
, catchend
, last
;
1033 /* Code to throw out to outer context, if we fall off end of catch
1035 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
,
1037 top_label_entry (&caught_return_label_stack
)));
1038 make_first_label(throw_label
);
1039 emit_jump (throw_label
);
1041 /* Find the start of the catch block. */
1042 last
= pop_last_insn ();
1043 catchstart
= NEXT_INSN (last
);
1044 catchend
= get_last_insn ();
1046 NEXT_INSN (last
) = 0;
1047 set_last_insn (last
);
1049 /* this level of catch blocks is done, so set up the successful catch jump
1050 label for the next layer of catch blocks. */
1051 pop_label_entry (&caught_return_label_stack
);
1053 push_except_stmts (&exceptstack
, catchstart
, catchend
);
1055 /* Here we fall through into the continuation code. */
1059 /* this is called from expand_exception_blocks () to expand the toplevel
1060 finalizations for a function. */
1062 expand_leftover_cleanups ()
1064 struct ehEntry
*entry
;
1065 rtx first_label
= NULL_RTX
;
1070 /* Will this help us not stomp on it? */
1071 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1072 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1074 while ((entry
= dequeue_eh_entry (&ehqueue
)) != 0)
1077 first_label
= entry
->exception_handler_label
;
1078 emit_label (entry
->exception_handler_label
);
1080 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
1082 /* leftover try block, opps. */
1083 if (entry
->finalization
== integer_zero_node
)
1091 struct ehEntry entry
;
1092 /* These are saved for the exception table. */
1094 label
= gen_label_rtx ();
1095 entry
.start_label
= first_label
;
1096 entry
.end_label
= label
;
1097 entry
.exception_handler_label
= gen_label_rtx ();
1098 entry
.finalization
= TerminateFunctionCall
;
1099 entry
.context
= current_function_decl
;
1100 assemble_external (TREE_OPERAND (Terminate
, 0));
1101 pop_rtl_from_perm ();
1103 LABEL_PRESERVE_P (entry
.start_label
) = 1;
1104 LABEL_PRESERVE_P (entry
.end_label
) = 1;
1105 LABEL_PRESERVE_P (entry
.exception_handler_label
) = 1;
1109 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (&entry
));
1111 /* After running the finalization, continue on out to the next
1112 cleanup, if we have nothing better to do. */
1113 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, entry
.end_label
));
1114 /* Will this help us not stomp on it? */
1115 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1116 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1117 make_first_label(throw_label
);
1118 emit_jump (throw_label
);
1119 emit_label (entry
.exception_handler_label
);
1120 expand_expr (entry
.finalization
, const0_rtx
, VOIDmode
, 0);
1125 /* call this to start a catch block. Typename is the typename, and identifier
1126 is the variable to place the object in or NULL if the variable doesn't
1127 matter. If typename is NULL, that means its a "catch (...)" or catch
1128 everything. In that case we don't need to do any type checking.
1129 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1131 expand_start_catch_block (declspecs
, declarator
)
1132 tree declspecs
, declarator
;
1134 rtx false_label_rtx
;
1135 rtx protect_label_rtx
;
1143 /* Create a binding level for the parm. */
1144 expand_start_bindings (0);
1149 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
1151 /* Figure out the type that the initializer is. */
1152 init_type
= TREE_TYPE (decl
);
1153 if (TREE_CODE (init_type
) != REFERENCE_TYPE
)
1154 init_type
= build_reference_type (init_type
);
1156 init
= convert_from_reference (save_expr (make_tree (init_type
, saved_throw_value
)));
1158 /* Do we need the below two lines? */
1159 /* Let `finish_decl' know that this initializer is ok. */
1160 DECL_INITIAL (decl
) = init
;
1161 /* This needs to be preallocated under the try block,
1162 in a union of all catch variables. */
1164 type
= TREE_TYPE (decl
);
1166 /* peel back references, so they match. */
1167 if (TREE_CODE (type
) == REFERENCE_TYPE
)
1168 type
= TREE_TYPE (type
);
1173 /* These are saved for the exception table. */
1175 false_label_rtx
= gen_label_rtx ();
1176 protect_label_rtx
= gen_label_rtx ();
1177 pop_rtl_from_perm ();
1178 push_label_entry (&false_label_stack
, false_label_rtx
);
1179 push_label_entry (&false_label_stack
, protect_label_rtx
);
1185 rtx call_rtx
, return_value_rtx
;
1186 tree catch_match_fcall
;
1187 tree catchmatch_arg
, argval
;
1189 typestring
= build_overload_name (type
, 1, 1);
1191 params
= tree_cons (NULL_TREE
,
1192 combine_strings (build_string (strlen (typestring
)+1, typestring
)),
1193 tree_cons (NULL_TREE
,
1194 make_tree (ptr_type_node
, saved_throw_type
),
1196 catch_match_fcall
= build_function_call (CatchMatch
, params
);
1197 call_rtx
= expand_call (catch_match_fcall
, NULL_RTX
, 0);
1198 assemble_external (TREE_OPERAND (CatchMatch
, 0));
1201 hard_function_value (integer_type_node
, catch_match_fcall
);
1203 /* did the throw type match function return TRUE? */
1204 emit_cmp_insn (return_value_rtx
, const0_rtx
, NE
, NULL_RTX
,
1205 GET_MODE (return_value_rtx
), 0, 0);
1207 /* if it returned FALSE, jump over the catch block, else fall into it */
1208 emit_jump_insn (gen_bne (false_label_rtx
));
1209 finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
1213 /* Fall into the catch all section. */
1216 /* This is the starting of something to protect. */
1217 emit_label (protect_label_rtx
);
1219 emit_line_note (input_filename
, lineno
);
1223 /* Call this to end a catch block. Its responsible for emitting the
1224 code to handle jumping back to the correct place, and for emitting
1225 the label to jump to if this catch block didn't match. */
1226 void expand_end_catch_block ()
1230 rtx start_protect_label_rtx
;
1231 rtx end_protect_label_rtx
;
1233 struct ehEntry entry
;
1235 /* label we jump to if we caught the exception */
1236 emit_jump (top_label_entry (&caught_return_label_stack
));
1238 /* Code to throw out to outer context, if we get a throw from within
1239 our catch handler. */
1240 /* These are saved for the exception table. */
1242 entry
.exception_handler_label
= gen_label_rtx ();
1243 pop_rtl_from_perm ();
1244 emit_label (entry
.exception_handler_label
);
1245 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
,
1247 top_label_entry (&caught_return_label_stack
)));
1248 make_first_label(throw_label
);
1249 emit_jump (throw_label
);
1250 /* No associated finalization. */
1251 entry
.finalization
= NULL_TREE
;
1252 entry
.context
= current_function_decl
;
1254 /* Because we are reordered out of line, we have to protect this. */
1255 /* label for the start of the protection region. */
1256 start_protect_label_rtx
= pop_label_entry (&false_label_stack
);
1258 /* Cleanup the EH paramater. */
1259 decls
= getdecls ();
1260 expand_end_bindings (decls
, decls
!= NULL_TREE
, 0);
1262 /* label we emit to jump to if this catch block didn't match. */
1263 emit_label (end_protect_label_rtx
= pop_label_entry (&false_label_stack
));
1265 /* Because we are reordered out of line, we have to protect this. */
1266 entry
.start_label
= start_protect_label_rtx
;
1267 entry
.end_label
= end_protect_label_rtx
;
1269 LABEL_PRESERVE_P (entry
.start_label
) = 1;
1270 LABEL_PRESERVE_P (entry
.end_label
) = 1;
1271 LABEL_PRESERVE_P (entry
.exception_handler_label
) = 1;
1273 /* These set up a call to throw the caught exception into the outer
1275 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (&entry
));
1279 /* cheesyness to save some typing. returns the return value rtx */
1281 do_function_call (func
, params
, return_type
)
1282 tree func
, params
, return_type
;
1285 func_call
= build_function_call (func
, params
);
1286 expand_call (func_call
, NULL_RTX
, 0);
1287 if (return_type
!= NULL_TREE
)
1288 return hard_function_value (return_type
, func_call
);
1292 /* unwind the stack. */
1294 do_unwind (throw_label
)
1298 extern FILE *asm_out_file
;
1303 /* call to __builtin_return_address () */
1304 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1305 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1306 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1307 /* In the return, the new pc is pc+8, as the value comming in is
1308 really the address of the call insn, not the next insn. */
1309 emit_move_insn (return_val_rtx
, plus_constant(gen_rtx (LABEL_REF
,
1312 /* We use three values, PC, type, and value */
1313 easy_expand_asm ("st %l0,[%fp]");
1314 easy_expand_asm ("st %l1,[%fp+4]");
1315 easy_expand_asm ("st %l2,[%fp+8]");
1316 easy_expand_asm ("ret");
1317 easy_expand_asm ("restore");
1320 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined(__alpha)
1321 extern FILE *asm_out_file
;
1326 /* call to __builtin_return_address () */
1327 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1328 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1329 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1331 /* I would like to do this here, but doesn't seem to work. */
1332 emit_move_insn (return_val_rtx
, gen_rtx (LABEL_REF
,
1335 /* So, for now, just pass throw label to stack unwinder. */
1337 /* We use three values, PC, type, and value */
1338 params
= tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
1339 gen_rtx (LABEL_REF
, Pmode
, throw_label
)), NULL_TREE
);
1341 do_function_call (Unwind
, params
, NULL_TREE
);
1342 assemble_external (TREE_OPERAND (Unwind
, 0));
1346 rtx temp_frame
= frame_pointer_rtx
;
1348 temp_frame
= memory_address (Pmode
, temp_frame
);
1349 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
1351 /* hopefully this will successfully pop the frame! */
1352 emit_move_insn (frame_pointer_rtx
, temp_frame
);
1353 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
1354 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
1355 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1356 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
1359 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1360 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
1362 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
1364 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1365 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
1369 if (flag_omit_frame_pointer
)
1370 sorry ("this implementation of exception handling requires a frame pointer");
1372 emit_move_insn (stack_pointer_rtx
,
1373 gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -8)));
1374 emit_move_insn (hard_frame_pointer_rtx
,
1375 gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -12)));
1379 /* is called from expand_exception_blocks () to generate the code in a function
1380 to "throw" if anything in the function needs to preform a throw.
1382 expands "throw" as the following psuedo code:
1385 eh = find_first_exception_match (saved_pc);
1386 if (!eh) goto gotta_rethrow_it;
1390 saved_pc = __builtin_return_address (0);
1391 pop_to_previous_level ();
1396 expand_builtin_throw ()
1401 rtx gotta_rethrow_it
= gen_label_rtx ();
1402 rtx gotta_call_terminate
= gen_label_rtx ();
1403 rtx unwind_and_throw
= gen_label_rtx ();
1404 rtx goto_unwind_and_throw
= gen_label_rtx ();
1406 make_first_label(throw_label
);
1407 emit_label (throw_label
);
1409 /* search for an exception handler for the saved_pc */
1410 return_val_rtx
= do_function_call (FirstExceptionMatch
,
1411 tree_cons (NULL_TREE
, make_tree (ptr_type_node
, saved_pc
), NULL_TREE
),
1413 assemble_external (TREE_OPERAND (FirstExceptionMatch
, 0));
1415 /* did we find one? */
1416 emit_cmp_insn (return_val_rtx
, const0_rtx
, EQ
, NULL_RTX
,
1417 GET_MODE (return_val_rtx
), 0, 0);
1419 /* if not, jump to gotta_rethrow_it */
1420 emit_jump_insn (gen_beq (gotta_rethrow_it
));
1422 /* we found it, so jump to it */
1423 emit_indirect_jump (return_val_rtx
);
1425 /* code to deal with unwinding and looking for it again */
1426 emit_label (gotta_rethrow_it
);
1428 /* call to __builtin_return_address () */
1430 /* This replaces a 'call' to __builtin_return_address */
1431 return_val_rtx
= gen_reg_rtx (Pmode
);
1432 emit_move_insn (return_val_rtx
, gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -4)));
1434 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1435 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1436 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1439 /* did __builtin_return_address () return a valid address? */
1440 emit_cmp_insn (return_val_rtx
, const0_rtx
, EQ
, NULL_RTX
,
1441 GET_MODE (return_val_rtx
), 0, 0);
1443 emit_jump_insn (gen_beq (gotta_call_terminate
));
1446 /* On the ARM, '__builtin_return_address', must have 4
1447 subtracted from it. */
1448 emit_insn (gen_add2_insn (return_val_rtx
, GEN_INT (-4)));
1450 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
1451 mode, the condition codes must be masked out of the return value, or else
1452 they will confuse BuiltinReturnAddress. This does not apply to ARM6 and
1453 later processors when running in 32 bit mode. */
1455 emit_insn (gen_rtx (SET
, SImode
, return_val_rtx
, gen_rtx (AND
, SImode
, return_val_rtx
, GEN_INT (0x03fffffc))));
1458 /* On the SPARC, __builtin_return_address is already -8, no need to
1459 subtract any more from it. */
1460 return_val_rtx
= plus_constant (return_val_rtx
, -1);
1465 emit_move_insn (saved_pc
, return_val_rtx
);
1466 do_unwind (throw_label
);
1467 make_first_label(throw_label
);
1468 emit_jump (throw_label
);
1470 /* no it didn't --> therefore we need to call terminate */
1471 emit_label (gotta_call_terminate
);
1472 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
1473 assemble_external (TREE_OPERAND (Terminate
, 0));
1477 /* This is called to expand all the toplevel exception handling
1478 finalization for a function. It should only be called once per
1481 expand_exception_blocks ()
1483 rtx catchstart
, catchend
;
1487 funcend
= gen_label_rtx ();
1488 emit_jump (funcend
);
1489 /* expand_null_return (); */
1491 while (pop_except_stmts (&exceptstack
, &catchstart
, &catchend
)) {
1492 last
= get_last_insn ();
1493 NEXT_INSN (last
) = catchstart
;
1494 PREV_INSN (catchstart
) = last
;
1495 NEXT_INSN (catchend
) = 0;
1496 set_last_insn (catchend
);
1499 expand_leftover_cleanups ();
1502 static int have_done
= 0;
1503 if (! have_done
&& TREE_PUBLIC (current_function_decl
)
1504 && DECL_INTERFACE_KNOWN (current_function_decl
)
1505 && ! DECL_EXTERNAL (current_function_decl
))
1508 expand_builtin_throw ();
1511 emit_label (funcend
);
1515 /* call this to expand a throw statement. This follows the following
1518 1. Allocate space to save the current PC onto the stack.
1519 2. Generate and emit a label and save its address into the
1520 newly allocated stack space since we can't save the pc directly.
1521 3. If this is the first call to throw in this function:
1522 generate a label for the throw block
1523 4. jump to the throw block label. */
1534 /* This is the label that represents where in the code we were, when
1535 we got an exception. This needs to be updated when we rethrow an
1536 exception, so that the matching routine knows to search out. */
1537 label
= gen_label_rtx ();
1542 /* throw expression */
1543 /* First, decay it. */
1544 exp
= default_conversion (exp
);
1545 type
= TREE_TYPE (exp
);
1548 char *typestring
= build_overload_name (type
, 1, 1);
1549 tree throw_type
= build1 (ADDR_EXPR
, ptr_type_node
, combine_strings (build_string (strlen (typestring
)+1, typestring
)));
1550 rtx throw_type_rtx
= expand_expr (throw_type
, NULL_RTX
, VOIDmode
, 0);
1551 rtx throw_value_rtx
;
1553 /* Make a copy of the thrown object. WP 15.1.5 */
1554 exp
= build_new (NULL_TREE
, type
, build_tree_list (NULL_TREE
, exp
), 0);
1556 if (exp
== error_mark_node
)
1557 error (" in thrown expression");
1558 throw_value_rtx
= expand_expr (exp
, NULL_RTX
, VOIDmode
, 0);
1559 emit_move_insn (saved_throw_value
, throw_value_rtx
);
1560 emit_move_insn (saved_throw_type
, throw_type_rtx
);
1565 /* rethrow current exception */
1566 /* This part is easy, as we don't have to do anything else. */
1569 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, label
));
1570 make_first_label(throw_label
);
1571 emit_jump (throw_label
);
1574 /* end of: my-cp-except.c */
1578 /* Output the exception table.
1579 Return the number of handlers. */
1581 build_exception_table ()
1585 extern FILE *asm_out_file
;
1586 struct ehEntry
*entry
;
1592 while (entry
= dequeue_eh_entry (&eh_table_output_queue
))
1594 tree context
= entry
->context
;
1596 if (context
&& ! TREE_ASM_WRITTEN (context
))
1601 exception_section ();
1603 /* Beginning marker for table. */
1604 ASM_OUTPUT_ALIGN (asm_out_file
, 2);
1605 ASM_OUTPUT_LABEL (asm_out_file
, "__EXCEPTION_TABLE__");
1606 output_exception_table_entry (asm_out_file
,
1607 const0_rtx
, const0_rtx
, const0_rtx
);
1610 output_exception_table_entry (asm_out_file
,
1611 entry
->start_label
, entry
->end_label
,
1612 entry
->exception_handler_label
);
1617 /* Ending marker for table. */
1618 ASM_OUTPUT_LABEL (asm_out_file
, "__EXCEPTION_END__");
1619 output_exception_table_entry (asm_out_file
,
1620 constm1_rtx
, constm1_rtx
, constm1_rtx
);
1623 #endif /* TRY_NEW_EH */
1628 register_exception_table ()
1631 emit_library_call (gen_rtx (SYMBOL_REF
, Pmode
, "__register_exceptions"), 0,
1633 gen_rtx (SYMBOL_REF
, Pmode
, "__EXCEPTION_TABLE__"),
1635 #endif /* TRY_NEW_EH */
1638 /* Build a throw expression. */
1643 if (e
!= error_mark_node
)
1645 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1646 TREE_SIDE_EFFECTS (e
) = 1;