Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

GC.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 
00003 // This file is part of Vesta.
00004 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Definitions of "new" and "delete" for use with the garbage collector.
00020 
00021 #include <sys/types.h> // for "size_t"
00022 #include <assert.h>
00023 #include <errno.h>
00024 
00025 #include <new> // std::bad_allox
00026 
00027 // First include the auto-generated header of #defines for the gc
00028 // library configuration.
00029 #if !defined(__osf__)
00030 #include <used_gc_flags.h>
00031 #endif
00032 
00033 // Now include gc.h
00034 #include <gc.h>
00035 
00036 #if defined(THREAD_LOCAL_ALLOC)
00037 extern "C"
00038 {
00039 #include <gc_local_alloc.h>
00040 }
00041 #endif
00042 
00043 #if defined(__osf__)
00044 // The DECWest collector doesn't publicly declare this, but it's there.
00045 extern "C" void GC_add_roots(void *low, void *high_plus_1);
00046 #endif
00047 
00048 #include "Basics.H"    // for Basics::gc_attribs
00049 
00050 using std::cerr;
00051 using std::endl;
00052 
00053 // ----------------------------------------------------------------------
00054 // There's some ugly code here to get the garbage collector
00055 // initialized and to handle chicken-and-egg initialization problems.
00056 
00057 // We use a static instance of BasicsGCInit (a special class defined
00058 // below) to call GC_init.  This ensures that the garbage collector is
00059 // initialized from the main thread, before we reach the entry point
00060 // of the main function.
00061 
00062 // In some cases, the C++ run-time library or other library
00063 // initialization code may call our overloaded new operator so early
00064 // that the garbage collector won't work right.  (Even calling GC_init
00065 // itself can cause problems in some cases.)  To avoid this, we use
00066 // malloc until the static instance of BasicsGCInit is constructed.
00067 // We keep a linked list of the blocks allocated with malloc in
00068 // pre_init_blocks (below).  After initializing the garbage collector
00069 // we add these blocks to the root set (with calls to GC_add_roots).
00070 // This protects any blocks allocated from the garbage collected heap
00071 // that are referenced by these early malloced blocks.
00072 
00073 // This may create some small memory leaks if any of these early
00074 // malloced blocks are ever deleted.  However we expect most of them
00075 // to be part of the initialization of static instances.  We could add
00076 // code to the delete operator to test whether a block being deleted
00077 // was one of these early malloced blocks and free it (after removing
00078 // it from the root set) in that case, but that would add a
00079 // significant time cost to the delete operator.
00080 // ----------------------------------------------------------------------
00081 
00082 // Data structure used to keep a linked list of blocks allocated with
00083 // malloc before the garbage collector is initialized.
00084 struct pre_init_block
00085 {
00086   struct pre_init_block *next;
00087   size_t size;
00088 };
00089 static struct pre_init_block *pre_init_blocks = 0;
00090 
00091 // This class has a single purpose: determine the offset from the
00092 // beginning of the heap block of the pointer given to the application
00093 // for an array allocation.  Most C++ run-times store an element count
00094 // at the beginning of the heap block for such allocations, so that
00095 // they know how many times to call the destructor when the block is
00096 // deleted.  We need to know this offset to tell the garbage collector
00097 // to consider pointers offset from the beginning of the block to be
00098 // valid references.
00099 class ArrayOffsetCalc
00100 {
00101 private:
00102   // This struct is private because only the "value" static member
00103   // function belwo should ever construct an instance.
00104   struct _dummy
00105   {
00106     int i;
00107 
00108     _dummy() throw() : i(1) {}
00109 
00110     // This placement new variant returns the block starting position
00111     // to the caller.
00112     void *operator new[](size_t size, void **block_start)
00113     {
00114       void *result;
00115       result = malloc(size);
00116       *block_start = result;
00117       return result;
00118     }
00119 
00120     // We need this because of a requirement for a matching placement
00121     // delete in case an exception is thrown during construction of an
00122     // object.
00123     void operator delete[](void *p, void **block_start) { free(p); }
00124 
00125     // We need this for the actual deletion which occurs.
00126     void operator delete[](void *p) { free(p); }
00127 
00128     // The class must have a destructor.  In some situations, the
00129     // run-time is smart enough to not keep an array count for an
00130     // array of instances of a class with no destructor.
00131     ~_dummy() { i = -1; }
00132   };
00133 
00134   // In some C++ run-times (at least gcc 3.3 on PowerPC Linux),
00135   // allocating an array of this object will get a *different* block
00136   // offset.  (I'm really not clear why this is.  It may have
00137   // something to do with the size of the struct and alignment, or it
00138   // may have to do with the fact that it contains a member variable
00139   // with a destructor but has no explicitly declared destructor.)
00140   struct _dummy2
00141   {
00142     unsigned long long uniqueid[2];
00143     _dummy nameA;
00144 
00145     void *operator new[](size_t size, void **block_start)
00146     {
00147       void *result;
00148       result = malloc(size);
00149       *block_start = result;
00150       return result;
00151     }
00152     void operator delete[](void *p, void **block_start) { free(p); }
00153     void operator delete[](void *p) { free(p); }
00154   };
00155 
00156 public:
00157   // Call these functions to get the pointer offset into a heap block
00158   // for an array.
00159 
00160   static unsigned int value()
00161   {
00162     // Allocate an array and capture the block start.
00163     void *bs;
00164     _dummy *as = new (&bs) _dummy[1];
00165     delete [] as;
00166     // Return the byte offset of the array start from the block start
00167     return (((char *) as) - ((char *) bs));
00168   }
00169 
00170   static unsigned int value2()
00171   {
00172     void *bs;
00173     _dummy2 *as = new (&bs) _dummy2[1];
00174     delete [] as;
00175     return (((char *) as) - ((char *) bs));
00176   }
00177 };
00178 
00179 // ------ MYGETENV  get a value from ENV, optionally print message if found
00180 
00181 static char *mygetenv (const char *env_name, bool vbose)
00182 {
00183   char *val = getenv(env_name);
00184   if (vbose && val != NULL)
00185     cerr << "GC_ENV: Detected " << val << " in ENV variable named: " << env_name << endl;
00186 
00187   return val;
00188 }
00189 
00190 // ------ GETENV_UNAME  get an unsigned, base 10, numerical value from env
00191 
00192 static int getenv_unum (const char *env_name, unsigned long *result, bool vbose)
00193 {
00194   // Returns 0 if name was not in ENV
00195   // Returns 1 if name was converted successfully
00196   // Returns 2 if name was non-numeric
00197   // Returns 3 if name produced overflow error
00198   // Make sure to include <errno.h>
00199 
00200   char *end_cnvt, *env_val;
00201   unsigned long t_val;
00202 
00203   if ((env_val = mygetenv(env_name, vbose)) == NULL)
00204     return 0;    // Not found
00205 
00206   errno = 0;      // strtoul only sets errno on overflow
00207   t_val = strtoul(env_val,&end_cnvt,10);
00208   if (errno == ERANGE)
00209     return 3;    // overflow
00210 
00211   if (env_val == end_cnvt ||  // there ere no digits...
00212       *end_cnvt != 0)      // ...or there were left-over bytes...
00213     return 2;    // non-numeric stuff
00214 
00215   *result = t_val;
00216   return 1;
00217 }
00218 
00219 // Initialize the garbage collector with a static instance of this
00220 // class.  This ensures that we're ready to go before main starts.
00221 class BasicsGCInit {
00222 public:
00223   static bool done;
00224   BasicsGCInit() throw ()
00225   {
00226     GC_init();
00227 
00228     // In the case where the garbage collector will not consider any
00229     // pointer to the interior of a block to be a valid reference, we
00230     // need to tell it a couple offsets which *should* be considered
00231     // valid references.
00232 
00233 #if !defined(ALL_INTERIOR_POINTERS) && defined(GC_REGISTER_DISPLACEMENT)
00234     // Needed for code which uses the LSB of a pointer as a boolean
00235     // flag (at least SharedTable from basics/generics does this).
00236     GC_REGISTER_DISPLACEMENT(1);
00237 
00238     // Needed for allocations of arrays of objects.  First add two
00239     // dynamically determined offsets.
00240     GC_REGISTER_DISPLACEMENT(ArrayOffsetCalc::value());
00241     GC_REGISTER_DISPLACEMENT(ArrayOffsetCalc::value2());
00242 
00243     // Some C++ run-time environments use more than one different
00244     // block offset for arrays under subtly different conditions.
00245     // Unfortunately, the dynamic detection may not cover all
00246     // possibilities, so also add a couple fixed offsets.
00247     GC_REGISTER_DISPLACEMENT(4);
00248     GC_REGISTER_DISPLACEMENT(8);
00249 #endif
00250 
00251 #if !defined(ALL_INTERIOR_POINTERS) && defined(__GNUC__) && (__GNUC__ >= 3)
00252     // Needed to force the gcc 3.[234] default allocator class to use
00253     // our new operator.  (See: bits/stl_alloc.h in 3.[23],
00254     // ext/pool_allocator.h and ext/mt_allocator.h in 3.4.)  If we
00255     // don't do this, it manages its own free lists using interior
00256     // pointers within heap blocks, which will not work correctly with
00257     // ALL_INTERIOR_POINTERS disabled.
00258 
00259 # if !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ < 4)
00260     // gcc 3.[23] use this environment variable
00261     putenv("GLIBCPP_FORCE_NEW=1");
00262 # endif
00263 # if !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 4)
00264     // gcc 3.4 switched to this environment variable
00265     putenv("GLIBCXX_FORCE_NEW=1");
00266 # endif
00267 
00268 #endif
00269 
00270 #if !defined(__osf__)
00271     // ----- Allow ENV to alter some GC behaviors
00272 
00273     bool vbose = false;
00274     int tstat;
00275 
00276     if (mygetenv("GC_ENV_VERBOSE", 1) != NULL)
00277        vbose = true;
00278 
00279     // how many GC retries before giving up after heap expand fails
00280     if ((tstat = getenv_unum("GC_MAX_RETRIES", &GC_max_retries, vbose)) > 1)
00281        cerr << "WARNING: Non-numeric or huge value in GC_MAX_RETRIES was ignored. value= " << getenv("GC_MAX_RETRIES") << endl;
00282 
00283     if (GC_max_retries > 10)
00284        GC_max_retries = 10;    // probably a mistake, should we announce the action ??
00285 
00286     if (GC_max_retries < 1)
00287        GC_max_retries = 1;    // local default (factory default = 0)
00288 
00289     if (vbose && tstat)
00290         cerr << "GC_ENV: GC_max_retires finally set to: " << GC_max_retries << endl;
00291 
00292     // free space divisor
00293     if ((tstat = getenv_unum("GC_FREE_SPACE_DIVISOR", &GC_free_space_divisor, vbose)) > 1)
00294         cerr << "WARNING: Non-numeric or huge value in GC_FREE_SPACE_DIVISOR was ignored. value= " << getenv("GC_FREE_SPACE_DIVISOR") << endl;
00295 
00296     if (GC_free_space_divisor < 3)
00297        GC_free_space_divisor = 3;    // as low as we could want to go
00298 
00299     if (GC_free_space_divisor > 100)
00300        GC_free_space_divisor = 100;    // probably a mistake, should we announce the action ??
00301 
00302     if (vbose && tstat)
00303         cerr << "GC_ENV: GC_free_space_divisor finally set to: " << GC_free_space_divisor << endl;
00304 
00305     if (mygetenv("GC_DONT_EXPAND", vbose) != NULL)
00306        // Don's expand heap unless forced, or explicitly asked
00307        GC_dont_expand = 1;    // Assume default is 0
00308 
00309     // --------------------------------
00310 #endif
00311 
00312     BasicsGCInit::done = true;
00313     // Add any blocks allocated with malloc before initialization to
00314     // the root set.
00315     struct pre_init_block *cur = pre_init_blocks;
00316     while(cur)
00317       {
00318         char *real_block = ((char *) (cur+1));
00319         GC_add_roots(real_block, real_block+cur->size);
00320         cur = cur->next;
00321       }
00322   }
00323 };
00324 bool BasicsGCInit::done = false;
00325 static BasicsGCInit gcInit; // cause GC to be initialized from main thread
00326 
00327 // early_alloc - Perform an allocation before the garbage collector
00328 // has been initialized.
00329 
00330 static void *early_alloc(size_t size)
00331 {
00332   // Allocate a block with malloc and keep a record of it so we
00333   // can add it to the GC root set later.
00334   struct pre_init_block *result_block =
00335     (struct pre_init_block *) ::malloc(sizeof(struct pre_init_block) +
00336                                        size);
00337   result_block->next = pre_init_blocks;
00338   result_block->size = size;
00339   pre_init_blocks = result_block;
00340   return ((void *) (result_block+1));
00341 }
00342 
00343 // ptrfree_alloc - Allocate a block which the caller promises will
00344 // contain no pointers.
00345 
00346 static void *ptrfree_alloc(size_t size,
00347                            const char *file, unsigned int line)
00348 {
00349   void *result;
00350 
00351   // If the garbage collector hasn't been initialized yet, we won't
00352   // use it.  (In some situations, things blow up when trying to use
00353   // the collector very early during process initialization.)
00354   if(!BasicsGCInit::done)
00355     return early_alloc(size);
00356 
00357   // If the caller promoises that this block will not contain any
00358   // pointers to other heap blocks, use the pointer-free (aka
00359   // atomic) variant.
00360 #if defined(GC_MALLOC_ATOMIC)
00361 # if defined(GC_DEBUG)
00362   // If requested, use the gc's debugging allocation function
00363   result = GC_debug_malloc_atomic_ignore_off_page(size, file, line);
00364 # else
00365 #  if defined(THREAD_LOCAL_ALLOC)
00366   // Use thread-local allocation for small blocks if it's
00367   // available.
00368   if(size < 1024)
00369     result = GC_local_malloc_atomic(size);
00370   else
00371 #  endif
00372     // With the Boehm collector, we use the ignore_off_page variant to
00373     // tell the GC library that we will always keep a pointer to
00374     // somewhere near the beginning of the block.  For arrays, the
00375     // pointer that the calling code gets isusually a few bytes into
00376     // the block, because the C++ runtime records the number of
00377     // elements in the array at the beginning of the block.
00378 
00379     result = GC_malloc_atomic_ignore_off_page(size);
00380 # endif
00381 #elif defined(__digital__)
00382   result = GC_malloc_ptrfree(size);
00383 #else
00384 # error Which garbage collector are we using?
00385 #endif
00386 
00387   // If we run out of memory, die with assert.  Technically, we should
00388   // throw std::bad_alloc, but that normally causes death by
00389   // unexpected exception, so we just do it here, with a more useful
00390   // message.
00391   if(result == 0)
00392     {
00393       cerr << "Out of memory trying to allocate " << size << " bytes at "
00394            << file << ":" << line << endl;
00395       abort();
00396     }
00397   return result;
00398 }
00399 
00400 // normal_alloc - Perform an allocation for a block which may contain
00401 // pointers.
00402 
00403 static void *normal_alloc(size_t size,
00404                           const char *file, unsigned int line)
00405 {
00406   void *result;
00407 
00408   // If the garbage collector hasn't been initialized yet, we won't
00409   // use it.  (In some situations, things blow up when trying to use
00410   // the collector very early during process initialization.)
00411   if(!BasicsGCInit::done)
00412     return early_alloc(size);
00413 
00414 #if defined(GC_MALLOC_ATOMIC)
00415 # if defined(GC_DEBUG)
00416   // If requested, use the gc's debugging allocation function
00417   result = GC_debug_malloc_ignore_off_page(size, file, line);
00418 # else
00419 #  if defined(THREAD_LOCAL_ALLOC)
00420   // Use thread-local allocation for small blocks if it's
00421   // available.
00422   if(size < 1024)
00423     result = GC_local_malloc(size);
00424   else
00425 #  endif
00426     result = GC_malloc_ignore_off_page(size);
00427 # endif
00428 #elif defined(__digital__)
00429   result = GC_malloc(size);
00430 #else
00431 # error Which garbage collector are we using?
00432 #endif
00433 
00434   // If we run out of memory, die with assert.  Technically, we should
00435   // throw std::bad_alloc, but that normally causes death by
00436   // unexpected exception, so we just do it here, with a more useful
00437   // message.
00438   if(result == 0)
00439     {
00440       cerr << "Out of memory trying to allocate " << size << " bytes at "
00441            << file << ":" << line << endl;
00442       abort();
00443     }
00444   return result;
00445 }
00446 
00447 Basics::gc_no_pointers_t Basics::gc_no_pointers;
00448 
00449 void *operator new(size_t size, Basics::gc_no_pointers_t unused,
00450                    const char *file, unsigned int line)
00451 {
00452   return ptrfree_alloc(size, file, line);
00453 }
00454 
00455 void *operator new[](size_t size, Basics::gc_no_pointers_t unused,
00456                      const char *file, unsigned int line)
00457 {
00458   return ptrfree_alloc(size, file, line);
00459 }
00460 
00461 void* operator new(size_t size,
00462                    const char *file, unsigned int line)
00463 {
00464   return normal_alloc(size, file, line);
00465 }
00466 
00467 void* operator new[](size_t size,
00468                      const char *file, unsigned int line)
00469 {
00470   return normal_alloc(size, file, line);
00471 }
00472 
00473 // Override the normal new operator to perform an allocation without
00474 // any GC attributes (i.e. not pointer-free).
00475 
00476 void* operator new(size_t size) throw(std::bad_alloc)
00477 {
00478   return normal_alloc(size, "<UNKNOWN>", 0);
00479 }
00480 
00481 void* operator new[](size_t size) throw(std::bad_alloc)
00482 {
00483   return normal_alloc(size, "<UNKNOWN>", 0);
00484 }
00485 
00486 // De-allocation functions do nothing.
00487 
00488 void operator delete(void *p) { /*SKIP*/ }
00489 void operator delete[](void *p) { /*SKIP*/ }
00490 

Generated on Mon May 8 00:48:28 2006 for Vesta by  doxygen 1.4.2