]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/except.c
83rd Cygnus<->FSF merge
[gcc.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995 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.
6
7 This file is part of GNU CC.
8
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)
12 any later version.
13
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.
18
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, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24
25 /* High-level class interface. */
26
27 #include "config.h"
28 #include "tree.h"
29 #include "rtl.h"
30 #include "cp-tree.h"
31 #include "flags.h"
32 #include "obstack.h"
33 #include "expr.h"
34 #include "output.h"
35
36 tree protect_list;
37
38 extern void (*interim_eh_hook) PROTO((tree));
39 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
40 static void end_eh_unwinder PROTO((rtx));
41
42 /* holds the fndecl for __builtin_return_address () */
43 tree builtin_return_address_fndecl;
44 tree throw_fndecl;
45
46 static int
47 doing_eh (do_warn)
48 int do_warn;
49 {
50 if (! flag_handle_exceptions)
51 {
52 static int warned = 0;
53 if (! warned && do_warn)
54 {
55 error ("exception handling disabled, use -fhandle-exceptions to enable.");
56 warned = 1;
57 }
58 return 0;
59 }
60 return 1;
61 }
62
63
64 /*
65 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
66 to supporting exception handling as per ANSI C++ working draft.
67 It is a complete rewrite of all the EH stuff that was here before
68 Shortcomings:
69 1. Throw specifications of functions still don't work.
70 Cool Things:
71 1. Destructors are called properly :-)
72 2. No overhead for the non-exception thrown case.
73 3. Fixing shortcoming 1 is simple.
74 -Tad Hunt (tad@mail.csh.rit.edu)
75
76 */
77
78 /* A couple of backend routines from m88k.c */
79
80 /* used to cache a call to __builtin_return_address () */
81 static tree BuiltinReturnAddress;
82
83
84 #include <stdio.h>
85
86 /* XXX - Tad: for EH */
87 /* output an exception table entry */
88
89 static void
90 output_exception_table_entry (file, start_label, end_label, eh_label)
91 FILE *file;
92 rtx start_label, end_label, eh_label;
93 {
94 assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
95 assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
96 assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
97 putc ('\n', file); /* blank line */
98 }
99
100 static void
101 easy_expand_asm (str)
102 char *str;
103 {
104 expand_asm (build_string (strlen (str)+1, str));
105 }
106
107
108 #if 0
109 /* This is the startup, and finish stuff per exception table. */
110
111 /* XXX - Tad: exception handling section */
112 #ifndef EXCEPT_SECTION_ASM_OP
113 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
114 #endif
115
116 #ifdef EXCEPT_SECTION_ASM_OP
117 typedef struct {
118 void *start_protect;
119 void *end_protect;
120 void *exception_handler;
121 } exception_table;
122 #endif /* EXCEPT_SECTION_ASM_OP */
123
124 #ifdef EXCEPT_SECTION_ASM_OP
125
126 /* on machines which support it, the exception table lives in another section,
127 but it needs a label so we can reference it... This sets up that
128 label! */
129 asm (EXCEPT_SECTION_ASM_OP);
130 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
131 asm (TEXT_SECTION_ASM_OP);
132
133 #endif /* EXCEPT_SECTION_ASM_OP */
134
135 #ifdef EXCEPT_SECTION_ASM_OP
136
137 /* we need to know where the end of the exception table is... so this
138 is how we do it! */
139
140 asm (EXCEPT_SECTION_ASM_OP);
141 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
142 asm (TEXT_SECTION_ASM_OP);
143
144 #endif /* EXCEPT_SECTION_ASM_OP */
145
146 #endif
147
148 static void
149 exception_section ()
150 {
151 #ifdef ASM_OUTPUT_SECTION_NAME
152 named_section (NULL_TREE, ".gcc_except_table");
153 #else
154 if (flag_pic)
155 data_section ();
156 else
157 #if defined (TARGET_POWERPC) /* are we on a __rs6000? */
158 data_section ();
159 #else
160 readonly_data_section ();
161 #endif
162 #endif
163 }
164
165
166
167
168 /* from: my-cp-except.c */
169
170 /* VI: ":set ts=4" */
171 #if 0
172 #include <stdio.h> */
173 #include "config.h"
174 #include "tree.h"
175 #include "rtl.h"
176 #include "cp-tree.h"
177 #endif
178 #include "decl.h"
179 #if 0
180 #include "flags.h"
181 #endif
182 #include "insn-flags.h"
183 #include "obstack.h"
184 #if 0
185 #include "expr.h"
186 #endif
187
188 /* ======================================================================
189 Briefly the algorithm works like this:
190
191 When a constructor or start of a try block is encountered,
192 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
193 new entry in the unwind protection stack and returns a label to
194 output to start the protection for that block.
195
196 When a destructor or end try block is encountered, pop_eh_entry
197 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
198 created when push_eh_entry () was called. The ehEntry structure
199 contains three things at this point. The start protect label,
200 the end protect label, and the exception handler label. The end
201 protect label should be output before the call to the destructor
202 (if any). If it was a destructor, then its parse tree is stored
203 in the finalization variable in the ehEntry structure. Otherwise
204 the finalization variable is set to NULL to reflect the fact that
205 is the the end of a try block. Next, this modified ehEntry node
206 is enqueued in the finalizations queue by calling
207 enqueue_eh_entry (&queue,entry).
208
209 +---------------------------------------------------------------+
210 |XXX: Will need modification to deal with partially |
211 | constructed arrays of objects |
212 | |
213 | Basically, this consists of keeping track of how many |
214 | of the objects have been constructed already (this |
215 | should be in a register though, so that shouldn't be a |
216 | problem. |
217 +---------------------------------------------------------------+
218
219 When a catch block is encountered, there is a lot of work to be
220 done.
221
222 Since we don't want to generate the catch block inline with the
223 regular flow of the function, we need to have some way of doing
224 so. Luckily, we can use sequences to defer the catch sections.
225 When the start of a catch block is encountered, we start the
226 sequence. After the catch block is generated, we end the
227 sequence.
228
229 Next we must insure that when the catch block is executed, all
230 finalizations for the matching try block have been completed. If
231 any of those finalizations throw an exception, we must call
232 terminate according to the ARM (section r.15.6.1). What this
233 means is that we need to dequeue and emit finalizations for each
234 entry in the ehQueue until we get to an entry with a NULL
235 finalization field. For any of the finalization entries, if it
236 is not a call to terminate (), we must protect it by giving it
237 another start label, end label, and exception handler label,
238 setting its finalization tree to be a call to terminate (), and
239 enqueue'ing this new ehEntry to be output at an outer level.
240 Finally, after all that is done, we can get around to outputting
241 the catch block which basically wraps all the "catch (...) {...}"
242 statements in a big if/then/else construct that matches the
243 correct block to call.
244
245 ===================================================================== */
246
247 extern rtx emit_insn PROTO((rtx));
248 extern rtx gen_nop PROTO(());
249
250 /* local globals for function calls
251 ====================================================================== */
252
253 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
254 "set_unexpected ()" after default_conversion. (lib-except.c) */
255 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
256
257 /* used to cache __find_first_exception_table_match ()
258 for throw (lib-except.c) */
259 static tree FirstExceptionMatch;
260
261 /* used to cache a call to __unwind_function () (lib-except.c) */
262 static tree Unwind;
263
264 /* holds a ready to emit call to "terminate ()". */
265 static tree TerminateFunctionCall;
266
267 static tree empty_fndecl;
268
269 /* ====================================================================== */
270
271
272
273 /* data structures for my various quick and dirty stacks and queues
274 Eventually, most of this should go away, because I think it can be
275 integrated with stuff already built into the compiler. */
276
277 /* =================================================================== */
278
279 struct labelNode {
280 union {
281 rtx rlabel;
282 tree tlabel;
283 } u;
284 struct labelNode *chain;
285 };
286
287
288 /* this is the most important structure here. Basically this is how I store
289 an exception table entry internally. */
290 struct ehEntry {
291 rtx start_label;
292 rtx end_label;
293 rtx exception_handler_label;
294
295 tree finalization;
296 tree context;
297 };
298
299 struct ehNode {
300 struct ehEntry *entry;
301 struct ehNode *chain;
302 };
303
304 struct ehStack {
305 struct ehNode *top;
306 };
307
308 struct ehQueue {
309 struct ehNode *head;
310 struct ehNode *tail;
311 };
312 /* ========================================================================= */
313
314
315
316 /* local globals - these local globals are for storing data necessary for
317 generating the exception table and code in the correct order.
318
319 ========================================================================= */
320
321 /* Holds the pc for doing "throw" */
322 static tree saved_pc;
323 /* Holds the type of the thing being thrown. */
324 static tree saved_throw_type;
325 /* Holds the value being thrown. */
326 static tree saved_throw_value;
327 /* Holds the cleanup for the value being thrown. */
328 static tree saved_cleanup;
329
330 static int throw_used;
331
332 static rtx catch_clauses;
333
334 static struct ehStack ehstack;
335 static struct ehQueue ehqueue;
336 static struct ehQueue eh_table_output_queue;
337 static struct labelNode *false_label_stack = NULL;
338 static struct labelNode *caught_return_label_stack = NULL;
339 /* ========================================================================= */
340
341 /* function prototypes */
342 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
343 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
344 static rtx push_eh_entry PROTO((struct ehStack *stack));
345 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
346 static void new_eh_queue PROTO((struct ehQueue *queue));
347 static void new_eh_stack PROTO((struct ehStack *stack));
348 static void push_label_entry PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
349 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
350 static tree top_label_entry PROTO((struct labelNode **labelstack));
351 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
352
353
354 /* Routines to save and restore eh context information. */
355 struct eh_context {
356 struct ehStack ehstack;
357 struct ehQueue ehqueue;
358 rtx catch_clauses;
359 struct labelNode *false_label_stack;
360 struct labelNode *caught_return_label_stack;
361 tree protect_list;
362 };
363
364 /* Save the context and push into a new one. */
365 void*
366 push_eh_context ()
367 {
368 struct eh_context *p
369 = (struct eh_context*)xmalloc (sizeof (struct eh_context));
370
371 p->ehstack = ehstack;
372 p->ehqueue = ehqueue;
373 p->catch_clauses = catch_clauses;
374 p->false_label_stack = false_label_stack;
375 p->caught_return_label_stack = caught_return_label_stack;
376 p->protect_list = protect_list;
377
378 new_eh_stack (&ehstack);
379 new_eh_queue (&ehqueue);
380 catch_clauses = NULL_RTX;
381 false_label_stack = NULL;
382 caught_return_label_stack = NULL;
383 protect_list = NULL_TREE;
384
385 return p;
386 }
387
388 /* Pop and restore the context. */
389 void
390 pop_eh_context (vp)
391 void *vp;
392 {
393 struct eh_context *p = (struct eh_context *)vp;
394
395 protect_list = p->protect_list;
396 caught_return_label_stack = p->caught_return_label_stack;
397 false_label_stack = p->false_label_stack;
398 catch_clauses = p->catch_clauses;
399 ehqueue = p->ehqueue;
400 ehstack = p->ehstack;
401
402 free (p);
403 }
404
405
406
407 /* All my cheesy stack/queue/misc data structure handling routines
408
409 ========================================================================= */
410
411 static void
412 push_label_entry (labelstack, rlabel, tlabel)
413 struct labelNode **labelstack;
414 rtx rlabel;
415 tree tlabel;
416 {
417 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
418
419 if (rlabel)
420 newnode->u.rlabel = rlabel;
421 else
422 newnode->u.tlabel = tlabel;
423 newnode->chain = *labelstack;
424 *labelstack = newnode;
425 }
426
427 static rtx
428 pop_label_entry (labelstack)
429 struct labelNode **labelstack;
430 {
431 rtx label;
432 struct labelNode *tempnode;
433
434 if (! *labelstack) return NULL_RTX;
435
436 tempnode = *labelstack;
437 label = tempnode->u.rlabel;
438 *labelstack = (*labelstack)->chain;
439 free (tempnode);
440
441 return label;
442 }
443
444 static tree
445 top_label_entry (labelstack)
446 struct labelNode **labelstack;
447 {
448 if (! *labelstack) return NULL_TREE;
449
450 return (*labelstack)->u.tlabel;
451 }
452
453 /* Push to permanent obstack for rtl generation.
454 One level only! */
455 static struct obstack *saved_rtl_obstack;
456
457 static void
458 push_rtl_perm ()
459 {
460 extern struct obstack permanent_obstack;
461 extern struct obstack *rtl_obstack;
462
463 saved_rtl_obstack = rtl_obstack;
464 rtl_obstack = &permanent_obstack;
465 }
466
467 /* Pop back to normal rtl handling. */
468 static void
469 pop_rtl_from_perm ()
470 {
471 extern struct obstack *rtl_obstack;
472 rtl_obstack = saved_rtl_obstack;
473 }
474
475 static rtx
476 push_eh_entry (stack)
477 struct ehStack *stack;
478 {
479 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
480 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
481
482 /* These are saved for the exception table. */
483 push_rtl_perm ();
484 entry->start_label = gen_label_rtx ();
485 entry->end_label = gen_label_rtx ();
486 entry->exception_handler_label = gen_label_rtx ();
487 pop_rtl_from_perm ();
488
489 LABEL_PRESERVE_P (entry->start_label) = 1;
490 LABEL_PRESERVE_P (entry->end_label) = 1;
491 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
492
493 entry->finalization = NULL_TREE;
494 entry->context = current_function_decl;
495
496 node->entry = entry;
497 node->chain = stack->top;
498 stack->top = node;
499
500 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
501
502 return entry->start_label;
503 }
504
505 /* Pop an entry from the given STACK. */
506 static struct ehEntry *
507 pop_eh_entry (stack)
508 struct ehStack *stack;
509 {
510 struct ehNode *tempnode;
511 struct ehEntry *tempentry;
512
513 tempnode = stack->top;
514 tempentry = tempnode->entry;
515 stack->top = stack->top->chain;
516 free (tempnode);
517
518 return tempentry;
519 }
520
521 static struct ehEntry *
522 copy_eh_entry (entry)
523 struct ehEntry *entry;
524 {
525 struct ehEntry *newentry;
526
527 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
528 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
529
530 return newentry;
531 }
532
533 static void
534 enqueue_eh_entry (queue, entry)
535 struct ehQueue *queue;
536 struct ehEntry *entry;
537 {
538 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
539
540 node->entry = entry;
541 node->chain = NULL;
542
543 if (queue->head == NULL)
544 {
545 queue->head = node;
546 }
547 else
548 {
549 queue->tail->chain = node;
550 }
551 queue->tail = node;
552 }
553
554 static struct ehEntry *
555 dequeue_eh_entry (queue)
556 struct ehQueue *queue;
557 {
558 struct ehNode *tempnode;
559 struct ehEntry *tempentry;
560
561 if (queue->head == NULL)
562 return NULL;
563
564 tempnode = queue->head;
565 queue->head = queue->head->chain;
566
567 tempentry = tempnode->entry;
568 free (tempnode);
569
570 return tempentry;
571 }
572
573 static void
574 new_eh_queue (queue)
575 struct ehQueue *queue;
576 {
577 queue->head = queue->tail = NULL;
578 }
579
580 static void
581 new_eh_stack (stack)
582 struct ehStack *stack;
583 {
584 stack->top = NULL;
585 }
586
587 /* cheesyness to save some typing. returns the return value rtx */
588 static rtx
589 do_function_call (func, params, return_type)
590 tree func, params, return_type;
591 {
592 tree func_call;
593 func_call = build_function_call (func, params);
594 expand_call (func_call, NULL_RTX, 0);
595 if (return_type != NULL_TREE)
596 return hard_function_value (return_type, func_call);
597 return NULL_RTX;
598 }
599
600 static void
601 expand_internal_throw (pc)
602 rtx pc;
603 {
604 emit_move_insn (DECL_RTL (saved_pc), pc);
605 #ifdef JUMP_TO_THROW
606 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
607 #else
608 do_function_call (Throw, NULL_TREE, NULL_TREE);
609 #endif
610 throw_used = 1;
611 }
612
613 /* ========================================================================= */
614
615 static void
616 lang_interim_eh (finalization)
617 tree finalization;
618 {
619 if (finalization)
620 end_protect (finalization);
621 else
622 start_protect ();
623 }
624
625 extern tree auto_function PROTO((tree, tree, enum built_in_function));
626
627 /* sets up all the global eh stuff that needs to be initialized at the
628 start of compilation.
629
630 This includes:
631 - Setting up all the function call trees
632 - Initializing the ehqueue
633 - Initializing the eh_table_output_queue
634 - Initializing the ehstack
635 */
636
637 void
638 init_exception_processing ()
639 {
640 extern tree define_function ();
641 tree unexpected_fndecl, terminate_fndecl;
642 tree set_unexpected_fndecl, set_terminate_fndecl;
643 tree catch_match_fndecl;
644 tree find_first_exception_match_fndecl;
645 tree unwind_fndecl;
646 tree declspecs;
647 tree d;
648
649 /* void (*)() */
650 tree PFV = build_pointer_type (build_function_type
651 (void_type_node, void_list_node));
652
653 /* arg list for the build_function_type call for set_terminate () and
654 set_unexpected () */
655 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
656
657 /* void (*pfvtype (void (*) ()))() */
658 tree pfvtype = build_function_type (PFV, pfvlist);
659
660 /* void vtype () */
661 tree vtype = build_function_type (void_type_node, void_list_node);
662
663 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
664 pfvtype, NOT_BUILT_IN);
665 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
666 pfvtype, NOT_BUILT_IN);
667 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
668 vtype, NOT_BUILT_IN);
669 terminate_fndecl = auto_function (get_identifier ("terminate"),
670 vtype, NOT_BUILT_IN);
671
672 interim_eh_hook = lang_interim_eh;
673
674 push_lang_context (lang_name_c);
675
676 catch_match_fndecl =
677 builtin_function (flag_rtti
678 ? "__throw_type_match_rtti"
679 : "__throw_type_match",
680 build_function_type (ptr_type_node,
681 tree_cons (NULL_TREE, ptr_type_node,
682 tree_cons (NULL_TREE, ptr_type_node,
683 tree_cons (NULL_TREE, ptr_type_node,
684 void_list_node)))),
685 NOT_BUILT_IN, NULL_PTR);
686 find_first_exception_match_fndecl =
687 builtin_function ("__find_first_exception_table_match",
688 build_function_type (ptr_type_node,
689 tree_cons (NULL_TREE, ptr_type_node,
690 void_list_node)),
691 NOT_BUILT_IN, NULL_PTR);
692 unwind_fndecl =
693 builtin_function ("__unwind_function",
694 build_function_type (void_type_node,
695 tree_cons (NULL_TREE, ptr_type_node,
696 void_list_node)),
697 NOT_BUILT_IN, NULL_PTR);
698 throw_fndecl =
699 builtin_function ("__throw",
700 build_function_type (void_type_node, void_list_node),
701 NOT_BUILT_IN, NULL_PTR);
702 DECL_EXTERNAL (throw_fndecl) = 0;
703 TREE_PUBLIC (throw_fndecl) = 0;
704 empty_fndecl =
705 builtin_function ("__empty",
706 build_function_type (void_type_node, void_list_node),
707 NOT_BUILT_IN, NULL_PTR);
708 DECL_EXTERNAL (empty_fndecl) = 1;
709 TREE_PUBLIC (empty_fndecl) = 1;
710
711 Unexpected = default_conversion (unexpected_fndecl);
712 Terminate = default_conversion (terminate_fndecl);
713 SetTerminate = default_conversion (set_terminate_fndecl);
714 SetUnexpected = default_conversion (set_unexpected_fndecl);
715 CatchMatch = default_conversion (catch_match_fndecl);
716 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
717 Unwind = default_conversion (unwind_fndecl);
718 Throw = default_conversion (throw_fndecl);
719 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
720
721 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
722
723 pop_lang_context ();
724
725 new_eh_queue (&ehqueue);
726 new_eh_queue (&eh_table_output_queue);
727 new_eh_stack (&ehstack);
728
729 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
730 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
731 d = start_decl (d, declspecs, 0, NULL_TREE);
732 DECL_COMMON (d) = 1;
733 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
734 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
735
736 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
737 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
738 d = start_decl (d, declspecs, 0, NULL_TREE);
739 DECL_COMMON (d) = 1;
740 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
741 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
742
743 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
744 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
745 d = start_decl (d, declspecs, 0, NULL_TREE);
746 DECL_COMMON (d) = 1;
747 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
748 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
749
750 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
751 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
752 d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
753 d = start_decl (d, declspecs, 0, NULL_TREE);
754 DECL_COMMON (d) = 1;
755 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
756 saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
757 }
758
759 /* call this to begin a block of unwind protection (ie: when an object is
760 constructed) */
761 void
762 start_protect ()
763 {
764 if (! doing_eh (0))
765 return;
766
767 emit_label (push_eh_entry (&ehstack));
768 }
769
770 /* call this to end a block of unwind protection. the finalization tree is
771 the finalization which needs to be run in order to cleanly unwind through
772 this level of protection. (ie: call this when a scope is exited)*/
773 void
774 end_protect (finalization)
775 tree finalization;
776 {
777 struct ehEntry *entry;
778
779 if (! doing_eh (0))
780 return;
781
782 entry = pop_eh_entry (&ehstack);
783
784 emit_label (entry->end_label);
785 /* Put in something that takes up space, as otherwise the end
786 address for the EH region could have the exact same address as
787 the outer region, causing us to miss the fact that resuming
788 exception handling with this PC value would be inside the outer
789 region. */
790 emit_insn (gen_nop ());
791
792 entry->finalization = finalization;
793
794 enqueue_eh_entry (&ehqueue, entry);
795 }
796
797 /* call this on start of a try block. */
798 void
799 expand_start_try_stmts ()
800 {
801 if (! doing_eh (1))
802 return;
803
804 start_protect ();
805 }
806
807 void
808 expand_end_try_stmts ()
809 {
810 end_protect (integer_zero_node);
811 }
812
813
814 /* call this to start processing of all the catch blocks. */
815 void
816 expand_start_all_catch ()
817 {
818 struct ehEntry *entry;
819 tree label;
820
821 if (! doing_eh (1))
822 return;
823
824 emit_line_note (input_filename, lineno);
825 label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
826
827 /* The label for the exception handling block we will save. This is
828 Lresume, in the documention. */
829 expand_label (label);
830
831 /* Put in something that takes up space, as otherwise the end
832 address for the EH region could have the exact same address as
833 the outer region, causing us to miss the fact that resuming
834 exception handling with this PC value would be inside the outer
835 region. */
836 emit_insn (gen_nop ());
837
838 push_label_entry (&caught_return_label_stack, NULL_RTX, label);
839
840 /* Start a new sequence for all the catch blocks. We will add this
841 to the gloabl sequence catch_clauses, when we have completed all
842 the handlers in this handler-seq. */
843 start_sequence ();
844
845 while (1)
846 {
847 entry = dequeue_eh_entry (&ehqueue);
848 emit_label (entry->exception_handler_label);
849
850 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
851
852 /* When we get down to the matching entry, stop. */
853 if (entry->finalization == integer_zero_node)
854 break;
855
856 /* The below can be optimized away, and we could just fall into the
857 next EH handler, if we are certain they are nested. */
858 /* Code to throw out to outer context, if we fall off end of the
859 handler. */
860 expand_internal_throw (gen_rtx (LABEL_REF,
861 Pmode,
862 entry->end_label));
863 free (entry);
864 }
865 }
866
867 /* call this to end processing of all the catch blocks. */
868 void
869 expand_end_all_catch ()
870 {
871 rtx new_catch_clause;
872
873 if (! doing_eh (1))
874 return;
875
876 /* Code to throw out to outer context, if we fall off end of catch
877 handlers. This is rethrow (Lresume, same id, same obj); in the
878 documentation. */
879 expand_internal_throw (gen_rtx (LABEL_REF,
880 Pmode,
881 DECL_RTL (top_label_entry (&caught_return_label_stack))));
882
883 /* Now we have the complete catch sequence. */
884 new_catch_clause = get_insns ();
885 end_sequence ();
886
887 /* this level of catch blocks is done, so set up the successful catch jump
888 label for the next layer of catch blocks. */
889 pop_label_entry (&caught_return_label_stack);
890
891 /* Add the new sequence of catchs to the main one for this
892 function. */
893 push_to_sequence (catch_clauses);
894 emit_insns (new_catch_clause);
895 catch_clauses = get_insns ();
896 end_sequence ();
897
898 /* Here we fall through into the continuation code. */
899 }
900
901 /* Build a type value for use at runtime for a type that is matched
902 against by the exception handling system. */
903 static tree
904 build_eh_type_type (type)
905 tree type;
906 {
907 char *typestring;
908 tree exp;
909
910 if (type == error_mark_node)
911 return error_mark_node;
912
913 /* peel back references, so they match. */
914 if (TREE_CODE (type) == REFERENCE_TYPE)
915 type = TREE_TYPE (type);
916
917 /* Peel off cv qualifiers. */
918 type = TYPE_MAIN_VARIANT (type);
919
920 if (flag_rtti)
921 {
922 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
923 }
924
925 typestring = build_overload_name (type, 1, 1);
926 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
927 return build1 (ADDR_EXPR, ptr_type_node, exp);
928 }
929
930 /* Build a type value for use at runtime for a exp that is thrown or
931 matched against by the exception handling system. */
932 static tree
933 build_eh_type (exp)
934 tree exp;
935 {
936 if (flag_rtti)
937 {
938 exp = build_typeid (exp);
939 return build1 (ADDR_EXPR, ptr_type_node, exp);
940 }
941 return build_eh_type_type (TREE_TYPE (exp));
942 }
943
944 /* This routine creates the cleanup for the exception handling object. */
945 static void
946 push_eh_cleanup ()
947 {
948 /* All cleanups must last longer than normal. */
949 int yes = suspend_momentary ();
950
951 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
952 tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
953 cp_expand_decl_cleanup (NULL_TREE, cleanup);
954
955 resume_momentary (yes);
956 }
957
958
959 /* call this to start a catch block. Typename is the typename, and identifier
960 is the variable to place the object in or NULL if the variable doesn't
961 matter. If typename is NULL, that means its a "catch (...)" or catch
962 everything. In that case we don't need to do any type checking.
963 (ie: it ends up as the "else" clause rather than an "else if" clause) */
964 void
965 expand_start_catch_block (declspecs, declarator)
966 tree declspecs, declarator;
967 {
968 rtx false_label_rtx;
969 rtx protect_label_rtx;
970 tree decl = NULL_TREE;
971 tree init;
972
973 if (! doing_eh (1))
974 return;
975
976 /* Create a binding level for the parm. */
977 expand_start_bindings (0);
978
979 false_label_rtx = gen_label_rtx ();
980 /* This is saved for the exception table. */
981 push_rtl_perm ();
982 protect_label_rtx = gen_label_rtx ();
983 pop_rtl_from_perm ();
984 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
985 push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
986
987 if (declspecs)
988 {
989 tree exp;
990 rtx call_rtx, return_value_rtx;
991 tree init_type;
992
993 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
994 NULL_TREE, NULL_TREE);
995
996 if (decl == NULL_TREE)
997 {
998 error ("invalid catch parameter");
999 return;
1000 }
1001
1002 /* Make sure we mark the catch param as used, otherwise we'll get
1003 a warning about an unused ((anonymous)). */
1004 TREE_USED (decl) = 1;
1005
1006 /* Figure out the type that the initializer is. */
1007 init_type = TREE_TYPE (decl);
1008 if (TREE_CODE (init_type) != REFERENCE_TYPE
1009 && TREE_CODE (init_type) != POINTER_TYPE)
1010 init_type = build_reference_type (init_type);
1011
1012 exp = saved_throw_value;
1013 exp = tree_cons (NULL_TREE,
1014 build_eh_type_type (TREE_TYPE (decl)),
1015 tree_cons (NULL_TREE,
1016 saved_throw_type,
1017 tree_cons (NULL_TREE, exp, NULL_TREE)));
1018 exp = build_function_call (CatchMatch, exp);
1019 call_rtx = expand_call (exp, NULL_RTX, 0);
1020 assemble_external (TREE_OPERAND (CatchMatch, 0));
1021
1022 return_value_rtx = hard_function_value (ptr_type_node, exp);
1023
1024 /* did the throw type match function return TRUE? */
1025 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1026 GET_MODE (return_value_rtx), 0, 0);
1027
1028 /* if it returned FALSE, jump over the catch block, else fall into it */
1029 emit_jump_insn (gen_beq (false_label_rtx));
1030
1031 push_eh_cleanup ();
1032
1033 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1034
1035 /* Do we need the below two lines? */
1036 /* Let `cp_finish_decl' know that this initializer is ok. */
1037 DECL_INITIAL (decl) = init;
1038 decl = pushdecl (decl);
1039 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1040 }
1041 else
1042 {
1043 push_eh_cleanup ();
1044
1045 /* Fall into the catch all section. */
1046 }
1047
1048 /* This is the starting of something to protect. */
1049 emit_label (protect_label_rtx);
1050
1051 emit_line_note (input_filename, lineno);
1052 }
1053
1054
1055 /* this is called from expand_exception_blocks and
1056 expand_end_catch_block to expand the toplevel finalizations for a
1057 function. We return the first label emitted, if any, otherwise
1058 return NULL_RTX. */
1059 static rtx
1060 expand_leftover_cleanups ()
1061 {
1062 struct ehEntry *entry;
1063 rtx first_label = NULL_RTX;
1064
1065 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1066 {
1067 if (! first_label)
1068 first_label = entry->exception_handler_label;
1069 emit_label (entry->exception_handler_label);
1070
1071 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1072
1073 /* The below can be optimized away, and we could just fall into the
1074 next EH handler, if we are certain they are nested. */
1075 /* Code to throw out to outer context, if we fall off end of the
1076 handler. */
1077 expand_internal_throw (gen_rtx (LABEL_REF,
1078 Pmode,
1079 entry->end_label));
1080
1081 /* leftover try block, opps. */
1082 if (entry->finalization == integer_zero_node)
1083 abort ();
1084
1085 free (entry);
1086 }
1087
1088 return first_label;
1089 }
1090
1091 /* Call this to end a catch block. Its responsible for emitting the
1092 code to handle jumping back to the correct place, and for emitting
1093 the label to jump to if this catch block didn't match. */
1094 void expand_end_catch_block ()
1095 {
1096 rtx start_protect_label_rtx;
1097 rtx end_protect_label_rtx;
1098 tree decls;
1099 struct ehEntry entry;
1100
1101 if (! doing_eh (1))
1102 return;
1103
1104 /* fall to outside the try statement when done executing handler and
1105 we fall off end of handler. This is jump Lresume in the
1106 documentation. */
1107 expand_goto (top_label_entry (&caught_return_label_stack));
1108
1109 /* We end the rethrow protection region as soon as we hit a label. */
1110 end_protect_label_rtx = expand_leftover_cleanups ();
1111
1112 /* Code to throw out to outer context, if we get a throw from within
1113 our catch handler. */
1114 /* These are saved for the exception table. */
1115 push_rtl_perm ();
1116 entry.exception_handler_label = gen_label_rtx ();
1117 pop_rtl_from_perm ();
1118 /* This label is Lhandler in the documentation. */
1119 emit_label (entry.exception_handler_label);
1120 expand_internal_throw (gen_rtx (LABEL_REF,
1121 Pmode,
1122 DECL_RTL (top_label_entry (&caught_return_label_stack))));
1123
1124 /* No associated finalization. */
1125 entry.finalization = NULL_TREE;
1126 entry.context = current_function_decl;
1127
1128 if (end_protect_label_rtx == NULL_RTX)
1129 end_protect_label_rtx = entry.exception_handler_label;
1130
1131 /* Because we are emitted out of line, we have to protect this. */
1132 /* label for the start of the protection region. */
1133 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1134
1135 /* Cleanup the EH parameter. */
1136 decls = getdecls ();
1137 expand_end_bindings (decls, decls != NULL_TREE, 0);
1138
1139 /* label we emit to jump to if this catch block didn't match. */
1140 /* This the closing } in the `if (eq) {' of the documentation. */
1141 emit_label (pop_label_entry (&false_label_stack));
1142
1143 /* Because we are reordered out of line, we have to protect this. */
1144 entry.start_label = start_protect_label_rtx;
1145 entry.end_label = end_protect_label_rtx;
1146
1147 LABEL_PRESERVE_P (entry.start_label) = 1;
1148 LABEL_PRESERVE_P (entry.end_label) = 1;
1149 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1150
1151 /* These set up a call to throw the caught exception into the outer
1152 context. */
1153 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1154 }
1155
1156 /* unwind the stack. */
1157 static void
1158 do_unwind (inner_throw_label)
1159 rtx inner_throw_label;
1160 {
1161 #if defined (SPARC_STACK_ALIGN) /* was sparc */
1162 /* This doesn't work for the flat model sparc, I bet. */
1163 tree fcall;
1164 tree params;
1165 rtx return_val_rtx;
1166 rtx temp;
1167
1168 /* call to __builtin_return_address () */
1169 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1170 fcall = build_function_call (BuiltinReturnAddress, params);
1171 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1172 /* In the return, the new pc is pc+8, as the value coming in is
1173 really the address of the call insn, not the next insn. */
1174 temp = gen_reg_rtx (Pmode);
1175 emit_move_insn (temp, inner_throw_label);
1176 emit_move_insn (return_val_rtx, plus_constant (temp, -8));
1177 easy_expand_asm ("ret");
1178 easy_expand_asm ("restore");
1179 emit_barrier ();
1180 #endif
1181 #if defined (ARM_FRAME_RTX) /* was __arm */
1182 if (flag_omit_frame_pointer)
1183 sorry ("this implementation of exception handling requires a frame pointer");
1184
1185 emit_move_insn (stack_pointer_rtx,
1186 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
1187 emit_move_insn (hard_frame_pointer_rtx,
1188 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
1189 #endif
1190 #if defined (TARGET_88000) /* was m88k */
1191 rtx temp_frame = frame_pointer_rtx;
1192
1193 temp_frame = memory_address (Pmode, temp_frame);
1194 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1195
1196 /* hopefully this will successfully pop the frame! */
1197 emit_move_insn (frame_pointer_rtx, temp_frame);
1198 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1199 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1200 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1201 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1202
1203 #if 0
1204 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1205 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1206
1207 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1208
1209 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1210 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1211 #endif
1212 #endif
1213 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
1214 tree fcall;
1215 tree params;
1216 rtx return_val_rtx;
1217
1218 #if 0
1219 /* I would like to do this here, but the move below doesn't seem to work. */
1220 /* call to __builtin_return_address () */
1221 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1222 fcall = build_function_call (BuiltinReturnAddress, params);
1223 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1224
1225 emit_move_insn (return_val_rtx, inner_throw_label);
1226 /* So, for now, just pass throw label to stack unwinder. */
1227 #endif
1228 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1229 inner_throw_label), NULL_TREE);
1230
1231 do_function_call (Unwind, params, NULL_TREE);
1232 assemble_external (TREE_OPERAND (Unwind, 0));
1233 emit_barrier ();
1234 #endif
1235 }
1236
1237
1238 /* Given the return address, compute the new pc to throw. This has to
1239 work for the current frame of the current function, and the one
1240 above it in the case of throw. */
1241 static rtx
1242 eh_outer_context (addr)
1243 rtx addr;
1244 {
1245 #if defined (ARM_FRAME_RTX) /* was __arm */
1246 /* On the ARM, '__builtin_return_address', must have 4
1247 subtracted from it. */
1248 emit_insn (gen_add2_insn (addr, GEN_INT (-4)));
1249
1250 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6
1251 in 26 bit mode, the condition codes must be masked out of the
1252 return value, or else they will confuse BuiltinReturnAddress.
1253 This does not apply to ARM6 and later processors when running in
1254 32 bit mode. */
1255 if (!TARGET_6)
1256 emit_insn (gen_rtx (SET, Pmode,
1257 addr,
1258 gen_rtx (AND, Pmode,
1259 addr, GEN_INT (0x03fffffc))));
1260 #else
1261 #if ! defined (SPARC_STACK_ALIGN) /* was sparc */
1262 #if defined (TARGET_SNAKE)
1263 /* On HPPA, the low order two bits hold the priviledge level, so we
1264 must get rid of them. */
1265 emit_insn (gen_rtx (SET, Pmode,
1266 addr,
1267 gen_rtx (AND, Pmode,
1268 addr, GEN_INT (0xfffffffc))));
1269 #endif
1270
1271 /* On the SPARC, __builtin_return_address is already -8 or -12, no
1272 need to subtract any more from it. */
1273 addr = plus_constant (addr, -1);
1274 #endif
1275 #endif
1276
1277 return addr;
1278 }
1279
1280 /* is called from expand_exception_blocks () to generate the code in a function
1281 to "throw" if anything in the function needs to perform a throw.
1282
1283 expands "throw" as the following pseudo code:
1284
1285 throw:
1286 eh = find_first_exception_match (saved_pc);
1287 if (!eh) goto gotta_rethrow_it;
1288 goto eh;
1289
1290 gotta_rethrow_it:
1291 saved_pc = __builtin_return_address (0);
1292 pop_to_previous_level ();
1293 goto throw;
1294
1295 */
1296 void
1297 expand_builtin_throw ()
1298 {
1299 tree fcall;
1300 tree params;
1301 rtx return_val_rtx;
1302 rtx gotta_rethrow_it;
1303 rtx gotta_call_terminate;
1304 rtx top_of_loop;
1305 rtx unwind_first;
1306 tree t;
1307
1308 if (! doing_eh (0))
1309 return;
1310
1311 if (! throw_used)
1312 return;
1313
1314 params = void_list_node;
1315 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1316 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1317 void_list_node),
1318 t, NULL_TREE, NULL_TREE, 0);
1319 store_parm_decls ();
1320 pushlevel (0);
1321 clear_last_expr ();
1322 push_momentary ();
1323 expand_start_bindings (0);
1324
1325 gotta_rethrow_it = gen_label_rtx ();
1326 gotta_call_terminate = gen_label_rtx ();
1327 top_of_loop = gen_label_rtx ();
1328 unwind_first = gen_label_rtx ();
1329
1330 emit_jump (unwind_first);
1331
1332 emit_label (top_of_loop);
1333
1334 /* search for an exception handler for the saved_pc */
1335 return_val_rtx = do_function_call (FirstExceptionMatch,
1336 tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1337 ptr_type_node);
1338 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1339
1340 /* did we find one? */
1341 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1342 GET_MODE (return_val_rtx), 0, 0);
1343
1344 /* if not, jump to gotta_rethrow_it */
1345 emit_jump_insn (gen_beq (gotta_rethrow_it));
1346
1347 /* we found it, so jump to it */
1348 emit_indirect_jump (return_val_rtx);
1349
1350 /* code to deal with unwinding and looking for it again */
1351 emit_label (gotta_rethrow_it);
1352
1353 /* call to __builtin_return_address () */
1354 #if defined (ARM_FRAME_RTX) /* was __arm */
1355 /* This should be moved into arm.h:RETURN_ADDR_RTX */
1356 /* This replaces a 'call' to __builtin_return_address */
1357 return_val_rtx = gen_reg_rtx (Pmode);
1358 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1359 #else
1360 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1361 fcall = build_function_call (BuiltinReturnAddress, params);
1362 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1363 #endif
1364
1365 /* did __builtin_return_address () return a valid address? */
1366 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1367 GET_MODE (return_val_rtx), 0, 0);
1368
1369 emit_jump_insn (gen_beq (gotta_call_terminate));
1370
1371 return_val_rtx = eh_outer_context (return_val_rtx);
1372
1373 /* Yes it did. */
1374 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1375
1376 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1377 emit_jump (top_of_loop);
1378
1379 /* no it didn't --> therefore we need to call terminate */
1380 emit_label (gotta_call_terminate);
1381 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1382 assemble_external (TREE_OPERAND (Terminate, 0));
1383
1384 {
1385 rtx ret_val, return_val_rtx;
1386 emit_label (unwind_first);
1387 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1388 0, hard_frame_pointer_rtx);
1389
1390 /* Set it up so that we continue inside, at the top of the loop. */
1391 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1392 #ifdef RETURN_ADDR_OFFSET
1393 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1394 if (return_val_rtx != ret_val)
1395 emit_move_insn (ret_val, return_val_rtx);
1396 #endif
1397
1398 /* Fall into epilogue to unwind prologue. */
1399 }
1400
1401 expand_end_bindings (getdecls(), 1, 0);
1402 poplevel (1, 0, 0);
1403 pop_momentary ();
1404
1405 finish_function (lineno, 0, 0);
1406 }
1407
1408
1409 void
1410 expand_start_eh_spec ()
1411 {
1412 start_protect ();
1413 }
1414
1415 static void
1416 expand_end_eh_spec (raises)
1417 tree raises;
1418 {
1419 tree expr, second_try;
1420 rtx check = gen_label_rtx ();
1421 rtx cont;
1422 rtx ret = gen_reg_rtx (Pmode);
1423 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1424 rtx end = gen_label_rtx ();
1425
1426 expr = make_node (RTL_EXPR);
1427 TREE_TYPE (expr) = void_type_node;
1428 RTL_EXPR_RTL (expr) = const0_rtx;
1429 TREE_SIDE_EFFECTS (expr) = 1;
1430 start_sequence_for_rtl_expr (expr);
1431 cont = gen_label_rtx ();
1432 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1433 emit_jump (check);
1434 emit_label (cont);
1435 jumpif (make_tree (integer_type_node, flag), end);
1436 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1437 assemble_external (TREE_OPERAND (Terminate, 0));
1438 emit_barrier ();
1439 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1440 end_sequence ();
1441
1442 second_try = expr;
1443
1444 expr = make_node (RTL_EXPR);
1445 TREE_TYPE (expr) = void_type_node;
1446 RTL_EXPR_RTL (expr) = const0_rtx;
1447 TREE_SIDE_EFFECTS (expr) = 1;
1448 start_sequence_for_rtl_expr (expr);
1449
1450 cont = gen_label_rtx ();
1451 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1452 emit_jump (check);
1453 emit_label (cont);
1454 jumpif (make_tree (integer_type_node, flag), end);
1455 start_protect ();
1456 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1457 assemble_external (TREE_OPERAND (Unexpected, 0));
1458 emit_barrier ();
1459 end_protect (second_try);
1460
1461 emit_label (check);
1462 emit_move_insn (flag, const1_rtx);
1463 cont = gen_label_rtx ();
1464 while (raises)
1465 {
1466 tree exp;
1467 tree match_type = TREE_VALUE (raises);
1468
1469 if (match_type)
1470 {
1471 /* check TREE_VALUE (raises) here */
1472 exp = saved_throw_value;
1473 exp = tree_cons (NULL_TREE,
1474 build_eh_type_type (match_type),
1475 tree_cons (NULL_TREE,
1476 saved_throw_type,
1477 tree_cons (NULL_TREE, exp, NULL_TREE)));
1478 exp = build_function_call (CatchMatch, exp);
1479 assemble_external (TREE_OPERAND (CatchMatch, 0));
1480
1481 jumpif (exp, cont);
1482 }
1483
1484 raises = TREE_CHAIN (raises);
1485 }
1486 emit_move_insn (flag, const0_rtx);
1487 emit_label (cont);
1488 emit_indirect_jump (ret);
1489 emit_label (end);
1490
1491 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1492 end_sequence ();
1493
1494 end_protect (expr);
1495 }
1496
1497 /* This is called to expand all the toplevel exception handling
1498 finalization for a function. It should only be called once per
1499 function. */
1500 void
1501 expand_exception_blocks ()
1502 {
1503 rtx funcend;
1504 rtx insns;
1505
1506 start_sequence ();
1507
1508 funcend = gen_label_rtx ();
1509 emit_jump (funcend);
1510 /* expand_null_return (); */
1511
1512 start_sequence ();
1513
1514 /* Add all the catch clauses here. */
1515 emit_insns (catch_clauses);
1516 catch_clauses = NULL_RTX;
1517
1518 expand_leftover_cleanups ();
1519
1520 insns = get_insns ();
1521 end_sequence ();
1522
1523 /* Do this after we expand leftover cleanups, so that the end_protect
1524 that expand_end_eh_spec does will match the right start_protect,
1525 and make sure it comes out before the terminate protected region. */
1526 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1527 {
1528 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1529 push_to_sequence (insns);
1530
1531 /* Now expand any new ones. */
1532 expand_leftover_cleanups ();
1533
1534 insns = get_insns ();
1535 end_sequence ();
1536 }
1537
1538 if (insns)
1539 {
1540 struct ehEntry entry;
1541
1542 /* These are saved for the exception table. */
1543 push_rtl_perm ();
1544 entry.start_label = gen_label_rtx ();
1545 entry.end_label = gen_label_rtx ();
1546 entry.exception_handler_label = gen_label_rtx ();
1547 entry.finalization = TerminateFunctionCall;
1548 entry.context = current_function_decl;
1549 assemble_external (TREE_OPERAND (Terminate, 0));
1550 pop_rtl_from_perm ();
1551
1552 LABEL_PRESERVE_P (entry.start_label) = 1;
1553 LABEL_PRESERVE_P (entry.end_label) = 1;
1554 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1555
1556 emit_label (entry.start_label);
1557 emit_insns (insns);
1558
1559 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1560
1561 emit_label (entry.exception_handler_label);
1562 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1563 emit_label (entry.end_label);
1564 emit_barrier ();
1565 }
1566
1567 {
1568 /* Mark the end of the stack unwinder. */
1569 rtx unwind_insns;
1570 start_sequence ();
1571 end_eh_unwinder (funcend);
1572 expand_leftover_cleanups ();
1573 unwind_insns = get_insns ();
1574 end_sequence ();
1575 if (unwind_insns)
1576 {
1577 insns = unwind_insns;
1578 emit_insns (insns);
1579 }
1580 }
1581
1582 emit_label (funcend);
1583
1584 /* Only if we had previous insns do we want to emit the jump around
1585 them. If there weren't any, then insns will remain NULL_RTX. */
1586 if (insns)
1587 insns = get_insns ();
1588 end_sequence ();
1589
1590 emit_insns (insns);
1591 }
1592
1593 tree
1594 start_anon_func ()
1595 {
1596 static int counter = 0;
1597 char name[32];
1598 tree params;
1599 tree t;
1600
1601 push_cp_function_context (NULL_TREE);
1602 push_to_top_level ();
1603
1604 /* No need to mangle this. */
1605 push_lang_context (lang_name_c);
1606
1607 params = void_list_node;
1608 /* tcf stands for throw clean funciton. */
1609 sprintf (name, "__tcf_%d", counter++);
1610 t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1611 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1612 void_list_node),
1613 t, NULL_TREE, NULL_TREE, 0);
1614 store_parm_decls ();
1615 pushlevel (0);
1616 clear_last_expr ();
1617 push_momentary ();
1618 expand_start_bindings (0);
1619 emit_line_note (input_filename, lineno);
1620
1621 pop_lang_context ();
1622
1623 return current_function_decl;
1624 }
1625
1626 void
1627 end_anon_func ()
1628 {
1629 expand_end_bindings (getdecls(), 1, 0);
1630 poplevel (1, 0, 0);
1631 pop_momentary ();
1632
1633 finish_function (lineno, 0, 0);
1634
1635 pop_from_top_level ();
1636 pop_cp_function_context (NULL_TREE);
1637 }
1638
1639 /* call this to expand a throw statement. This follows the following
1640 algorithm:
1641
1642 1. Allocate space to save the current PC onto the stack.
1643 2. Generate and emit a label and save its address into the
1644 newly allocated stack space since we can't save the pc directly.
1645 3. If this is the first call to throw in this function:
1646 generate a label for the throw block
1647 4. jump to the throw block label. */
1648 void
1649 expand_throw (exp)
1650 tree exp;
1651 {
1652 rtx label;
1653
1654 if (! doing_eh (1))
1655 return;
1656
1657 /* This is the label that represents where in the code we were, when
1658 we got an exception. This needs to be updated when we rethrow an
1659 exception, so that the matching routine knows to search out. */
1660 label = gen_label_rtx ();
1661 emit_label (label);
1662
1663 if (exp)
1664 {
1665 tree throw_type;
1666 tree cleanup = empty_fndecl, e;
1667
1668 /* throw expression */
1669 /* First, decay it. */
1670 exp = decay_conversion (exp);
1671
1672 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1673 {
1674 throw_type = build_eh_type (exp);
1675 exp = build_reinterpret_cast (ptr_type_node, exp);
1676 }
1677 else
1678 {
1679 rtx cleanup_insns;
1680 tree object;
1681 /* Make a copy of the thrown object. WP 15.1.5 */
1682 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1683 build_tree_list (NULL_TREE, exp),
1684 0);
1685
1686 if (exp == error_mark_node)
1687 error (" in thrown expression");
1688
1689 object = build_indirect_ref (exp, NULL_PTR);
1690 throw_type = build_eh_type (object);
1691
1692 start_sequence ();
1693 object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1694 object = build_indirect_ref (object, NULL_PTR);
1695 cleanup = maybe_build_cleanup (object);
1696 if (cleanup)
1697 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1698 cleanup_insns = get_insns ();
1699 end_sequence ();
1700
1701 if (cleanup && cleanup_insns)
1702 {
1703 cleanup = start_anon_func ();
1704
1705 expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1706
1707 end_anon_func ();
1708
1709 mark_addressable (cleanup);
1710 }
1711 else
1712 {
1713 cleanup = empty_fndecl;
1714 }
1715 }
1716
1717 if (cleanup == empty_fndecl)
1718 assemble_external (empty_fndecl);
1719
1720 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1721 expand_expr (e, const0_rtx, VOIDmode, 0);
1722
1723 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1724 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1725 expand_expr (e, const0_rtx, VOIDmode, 0);
1726
1727 cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1728 cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1729 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1730 }
1731 else
1732 {
1733 /* rethrow current exception */
1734 /* This part is easy, as we don't have to do anything else. */
1735 }
1736
1737 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1738 }
1739
1740 void
1741 end_protect_partials () {
1742 while (protect_list)
1743 {
1744 end_protect (TREE_VALUE (protect_list));
1745 protect_list = TREE_CHAIN (protect_list);
1746 }
1747 }
1748
1749 int
1750 might_have_exceptions_p ()
1751 {
1752 if (eh_table_output_queue.head)
1753 return 1;
1754 return 0;
1755 }
1756
1757 /* Output the exception table.
1758 Return the number of handlers. */
1759 void
1760 emit_exception_table ()
1761 {
1762 int count = 0;
1763 extern FILE *asm_out_file;
1764 struct ehEntry *entry;
1765
1766 if (! doing_eh (0))
1767 return;
1768
1769 exception_section ();
1770
1771 /* Beginning marker for table. */
1772 assemble_align (GET_MODE_ALIGNMENT (Pmode));
1773 assemble_label ("__EXCEPTION_TABLE__");
1774 output_exception_table_entry (asm_out_file,
1775 const0_rtx, const0_rtx, const0_rtx);
1776
1777 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1778 {
1779 tree context = entry->context;
1780
1781 if (context && ! TREE_ASM_WRITTEN (context))
1782 continue;
1783
1784 count++;
1785 output_exception_table_entry (asm_out_file,
1786 entry->start_label, entry->end_label,
1787 entry->exception_handler_label);
1788 }
1789
1790 /* Ending marker for table. */
1791 assemble_label ("__EXCEPTION_END__");
1792 output_exception_table_entry (asm_out_file,
1793 constm1_rtx, constm1_rtx, constm1_rtx);
1794 }
1795
1796 void
1797 register_exception_table ()
1798 {
1799 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1800 VOIDmode, 1,
1801 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1802 Pmode);
1803 }
1804
1805 /* Build a throw expression. */
1806 tree
1807 build_throw (e)
1808 tree e;
1809 {
1810 if (e != error_mark_node)
1811 {
1812 e = build1 (THROW_EXPR, void_type_node, e);
1813 TREE_SIDE_EFFECTS (e) = 1;
1814 TREE_USED (e) = 1;
1815 }
1816 return e;
1817 }
1818
1819 void
1820 start_eh_unwinder ()
1821 {
1822 start_protect ();
1823 }
1824
1825 static void
1826 end_eh_unwinder (end)
1827 rtx end;
1828 {
1829 tree expr;
1830 rtx return_val_rtx, ret_val, label;
1831
1832 if (! doing_eh (0))
1833 return;
1834
1835 expr = make_node (RTL_EXPR);
1836 TREE_TYPE (expr) = void_type_node;
1837 RTL_EXPR_RTL (expr) = const0_rtx;
1838 TREE_SIDE_EFFECTS (expr) = 1;
1839 start_sequence_for_rtl_expr (expr);
1840
1841 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1842 0, hard_frame_pointer_rtx);
1843 return_val_rtx = copy_to_reg (ret_val);
1844
1845 return_val_rtx = eh_outer_context (return_val_rtx);
1846
1847 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1848
1849 #ifdef JUMP_TO_THROW
1850 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1851 #else
1852 label = gen_label_rtx ();
1853 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1854 #endif
1855
1856 #ifdef RETURN_ADDR_OFFSET
1857 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1858 if (return_val_rtx != ret_val)
1859 emit_move_insn (ret_val, return_val_rtx);
1860 #endif
1861
1862 emit_jump (end);
1863
1864 #ifndef JUMP_TO_THROW
1865 emit_label (label);
1866 do_function_call (Throw, NULL_TREE, NULL_TREE);
1867 #endif
1868
1869 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1870 end_sequence ();
1871 end_protect (expr);
1872 }
This page took 0.114867 seconds and 5 git commands to generate.