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. */
36 extern void (*interim_eh_hook
) PROTO((tree
));
38 /* holds the fndecl for __builtin_return_address () */
39 tree builtin_return_address_fndecl
;
41 /* Define at your own risk! */
63 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined (__arm) || defined (__alpha)
73 static int warned
= 0;
76 sorry ("exception handling not supported");
82 expand_exception_blocks ()
92 end_protect (finalization
)
98 expand_start_try_stmts ()
104 expand_end_try_stmts ()
109 expand_start_all_catch ()
114 expand_end_all_catch ()
119 expand_start_catch_block (declspecs
, declarator
)
120 tree declspecs
, declarator
;
125 expand_end_catch_block ()
130 init_exception_processing ()
143 /* Make 'label' the first numbered label of the current function */
145 make_first_label(label
)
148 if (CODE_LABEL_NUMBER(label
) < get_first_label_num())
149 set_new_first_and_last_label_num (CODE_LABEL_NUMBER(label
),
157 if (! flag_handle_exceptions
)
159 static int warned
= 0;
160 if (! warned
&& do_warn
)
162 error ("exception handling disabled, use -fhandle-exceptions to enable.");
172 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
173 to supporting exception handling as per Stroustrup's 2nd edition.
174 It is a complete rewrite of all the EH stuff that was here before
176 1. The type of the throw and catch must still match
177 exactly (no support yet for matching base classes)
178 2. Throw specifications of functions still doesnt't work.
180 1. Destructors are called properly :-)
181 2. No overhead for the non-exception thrown case.
182 3. Fixing shortcomings 1 and 2 is simple.
183 -Tad Hunt (tad@mail.csh.rit.edu)
187 /* A couple of backend routines from m88k.c */
189 /* used to cache a call to __builtin_return_address () */
190 static tree BuiltinReturnAddress
;
198 /* XXX - Tad: for EH */
199 /* output an exception table entry */
202 output_exception_table_entry (file
, start_label
, end_label
, eh_label
)
204 rtx start_label
, end_label
, eh_label
;
208 assemble_integer (start_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
209 assemble_integer (end_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
210 assemble_integer (eh_label
, BITS_PER_WORD
/BITS_PER_UNIT
, 1);
211 putc ('\n', file
); /* blank line */
215 easy_expand_asm (str
)
218 expand_asm (build_string (strlen (str
)+1, str
));
223 /* This is the startup, and finish stuff per exception table. */
225 /* XXX - Tad: exception handling section */
226 #ifndef EXCEPT_SECTION_ASM_OP
227 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
230 #ifdef EXCEPT_SECTION_ASM_OP
234 void *exception_handler
;
236 #endif /* EXCEPT_SECTION_ASM_OP */
238 #ifdef EXCEPT_SECTION_ASM_OP
240 /* on machines which support it, the exception table lives in another section,
241 but it needs a label so we can reference it... This sets up that
243 asm (EXCEPT_SECTION_ASM_OP
);
244 exception_table __EXCEPTION_TABLE__
[1] = { (void*)0, (void*)0, (void*)0 };
245 asm (TEXT_SECTION_ASM_OP
);
247 #endif /* EXCEPT_SECTION_ASM_OP */
249 #ifdef EXCEPT_SECTION_ASM_OP
251 /* we need to know where the end of the exception table is... so this
254 asm (EXCEPT_SECTION_ASM_OP
);
255 exception_table __EXCEPTION_END__
[1] = { (void*)-1, (void*)-1, (void*)-1 };
256 asm (TEXT_SECTION_ASM_OP
);
258 #endif /* EXCEPT_SECTION_ASM_OP */
265 #ifdef ASM_OUTPUT_SECTION_NAME
266 named_section (NULL_TREE
, ".gcc_except_table");
271 #if defined(__rs6000)
274 readonly_data_section ();
282 /* from: my-cp-except.c */
284 /* VI: ":set ts=4" */
286 #include <stdio.h> */
296 #include "insn-flags.h"
302 /* ======================================================================
303 Briefly the algorithm works like this:
305 When a constructor or start of a try block is encountered,
306 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
307 new entry in the unwind protection stack and returns a label to
308 output to start the protection for that block.
310 When a destructor or end try block is encountered, pop_eh_entry
311 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
312 created when push_eh_entry () was called. The ehEntry structure
313 contains three things at this point. The start protect label,
314 the end protect label, and the exception handler label. The end
315 protect label should be output before the call to the destructor
316 (if any). If it was a destructor, then its parse tree is stored
317 in the finalization variable in the ehEntry structure. Otherwise
318 the finalization variable is set to NULL to reflect the fact that
319 is the the end of a try block. Next, this modified ehEntry node
320 is enqueued in the finalizations queue by calling
321 enqueue_eh_entry (&queue,entry).
323 +---------------------------------------------------------------+
324 |XXX: Will need modification to deal with partially |
325 | constructed arrays of objects |
327 | Basically, this consists of keeping track of how many |
328 | of the objects have been constructed already (this |
329 | should be in a register though, so that shouldn't be a |
331 +---------------------------------------------------------------+
333 When a catch block is encountered, there is a lot of work to be
336 Since we don't want to generate the catch block inline with the
337 regular flow of the function, we need to have some way of doing
338 so. Luckily, we have a couple of routines "get_last_insn ()" and
339 "set_last_insn ()" provided. When the start of a catch block is
340 encountered, we save a pointer to the last insn generated. After
341 the catch block is generated, we save a pointer to the first
342 catch block insn and the last catch block insn with the routines
343 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
344 to be the last insn generated before the catch block, and set the
345 NEXT_INSN (last_insn) to zero.
347 Since catch blocks might be nested inside other catch blocks, and
348 we munge the chain of generated insns after the catch block is
349 generated, we need to store the pointers to the last insn
350 generated in a stack, so that when the end of a catch block is
351 encountered, the last insn before the current catch block can be
352 popped and set to be the last insn, and the first and last insns
353 of the catch block just generated can be enqueue'd for output at
356 Next we must insure that when the catch block is executed, all
357 finalizations for the matching try block have been completed. If
358 any of those finalizations throw an exception, we must call
359 terminate according to the ARM (section r.15.6.1). What this
360 means is that we need to dequeue and emit finalizations for each
361 entry in the ehQueue until we get to an entry with a NULL
362 finalization field. For any of the finalization entries, if it
363 is not a call to terminate (), we must protect it by giving it
364 another start label, end label, and exception handler label,
365 setting its finalization tree to be a call to terminate (), and
366 enqueue'ing this new ehEntry to be output at an outer level.
367 Finally, after all that is done, we can get around to outputting
368 the catch block which basically wraps all the "catch (...) {...}"
369 statements in a big if/then/else construct that matches the
370 correct block to call.
372 ===================================================================== */
374 extern rtx emit_insn
PROTO((rtx
));
375 extern rtx gen_nop
PROTO(());
377 /* local globals for function calls
378 ====================================================================== */
380 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
381 "set_unexpected ()" after default_conversion. (lib-except.c) */
382 static tree Terminate
, Unexpected
, SetTerminate
, SetUnexpected
, CatchMatch
;
384 /* used to cache __find_first_exception_table_match ()
385 for throw (lib-except.c) */
386 static tree FirstExceptionMatch
;
388 /* used to cache a call to __unwind_function () (lib-except.c) */
391 /* holds a ready to emit call to "terminate ()". */
392 static tree TerminateFunctionCall
;
394 /* ====================================================================== */
398 /* data structures for my various quick and dirty stacks and queues
399 Eventually, most of this should go away, because I think it can be
400 integrated with stuff already built into the compiler. */
402 /* =================================================================== */
406 struct labelNode
*chain
;
410 /* this is the most important structure here. Basically this is how I store
411 an exception table entry internally. */
415 rtx exception_handler_label
;
422 struct ehEntry
*entry
;
423 struct ehNode
*chain
;
439 struct exceptNode
*chain
;
443 struct exceptNode
*top
;
445 /* ========================================================================= */
449 /* local globals - these local globals are for storing data necessary for
450 generating the exception table and code in the correct order.
452 ========================================================================= */
454 /* Holds the pc for doing "throw" */
456 /* Holds the type of the thing being thrown. */
457 rtx saved_throw_type
;
458 /* Holds the value being thrown. */
459 rtx saved_throw_value
;
463 static struct ehStack ehstack
;
464 static struct ehQueue ehqueue
;
465 static struct ehQueue eh_table_output_queue
;
466 static struct exceptStack exceptstack
;
467 static struct labelNode
*false_label_stack
= NULL
;
468 static struct labelNode
*caught_return_label_stack
= NULL
;
469 /* ========================================================================= */
471 /* function prototypes */
472 static struct ehEntry
*pop_eh_entry
PROTO((struct ehStack
*stack
));
473 static void enqueue_eh_entry
PROTO((struct ehQueue
*queue
, struct ehEntry
*entry
));
474 static void push_except_stmts
PROTO((struct exceptStack
*exceptstack
,
475 rtx catchstart
, rtx catchend
));
476 static int pop_except_stmts
PROTO((struct exceptStack
*exceptstack
,
477 rtx
*catchstart
, rtx
*catchend
));
478 static rtx push_eh_entry
PROTO((struct ehStack
*stack
));
479 static struct ehEntry
*dequeue_eh_entry
PROTO((struct ehQueue
*queue
));
480 static void new_eh_queue
PROTO((struct ehQueue
*queue
));
481 static void new_eh_stack
PROTO((struct ehStack
*stack
));
482 static void new_except_stack
PROTO((struct exceptStack
*queue
));
483 static void push_last_insn
PROTO(());
484 static rtx pop_last_insn
PROTO(());
485 static void push_label_entry
PROTO((struct labelNode
**labelstack
, rtx label
));
486 static rtx pop_label_entry
PROTO((struct labelNode
**labelstack
));
487 static rtx top_label_entry
PROTO((struct labelNode
**labelstack
));
488 static struct ehEntry
*copy_eh_entry
PROTO((struct ehEntry
*entry
));
492 /* All my cheesy stack/queue/misc data structure handling routines
494 ========================================================================= */
497 push_label_entry (labelstack
, label
)
498 struct labelNode
**labelstack
;
501 struct labelNode
*newnode
=(struct labelNode
*)xmalloc (sizeof (struct labelNode
));
503 newnode
->label
= label
;
504 newnode
->chain
= *labelstack
;
505 *labelstack
= newnode
;
509 pop_label_entry (labelstack
)
510 struct labelNode
**labelstack
;
513 struct labelNode
*tempnode
;
515 if (! *labelstack
) return NULL_RTX
;
517 tempnode
= *labelstack
;
518 label
= tempnode
->label
;
519 *labelstack
= (*labelstack
)->chain
;
526 top_label_entry (labelstack
)
527 struct labelNode
**labelstack
;
529 if (! *labelstack
) return NULL_RTX
;
531 return (*labelstack
)->label
;
535 push_except_stmts (exceptstack
, catchstart
, catchend
)
536 struct exceptStack
*exceptstack
;
537 rtx catchstart
, catchend
;
539 struct exceptNode
*newnode
= (struct exceptNode
*)
540 xmalloc (sizeof (struct exceptNode
));
542 newnode
->catchstart
= catchstart
;
543 newnode
->catchend
= catchend
;
544 newnode
->chain
= exceptstack
->top
;
546 exceptstack
->top
= newnode
;
550 pop_except_stmts (exceptstack
, catchstart
, catchend
)
551 struct exceptStack
*exceptstack
;
552 rtx
*catchstart
, *catchend
;
554 struct exceptNode
*tempnode
;
556 if (!exceptstack
->top
) {
557 *catchstart
= *catchend
= NULL_RTX
;
561 tempnode
= exceptstack
->top
;
562 exceptstack
->top
= exceptstack
->top
->chain
;
564 *catchstart
= tempnode
->catchstart
;
565 *catchend
= tempnode
->catchend
;
571 /* Push to permanent obstack for rtl generation.
573 static struct obstack
*saved_rtl_obstack
;
577 extern struct obstack permanent_obstack
;
578 extern struct obstack
*rtl_obstack
;
580 saved_rtl_obstack
= rtl_obstack
;
581 rtl_obstack
= &permanent_obstack
;
584 /* Pop back to normal rtl handling. */
588 extern struct obstack permanent_obstack
;
589 extern struct obstack
*rtl_obstack
;
591 rtl_obstack
= saved_rtl_obstack
;
595 push_eh_entry (stack
)
596 struct ehStack
*stack
;
598 struct ehNode
*node
= (struct ehNode
*)xmalloc (sizeof (struct ehNode
));
599 struct ehEntry
*entry
= (struct ehEntry
*)xmalloc (sizeof (struct ehEntry
));
607 /* These are saved for the exception table. */
609 entry
->start_label
= gen_label_rtx ();
610 entry
->end_label
= gen_label_rtx ();
611 entry
->exception_handler_label
= gen_label_rtx ();
612 pop_rtl_from_perm ();
614 LABEL_PRESERVE_P (entry
->start_label
) = 1;
615 LABEL_PRESERVE_P (entry
->end_label
) = 1;
616 LABEL_PRESERVE_P (entry
->exception_handler_label
) = 1;
618 entry
->finalization
= NULL_TREE
;
619 entry
->context
= current_function_decl
;
622 node
->chain
= stack
->top
;
625 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (entry
));
627 return entry
->start_label
;
630 static struct ehEntry
*
632 struct ehStack
*stack
;
634 struct ehNode
*tempnode
;
635 struct ehEntry
*tempentry
;
637 if (stack
&& (tempnode
= stack
->top
)) {
638 tempentry
= tempnode
->entry
;
639 stack
->top
= stack
->top
->chain
;
648 static struct ehEntry
*
649 copy_eh_entry (entry
)
650 struct ehEntry
*entry
;
652 struct ehEntry
*newentry
;
654 newentry
= (struct ehEntry
*)xmalloc (sizeof (struct ehEntry
));
655 memcpy ((void*)newentry
, (void*)entry
, sizeof (struct ehEntry
));
661 enqueue_eh_entry (queue
, entry
)
662 struct ehQueue
*queue
;
663 struct ehEntry
*entry
;
665 struct ehNode
*node
= (struct ehNode
*)xmalloc (sizeof (struct ehNode
));
670 if (queue
->head
== NULL
)
676 queue
->tail
->chain
= node
;
681 static struct ehEntry
*
682 dequeue_eh_entry (queue
)
683 struct ehQueue
*queue
;
685 struct ehNode
*tempnode
;
686 struct ehEntry
*tempentry
;
688 if (queue
->head
== NULL
)
691 tempnode
= queue
->head
;
692 queue
->head
= queue
->head
->chain
;
694 tempentry
= tempnode
->entry
;
702 struct ehQueue
*queue
;
704 queue
->head
= queue
->tail
= NULL
;
709 struct ehStack
*stack
;
715 new_except_stack (stack
)
716 struct exceptStack
*stack
;
720 /* ========================================================================= */
723 lang_interim_eh (finalization
)
727 end_protect (finalization
);
732 extern tree auto_function
PROTO((tree
, tree
, enum built_in_function
));
734 /* sets up all the global eh stuff that needs to be initialized at the
735 start of compilation.
738 - Setting up all the function call trees
739 - Initializing the ehqueue
740 - Initializing the eh_table_output_queue
741 - Initializing the ehstack
742 - Initializing the exceptstack
746 init_exception_processing ()
748 extern tree
define_function ();
749 tree unexpected_fndecl
, terminate_fndecl
;
750 tree set_unexpected_fndecl
, set_terminate_fndecl
;
751 tree catch_match_fndecl
;
752 tree find_first_exception_match_fndecl
;
756 tree PFV
= build_pointer_type (build_function_type
757 (void_type_node
, void_list_node
));
759 /* arg list for the build_function_type call for set_terminate () and
761 tree pfvlist
= tree_cons (NULL_TREE
, PFV
, void_list_node
);
763 /* void (*pfvtype (void (*) ()))() */
764 tree pfvtype
= build_function_type (PFV
, pfvlist
);
767 tree vtype
= build_function_type (void_type_node
, void_list_node
);
769 set_terminate_fndecl
= auto_function (get_identifier ("set_terminate"),
770 pfvtype
, NOT_BUILT_IN
);
771 set_unexpected_fndecl
= auto_function (get_identifier ("set_unexpected"),
772 pfvtype
, NOT_BUILT_IN
);
773 unexpected_fndecl
= auto_function (get_identifier ("unexpected"),
774 vtype
, NOT_BUILT_IN
);
775 terminate_fndecl
= auto_function (get_identifier ("terminate"),
776 vtype
, NOT_BUILT_IN
);
778 interim_eh_hook
= lang_interim_eh
;
780 push_lang_context (lang_name_c
);
783 define_function ("__throw_type_match",
784 build_function_type (integer_type_node
,
785 tree_cons (NULL_TREE
, string_type_node
, tree_cons (NULL_TREE
, ptr_type_node
, void_list_node
))),
789 find_first_exception_match_fndecl
=
790 define_function ("__find_first_exception_table_match",
791 build_function_type (ptr_type_node
,
792 tree_cons (NULL_TREE
, ptr_type_node
,
798 define_function ("__unwind_function",
799 build_function_type (void_type_node
,
800 tree_cons (NULL_TREE
, ptr_type_node
, void_list_node
)),
805 Unexpected
= default_conversion (unexpected_fndecl
);
806 Terminate
= default_conversion (terminate_fndecl
);
807 SetTerminate
= default_conversion (set_terminate_fndecl
);
808 SetUnexpected
= default_conversion (set_unexpected_fndecl
);
809 CatchMatch
= default_conversion (catch_match_fndecl
);
810 FirstExceptionMatch
= default_conversion (find_first_exception_match_fndecl
);
811 Unwind
= default_conversion (unwind_fndecl
);
812 BuiltinReturnAddress
= default_conversion (builtin_return_address_fndecl
);
814 TerminateFunctionCall
= build_function_call (Terminate
, NULL_TREE
);
817 throw_label
= gen_label_rtx ();
819 saved_pc
= gen_rtx (REG
, Pmode
, 16);
820 saved_throw_type
= gen_rtx (REG
, Pmode
, 17);
821 saved_throw_value
= gen_rtx (REG
, Pmode
, 18);
824 saved_pc
= gen_rtx (REG
, Pmode
, 3);
825 saved_throw_type
= gen_rtx (REG
, Pmode
, 4);
826 saved_throw_value
= gen_rtx (REG
, Pmode
, 5);
829 saved_pc
= gen_rtx (REG
, Pmode
, 13);
830 saved_throw_type
= gen_rtx (REG
, Pmode
, 14);
831 saved_throw_value
= gen_rtx (REG
, Pmode
, 15);
834 saved_pc
= gen_rtx (REG
, Pmode
, 5);
835 saved_throw_type
= gen_rtx (REG
, Pmode
, 6);
836 saved_throw_value
= gen_rtx (REG
, Pmode
, 7);
839 saved_pc
= gen_rtx (REG
, Pmode
, 10);
840 saved_throw_type
= gen_rtx (REG
, Pmode
, 11);
841 saved_throw_value
= gen_rtx (REG
, Pmode
, 12);
844 saved_pc
= gen_rtx (REG
, Pmode
, 16);
845 saved_throw_type
= gen_rtx (REG
, Pmode
, 17);
846 saved_throw_value
= gen_rtx (REG
, Pmode
, 18);
849 saved_pc
= gen_rtx (REG
, Pmode
, 7);
850 saved_throw_type
= gen_rtx (REG
, Pmode
, 8);
851 saved_throw_value
= gen_rtx (REG
, Pmode
, 9);
854 saved_pc
= gen_rtx (REG
, Pmode
, 9);
855 saved_throw_type
= gen_rtx (REG
, Pmode
, 10);
856 saved_throw_value
= gen_rtx (REG
, Pmode
, 11);
858 new_eh_queue (&ehqueue
);
859 new_eh_queue (&eh_table_output_queue
);
860 new_eh_stack (&ehstack
);
861 new_except_stack (&exceptstack
);
864 /* call this to begin a block of unwind protection (ie: when an object is
871 emit_label (push_eh_entry (&ehstack
));
875 /* call this to end a block of unwind protection. the finalization tree is
876 the finalization which needs to be run in order to cleanly unwind through
877 this level of protection. (ie: call this when a scope is exited)*/
879 end_protect (finalization
)
882 struct ehEntry
*entry
;
887 entry
= pop_eh_entry (&ehstack
);
889 emit_label (entry
->end_label
);
891 entry
->finalization
= finalization
;
893 enqueue_eh_entry (&ehqueue
, entry
);
896 /* call this on start of a try block. */
898 expand_start_try_stmts ()
907 expand_end_try_stmts ()
909 end_protect (integer_zero_node
);
912 struct insn_save_node
{
914 struct insn_save_node
*chain
;
917 static struct insn_save_node
*InsnSave
= NULL
;
920 /* Used to keep track of where the catch blocks start. */
924 struct insn_save_node
*newnode
= (struct insn_save_node
*)
925 xmalloc (sizeof (struct insn_save_node
));
927 newnode
->last
= get_last_insn ();
928 newnode
->chain
= InsnSave
;
932 /* Use to keep track of where the catch blocks start. */
936 struct insn_save_node
*tempnode
;
939 if (!InsnSave
) return NULL_RTX
;
942 temprtx
= tempnode
->last
;
943 InsnSave
= InsnSave
->chain
;
950 /* call this to start processing of all the catch blocks. */
952 expand_start_all_catch ()
954 struct ehEntry
*entry
;
960 emit_line_note (input_filename
, lineno
);
961 label
= gen_label_rtx ();
962 /* The label for the exception handling block we will save. */
965 push_label_entry (&caught_return_label_stack
, label
);
967 /* Remember where we started. */
970 emit_insn (gen_nop ());
972 /* Will this help us not stomp on it? */
973 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
974 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
978 entry
= dequeue_eh_entry (&ehqueue
);
979 emit_label (entry
->exception_handler_label
);
981 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
983 /* When we get down to the matching entry, stop. */
984 if (entry
->finalization
== integer_zero_node
)
990 /* This goes when the below moves out of our way. */
992 label
= gen_label_rtx ();
996 /* All this should be out of line, and saved back in the exception handler
999 entry
->start_label
= entry
->exception_handler_label
;
1000 /* These are saved for the exception table. */
1002 entry
->end_label
= gen_label_rtx ();
1003 entry
->exception_handler_label
= gen_label_rtx ();
1004 entry
->finalization
= TerminateFunctionCall
;
1005 entry
->context
= current_function_decl
;
1006 assemble_external (TREE_OPERAND (Terminate
, 0));
1007 pop_rtl_from_perm ();
1009 LABEL_PRESERVE_P (entry
->start_label
) = 1;
1010 LABEL_PRESERVE_P (entry
->end_label
) = 1;
1011 LABEL_PRESERVE_P (entry
->exception_handler_label
) = 1;
1013 emit_label (entry
->end_label
);
1015 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (entry
));
1017 /* After running the finalization, continue on out to the next
1018 cleanup, if we have nothing better to do. */
1019 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, entry
->end_label
));
1020 /* Will this help us not stomp on it? */
1021 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1022 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1023 make_first_label(throw_label
);
1024 emit_jump (throw_label
);
1025 emit_label (entry
->exception_handler_label
);
1026 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
1032 /* call this to end processing of all the catch blocks. */
1034 expand_end_all_catch ()
1036 rtx catchstart
, catchend
, last
;
1042 /* Code to throw out to outer context, if we fall off end of catch
1044 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
,
1046 top_label_entry (&caught_return_label_stack
)));
1047 make_first_label(throw_label
);
1048 emit_jump (throw_label
);
1050 /* Find the start of the catch block. */
1051 last
= pop_last_insn ();
1052 catchstart
= NEXT_INSN (last
);
1053 catchend
= get_last_insn ();
1055 NEXT_INSN (last
) = 0;
1056 set_last_insn (last
);
1058 /* this level of catch blocks is done, so set up the successful catch jump
1059 label for the next layer of catch blocks. */
1060 pop_label_entry (&caught_return_label_stack
);
1062 push_except_stmts (&exceptstack
, catchstart
, catchend
);
1064 /* Here we fall through into the continuation code. */
1068 /* this is called from expand_exception_blocks () to expand the toplevel
1069 finalizations for a function. */
1071 expand_leftover_cleanups ()
1073 struct ehEntry
*entry
;
1074 rtx first_label
= NULL_RTX
;
1079 /* Will this help us not stomp on it? */
1080 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1081 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1083 while ((entry
= dequeue_eh_entry (&ehqueue
)) != 0)
1086 first_label
= entry
->exception_handler_label
;
1087 emit_label (entry
->exception_handler_label
);
1089 expand_expr (entry
->finalization
, const0_rtx
, VOIDmode
, 0);
1091 /* leftover try block, opps. */
1092 if (entry
->finalization
== integer_zero_node
)
1100 struct ehEntry entry
;
1101 /* These are saved for the exception table. */
1103 label
= gen_label_rtx ();
1104 entry
.start_label
= first_label
;
1105 entry
.end_label
= label
;
1106 entry
.exception_handler_label
= gen_label_rtx ();
1107 entry
.finalization
= TerminateFunctionCall
;
1108 entry
.context
= current_function_decl
;
1109 assemble_external (TREE_OPERAND (Terminate
, 0));
1110 pop_rtl_from_perm ();
1112 LABEL_PRESERVE_P (entry
.start_label
) = 1;
1113 LABEL_PRESERVE_P (entry
.end_label
) = 1;
1114 LABEL_PRESERVE_P (entry
.exception_handler_label
) = 1;
1118 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (&entry
));
1120 /* After running the finalization, continue on out to the next
1121 cleanup, if we have nothing better to do. */
1122 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, entry
.end_label
));
1123 /* Will this help us not stomp on it? */
1124 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_type
));
1125 emit_insn (gen_rtx (USE
, VOIDmode
, saved_throw_value
));
1126 make_first_label(throw_label
);
1127 emit_jump (throw_label
);
1128 emit_label (entry
.exception_handler_label
);
1129 expand_expr (entry
.finalization
, const0_rtx
, VOIDmode
, 0);
1134 /* call this to start a catch block. Typename is the typename, and identifier
1135 is the variable to place the object in or NULL if the variable doesn't
1136 matter. If typename is NULL, that means its a "catch (...)" or catch
1137 everything. In that case we don't need to do any type checking.
1138 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1140 expand_start_catch_block (declspecs
, declarator
)
1141 tree declspecs
, declarator
;
1143 rtx false_label_rtx
;
1144 rtx protect_label_rtx
;
1152 /* Create a binding level for the parm. */
1153 expand_start_bindings (0);
1158 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
1160 /* Figure out the type that the initializer is. */
1161 init_type
= TREE_TYPE (decl
);
1162 if (TREE_CODE (init_type
) != REFERENCE_TYPE
)
1163 init_type
= build_reference_type (init_type
);
1165 init
= convert_from_reference (save_expr (make_tree (init_type
, saved_throw_value
)));
1167 /* Do we need the below two lines? */
1168 /* Let `finish_decl' know that this initializer is ok. */
1169 DECL_INITIAL (decl
) = init
;
1170 /* This needs to be preallocated under the try block,
1171 in a union of all catch variables. */
1173 type
= TREE_TYPE (decl
);
1175 /* peel back references, so they match. */
1176 if (TREE_CODE (type
) == REFERENCE_TYPE
)
1177 type
= TREE_TYPE (type
);
1182 /* These are saved for the exception table. */
1184 false_label_rtx
= gen_label_rtx ();
1185 protect_label_rtx
= gen_label_rtx ();
1186 pop_rtl_from_perm ();
1187 push_label_entry (&false_label_stack
, false_label_rtx
);
1188 push_label_entry (&false_label_stack
, protect_label_rtx
);
1194 rtx call_rtx
, return_value_rtx
;
1195 tree catch_match_fcall
;
1196 tree catchmatch_arg
, argval
;
1198 typestring
= build_overload_name (type
, 1, 1);
1200 params
= tree_cons (NULL_TREE
,
1201 combine_strings (build_string (strlen (typestring
)+1, typestring
)),
1202 tree_cons (NULL_TREE
,
1203 make_tree (ptr_type_node
, saved_throw_type
),
1205 catch_match_fcall
= build_function_call (CatchMatch
, params
);
1206 call_rtx
= expand_call (catch_match_fcall
, NULL_RTX
, 0);
1207 assemble_external (TREE_OPERAND (CatchMatch
, 0));
1210 hard_function_value (integer_type_node
, catch_match_fcall
);
1212 /* did the throw type match function return TRUE? */
1213 emit_cmp_insn (return_value_rtx
, const0_rtx
, NE
, NULL_RTX
,
1214 GET_MODE (return_value_rtx
), 0, 0);
1216 /* if it returned FALSE, jump over the catch block, else fall into it */
1217 emit_jump_insn (gen_bne (false_label_rtx
));
1218 finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
1222 /* Fall into the catch all section. */
1225 /* This is the starting of something to protect. */
1226 emit_label (protect_label_rtx
);
1228 emit_line_note (input_filename
, lineno
);
1232 /* Call this to end a catch block. Its responsible for emitting the
1233 code to handle jumping back to the correct place, and for emitting
1234 the label to jump to if this catch block didn't match. */
1235 void expand_end_catch_block ()
1239 rtx start_protect_label_rtx
;
1240 rtx end_protect_label_rtx
;
1242 struct ehEntry entry
;
1244 /* label we jump to if we caught the exception */
1245 emit_jump (top_label_entry (&caught_return_label_stack
));
1247 /* Code to throw out to outer context, if we get a throw from within
1248 our catch handler. */
1249 /* These are saved for the exception table. */
1251 entry
.exception_handler_label
= gen_label_rtx ();
1252 pop_rtl_from_perm ();
1253 emit_label (entry
.exception_handler_label
);
1254 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
,
1256 top_label_entry (&caught_return_label_stack
)));
1257 make_first_label(throw_label
);
1258 emit_jump (throw_label
);
1259 /* No associated finalization. */
1260 entry
.finalization
= NULL_TREE
;
1261 entry
.context
= current_function_decl
;
1263 /* Because we are reordered out of line, we have to protect this. */
1264 /* label for the start of the protection region. */
1265 start_protect_label_rtx
= pop_label_entry (&false_label_stack
);
1267 /* Cleanup the EH paramater. */
1268 decls
= getdecls ();
1269 expand_end_bindings (decls
, decls
!= NULL_TREE
, 0);
1271 /* label we emit to jump to if this catch block didn't match. */
1272 emit_label (end_protect_label_rtx
= pop_label_entry (&false_label_stack
));
1274 /* Because we are reordered out of line, we have to protect this. */
1275 entry
.start_label
= start_protect_label_rtx
;
1276 entry
.end_label
= end_protect_label_rtx
;
1278 LABEL_PRESERVE_P (entry
.start_label
) = 1;
1279 LABEL_PRESERVE_P (entry
.end_label
) = 1;
1280 LABEL_PRESERVE_P (entry
.exception_handler_label
) = 1;
1282 /* These set up a call to throw the caught exception into the outer
1284 enqueue_eh_entry (&eh_table_output_queue
, copy_eh_entry (&entry
));
1288 /* cheesyness to save some typing. returns the return value rtx */
1290 do_function_call (func
, params
, return_type
)
1291 tree func
, params
, return_type
;
1294 func_call
= build_function_call (func
, params
);
1295 expand_call (func_call
, NULL_RTX
, 0);
1296 if (return_type
!= NULL_TREE
)
1297 return hard_function_value (return_type
, func_call
);
1301 /* unwind the stack. */
1303 do_unwind (throw_label
)
1307 extern FILE *asm_out_file
;
1312 /* call to __builtin_return_address () */
1313 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1314 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1315 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1316 /* In the return, the new pc is pc+8, as the value comming in is
1317 really the address of the call insn, not the next insn. */
1318 emit_move_insn (return_val_rtx
, plus_constant(gen_rtx (LABEL_REF
,
1321 /* We use three values, PC, type, and value */
1322 easy_expand_asm ("st %l0,[%fp]");
1323 easy_expand_asm ("st %l1,[%fp+4]");
1324 easy_expand_asm ("st %l2,[%fp+8]");
1325 easy_expand_asm ("ret");
1326 easy_expand_asm ("restore");
1329 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined(__alpha)
1330 extern FILE *asm_out_file
;
1335 /* call to __builtin_return_address () */
1336 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1337 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1338 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1340 /* I would like to do this here, but doesn't seem to work. */
1341 emit_move_insn (return_val_rtx
, gen_rtx (LABEL_REF
,
1344 /* So, for now, just pass throw label to stack unwinder. */
1346 /* We use three values, PC, type, and value */
1347 params
= tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
1348 gen_rtx (LABEL_REF
, Pmode
, throw_label
)), NULL_TREE
);
1350 do_function_call (Unwind
, params
, NULL_TREE
);
1351 assemble_external (TREE_OPERAND (Unwind
, 0));
1355 rtx temp_frame
= frame_pointer_rtx
;
1357 temp_frame
= memory_address (Pmode
, temp_frame
);
1358 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
1360 /* hopefully this will successfully pop the frame! */
1361 emit_move_insn (frame_pointer_rtx
, temp_frame
);
1362 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
1363 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
1364 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1365 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
1368 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1369 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
1371 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
1373 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
1374 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
1378 if (flag_omit_frame_pointer
)
1379 sorry ("this implementation of exception handling requires a frame pointer");
1381 emit_move_insn (stack_pointer_rtx
,
1382 gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -8)));
1383 emit_move_insn (hard_frame_pointer_rtx
,
1384 gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -12)));
1388 /* is called from expand_exception_blocks () to generate the code in a function
1389 to "throw" if anything in the function needs to preform a throw.
1391 expands "throw" as the following psuedo code:
1394 eh = find_first_exception_match (saved_pc);
1395 if (!eh) goto gotta_rethrow_it;
1399 saved_pc = __builtin_return_address (0);
1400 pop_to_previous_level ();
1405 expand_builtin_throw ()
1410 rtx gotta_rethrow_it
= gen_label_rtx ();
1411 rtx gotta_call_terminate
= gen_label_rtx ();
1412 rtx unwind_and_throw
= gen_label_rtx ();
1413 rtx goto_unwind_and_throw
= gen_label_rtx ();
1415 make_first_label(throw_label
);
1416 emit_label (throw_label
);
1418 /* search for an exception handler for the saved_pc */
1419 return_val_rtx
= do_function_call (FirstExceptionMatch
,
1420 tree_cons (NULL_TREE
, make_tree (ptr_type_node
, saved_pc
), NULL_TREE
),
1422 assemble_external (TREE_OPERAND (FirstExceptionMatch
, 0));
1424 /* did we find one? */
1425 emit_cmp_insn (return_val_rtx
, const0_rtx
, EQ
, NULL_RTX
,
1426 GET_MODE (return_val_rtx
), 0, 0);
1428 /* if not, jump to gotta_rethrow_it */
1429 emit_jump_insn (gen_beq (gotta_rethrow_it
));
1431 /* we found it, so jump to it */
1432 emit_indirect_jump (return_val_rtx
);
1434 /* code to deal with unwinding and looking for it again */
1435 emit_label (gotta_rethrow_it
);
1437 /* call to __builtin_return_address () */
1439 /* This replaces a 'call' to __builtin_return_address */
1440 return_val_rtx
= gen_reg_rtx (Pmode
);
1441 emit_move_insn (return_val_rtx
, gen_rtx (MEM
, SImode
, plus_constant (hard_frame_pointer_rtx
, -4)));
1443 params
=tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
1444 fcall
= build_function_call (BuiltinReturnAddress
, params
);
1445 return_val_rtx
= expand_expr (fcall
, NULL_RTX
, SImode
, 0);
1448 /* did __builtin_return_address () return a valid address? */
1449 emit_cmp_insn (return_val_rtx
, const0_rtx
, EQ
, NULL_RTX
,
1450 GET_MODE (return_val_rtx
), 0, 0);
1452 emit_jump_insn (gen_beq (gotta_call_terminate
));
1455 /* On the ARM, '__builtin_return_address', must have 4
1456 subtracted from it. */
1457 emit_insn (gen_add2_insn (return_val_rtx
, GEN_INT (-4)));
1459 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
1460 mode, the condition codes must be masked out of the return value, or else
1461 they will confuse BuiltinReturnAddress. This does not apply to ARM6 and
1462 later processors when running in 32 bit mode. */
1464 emit_insn (gen_rtx (SET
, SImode
, return_val_rtx
, gen_rtx (AND
, SImode
, return_val_rtx
, GEN_INT (0x03fffffc))));
1467 /* On the SPARC, __builtin_return_address is already -8, no need to
1468 subtract any more from it. */
1469 return_val_rtx
= plus_constant (return_val_rtx
, -1);
1474 emit_move_insn (saved_pc
, return_val_rtx
);
1475 do_unwind (throw_label
);
1476 make_first_label(throw_label
);
1477 emit_jump (throw_label
);
1479 /* no it didn't --> therefore we need to call terminate */
1480 emit_label (gotta_call_terminate
);
1481 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
1482 assemble_external (TREE_OPERAND (Terminate
, 0));
1486 /* This is called to expand all the toplevel exception handling
1487 finalization for a function. It should only be called once per
1490 expand_exception_blocks ()
1492 rtx catchstart
, catchend
;
1496 funcend
= gen_label_rtx ();
1497 emit_jump (funcend
);
1498 /* expand_null_return (); */
1500 while (pop_except_stmts (&exceptstack
, &catchstart
, &catchend
)) {
1501 last
= get_last_insn ();
1502 NEXT_INSN (last
) = catchstart
;
1503 PREV_INSN (catchstart
) = last
;
1504 NEXT_INSN (catchend
) = 0;
1505 set_last_insn (catchend
);
1508 expand_leftover_cleanups ();
1511 static int have_done
= 0;
1512 if (! have_done
&& TREE_PUBLIC (current_function_decl
)
1513 && DECL_INTERFACE_KNOWN (current_function_decl
)
1514 && ! DECL_EXTERNAL (current_function_decl
))
1517 expand_builtin_throw ();
1520 emit_label (funcend
);
1524 /* call this to expand a throw statement. This follows the following
1527 1. Allocate space to save the current PC onto the stack.
1528 2. Generate and emit a label and save its address into the
1529 newly allocated stack space since we can't save the pc directly.
1530 3. If this is the first call to throw in this function:
1531 generate a label for the throw block
1532 4. jump to the throw block label. */
1543 /* This is the label that represents where in the code we were, when
1544 we got an exception. This needs to be updated when we rethrow an
1545 exception, so that the matching routine knows to search out. */
1546 label
= gen_label_rtx ();
1551 /* throw expression */
1552 /* First, decay it. */
1553 exp
= default_conversion (exp
);
1554 type
= TREE_TYPE (exp
);
1557 char *typestring
= build_overload_name (type
, 1, 1);
1558 tree throw_type
= build1 (ADDR_EXPR
, ptr_type_node
, combine_strings (build_string (strlen (typestring
)+1, typestring
)));
1559 rtx throw_type_rtx
= expand_expr (throw_type
, NULL_RTX
, VOIDmode
, 0);
1560 rtx throw_value_rtx
;
1562 /* Make a copy of the thrown object. WP 15.1.5 */
1563 exp
= build_new (NULL_TREE
, type
, build_tree_list (NULL_TREE
, exp
), 0);
1565 if (exp
== error_mark_node
)
1566 error (" in thrown expression");
1567 throw_value_rtx
= expand_expr (exp
, NULL_RTX
, VOIDmode
, 0);
1568 emit_move_insn (saved_throw_value
, throw_value_rtx
);
1569 emit_move_insn (saved_throw_type
, throw_type_rtx
);
1574 /* rethrow current exception */
1575 /* This part is easy, as we don't have to do anything else. */
1578 emit_move_insn (saved_pc
, gen_rtx (LABEL_REF
, Pmode
, label
));
1579 make_first_label(throw_label
);
1580 emit_jump (throw_label
);
1583 /* end of: my-cp-except.c */
1587 end_protect_partials () {
1588 while (protect_list
)
1590 end_protect (TREE_VALUE (protect_list
));
1591 protect_list
= TREE_CHAIN (protect_list
);
1596 might_have_exceptions_p ()
1599 if (eh_table_output_queue
.head
)
1605 /* Output the exception table.
1606 Return the number of handlers. */
1608 emit_exception_table ()
1612 extern FILE *asm_out_file
;
1613 struct ehEntry
*entry
;
1619 exception_section ();
1621 /* Beginning marker for table. */
1622 ASM_OUTPUT_ALIGN (asm_out_file
, 2);
1623 ASM_OUTPUT_LABEL (asm_out_file
, "__EXCEPTION_TABLE__");
1624 output_exception_table_entry (asm_out_file
,
1625 const0_rtx
, const0_rtx
, const0_rtx
);
1627 while (entry
= dequeue_eh_entry (&eh_table_output_queue
))
1629 tree context
= entry
->context
;
1631 if (context
&& ! TREE_ASM_WRITTEN (context
))
1635 output_exception_table_entry (asm_out_file
,
1636 entry
->start_label
, entry
->end_label
,
1637 entry
->exception_handler_label
);
1640 /* Ending marker for table. */
1641 ASM_OUTPUT_LABEL (asm_out_file
, "__EXCEPTION_END__");
1642 output_exception_table_entry (asm_out_file
,
1643 constm1_rtx
, constm1_rtx
, constm1_rtx
);
1645 #endif /* TRY_NEW_EH */
1649 register_exception_table ()
1652 emit_library_call (gen_rtx (SYMBOL_REF
, Pmode
, "__register_exceptions"), 0,
1654 gen_rtx (SYMBOL_REF
, Pmode
, "__EXCEPTION_TABLE__"),
1656 #endif /* TRY_NEW_EH */
1659 /* Build a throw expression. */
1664 if (e
!= error_mark_node
)
1666 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1667 TREE_SIDE_EFFECTS (e
) = 1;