This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Destructor ordering V2


This is a revised patch for ordering of destructors. Relative to the
previous patch, it

- uses a modified atexit_cookie interface if available, following the
  proposal of Roland McGrath
- places all atexit cookies into a .dtors.atexit section.
- for -fdtors-dynamic, marks head of dtors list as weak, so we get
  one for all shared libraries

Any opinions?

Martin

gcc/ChangeLog
Thu Sep 17 09:30:31 1998  Martin von L÷wis  <loewis@informatik.hu-berlin.de>

	* crtstuff.c (DTORS_ATEXIT_SECTION_ASM_OP): New macro.
	(__DTORS_ATEXIT__): New array.
	(__do_global_ctors_aux): Fill it with cookies.


cp/ChangeLog
1998-09-17  Martin von L÷wis  <loewis@informatik.hu-berlin.de>

	* cp-tree.h (dtor_ordering): New enumeration.
	* decl.c (expand_static_init): Call expand_static_init_dynamic for
	dynamic and atexit ordering.
	* decl2.c (flag_dtors_ordering): New flag variable.
	(lang_decode_option): Initialize it.
	(do_dtors): Do nothing for dynamic and atexit ordering.
	(do_ctors): Instead, call do_dynamic_dtor.
	* init.c (dtorlist_type_node, dtorlist_ptr_node,
	null_dtorlist_node): New static variables.
	(init_init_processing): Initialize them.
	(build_atexit_cookie): New function.
	(expand_static_init_dynamic, do_dynamic_dtor): New functions.
	* lang_options.h (-fdtors-static, -fdtors-dynamic,
	-fdtors-atexit): New flags.
	* initialize.c: New file.
	* Make-lang.in: Compile it into libgcc2.


Index: crtstuff.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/crtstuff.c,v
retrieving revision 1.14
diff -c -p -r1.14 crtstuff.c
*** crtstuff.c	1998/06/08 18:30:12	1.14
--- crtstuff.c	1998/09/17 07:21:37
*************** Boston, MA 02111-1307, USA.  */
*** 56,61 ****
--- 56,68 ----
  #include <stddef.h>
  #include "frame.h"
  
+ /* On glibc systems, we need to know whether run_atexit is
+    supported. */
+ #ifdef __linux__
+ #define _GNU_SOURCE
+ #include <stdlib.h>
+ #endif
+ 
  /* Provide default definitions for the pseudo-ops used to switch to the
     .ctors and .dtors sections.
   
*************** Boston, MA 02111-1307, USA.  */
*** 81,86 ****
--- 88,96 ----
  #if !defined (EH_FRAME_SECTION_ASM_OP) && defined (DWARF2_UNWIND_INFO) && defined(ASM_OUTPUT_SECTION_NAME)
  #define EH_FRAME_SECTION_ASM_OP	".section\t.eh_frame,\"aw\""
  #endif
+ #if defined(ASM_OUTPUT_SECTION_NAME)
+ #define DTORS_ATEXIT_SECTION_ASM_OP ".section\t.dtors.atexit,\"aw\""
+ #endif
  
  #ifdef OBJECT_FORMAT_ELF
  
*************** typedef void (*func_ptr) (void);
*** 126,131 ****
--- 136,142 ----
  
  static char __EH_FRAME_BEGIN__[];
  static func_ptr __DTOR_LIST__[];
+ static void * __DTORS_ATEXIT__[];
  static void
  __do_global_dtors_aux ()
  {
*************** __do_global_dtors_aux ()
*** 135,140 ****
--- 146,157 ----
    if (completed)
      return;
  
+ #ifdef __HAVE_ATEXIT_COOKIE
+   /* The first entry is -1, the others (including the terminator)
+      have the cookie. */
+   run_atexit (__DTORS_ATEXIT__[1]);
+ #endif
+ 
    while (*p)
      {
        p++;
*************** asm (DTORS_SECTION_ASM_OP);	/* cc1 doesn
*** 305,310 ****
--- 322,332 ----
  STATIC func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) };
  #endif
  
+ #ifdef DTORS_SECTION_ASM_OP
+ asm (DTORS_ATEXIT_SECTION_ASM_OP);
+ STATIC void* __DTORS_ATEXIT__[1] = { (void*)-1 };
+ #endif
+ 
  #ifdef EH_FRAME_SECTION_ASM_OP
  /* Stick a label at the beginning of the frame unwind info so we can register
     and deregister it with the exception handling library code.  */
*************** char __EH_FRAME_BEGIN__[] = { };
*** 325,334 ****
--- 347,363 ----
  #ifdef OBJECT_FORMAT_ELF
  
  static func_ptr __CTOR_END__[];
+ static void* __DTORS_ATEXIT_END__[];
  static void
  __do_global_ctors_aux ()
  {
    func_ptr *p;
+ #ifdef __HAVE_ATEXIT_COOKIE
+   void **d;
+   for (d = __DTORS_ATEXIT_END__; *d != (void*) -1; d--)
+     /* initialize everything with the address of the dtors_atexit list. */
+     *d = __DTORS_ATEXIT_END__;
+ #endif
    for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
      (*p) ();
  }
*************** init_dummy ()
*** 356,362 ****
      extern char **__environ;
  
      ___brk_addr = __environ;
!     atexit ();
    }
  #endif
  }
--- 385,391 ----
      extern char **__environ;
  
      ___brk_addr = __environ;
!     atexit (0);
    }
  #endif
  }
*************** DTOR_LIST_END;
*** 446,451 ****
--- 475,486 ----
  asm (DTORS_SECTION_ASM_OP);	/* cc1 doesn't know that we are switching! */
  STATIC func_ptr __DTOR_END__[1] __attribute__ ((__unused__))
    = { (func_ptr) 0 };
+ #endif
+ 
+ #ifdef DTORS_SECTION_ASM_OP
+ asm (DTORS_ATEXIT_SECTION_ASM_OP);
+ STATIC void* __DTORS_ATEXIT_END__[1] __attribute__ ((unused))
+   = { 0 };
  #endif
  
  #ifdef EH_FRAME_SECTION_ASM_OP
Index: cp/Make-lang.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.19
diff -c -p -r1.19 Make-lang.in
*** Make-lang.in	1998/09/07 14:24:55	1.19
--- Make-lang.in	1998/09/17 07:21:59
*************** CXX_EXTRA_HEADERS = $(srcdir)/cp/inc/typ
*** 61,70 ****
  
  # Extra code to include in libgcc2.
  CXX_LIB2FUNCS = tinfo.o tinfo2.o new.o opnew.o opnewnt.o opvnew.o opvnewnt.o \
! 	opdel.o opdelnt.o opvdel.o opvdelnt.o exception.o
  CXX_LIB2SRCS = $(srcdir)/cp/new.cc $(srcdir)/cp/new1.cc $(srcdir)/cp/new2.cc \
  	$(srcdir)/cp/exception.cc $(srcdir)/cp/tinfo.cc \
! 	$(srcdir)/cp/tinfo2.cc $(srcdir)/cp/tinfo.h
  #
  # Define the names for selecting c++ in LANGUAGES.
  # Note that it would be nice to move the dependency on g++
--- 61,70 ----
  
  # Extra code to include in libgcc2.
  CXX_LIB2FUNCS = tinfo.o tinfo2.o new.o opnew.o opnewnt.o opvnew.o opvnewnt.o \
! 	opdel.o opdelnt.o opvdel.o opvdelnt.o exception.o initialize.o
  CXX_LIB2SRCS = $(srcdir)/cp/new.cc $(srcdir)/cp/new1.cc $(srcdir)/cp/new2.cc \
  	$(srcdir)/cp/exception.cc $(srcdir)/cp/tinfo.cc \
! 	$(srcdir)/cp/tinfo2.cc $(srcdir)/cp/tinfo.h $(srcdir)/cp/initialize.c
  #
  # Define the names for selecting c++ in LANGUAGES.
  # Note that it would be nice to move the dependency on g++
*************** tinfo2.o: cc1plus$(exeext) $(srcdir)/cp/
*** 148,153 ****
--- 148,156 ----
  exception.o: cc1plus$(exeext) $(srcdir)/cp/exception.cc
  	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
  	  -c -fexceptions $(srcdir)/cp/exception.cc
+ initialize.o: cc1$(exeext) $(srcdir)/cp/initialize.c
+ 	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ 	  -c $(srcdir)/cp/initialize.c
  new.o: cc1plus$(exeext) $(srcdir)/cp/new.cc
  	$(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
  	  -c $(srcdir)/cp/new.cc
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.139
diff -c -p -r1.139 cp-tree.h
*** cp-tree.h	1998/09/09 02:14:53	1.139
--- cp-tree.h	1998/09/17 07:22:02
*************** extern int flag_gnu_binutils;
*** 324,329 ****
--- 325,335 ----
  
  extern int flag_no_ident;
  
+ /* Three different ways of ordering destructors. */
+ 
+ enum dtor_ordering {dtors_static, dtors_dynamic, dtors_atexit};
+ enum dtor_ordering flag_dtors_ordering;
+ 
  /* Nonzero means warn about implicit declarations.  */
  
  extern int warn_implicit;
*************** extern tree build_x_delete			PROTO((tree
*** 2704,2709 ****
--- 2710,2717 ----
  extern tree build_delete			PROTO((tree, tree, tree, int, int));
  extern tree build_vbase_delete			PROTO((tree, tree));
  extern tree build_vec_delete			PROTO((tree, tree, tree, tree, int));
+ extern void expand_static_init_dynamic		PROTO((tree, tree));
+ extern void do_dynamic_dtor			PROTO((tree));
  
  /* in input.c */
  
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.210
diff -c -p -r1.210 decl.c
*** decl.c	1998/09/10 11:20:40	1.210
--- decl.c	1998/09/17 07:22:20
*************** expand_static_init (decl, init)
*** 7653,7659 ****
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	cp_error ("multiple initializations given for `%D'", decl);
      }
!   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ())
      {
        /* Emit code to perform this initialization but once.  */
        tree temp;
--- 7653,7660 ----
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	cp_error ("multiple initializations given for `%D'", decl);
      }
!   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ()
! 	   && flag_dtors_ordering == dtors_static)
      {
        /* Emit code to perform this initialization but once.  */
        tree temp;
*************** expand_static_init (decl, init)
*** 7726,7731 ****
--- 7727,7734 ----
        /* Resume old (possibly temporary) allocation.  */
        pop_obstacks ();
      }
+   else if (! toplevel_bindings_p () && ! pseudo_global_level_p ())
+       expand_static_init_dynamic (decl,init);
    else
      {
        /* This code takes into account memory allocation
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.133
diff -c -p -r1.133 decl2.c
*** decl2.c	1998/09/07 14:25:04	1.133
--- decl2.c	1998/09/17 07:22:26
*************** int flag_init_priority = 1;
*** 181,186 ****
--- 181,190 ----
  int flag_init_priority;
  #endif
  
+ /* Define destructor ordering. */
+ 
+ enum dtor_ordering flag_dtors_ordering = dtors_dynamic;
+ 
  /* Nonzero means warn about implicit declarations.  */
  
  int warn_implicit = 1;
*************** lang_decode_option (argc, argv)
*** 580,597 ****
--- 584,609 ----
  	  flag_guiding_decls = 0;
  	  found = 1;
  	}
+       else if (!strcmp (p, "dtors-static"))
+ 	  flag_dtors_ordering = dtors_static;
+       else if (!strcmp (p, "dtors-dynamic"))
+ 	  flag_dtors_ordering = dtors_dynamic;
+       else if (!strcmp (p, "dtors-atexit"))
+ 	  flag_dtors_ordering = dtors_atexit;
        else if (!strcmp (p, "new-abi"))
  	{
  	  flag_new_abi = 1;
  	  flag_do_squangling = 1;
  	  flag_honor_std = 1;
  	  flag_vtable_thunks = 1;
+ 	  flag_dtors_ordering = dtors_dynamic;
  	}
        else if (!strcmp (p, "no-new-abi"))
  	{
  	  flag_new_abi = 0;
  	  flag_do_squangling = 0;
  	  flag_honor_std = 0;
+ 	  flag_dtors_ordering = dtors_static;
  	}
        else if (!strncmp (p, "template-depth-", 15))
  	{
*************** lang_decode_option (argc, argv)
*** 749,755 ****
      }
    else if (!strcmp (p, "-ansi"))
      flag_no_nonansi_builtin = 1, flag_ansi = 1,
!     flag_no_gnu_keywords = 1, flag_operator_names = 1;
  #ifdef SPEW_DEBUG
    /* Undocumented, only ever used when you're invoking cc1plus by hand, since
       it's probably safe to assume no sane person would ever want to use this
--- 761,768 ----
      }
    else if (!strcmp (p, "-ansi"))
      flag_no_nonansi_builtin = 1, flag_ansi = 1,
!     flag_no_gnu_keywords = 1, flag_operator_names = 1,
!     flag_dtors_ordering = dtors_atexit;
  #ifdef SPEW_DEBUG
    /* Undocumented, only ever used when you're invoking cc1plus by hand, since
       it's probably safe to assume no sane person would ever want to use this
*************** do_dtors (start)
*** 3149,3154 ****
--- 3162,3171 ----
        initp = TREE_INT_CST_LOW (TREE_PURPOSE (start));
        vars = TREE_VALUE (start);
      }
+   else if (flag_dtors_ordering != dtors_static)
+     /* For dynamic and atexit registration, the destructors will 
+        be registered during construction. */
+     return;
    else
      {
        initp = 0;
*************** do_ctors (start)
*** 3309,3319 ****
--- 3326,3342 ----
  	  /* Cleanup any temporaries needed for the initial value.  */
  	  expand_end_target_temps ();
  
+ 	  /* If we need to register the destructor, do it now. */
+ 	  if (flag_dtors_ordering == dtors_dynamic ||
+ 	      flag_dtors_ordering == dtors_atexit)
+ 	    do_dynamic_dtor (decl);
+ 
  	  if (protect)
  	    expand_end_cond ();
  
  	  DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
  	  DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+ 
  	}
        else if (decl == error_mark_node)
  	/* OK */;
Index: cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.65
diff -c -p -r1.65 init.c
*** init.c	1998/09/07 14:25:09	1.65
--- init.c	1998/09/17 07:22:30
*************** static tree minus_one;
*** 73,81 ****
  
  static tree BI_header_type, BI_header_size;
  
  void init_init_processing ()
  {
!   tree fields[1];
  
    minus_one = build_int_2 (-1, -1);
  
--- 73,86 ----
  
  static tree BI_header_type, BI_header_size;
  
+ /* Destructor lists. */
+ static tree dtorlist_type_node;
+ static tree dtorlist_ptr_node;
+ static tree null_dtorlist_node;
+ 
  void init_init_processing ()
  {
!   tree t1, fields[2];
  
    minus_one = build_int_2 (-1, -1);
  
*************** void init_init_processing ()
*** 87,92 ****
--- 92,111 ----
    finish_builtin_type (BI_header_type, "__new_cookie", fields,
  		       0, double_type_node);
    BI_header_size = size_in_bytes (BI_header_type);
+ 
+   /* struct __dtorlist. This must match initialize.c.  */
+   dtorlist_type_node = t1 = make_lang_type (RECORD_TYPE);
+   fields[0] = build_lang_field_decl 
+     (FIELD_DECL, get_identifier ("dtor"), 
+      build_pointer_type (build_function_type 
+ 			 (void_type_node, void_list_node)));
+   fields[1] = build_lang_field_decl 
+     (FIELD_DECL, get_identifier ("next"), build_pointer_type (t1));
+   finish_builtin_type (t1, "__dtorlist", fields, 1, ptr_type_node);
+   dtorlist_ptr_node = build_pointer_type (t1);
+ 
+   null_dtorlist_node = build_int_2 (0, 0);
+   TREE_TYPE (null_dtorlist_node) = dtorlist_ptr_node;
  }
  
  /* Subroutine of emit_base_init.  For BINFO, initialize all the
*************** build_vec_delete (base, maxindex, auto_d
*** 3301,3304 ****
--- 3320,3612 ----
  
    return build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
  			     use_global_delete);
+ }
+ 
+ /* Build an atexit cookie for this translation unit. */
+ static tree the_atexit_cookie;
+ 
+ static tree
+ build_atexit_cookie ()
+ {
+   if (the_atexit_cookie)
+     return the_atexit_cookie;
+ #ifdef ASM_OUTPUT_SECTION_NAME
+   the_atexit_cookie = get_temp_name (ptr_type_node, 1);
+   DECL_INITIAL (the_atexit_cookie) = null_pointer_node;
+   {
+     char section_name[] = ".dtors.atexit";
+     DECL_SECTION_NAME (the_atexit_cookie) = 
+       build_string (strlen(section_name), section_name);
+   }
+   rest_of_decl_compilation (the_atexit_cookie, NULL, 0, 0);
+   the_atexit_cookie = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node),
+ 			      the_atexit_cookie);
+ #else
+   the_atexit_cookie = build_int_2 (0, 0);
+   TREE_TYPE (the_atexit_cookie) = build_pointer_type (ptr_type_node);
+ #endif
+   return the_atexit_cookie;
+ }  
+ 
+ /* Emit code to perform this initialization but once.  */
+ 
+ void
+ expand_static_init_dynamic (decl, init)
+      tree decl, init;
+ {
+   extern struct obstack permanent_obstack;
+   tree temp, ptemp, e, cleanup, registry;
+   tree PFV, fn;
+ 
+   /* Remember this information until end of file.  */
+   push_obstacks (&permanent_obstack, &permanent_obstack);
+ 
+   /* Emit code to perform this initialization but once.  */
+   temp = get_temp_name (integer_type_node, 1);
+   rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
+ 
+   fn = get_identifier ("__cp_init_begin");
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare int __cp_init_begin (int *); */
+       tree tmp;
+       tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (integer_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+ 
+   e = build1 (ADDR_EXPR, ptr_type_node, temp);
+   e = expr_tree_cons (NULL_TREE, e, NULL_TREE);
+   e = build_function_call (fn, e);
+ 
+   expand_start_cond (e, 0);
+   expand_start_target_temps ();
+ 
+   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
+       || (init && TREE_CODE (init) == TREE_LIST))
+     {
+       /* This implements the following pseudo code
+          try{
+            initialization;
+          }catch(...){
+            __cp_init_failed(&_tmp_flag);
+            throw;
+          }
+       */
+       begin_try_block ();
+       expand_aggr_init (decl, init, 0, 0);
+       do_pending_stack_adjust ();
+       expand_start_all_catch ();
+       /* expand_start_catch_block (NULL_TREE, NULL_TREE); */
+ 
+       fn = get_identifier ("__cp_init_failed");
+       if (IDENTIFIER_GLOBAL_VALUE (fn))
+ 	fn = IDENTIFIER_GLOBAL_VALUE (fn);
+       else
+ 	{
+ 	  /* Declare void __cp_init_failed (int *); */
+ 	  tree tmp;
+ 	  tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ 	  fn = build_lang_decl (FUNCTION_DECL, fn,
+ 				build_function_type (void_type_node, tmp));
+ 	  DECL_EXTERNAL (fn) = 1;
+ 	  TREE_PUBLIC (fn) = 1;
+ 	  DECL_ARTIFICIAL (fn) = 1;
+ 	  pushdecl_top_level (fn);
+ 	  make_function_rtl (fn);
+ 	  assemble_external (fn);
+ 	}
+ 
+       e = build1 (ADDR_EXPR, ptr_type_node, temp);
+       e = expr_tree_cons (NULL_TREE, e, NULL_TREE);
+       e = build_function_call (fn, e);
+       expand_expr_stmt (e);
+ 
+       /* expand_expr_stmt (build_throw (NULL_TREE));
+          expand_end_catch_block (); */
+       expand_end_all_catch ();
+     }
+   else if (init)
+     expand_assignment (decl, init, 0, 0);
+ 
+   /* Cleanup any temporaries needed for the initial value.  */
+   expand_end_target_temps ();
+ 
+   /* void (*)(); */
+   PFV = build_pointer_type (build_function_type
+ 			    (void_type_node, void_list_node));
+ 
+   if (flag_dtors_ordering == dtors_atexit)
+     fn = get_identifier ("__cp_init_complete_atexit");
+   else
+     fn = get_identifier ("__cp_init_complete");
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare void 
+ 	 __cp_init_complete (int *, void (*)(), struct __dtorlist *);
+ 	 or void
+ 	 __cp_init_complete_atexit (int *, void (*)(), void **);
+ 	 respectively. */
+       tree tmp;
+       if (flag_dtors_ordering == dtors_atexit)
+ 	tmp = build_pointer_type (build_pointer_type (void_type_node));
+       else
+ 	tmp = dtorlist_ptr_node;
+       tmp = tree_cons (NULL_TREE, ptr_type_node, tree_cons
+ 		       (NULL_TREE, PFV, tree_cons
+ 			(NULL_TREE, tmp, void_list_node)));
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (void_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+ 
+   /* Call init_complete. */
+   if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
+     {
+       e = start_anon_func ();
+       expand_expr_stmt (build_cleanup (decl));
+       end_anon_func ();
+       mark_addressable (e);
+       cleanup = build_unary_op (ADDR_EXPR, e, 0);
+       if (flag_dtors_ordering == dtors_atexit)
+ 	/* Under strict compliance, we don't run our own
+ 	   destructor registry, but use atexit or equivalent.
+ 	   If we have atexit_cookie, we'll pass it a special 
+ 	   variable. */
+ 	registry = build_atexit_cookie ();
+       else if (flag_dtors_ordering == dtors_dynamic)
+ 	{
+ 	  registry = get_temp_name (dtorlist_type_node, 1);
+ 	  rest_of_decl_compilation (registry, NULL_PTR, 0, 0);
+ 	  registry = build1 (ADDR_EXPR, dtorlist_ptr_node, registry);
+ 	}
+       else
+ 	/* We don't do static registration here. */
+ 	my_friendly_abort (980830);
+     }
+   else
+     {
+       static tree null_fptr = NULL_TREE;
+       if (null_fptr == NULL_TREE)
+ 	{
+ 	  tree ftype = build_pointer_type (build_function_type 
+ 					   (void_type_node, void_list_node));
+ 	  layout_type (ftype);
+ 	  null_fptr = build_int_2 (0, 0);
+ 	  TREE_TYPE (null_fptr) = ftype;
+ 	}
+       cleanup = null_fptr;
+       if (flag_dtors_ordering == dtors_atexit)
+ 	registry = build_atexit_cookie ();
+       else
+ 	registry = null_dtorlist_node;
+     }
+   
+   e = expr_tree_cons (NULL_TREE, registry, NULL_TREE);
+   e = expr_tree_cons (NULL_TREE, cleanup, e);
+   ptemp = build1 (ADDR_EXPR, ptr_type_node, temp);
+   e = expr_tree_cons (NULL_TREE, ptemp, e);
+   e = build_function_call (fn, e);
+   
+   expand_expr_stmt (e);
+   expand_end_cond ();
+ 
+   /* Resume old (possibly temporary) allocation.  */
+   pop_obstacks ();
+ }
+ 
+ /* Register a single destructor function at runtime. */
+ void
+ do_dynamic_dtor (decl)
+      tree decl;
+ {
+   tree type = TREE_TYPE (decl);
+   tree e, fn, registry, dtor;
+ 
+   if (!TYPE_NEEDS_DESTRUCTOR (type) || DECL_EXTERNAL (decl))
+     return;
+ 
+   dtor = start_anon_func ();
+ 
+   if (member_p (decl))
+     {
+       DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl);
+       DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+     }
+       
+   /* We need no protection agains multiple destruction here,
+      since the constructor is protected and registers us.  */
+   expand_expr_stmt (build_cleanup (decl));
+       
+   DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
+   DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+   
+   end_anon_func ();
+   mark_addressable (dtor);
+ 
+   if (flag_dtors_ordering == dtors_atexit)
+     fn = get_identifier ("__cp_register_dtor_atexit");
+   else
+     fn = get_identifier ("__cp_register_dtor");
+     
+   if (IDENTIFIER_GLOBAL_VALUE (fn))
+     fn = IDENTIFIER_GLOBAL_VALUE (fn);
+   else
+     {
+       /* Declare void 
+ 	 __cp_register_dtor (void (*)(), struct __dtorlist *); 
+          or void
+ 	 __cp_register_dtor_atexit (void (*)(), void **); 
+ 	 respectively.  */
+       tree tmp, PFV;
+       PFV = build_pointer_type (build_function_type
+ 				(void_type_node, void_list_node));
+       if (flag_dtors_ordering == dtors_atexit)
+ 	tmp = build_pointer_type (ptr_type_node);
+       else
+ 	tmp = dtorlist_ptr_node;
+       tmp = tree_cons(NULL_TREE, PFV, tree_cons
+ 		      (NULL_TREE, tmp, void_list_node));
+       fn = build_lang_decl (FUNCTION_DECL, fn,
+ 			    build_function_type (void_type_node, tmp));
+       DECL_EXTERNAL (fn) = 1;
+       TREE_PUBLIC (fn) = 1;
+       DECL_ARTIFICIAL (fn) = 1;
+       pushdecl_top_level (fn);
+       make_function_rtl (fn);
+       assemble_external (fn);
+     }
+   
+   if (flag_dtors_ordering == dtors_atexit)
+     registry = build_atexit_cookie ();
+   else if (flag_dtors_ordering == dtors_dynamic)
+     {
+       /* We could make this shared if the object is shared. */
+       registry = get_temp_name (dtorlist_type_node, 1);
+       rest_of_decl_compilation (registry, NULL_PTR, 0, 0);
+       registry = build1 (ADDR_EXPR, dtorlist_ptr_node, registry);
+     }
+   else
+     /* We don't do static registration here. */
+     my_friendly_abort (980830);
+ 
+   e = expr_tree_cons (NULL_TREE, registry, NULL_TREE);
+   e = expr_tree_cons (NULL_TREE, dtor, e);
+   e = build_function_call (fn, e);
+   expand_expr_stmt (e);
  }
Index: cp/lang-options.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lang-options.h,v
retrieving revision 1.19
diff -c -p -r1.19 lang-options.h
*** lang-options.h	1998/09/07 14:25:11	1.19
--- lang-options.h	1998/09/17 07:22:30
*************** DEFINE_LANG_NAME ("C++")
*** 67,72 ****
--- 67,75 ----
    { "-fno-implicit-templates", "" },
    { "-finit-priority", "Handle the init_priority attribute" },
    { "-fno-init-priority", "" },
+   { "-fdtors-atexit", "Register destructors with atexit" },
+   { "-fdtors-dynamic", "Register destructors dynamically" },
+   { "-fdtors-static", "Register destructors at compile time" },
    { "-flabels-ok", "Labels can be used as first class objects" },
    { "-fno-labels-ok", "" },
    { "-fmemoize-lookups", "" },
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ cp/initialize.c	Sat Sep 12 13:40:20 1998
@@ -0,0 +1,165 @@
+// Functions for Initialization Support for C++, -*- C -*-
+// Copyright (C) 1998 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// GNU CC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GNU CC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA. 
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+/* Find out whether we have atexit_cookie. At the moment, we expect it
+   only from the GNU C library. */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include "gthr.h"
+
+#ifdef SUPPORTS_WEAK
+#define WEAK __attribute__((weak))
+#else
+/* The locks won't be shared between shared libraries.
+   The list of destructors won't be, either. */
+#define WEAK
+#endif
+
+__gthread_mutex_t initlock WEAK = __GTHREAD_MUTEX_INIT;
+
+struct __dtorlist{
+  void (*dtor)();
+  struct __dtorlist *next;
+};
+
+static struct __dtorlist *__cp_dtors WEAK;
+
+/* These are meant to be per shared object. For destructors meant to
+   run during dlclose, this only works if a copy of this file is
+   linked into every shared library used in dlopen.  */
+
+static void *min_dtor, *max_dtor;
+
+/* For static initialization, this runs unprotected.
+   For dynamic (block-static) ctors, we hold the initlock.  */
+
+void
+__cp_register_dtor (void (*dtor)(), struct __dtorlist *entry)
+{
+  entry->dtor = dtor;
+  entry->next = __cp_dtors;
+  __cp_dtors = entry;
+  if (!min_dtor || min_dtor > (void*)dtor)
+    min_dtor = dtor;
+  if (!max_dtor || max_dtor < (void*)dtor)
+    max_dtor = dtor;
+}
+
+void
+__cp_register_dtor_atexit (void (*dtor)(), void **cookie __attribute((unused)))
+{
+#ifdef __HAVE_ATEXIT_COOKIE
+  atexit_cookie (dtor, cookie);
+#else
+  atexit(dtor);
+#endif
+}
+
+static void __cp_run_dtors () __attribute__((destructor));
+
+static void
+__cp_run_dtors ()
+{
+  /* First, run everything and clear the function pointer */
+  struct __dtorlist *entry, *prev;
+  for (entry = __cp_dtors; entry; entry = entry->next)
+    if (entry->dtor && (void*)entry->dtor >= min_dtor
+	&& (void*)entry->dtor <= max_dtor)
+      {
+	entry->dtor();
+	entry->dtor = 0;
+      }
+  /* When removing from the list, obtain the lock. */
+  __gthread_mutex_lock (&initlock);
+  for (entry = __cp_dtors, prev = 0; entry; 
+       prev = entry, entry = entry->next)
+    if (!entry->dtor)
+      {
+	if (prev)
+	  prev->next = entry->next;
+	else
+	  __cp_dtors = entry->next;
+      }
+  __gthread_mutex_unlock (&initlock);
+}
+
+/* Initialization variables have the following states:
+   0 - uninitialized
+   1 - initialization in progress
+   2 - initialization complete
+*/
+
+int
+__cp_init_begin (int * p)
+{
+  if (*p == 2)
+    /* Nothing to do. */
+    return 0;
+  __gthread_mutex_lock (&initlock);
+  switch (*p)
+    {
+    case 0:
+      *p = 1;
+      /* Could release lock here if we had condition variables. */
+      return 1;
+    case 2:
+      /* Done. */
+      __gthread_mutex_unlock (&initlock);
+      return 0;
+    }
+  /* Must have been 1, or some illegal value. With us holding the
+     lock, this should not happen. */
+  __gthread_mutex_unlock (&initlock);
+  abort ();
+  return 0;
+}
+
+void
+__cp_init_failed (int* p)
+{
+  *p = 0;
+  __gthread_mutex_unlock (&initlock);
+}
+
+void
+__cp_init_complete (int *p, void (*dtor)(), struct __dtorlist *entry)
+{
+  if (dtor)
+    __cp_register_dtor (dtor, entry);
+  *p = 2;
+  __gthread_mutex_unlock (&initlock);
+}
+
+void
+__cp_init_complete_atexit (int *p, void (*dtor)(), void **cookie)
+{
+  if (dtor)
+    __cp_register_dtor_atexit (dtor, cookie);
+  *p = 2;
+  __gthread_mutex_unlock (&initlock);
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]