First cut of changes to utilize the new exception handling model
authorAndrew MacLeod <amacleod@cygnus.com>
Thu, 14 May 1998 13:39:15 +0000 (13:39 +0000)
committerAndrew Macleod <amacleod@gcc.gnu.org>
Thu, 14 May 1998 13:39:15 +0000 (13:39 +0000)
From-SVN: r19746

14 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/except.c
gcc/cp/exception.cc
gcc/cp/parse.y
gcc/cp/semantics.c
gcc/eh-common.h [new file with mode: 0644]
gcc/except.c
gcc/except.h
gcc/final.c
gcc/flow.c
gcc/function.h
gcc/integrate.c
gcc/libgcc2.c

index c99ab5ea9b3be4076077747660a6de5fe73d00e6..1f14869dce3eea6ddc5f19044ac8712fa2cfc448 100644 (file)
@@ -1,3 +1,65 @@
+Thu May 14 16:30:47 EDT 1998  Andrew MacLeod  <amacleod@cygnus.com>
+
+       * eh-common.h: New file for basic EH data structures.
+       * except.h: Various prototypes and structures for NEW_EH_MODEL
+       * function.h (struct function): Add a struct eh_stack for the catch
+       clause stack.
+       * except.c (gen_exception_label): New function to generate an 
+       exception label.
+       (push_eh_entry): Use gen_exception_label() and init 'label_used' field.
+       (push_entry): New function to push an existing entry onto a stack.
+       (receive_exception_label): New function to emit the code required 
+       at the start of all catch blocks.
+       (struct func_eh_entry): New structure for maintaining handlers
+       associated with EH regions.
+       (new_eh_region_entry): New function to register an EH region.
+       (add_new_handler): New function to register a handler with a region.
+       (get_new_handler): Creates  anew handler entry for registering.
+       (find_func_region): New function to convert a NOTE eh region number
+       to an Eh region index.
+       (get_first_handler): New function to get the first handler in a region.
+       (clear_function_eh_region): New function to release memory.
+       (duplicate_handlers): New function to duplicate a list of handlers.
+       (expand_eh_region_end): Create a new region entry node as well.
+       (expand_leftover_cleanups): Call receive_exception_label() and
+       register the cleanup as a handler to the current region.
+       (expand_start_catch): New function to start a catch clause.
+       (expand_end_catch): New function to end a catch clause.
+       (expand_start_all_catch): restructure to not do the equivilent of
+       what expand_start_catch() does now. Push the exception region being
+       handled onto the catch stack.
+       (output_exception_table_entry): Issue an entry for each handler
+       associated with a region.
+       (set_exception_lang_code): New function for setting the language code.
+       (set_exception_version_code): New function to set the version number.
+       (output_exception_table): Output version and language codes.
+       (find_exception_handler_labels): Find handler labels using new scheme.
+       (is_exception_handler_label): New function, returns 1 if label is
+       present as a handler in some exception region.
+       (check_exception_handler_labels): Use the new scheme.
+       (init_eh_for_function): Initialize the catch stack.
+       (save_eh_status): Save the catch stack.
+       (restore_eh_status): Restore the catch stack.
+       (scan_region): Don't remove unreferenced handler label. Flow does it.
+       (get_reg_for_handler): New function to get the eh_context pointer
+       passed by __throw.
+       (expand_builtin_eh_stub): Changes required for NEW_EH_MODEL only.
+       * final.c (final_scan_insn): With NEW_EH_MODEL, add EH table
+       entry when processing END region rather that START region.
+       * flow.c (find_basic_blocks_1): Find all potential handler regions
+       now that we don't automatically know what the labels might be.
+       Let scan_region() remove unreferenced EH BEGIN/END labels.
+       * integrate.c (get_label_from_map): Put inlined labels onto the
+       permanent obstack since we dont know which ones might be exception
+       labels.
+       (save_for_inline_copying): Make new copies of all the handlers.
+       (expand_inline_function): Make new copies of all the handlers.
+       * libgcc2.c: Remove local struct decls, and include eh-common.h.
+       (find_exception_handler): With NEW_EH_MODEL the first matching 
+       region we find is the right one. Add eh_info as a new parameter.
+       (__throw): Pass eh_info to find_exception_handler. Set handler
+       and pass use different regs  under NEW_EH_MODEL.
+
 Thu May 14 12:58:21 1998  Jim Wilson  <wilson@cygnus.com>
 
        * i960.h (hard_regno_mode_ok): Changed to function from array of
index bdd7a16bcef86c94987aa6db4b5398a47a41e733..ae3695b0b6f61eb729a9d8d4e06777c00aee7a03 100644 (file)
@@ -1,3 +1,19 @@
+Thu May 14 16:30:47 EDT 1998  Andrew MacLeod  <amacleod@cygnus.com>
+
+       * exception.cc: Include eh-common.h.
+       (struct cp_eh_info): add eh_info struct with NEW_EH_MODEL.
+       (__cplus_type_matcher): First stab at new C++ runtime type matcher.
+       (__cp_push_exception): Initialize eh_info struct as well.
+       * except.c: Remove local structs and include eh-common.h.
+       (init_exception_processing): Set language and version codes.
+       (call_eh_info): add presence of eh_info to runtime description of 
+       struct cp_eh_info.
+       (expand_end_eh_spec): call start_catch_block() and end_catch_block().
+       * semantics.c (finish_try_block): call start_catch_block() and 
+       end_catch_block().
+       * parse.y (function_try_block): call start_catch_block() and 
+       end_catch_block().
+
 Thu May 14 12:27:34 1998  Brendan Kehoe  <brendan@cygnus.com>
 
        * typeck.c (original_type): New function.
index 6a98a13e58856f5b16b3ece13d2a951b31fac557..5b6831471a54006f2f339e3f362a5a05250ecd26 100644 (file)
@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA.  */
 #include "function.h"
 #include "defaults.h"
 #include "toplev.h"
+#include "eh-common.h"
 
 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 
@@ -65,14 +66,6 @@ static tree do_pop_exception PROTO((void));
 #define EXCEPT_SECTION_ASM_OP  "section\t.gcc_except_table,\"a\",@progbits"
 #endif
 
-#ifdef EXCEPT_SECTION_ASM_OP
-typedef struct {
-    void *start_region;
-    void *end_region;
-    void *exception_handler;
- } exception_table;
-#endif /* EXCEPT_SECTION_ASM_OP */
-
 #ifdef EXCEPT_SECTION_ASM_OP
 
  /* on machines which support it, the exception table lives in another section,
@@ -227,6 +220,11 @@ init_exception_processing ()
 
   push_lang_context (lang_name_c);
 
+#ifdef NEW_EH_MODEL
+  set_exception_lang_code (EH_LANG_C_plus_plus);
+  set_exception_version_code (1);
+#endif
+
   CatchMatch
     = builtin_function (flag_rtti
                        ? "__throw_type_match_rtti"
@@ -269,7 +267,8 @@ call_eh_info ()
     fn = IDENTIFIER_GLOBAL_VALUE (fn);
   else
     {
-      tree t, fields[6];
+      tree t1,t, fields[7];
+      int fo = 0;
 
       /* Declare cp_eh_info * __cp_exception_info (void),
         as defined in exception.cc. */
@@ -278,25 +277,56 @@ call_eh_info ()
 
       /* struct cp_eh_info.  This must match exception.cc.  Note that this
         type is not pushed anywhere.  */
+#ifdef NEW_EH_MODEL
+      t1= make_lang_type (RECORD_TYPE);
+      fields[0] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("handler_label"), ptr_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("dynamic_handler_chain"), ptr_type_node);
+      fields[2] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("info"), ptr_type_node);
+      /* N.B.: The fourth field LEN is expected to be
+        the number of fields - 1, not the total number of fields.  */
+      finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node);
+      t1 = build_pointer_type (t1);
+
+      t1= make_lang_type (RECORD_TYPE);
+      fields[0] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("match_function"), ptr_type_node);
+      fields[1] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("coerced_value"), ptr_type_node);
+      fields[2] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("language"), short_integer_type_node);
+      fields[3] = build_lang_field_decl (FIELD_DECL, 
+                    get_identifier ("version"), short_integer_type_node);
+      /* N.B.: The fourth field LEN is expected to be
+        the number of fields - 1, not the total number of fields.  */
+      finish_builtin_type (t1, "__eh_info", fields, 3, ptr_type_node);
+      fo = 1;
+#endif
       t = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
+#ifdef NEW_EH_MODEL
+      fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("eh_info"),
+                                        t1);
+#endif
+      fields[0+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
                                         ptr_type_node);
-      fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
+      fields[1+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
                                         ptr_type_node);
-      fields[2] = build_lang_field_decl
+      fields[2+fo] = build_lang_field_decl
        (FIELD_DECL, get_identifier ("cleanup"),
         build_pointer_type (build_function_type
                             (ptr_type_node, tree_cons
                              (NULL_TREE, ptr_type_node, void_list_node))));
-      fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
+      fields[3+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
                                         boolean_type_node);
-      fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
+      fields[4+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
                                         build_pointer_type (t));
-      fields[5] = build_lang_field_decl
+      fields[5+fo] = build_lang_field_decl
        (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
       /* N.B.: The fourth field LEN is expected to be
         the number of fields - 1, not the total number of fields.  */
-      finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
+      finish_builtin_type (t, "cp_eh_info", fields, 5+fo, ptr_type_node);
       t = build_pointer_type (t);
 
       /* And now the function.  */
@@ -681,6 +711,7 @@ expand_end_eh_spec (raises)
   int count = 0;
 
   expand_start_all_catch ();
+  expand_start_catch (NULL);
   expand_start_catch_block (NULL_TREE, NULL_TREE);
 
   /* Build up an array of type_infos.  */
@@ -733,6 +764,7 @@ expand_end_eh_spec (raises)
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
   expand_end_catch_block ();
+  expand_end_catch ();
   expand_end_all_catch ();
 }
 
index d6709c5d23d97054e0edf6192bf81492f0daf5ee..461dba40c34d708cad983462f426be73fdcfdc55 100644 (file)
@@ -30,6 +30,7 @@
 #include "typeinfo"
 #include "exception"
 #include <stddef.h>
+#include "eh-common.h"
 
 /* Define terminate, unexpected, set_terminate, set_unexpected as
    well as the default terminate func and default unexpected func.  */
@@ -85,6 +86,9 @@ std::unexpected ()
 
 struct cp_eh_info
 {
+#ifdef NEW_EH_MODEL
+  __eh_info eh_info;
+#endif
   void *value;
   void *type;
   void (*cleanup)(void *, int);
@@ -133,6 +137,29 @@ __eh_free (void *p)
   free (p);
 }
 
+
+#ifdef NEW_EH_MODEL
+
+typedef void * (* rtimetype) (void);
+
+extern "C" void *
+__cplus_type_matcher (cp_eh_info *info, exception_table *matching_info, 
+                                 exception_descriptor *exception_table)
+{
+  void *ret;
+
+  if (exception_table->lang.language != EH_LANG_C_plus_plus)
+    return NULL;
+
+  /* we don't worry about version info yet, there is only one version! */
+  
+  void *match_type = ((rtimetype) (matching_info->match_info)) ();
+  ret = __throw_type_match_rtti (match_type, info->type, info->value);
+  return ret;
+}
+#endif
+
+
 /* Compiler hook to push a new exception onto the stack.
    Used by expand_throw().  */
 
@@ -147,6 +174,13 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
   p->handlers = 0;
   p->caught = false;
 
+#ifdef NEW_EH_MODEL
+  p->eh_info.match_function = __cplus_type_matcher;
+  p->eh_info.language = EH_LANG_C_plus_plus;
+  p->eh_info.version = 1;
+  p->eh_info.coerced_value = NULL;
+#endif
+
   cp_eh_info **q = __get_eh_info ();
 
   p->next = *q;
index d9df9b8919fed3c39b8f48e6517efaa61a66c98a..9bdc979df7f0bdbac42302957934fe9788111d0d 100644 (file)
@@ -3222,12 +3222,16 @@ function_try_block:
                  expand_start_early_try_stmts ();
                }
          ctor_initializer_opt compstmt
-               { expand_start_all_catch (); }
+               { 
+                  expand_start_all_catch (); 
+                  expand_start_catch (NULL);
+                }
          handler_seq
                {
                  int nested = (hack_decl_function_context
                                (current_function_decl) != NULL_TREE);
                  expand_end_all_catch ();
+                  expand_end_catch ();
                  finish_function (lineno, (int)$3, nested);
                }
        ;
index d58ba1db84b7c5060b04d20a0fcf9e55db018a31..25016423365ca2464dbe947a27c3736a203cf7db 100644 (file)
@@ -587,7 +587,10 @@ finish_try_block (try_block)
   if (processing_template_decl)
     RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
   else
-    expand_start_all_catch ();  
+    {
+      expand_start_all_catch ();  
+      expand_start_catch (NULL);
+    }
 }
 
 /* Finish a handler-sequence for a try-block, which may be given by
@@ -600,7 +603,10 @@ finish_handler_sequence (try_block)
   if (processing_template_decl)
     RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
   else
-    expand_end_all_catch ();
+    {
+      expand_end_catch ();
+      expand_end_all_catch ();
+    }
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
diff --git a/gcc/eh-common.h b/gcc/eh-common.h
new file mode 100644 (file)
index 0000000..708946b
--- /dev/null
@@ -0,0 +1,133 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of GNU CC.  */
+
+/* This file contains the structures required for the language
+   independant exception handling model. Both the static compiler and
+   the runtime library share this file. */
+
+/* The compiler flag NEW_EH_MODEL is used to determine whether the 
+   compiler supports the new runtime typechecking mechanism or not. Under
+   the new model, runtime info is contained in the exception table, and
+   the __throw() library routine determines which handler to call based
+   on the results of a call to a matching function provided by the expcetion
+   thrower.  Otherwise the old scheme of calling any handler which matches
+   an exception range is used, and the handler is responsible for all
+   checking of runtime conditions. If the handler wasn't suppose to
+   get the exception, it performs a re-throw. */
+
+#include "gansidecl.h"
+
+
+#ifndef NEW_EH_MODEL
+
+struct eh_context
+{
+  void **dynamic_handler_chain;
+  /* This is language dependent part of the eh context. */
+  void *info;
+};
+
+#else
+
+/* The handler_label field MUST be the first field in this structure. The 
+   __throw()  library routine expects uses __eh_stub() from except.c, which
+   simply dereferences the context pointer to get the handler */
+
+struct eh_context
+{
+  void *handler_label;
+  void **dynamic_handler_chain;
+  /* This is language dependent part of the eh context. */
+  void *info;
+};
+
+#endif
+
+
+#ifndef EH_TABLE_LOOKUP
+
+#ifndef NEW_EH_MODEL
+
+typedef struct exception_table 
+{
+  void *start_region;
+  void *end_region;
+  void *exception_handler;
+} exception_table;
+
+typedef exception_table exception_descriptor;
+
+#else
+
+typedef struct exception_table 
+{
+  void *start_region;
+  void *end_region;
+  void *exception_handler;
+  void *match_info;              /* runtime type info */
+} exception_table;
+
+
+/* The language identifying portion of an exception table */
+
+typedef struct exception_lang_info 
+{
+  short language;
+  short version;  
+} exception_lang_info;
+
+/* Each function has an exception_descriptor which contains the
+   language info, and a table of exception ranges and handlers */
+
+typedef struct exception_descriptor 
+{
+  exception_lang_info lang;
+  exception_table table[1];
+} exception_descriptor;
+
+
+/* A pointer to a matching function is initialized at runtime by the 
+   specific language if run-time exceptions are supported. 
+   The function takes 3 parameters
+    1 - runtime exception that has been thrown info. (__eh_info *)
+    2 - Match info pointer from the region being considered (void *)
+    3 - exception table region is in (exception descriptor *)
+*/
+
+typedef void * (*__eh_matcher)          PROTO ((void *, void *, void *));
+
+/* This is the runtime exception information. This forms the minimum required
+   information for an exception info pointer in an eh_context structure. */
+
+typedef struct __eh_info 
+{
+  __eh_matcher match_function;
+  void *coerced_value;
+  short language;
+  short version;
+} __eh_info;
+
+/* Convienient language codes for ID the originating language. Similar
+   to the codes in dwarf2.h. */
+
+enum exception_source_language
+  {
+    EH_LANG_C89 = 0x0001,
+    EH_LANG_C = 0x0002,
+    EH_LANG_Ada83 = 0x0003,
+    EH_LANG_C_plus_plus = 0x0004,
+    EH_LANG_Cobol74 = 0x0005,
+    EH_LANG_Cobol85 = 0x0006,
+    EH_LANG_Fortran77 = 0x0007,
+    EH_LANG_Fortran90 = 0x0008,
+    EH_LANG_Pascal83 = 0x0009,
+    EH_LANG_Modula2 = 0x000a,
+    EH_LANG_Java = 0x000b,
+    EH_LANG_Mips_Assembler = 0x8001
+  };
+
+#endif
+
+#endif  /* EH_TABLE_LOOKUP */
+
+
index 4d69240a5481bf5dc93befee8e036f54a043857f..a2213a8e60209bffd7cecce51393eeca11df3791 100644 (file)
@@ -390,6 +390,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "defaults.h"
+#include "eh-common.h"
 #include "system.h"
 #include "rtl.h"
 #include "tree.h"
@@ -442,6 +443,12 @@ rtx current_function_ehc;
 
 static struct eh_stack ehstack;
 
+
+/* This stack is used to represent what the current eh region is
+   for the catch blocks beings processed */
+
+static struct eh_stack catchstack;
+
 /* A queue used for tracking which exception regions have closed but
    whose handlers have not yet been expanded. Regions are emitted in
    groups in an attempt to improve paging performance.
@@ -553,6 +560,20 @@ top_label_entry (stack)
   return (*stack)->u.tlabel;
 }
 
+/* get an exception label. These must be on the permanent obstack */
+
+rtx
+gen_exception_label ()
+{
+  rtx lab;
+
+  push_obstacks_nochange ();
+  end_temporary_allocation ();
+  lab = gen_label_rtx ();
+  pop_obstacks ();
+  return lab;
+}
+
 /* Push a new eh_node entry onto STACK.  */
 
 static void
@@ -563,9 +584,22 @@ push_eh_entry (stack)
   struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
 
   entry->outer_context = gen_label_rtx ();
-  entry->exception_handler_label = gen_label_rtx ();
   entry->finalization = NULL_TREE;
+  entry->label_used = 0;
+  entry->exception_handler_label = gen_exception_label ();
+
+  node->entry = entry;
+  node->chain = stack->top;
+  stack->top = node;
+}
 
+/* push an existing entry onto a stack. */
+static void
+push_entry (stack, entry)
+     struct eh_stack *stack;
+     struct eh_entry *entry;
+{
+  struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
   node->entry = entry;
   node->chain = stack->top;
   stack->top = node;
@@ -631,6 +665,185 @@ dequeue_eh_entry (queue)
 
   return tempentry;
 }
+
+static void
+receive_exception_label (handler_label)
+     rtx handler_label;
+{
+  emit_label (handler_label);
+  
+#ifdef HAVE_exception_receiver
+  if (! exceptions_via_longjmp)
+    if (HAVE_exception_receiver)
+      emit_insn (gen_exception_receiver ());
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+  if (! exceptions_via_longjmp)
+    if (HAVE_nonlocal_goto_receiver)
+      emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+}
+
+
+struct func_eh_entry 
+{
+  int range_number;   /* EH region number from EH NOTE insn's */
+  struct handler_info *handlers;
+};
+
+
+/* table of function eh regions */
+static struct func_eh_entry *function_eh_regions = NULL;
+static int num_func_eh_entries = 0;
+static int current_func_eh_entry = 0;
+
+#define SIZE_FUNC_EH(X)   (sizeof (struct func_eh_entry) * X)
+
+/* Add a new eh_entry for this function, and base it off of the information
+   in the EH_ENTRY parameter. A NULL parameter is invalid. The number
+   returned is an number which uniquely identifies this exception range. */
+
+int 
+new_eh_region_entry (note_eh_region) 
+     int note_eh_region;
+{
+  if (current_func_eh_entry == num_func_eh_entries) 
+    {
+      if (num_func_eh_entries == 0)
+        {
+          function_eh_regions = 
+                        (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
+          num_func_eh_entries = 50;
+        }
+      else
+        {
+          num_func_eh_entries  = num_func_eh_entries * 3 / 2;
+          function_eh_regions = (struct func_eh_entry *) 
+            realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
+        }
+    }
+  function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
+  function_eh_regions[current_func_eh_entry].handlers = NULL;
+
+  return current_func_eh_entry++;
+}
+
+/* Add new handler information to an exception range. The  first parameter
+   specifies the range number (returned from new_eh_entry()). The second
+   parameter specifies the handler.  By default the handler is inserted at
+   the end of the list. A handler list may contain only ONE NULL_TREE
+   typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
+   is always output as the LAST handler in the exception table for a region. */
+
+void 
+add_new_handler (region, newhandler)
+     int region;
+     struct handler_info *newhandler;
+{
+  struct handler_info *last;
+
+  newhandler->next = NULL;
+  last = function_eh_regions[region].handlers;
+  if (last == NULL)
+    function_eh_regions[region].handlers = newhandler;
+  else 
+    {
+      for ( ; last->next != NULL; last = last->next)
+        last->next = newhandler;
+    }
+}
+
+/* Create a new handler structure initialized with the handler label and
+   typeinfo fields passed in. */
+
+struct handler_info *
+get_new_handler (handler, typeinfo)
+     rtx handler;
+     void *typeinfo;
+{
+  struct handler_info* ptr;
+  ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
+  ptr->handler_label = handler;
+  ptr->type_info = typeinfo;
+  ptr->next = NULL;
+
+  return ptr;
+}
+
+
+
+/* Find the index in function_eh_regions associated with a NOTE region. If
+   the region cannot be found, a -1 is returned. This should never happen! */
+
+int 
+find_func_region (insn_region)
+     int insn_region;
+{
+  int x;
+  for (x = 0; x < current_func_eh_entry; x++)
+    if (function_eh_regions[x].range_number == insn_region)
+      return x;
+
+  return -1;
+}
+
+/* Get a pointer to the first handler in an exception region's list. */
+
+struct handler_info *
+get_first_handler (region)
+     int region;
+{
+  return function_eh_regions[find_func_region (region)].handlers;
+}
+
+/* Clean out the function_eh_region table and free all memory */
+
+static void
+clear_function_eh_region ()
+{
+  int x;
+  struct handler_info *ptr, *next;
+  for (x = 0; x < current_func_eh_entry; x++)
+    for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next)
+      {
+        next = ptr->next;
+        free (ptr);
+      }
+  free (function_eh_regions);
+  num_func_eh_entries  = 0;
+  current_func_eh_entry = 0;
+}
+
+/* Make a duplicate of an exception region by copying all the handlers
+   for an exception region. Return the new handler index. */
+
+int 
+duplicate_handlers (old_note_eh_region, new_note_eh_region)
+     int old_note_eh_region, new_note_eh_region;
+{
+  struct handler_info *ptr, *new_ptr;
+  int new_region, region;
+
+  region = find_func_region (old_note_eh_region);
+  if (region == -1)
+    error ("Cannot duplicate non-existant exception region.");
+
+  if (find_func_region (new_note_eh_region) != -1)
+    error ("Cannot duplicate EH region because new note region already exists");
+
+  new_region = new_eh_region_entry (new_note_eh_region);
+  ptr = function_eh_regions[region].handlers;
+
+  for ( ; ptr; ptr = ptr->next) 
+    {
+      new_ptr = get_new_handler (ptr->handler_label, ptr->type_info);
+      add_new_handler (new_region, new_ptr);
+    }
+
+  return new_region;
+}
+
 \f
 /* Routine to see if exception handling is turned on.
    DO_WARN is non-zero if we want to inform the user that exception
@@ -1118,6 +1331,9 @@ expand_eh_region_end (handler)
 
   entry->finalization = handler;
 
+  /* create region entry in final exception table */
+  new_eh_region_entry (NOTE_BLOCK_NUMBER (note));
+
   enqueue_eh_entry (&ehqueue, entry);
 
   /* If we have already started ending the bindings, don't recurse.
@@ -1232,19 +1448,13 @@ expand_leftover_cleanups ()
        abort ();
 
       /* Output the label for the start of the exception handler.  */
-      emit_label (entry->exception_handler_label);
 
-#ifdef HAVE_exception_receiver
-      if (! exceptions_via_longjmp)
-       if (HAVE_exception_receiver)
-         emit_insn (gen_exception_receiver ());
-#endif
+      receive_exception_label (entry->exception_handler_label);
 
-#ifdef HAVE_nonlocal_goto_receiver
-      if (! exceptions_via_longjmp)
-       if (HAVE_nonlocal_goto_receiver)
-         emit_insn (gen_nonlocal_goto_receiver ());
-#endif
+      /* register a handler for this cleanup region */
+      add_new_handler (
+        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
+        get_new_handler (entry->exception_handler_label, NULL));
 
       /* And now generate the insns for the handler.  */
       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
@@ -1270,6 +1480,37 @@ expand_start_try_stmts ()
   expand_eh_region_start ();
 }
 
+/* Called to begin a catch clause. The parameter is the object which
+   will be passed to the runtime type check routine. */
+void 
+expand_start_catch (rtime)
+     tree rtime;
+{
+  rtx handler_label = catchstack.top->entry->exception_handler_label;
+  int insn_region_num = CODE_LABEL_NUMBER (handler_label);
+  int eh_region_entry = find_func_region (insn_region_num);
+
+  /* If we've already issued this label, pick a new one */
+  if (catchstack.top->entry->label_used == 0)
+    handler_label = gen_exception_label ();
+  else
+    catchstack.top->entry->label_used = 1;
+
+  receive_exception_label (handler_label);
+
+  add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
+}
+
+/* End a catch clause by dequeuing the current region */
+
+void 
+expand_end_catch ()
+{
+  struct eh_entry *entry;
+  entry = pop_eh_entry (&catchstack);
+  free (entry);
+}
+
 /* Generate RTL for the start of a group of catch clauses. 
 
    It is responsible for starting a new instruction sequence for the
@@ -1308,12 +1549,13 @@ expand_start_all_catch ()
      the handlers in this handler-seq.  */
   start_sequence ();
 
-  while (1)
+  entry = dequeue_eh_entry (&ehqueue);
+  for ( ; entry->finalization != integer_zero_node;
+                                 entry = dequeue_eh_entry (&ehqueue))
     {
       rtx prev;
 
-      entry = dequeue_eh_entry (&ehqueue);
-      /* Emit the label for the exception handler for this region, and
+      /* Emit the label for the cleanup handler for this region, and
         expand the code for the handler. 
 
         Note that a catch region is handled as a side-effect here;
@@ -1322,29 +1564,15 @@ expand_start_all_catch ()
         expand_expr call below. But, the label for the handler will
         still be emitted, so any code emitted after this point will
         end up being the handler.  */
-      emit_label (entry->exception_handler_label);
-
-#ifdef HAVE_exception_receiver
-      if (! exceptions_via_longjmp)
-       if (HAVE_exception_receiver)
-         emit_insn (gen_exception_receiver ());
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
-      if (! exceptions_via_longjmp)
-       if (HAVE_nonlocal_goto_receiver)
-         emit_insn (gen_nonlocal_goto_receiver ());
-#endif
+      
+      receive_exception_label (entry->exception_handler_label);
 
-      /* When we get down to the matching entry for this try block, stop.  */
-      if (entry->finalization == integer_zero_node)
-       {
-         /* Don't forget to free this entry.  */
-         free (entry);
-         break;
-       }
+      /* register a handler for this cleanup region */
+      add_new_handler (
+        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
+        get_new_handler (entry->exception_handler_label, NULL));
 
-      /* And now generate the insns for the handler.  */
+      /* And now generate the insns for the cleanup handler.  */
       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
 
       prev = get_last_insn ();
@@ -1358,6 +1586,12 @@ expand_start_all_catch ()
       free (entry);
     }
 
+  /* At this point, all the cleanups are done, and the ehqueue now has
+     the current exception region at its head. We dequeue it, and put it
+     on the catch stack. */
+
+    push_entry (&catchstack, entry);
+
   /* If we are not doing setjmp/longjmp EH, because we are reordered
      out of line, we arrange to rethrow in the outer context.  We need to
      do this because we are not physically within the region, if any, that
@@ -1496,15 +1730,16 @@ protect_with_terminate (e)
    handler for the region. This is added by add_eh_table_entry and
    used by output_exception_table_entry.  */
 
-static int *eh_table;
-static int eh_table_size;
-static int eh_table_max_size;
+static int *eh_table = NULL;
+static int eh_table_size = 0;
+static int eh_table_max_size = 0;
 
 /* Note the need for an exception table entry for region N.  If we
    don't need to output an explicit exception table, avoid all of the
    extra work.
 
    Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
+   (Or NOTE_INSN_EH_REGION_END sometimes)
    N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
    label number of the exception handler for the region.  */
 
@@ -1562,24 +1797,60 @@ output_exception_table_entry (file, n)
 {
   char buf[256];
   rtx sym;
+  int eh_entry;
+  struct handler_info *handler;
+
+  handler = get_first_handler (n);
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
-  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-  assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+  for ( ; handler != NULL; handler = handler->next)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
+      sym = gen_rtx_SYMBOL_REF (Pmode, buf);
+      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
-  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-  assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
+      sym = gen_rtx_SYMBOL_REF (Pmode, buf);
+      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      
+      assemble_integer (handler->handler_label, 
+                                         POINTER_SIZE / BITS_PER_UNIT, 1);
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
-  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-  assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+#ifdef NEW_EH_MODEL
+    /* for now make sure the sizes match */
+      if (handler->type_info == NULL)
+        assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+      else
+        output_constant ((tree)(handler->type_info), 
+                                                POINTER_SIZE / BITS_PER_UNIT);
+#endif
 
-  putc ('\n', file);           /* blank line */
+      putc ('\n', file);               /* blank line */
+    }
 }
 
 /* Output the exception table if we have and need one.  */
 
+#ifdef NEW_EH_MODEL
+
+static short language_code = 0;
+static short version_code = 0; 
+
+/* This routine will set the language code for exceptions. */
+void set_exception_lang_code (code)
+     short code;
+{
+  language_code = code;
+}
+
+/* This routine will set the language version code for exceptions. */
+void set_exception_version_code (code)
+     short code;
+{
+  version_code = code;
+}
+
+#endif
+
 void
 output_exception_table ()
 {
@@ -1595,15 +1866,31 @@ output_exception_table ()
   assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
   assemble_label ("__EXCEPTION_TABLE__");
 
+#ifdef NEW_EH_MODEL
+  assemble_integer (GEN_INT (language_code), 2 , 1); 
+  assemble_integer (GEN_INT (version_code), 2 , 1);
+
+  /* Add enough padding to make sure table aligns on a pointer boundry. */
+  i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
+  for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
+    ;
+  if (i != 0)
+    assemble_integer (const0_rtx, i , 1);
+#endif
+
   for (i = 0; i < eh_table_size; ++i)
     output_exception_table_entry (asm_out_file, eh_table[i]);
 
   free (eh_table);
+  clear_function_eh_region ();
 
   /* Ending marker for table.  */
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+#ifndef NEW_EH_MODEL
+  /* for binary compatability, the old __throw checked the second
+     position for a -1, so we should output at least 2 -1's */
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
-  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+#endif
   putc ('\n', asm_out_file);           /* blank line */
 }
 \f
@@ -1662,9 +1949,6 @@ void
 find_exception_handler_labels ()
 {
   rtx insn;
-  int max_labelno = max_label_num ();
-  int min_labelno = get_first_label_num ();
-  rtx *labels;
 
   exception_handler_labels = NULL_RTX;
 
@@ -1672,53 +1956,42 @@ find_exception_handler_labels ()
   if (! doing_eh (0))
     return;
 
-  /* Generate a handy reference to each label.  */
-
-  /* We call xmalloc here instead of alloca; we did the latter in the past,
-     but found that it can sometimes end up being asked to allocate space
-     for more than 1 million labels.  */
-  labels = (rtx *) xmalloc ((max_labelno - min_labelno) * sizeof (rtx));
-  bzero ((char *) labels, (max_labelno - min_labelno) * sizeof (rtx));
-
-  /* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER.  */
-  labels -= min_labelno;
-
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == CODE_LABEL)
-       if (CODE_LABEL_NUMBER (insn) >= min_labelno
-           && CODE_LABEL_NUMBER (insn) < max_labelno)
-         labels[CODE_LABEL_NUMBER (insn)] = insn;
-    }
-
   /* For each start of a region, add its label to the list.  */
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
+      struct handler_info* ptr;
       if (GET_CODE (insn) == NOTE
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
        {
-         rtx label = NULL_RTX;
-
-         if (NOTE_BLOCK_NUMBER (insn) >= min_labelno
-             && NOTE_BLOCK_NUMBER (insn) < max_labelno)
-           {
-             label = labels[NOTE_BLOCK_NUMBER (insn)];
-
-             if (label)
-               exception_handler_labels
-                 = gen_rtx_EXPR_LIST (VOIDmode,
-                                      label, exception_handler_labels);
-             else
-               warning ("didn't find handler for EH region %d",
-                        NOTE_BLOCK_NUMBER (insn));
-           }
-         else
-           warning ("mismatched EH region %d", NOTE_BLOCK_NUMBER (insn));
+          ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
+          for ( ; ptr; ptr = ptr->next) 
+            {
+              /* make sure label isn't in the list already */
+              rtx x;
+              for (x = exception_handler_labels; x; x = XEXP (x, 1))
+                if (XEXP (x, 0) == ptr->handler_label)
+                  break;
+              if (! x)
+                exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
+                               ptr->handler_label, exception_handler_labels);
+            }
        }
     }
+}
+
+/* Return a value of 1 if the parameter label number is an exception handler
+   label. Return 0 otherwise. */
 
-  free (labels + min_labelno);
+int
+is_exception_handler_label (lab)
+     int lab;
+{
+  rtx x;
+  for (x = exception_handler_labels ; x ; x = XEXP (x, 1))
+    if (lab == CODE_LABEL_NUMBER (XEXP (x, 0)))
+      return 1;
+  return 0;
 }
 
 /* Perform sanity checking on the exception_handler_labels list.
@@ -1730,60 +2003,24 @@ find_exception_handler_labels ()
 void
 check_exception_handler_labels ()
 {
-  rtx insn, handler;
+  rtx insn, insn2;
 
   /* If we aren't doing exception handling, there isn't much to check.  */
   if (! doing_eh (0))
     return;
 
-  /* Ensure that the CODE_LABEL_NUMBER for the CODE_LABEL entry point
-     in each handler corresponds to the CODE_LABEL_NUMBER of the
-     handler.  */
-
-  for (handler = exception_handler_labels;
-       handler;
-       handler = XEXP (handler, 1))
+  /* Make sure there is no more than 1 copy of a label */
+  for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
     {
-      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-       {
-         if (GET_CODE (insn) == CODE_LABEL)
-           {
-             if (CODE_LABEL_NUMBER (insn)
-                 == CODE_LABEL_NUMBER (XEXP (handler, 0)))
-               {
-                 if (insn != XEXP (handler, 0))
-                   warning ("mismatched handler %d",
-                            CODE_LABEL_NUMBER (insn));
-                 break;
-               }
-           }
-       }
-      if (insn == NULL_RTX)
-       warning ("handler not found %d",
-                CODE_LABEL_NUMBER (XEXP (handler, 0)));
+      int count = 0;
+      for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1))
+        if (XEXP (insn, 0) == XEXP (insn2, 0))
+          count++;
+      if (count != 1)
+       warning ("Counted %d copies of EH region %d in list.\n", count, 
+                                        CODE_LABEL_NUMBER (insn));
     }
 
-  /* Now go through and make sure that for each region there is a
-     corresponding label.  */
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == NOTE
-         && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
-             || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
-       {
-         for (handler = exception_handler_labels;
-              handler;
-              handler = XEXP (handler, 1))
-           {
-             if (CODE_LABEL_NUMBER (XEXP (handler, 0))
-                 == NOTE_BLOCK_NUMBER (insn))
-               break;
-           }
-         if (handler == NULL_RTX && !flag_syntax_only)
-           warning ("region exists, no handler %d",
-                    NOTE_BLOCK_NUMBER (insn));
-       }
-    }
 }
 \f
 /* This group of functions initializes the exception handling data
@@ -1805,6 +2042,7 @@ void
 init_eh_for_function ()
 {
   ehstack.top = 0;
+  catchstack.top = 0;
   ehqueue.head = ehqueue.tail = 0;
   catch_clauses = NULL_RTX;
   false_label_stack = 0;
@@ -1826,6 +2064,7 @@ save_eh_status (p)
     abort ();
 
   p->ehstack = ehstack;
+  p->catchstack = catchstack;
   p->ehqueue = ehqueue;
   p->catch_clauses = catch_clauses;
   p->false_label_stack = false_label_stack;
@@ -1853,6 +2092,7 @@ restore_eh_status (p)
   catch_clauses        = p->catch_clauses;
   ehqueue = p->ehqueue;
   ehstack = p->ehstack;
+  catchstack = p->catchstack;
   current_function_ehc = p->ehc;
 }
 \f
@@ -1951,6 +2191,10 @@ scan_region (insn, n, delete_outer)
       delete_insn (start);
       delete_insn (insn);
 
+/* We no longer removed labels here, since flow will now remove any
+   handler which cannot be called any more. */
+   
+#if 0
       /* Only do this part if we have built the exception handler
          labels.  */
       if (exception_handler_labels)
@@ -1984,6 +2228,7 @@ scan_region (insn, n, delete_outer)
              prev = &XEXP (x, 1);
            }
        }
+#endif
     }
   return insn;
 }
@@ -2133,6 +2378,20 @@ eh_regs (r1, r2, outgoing)
   *r2 = reg2;
 }
 
+
+/* Retrieve the register which contains the pointer to the eh_context
+   structure set the __throw. */
+
+rtx 
+get_reg_for_handler ()
+{
+  rtx reg1;
+  reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
+                          current_function_decl);
+  return reg1;
+}
+
+
 /* Emit inside of __throw a stub which adjusts the stack pointer and jumps
    to the exception handler.  __throw will set up the necessary values
    and then return to the stub.  */
@@ -2150,8 +2409,28 @@ expand_builtin_eh_stub ()
   eh_regs (&handler, &offset, 0);
 
   adjust_stack (offset);
+#ifdef NEW_EH_MODEL
+
+  /* Handler is in fact a pointer to the _eh_context structure, we need 
+     to pick out the handler field (first element), and jump to there, 
+     leaving the pointer to _eh_conext in the same hardware register. */
+  {
+    rtx jump_to, temp;
+
+    temp = gen_rtx_MEM (Pmode, handler);  
+    MEM_IN_STRUCT_P (temp) = 1;
+    RTX_UNCHANGING_P (temp) = 1;
+    emit_insn (gen_rtx_SET (Pmode, offset, temp));
+    emit_insn (gen_rtx_USE (Pmode, handler));
+
+    emit_indirect_jump (offset);
+   
+  }
+
+#else
   emit_indirect_jump (handler);
 
+#endif
   emit_label (after_stub);
   return gen_rtx_LABEL_REF (Pmode, stub_start);
 }
@@ -2213,7 +2492,8 @@ set_insn_eh_region (first, region_num)
 
 /* Free the insn table, an make sure it cannot be used again. */
 
-void free_insn_eh_region () 
+void 
+free_insn_eh_region () 
 {
   if (!doing_eh (0))
     return;
@@ -2229,7 +2509,8 @@ void free_insn_eh_region ()
    this routine. If it is unavailable, passing a value of 0 will 
    cause this routine to calculate it as well. */
 
-void init_insn_eh_region (first, max_uid)
+void 
+init_insn_eh_region (first, max_uid)
      rtx first;
      int max_uid;
 {
@@ -2255,8 +2536,9 @@ void init_insn_eh_region (first, max_uid)
 
 /* Check whether 2 instructions are within the same region. */
 
-int in_same_eh_region(insn1, insn2) 
-     rtx insn1,insn2;
+int 
+in_same_eh_region (insn1, insn2) 
+     rtx insn1, insn2;
 {
   int ret, uid1, uid2;
 
index d93a8c979d81f4ca3de5bdea363ca06bd9595502..6cb6dc8878f45959b858aebdf7769047298d6eec 100644 (file)
@@ -43,6 +43,10 @@ struct label_node {
    EXCEPTION_HANDLER_LABEL is the label corresponding to the handler
    for this region.
 
+   LABEL_USED indicates whether a CATCH block has already used this
+   label or not. New ones are needed for additional catch blocks if
+   it has.
+
    FINALIZATION is the tree codes for the handler, or is NULL_TREE if
    one hasn't been generated yet, or is integer_zero_node to mark the
    end of a group of try blocks.  */
@@ -50,8 +54,8 @@ struct label_node {
 struct eh_entry {
   rtx outer_context;
   rtx exception_handler_label;
-
   tree finalization;
+  int label_used;
 };
 
 /* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
@@ -145,17 +149,89 @@ extern int doing_eh                                      PROTO ((int));
 
 /* Toplevel initialization for EH.  */
 
+#ifdef NEW_EH_MODEL
+
+void set_exception_lang_code                    PROTO((short));
+void set_exception_version_code                 PROTO((short));
+
+#endif
+
+/* A list of handlers asocciated with an exception region. HANDLER_LABEL
+   is the the label that control should be transfered to if the data
+   in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO
+   means This is a cleanup, and must always be called. A value of
+   CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
+   is still performed to avoid being caught by a different language
+   exception. NEXT is a pointer to the next handler for this region. 
+   NULL means there are no more. */
+
+#define CATCH_ALL_TYPE   (tree *) -1
+
+typedef struct handler_info 
+{
+  rtx  handler_label;
+  void *type_info;
+  struct handler_info *next;
+} handler_info;
+
+
+/* Add a new eh_entry for this function, The parameter specifies what
+   exception region number NOTE insns use to delimit this range. 
+   The integer returned is uniquely identifies this exception range
+   within an internal table. */
+
+int new_eh_region_entry                         PROTO((int));
+
+/* Add new handler information to an exception range. The  first parameter
+   specifies the range number (returned from new_eh_entry()). The second
+   parameter specifies the handler.  By default the handler is inserted at
+   the end of the list. A handler list may contain only ONE NULL_TREE
+   typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
+   is always output as the LAST handler in the exception table for a region. */
+
+void add_new_handler                       PROTO((int, struct handler_info *));
+
+/* Create a new handler structure initialized with the handler label and
+   typeinfo fields passed in. */
+
+struct handler_info *get_new_handler            PROTO((rtx, void *));
+
+/* Make a duplicate of an exception region by copying all the handlers
+   for an exception region. Return the new handler index. */
+
+int duplicate_handlers                          PROTO((int, int));
+
+
+/* Get a pointer to the first handler in an exception region's list. */
+
+struct handler_info *get_first_handler          PROTO((int));
+
+
 extern void init_eh                            PROTO((void));
 
 /* Initialization for the per-function EH data.  */
 
 extern void init_eh_for_function               PROTO((void));
 
+/* Generate an exception label. Use instead of gen_label_rtx */
+
+extern rtx gen_exception_label                  PROTO((void));
+
 /* Adds an EH table entry for EH entry number N. Called from
    final_scan_insn for NOTE_INSN_EH_REGION_BEG.  */
 
 extern void add_eh_table_entry                 PROTO((int n));
 
+/* Start a catch clause, triggered by runtime value paramter. */
+
+#ifdef TREE_CODE
+extern void expand_start_catch                  PROTO((tree));
+#endif
+
+/* End a catch clause. */
+
+extern void expand_end_catch                    PROTO((void));
+
 /* Returns a non-zero value if we need to output an exception table.  */
 
 extern int exception_table_p                   PROTO((void));
@@ -225,6 +301,10 @@ extern void end_eh_unwinder                        PROTO((void));
 
 extern void find_exception_handler_labels      PROTO((void));
 
+/* Determine if an arbitrary label is an exception label */
+
+extern int is_exception_handler_label           PROTO((int));
+
 /* Performs sanity checking on the check_exception_handler_labels
    list.  */
 
index d45b577419631b36bb6a221ec52d2a8dbcae923f..89436e4fb5881fb4ae9741274a1291fc304e830a 100644 (file)
@@ -1988,7 +1988,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          && ! exceptions_via_longjmp)
        {
          ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
+#ifndef NEW_EH_MODEL
          add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
+#endif
 #ifdef ASM_OUTPUT_EH_REGION_BEG
          ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
 #endif
@@ -1999,6 +2001,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          && ! exceptions_via_longjmp)
        {
          ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
+#ifdef NEW_EH_MODEL
+         add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
+#endif
 #ifdef ASM_OUTPUT_EH_REGION_END
          ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
 #endif
index 14791e2de32e1dca9e8fdbbebd20def13bc27d43..95beb78d1cae5d060a938b69e454cbc072a18776 100644 (file)
@@ -396,7 +396,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
   register char *block_marked = (char *) alloca (n_basic_blocks);
   /* An array of CODE_LABELs, indexed by UID for the start of the active
      EH handler for each insn in F.  */
-  rtx *active_eh_handler;
+  int *active_eh_region;
+  int *nested_eh_region;
   /* List of label_refs to all labels whose addresses are taken
      and used as data.  */
   rtx label_value_list;
@@ -406,7 +407,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
   int in_libcall_block = 0;
 
   pass = 1;
-  active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx));
+  active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
+  nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
  restart:
 
   label_value_list = 0;
@@ -414,7 +416,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
   bzero (block_live, n_basic_blocks);
   bzero (block_marked, n_basic_blocks);
   bzero (basic_block_computed_jump_target, n_basic_blocks);
-  bzero ((char *) active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx));
+  bzero ((char *) active_eh_region, (max_uid_for_flow + 1) * sizeof (int));
+  bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
   current_function_has_computed_jump = 0;
 
   /* Initialize with just block 0 reachable and no blocks marked.  */
@@ -482,20 +485,18 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
                                                    label_value_list);
        }
 
-      /* Keep a lifo list of the currently active exception handlers.  */
+      /* Keep a lifo list of the currently active exception notes.  */
       if (GET_CODE (insn) == NOTE)
        {
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
            {
-             for (x = exception_handler_labels; x; x = XEXP (x, 1))
-               if (CODE_LABEL_NUMBER (XEXP (x, 0)) == NOTE_BLOCK_NUMBER (insn))
-                 {
-                   eh_note = gen_rtx_EXPR_LIST (VOIDmode,
-                                                XEXP (x, 0), eh_note);
-                   break;
-                 }
-             if (x == NULL_RTX)
-               abort ();
+              if (eh_note)
+                nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = 
+                                     NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
+              else
+                nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = 0;
+             eh_note = gen_rtx_EXPR_LIST (VOIDmode,
+                                                insn, eh_note);
            }
          else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
            eh_note = XEXP (eh_note, 1);
@@ -509,8 +510,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
               && (asynchronous_exceptions
                   || (GET_CODE (insn) == CALL_INSN
                       && ! in_libcall_block)))
-       active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0);
-
+       active_eh_region[INSN_UID (insn)] = 
+                                        NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
       BLOCK_NUM (insn) = i;
 
       if (code != NOTE)
@@ -655,11 +656,20 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
                                     && ! find_reg_note (insn, REG_RETVAL,
                                                         NULL_RTX)))
                          {
-                           if (active_eh_handler[INSN_UID (insn)])
-                             mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
-                                                                active_eh_handler[INSN_UID (insn)]),
-                                             insn, 0);
-
+                           if (active_eh_region[INSN_UID (insn)]) 
+                              {
+                                int region;
+                                handler_info *ptr;
+                                region = active_eh_region[INSN_UID (insn)];
+                                for ( ; region; 
+                                             region = nested_eh_region[region]) 
+                                  {
+                                    ptr = get_first_handler (region);
+                                    for ( ; ptr ; ptr = ptr->next)
+                                      mark_label_ref (gen_rtx_LABEL_REF 
+                                       (VOIDmode, ptr->handler_label), insn, 0);
+                                  }
+                              }
                            if (!asynchronous_exceptions)
                              {
                                for (x = nonlocal_label_list;
@@ -764,6 +774,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
                            /* Now we have to find the EH_BEG and EH_END notes
                               associated with this label and remove them.  */
 
+#if 0
+/* Handlers and labels no longer needs to have the same values.
+   If there are no references, scan_region will remove any region
+   labels which are of no use. */
                            for (x = get_insns (); x; x = NEXT_INSN (x))
                              {
                                if (GET_CODE (x) == NOTE
@@ -778,6 +792,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
                                    NOTE_SOURCE_FILE (x) = 0;
                                  }
                              }
+#endif
                            break;
                          }
                        prev = &XEXP (x, 1);
index f90830b94f4092f257828560249ee520678f732f..e31f48416745ee36af8e80fb8e7c0f62c549c9d7 100644 (file)
@@ -133,6 +133,7 @@ struct function
 
   /* For exception handling information.  */
   struct eh_stack ehstack;
+  struct eh_stack catchstack;
   struct eh_queue ehqueue;
   rtx catch_clauses;
   struct label_node *false_label_stack;
index 2f8dde132dd5dcf1f332c4738357757d353a44af..7a588884e86b2b1d6f3a112ded59b8a3e4f71381 100644 (file)
@@ -95,7 +95,12 @@ get_label_from_map (map, i)
   rtx x = map->label_map[i];
 
   if (x == NULL_RTX)
-    x = map->label_map[i] = gen_label_rtx();
+    {                     
+      push_obstacks_nochange ();
+      end_temporary_allocation ();
+      x = map->label_map[i] = gen_label_rtx();
+      pop_obstacks ();
+    }
 
   return x;
 }
@@ -658,10 +663,28 @@ save_for_inline_copying (fndecl)
          if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
              || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
            {
+              int new_region = CODE_LABEL_NUMBER 
+                                        (label_map[NOTE_BLOCK_NUMBER (copy)]);
+
+              /* we have to duplicate the handlers for the original */
+              if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) 
+                {
+                  handler_info *ptr, *temp;
+                  int nr;
+                  nr = new_eh_region_entry (new_region);
+                  ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
+                  for ( ; ptr; ptr = ptr->next)
+                    {
+                      temp = get_new_handler (
+                           label_map[CODE_LABEL_NUMBER (ptr->handler_label)],
+                                                               ptr->type_info);
+                      add_new_handler (nr, temp);
+                    }
+                }
+                
              /* We have to forward these both to match the new exception
                 region.  */
-             NOTE_BLOCK_NUMBER (copy)
-               = CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);
+             NOTE_BLOCK_NUMBER (copy) = new_region;
              
            }
          RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
@@ -2038,6 +2061,22 @@ expand_inline_function (fndecl, parms, target, ignore, type,
                  rtx label
                    = get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
 
+                  /* we have to duplicate the handlers for the original */
+                  if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
+                    {
+                      handler_info *ptr, *temp;
+                      int nr;
+                      nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
+                      ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
+                      for ( ; ptr; ptr = ptr->next)
+                        {
+                          temp = get_new_handler ( get_label_from_map (map, 
+                                      CODE_LABEL_NUMBER (ptr->handler_label)),
+                                                               ptr->type_info);
+                          add_new_handler (nr, temp);
+                        }
+                    }
+
                  /* We have to forward these both to match the new exception
                     region.  */
                  NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
index 1b33c05b1b46ad3db64406d59e744c147d71ac37..c8604124a19e0df819eb71f428eeeccbf79408d0 100644 (file)
@@ -3046,14 +3046,10 @@ __empty ()
 {
 }
 \f
-/* EH context structure. */
 
-struct eh_context
-{
-  void **dynamic_handler_chain;
-  /* This is language dependent part of the eh context. */
-  void *info;
-};
+/* Include definitions of EH context and table layout */
+
+#include "eh-common.h"
 
 /* This is a safeguard for dynamic handler chain. */
 
@@ -3361,11 +3357,6 @@ EH_TABLE_LOOKUP
 #else
 
 #ifdef DWARF2_UNWIND_INFO
-typedef struct exception_table {
-  void *start;
-  void *end;
-  void *exception_handler;
-} exception_table;
 
 /* This routine takes a PC and a pointer to the exception region TABLE for
    its translation unit, and returns the address of the exception handler
@@ -3376,31 +3367,68 @@ typedef struct exception_table {
    an inner block.  */
 
 static void *
-find_exception_handler (void *pc, exception_table *table)
+find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
 {
   if (table)
     {
+#ifdef NEW_EH_MODEL
+      /* The new model assumed the table is sorted inner-most out so the
+         first region we find which matches is the correct one */
+
+      int pos;
+      void *ret;
+      exception_table *tab = &(table->table[0]);
+
+      /* Subtract 1 from the PC to avoid hitting the next region */
+      pc--;
+      
+      /* We can't do a binary search because the table is in inner-most
+         to outermost address ranges within functions */
+      for (pos = 0; tab[pos].start_region != (void *) -1; pos++)
+        { 
+          if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+            {
+              if (tab[pos].match_info)
+                {
+                  __eh_matcher matcher = ((__eh_info *)eh_info)->match_function;
+                  /* match info but no matcher is NOT a match */
+                  if (matcher) 
+                    {
+                      ret = (*matcher)(eh_info, tab[pos].match_info, table);
+                      if (ret)
+                        {
+                          ((__eh_info *)eh_info)->coerced_value = ret;
+                          return tab[pos].exception_handler;
+                        }
+                    }
+                }
+              else
+                return tab[pos].exception_handler;
+            }
+        }
+#else
       int pos;
       int best = -1;
 
       /* We can't do a binary search because the table isn't guaranteed
-        to be sorted from function to function.  */
-      for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
-       {
-         if (table[pos].start <= pc && table[pos].end > pc)
-           {
-             /* This can apply.  Make sure it is at least as small as
-                the previous best.  */
-             if (best == -1 || (table[pos].end <= table[best].end
-                                && table[pos].start >= table[best].start))
-               best = pos;
-           }
-         /* But it is sorted by starting PC within a function.  */
-         else if (best >= 0 && table[pos].start > pc)
-           break;
-       }
+         to be sorted from function to function.  */
+      for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+        {
+          if (table[pos].start_region <= pc && table[pos].end_region > pc)
+            {
+              /* This can apply.  Make sure it is at least as small as
+                 the previous best.  */
+              if (best == -1 || (table[pos].end_region <= table[best].end_region
+                        && table[pos].start_region >= table[best].start_region))
+                best = pos;
+            }
+          /* But it is sorted by starting PC within a function.  */
+          else if (best >= 0 && table[pos].start_region > pc)
+            break;
+        }
       if (best != -1)
-       return table[best].exception_handler;
+        return table[best].exception_handler;
+#endif
     }
 
   return (void *) 0;
@@ -3583,7 +3611,7 @@ label:
       if (! udata)
        break;
 
-      handler = find_exception_handler (pc, udata->eh_ptr);
+      handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
 
       /* If we found one, we can stop searching.  */
       if (handler)
@@ -3602,6 +3630,10 @@ label:
   if (! handler)
     __terminate ();
 
+#ifdef NEW_EH_MODEL
+  eh->handler_label = handler;
+#endif
+
   if (pc == saved_pc)
     /* We found a handler in the throw context, no need to unwind.  */
     udata = my_udata;
@@ -3669,7 +3701,13 @@ label:
 
   /* Set up the registers we use to communicate with the stub.
      We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack.  */
+
+#ifdef NEW_EH_MODEL
+  __builtin_set_eh_regs ((void *)eh,
+#else
   __builtin_set_eh_regs (handler,
+#endif
+
 #ifdef STACK_GROWS_DOWNWARD
                         udata->cfa - my_udata->cfa
 #else