Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
cxx_memory.cxx
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 #include "defs.h"
00037 #include "cxx_memory.h"
00038 #include "errors.h"
00039 
00040 MEM_POOL* _dummy_new_mempool = (MEM_POOL*) -1;
00041 MEM_POOL* _dummy_delete_mempool = (MEM_POOL*) -1;
00042 size_t _dummy_pad = 0;
00043 
00044 int         _alloc_callsite_line = 0;
00045 const char *_alloc_callsite_file = NULL;
00046 
00047 /* Description of new scheme:
00048  * ==========================
00049  *
00050  * Many C++ implementations don't support calling destructors for 
00051  * array objects allocated using placement new (which we need since we
00052  * want to allocate memory from the memory pools rather than malloc).
00053  * In fact, I believe the language is either ambiguous about this, or
00054  * explicitly does not support this.
00055  *
00056  * We need to mangle new/delete to call MEM_POOL_Alloc and MEM_POOL_FREE
00057  * instead of malloc and free. 
00058  *
00059  * We used to do this using placement new/delete in which we would pass in 
00060  * extra arguments to new/delete (e.g. mempool) and then have them allocate
00061  * memory from the right place. To make sure that constructors/destructors 
00062  * for arrays of objects allocated using placement new were called correctly,
00063  * Shankar et al had a hack using hash tables to maintain the number of
00064  * elements and call the destructors correctly. This hack was invoked using
00065  * -Wf,-Yv to the 5.3 compilers.
00066  *
00067  * This hack is gone in Mongoose. We therefore use the following scheme:
00068  * - instead of using placement new, we communicate with new using global
00069  *   variables instead of parameters. As a result the standard C++ 
00070  *   implementation automatically counts the number of array elements, and
00071  *   calls the constructor/destructor the correct number of times.
00072  * - we define the CXX_NEW and CXX_NEW_ARRAY macros to set the global
00073  *   _dummy_new_mempool variable, and the new operator to MEM_POOL_Alloc 
00074  *   memory from this memory pool. Since CXX_NEW must be an expression, we
00075  *   cannot have a scope within which to save the incoming value of this dummy,
00076  *   and therefore there is a likelihood of this variable being overwritten
00077  *   before it is used. Therefore the new operator resets this dummy to be -1
00078  *   so that when the actual new comes around, it's value is gone, leading to
00079  *   a compiler-runtime error. Thus CXX_NEWs cannot be nested.
00080  *   Note that the last value in the expressions must be the return value
00081  *   of the new operator, to have the types in the assignment x = CXX_NEW(...)
00082  *   work out OK.
00083  * - we define the CXX_DELETE and CXX_DELETE_ARRAY macros to set the global
00084  *   value of dummy_delete_mempool, which is used by the operator delete
00085  *   to MEM_POOL_FREE the memory appropriately. Since CXX_DELETE is a 
00086  *   statement and not an expression, it can have a scope and save the 
00087  *   incoming value in a stack variable. So CXX_DELETEs can be nested.
00088  * - the final issue is to make sure that no one ever calls the original 
00089  *   new/delete operators -- this is arranged by exporting the new and delete
00090  *   operators (__nw__FUi and __dl__FPv) in be/be/Exported. This overrides
00091  *   calls to new and delete in libC from __vec_new, __vec_delete, etc.
00092  *
00093  *
00094  *
00095  * ABANDONED SCHEME:
00096  * =================
00097  *
00098  * I experimented with another scheme in which I explicitly maintained the
00099  * number of elements of an array in 8 extra bytes of storage before the 
00100  * pointer for all arrays. This scheme was abandoned since the above works 
00101  * better, but here are some lessons learnt. The scheme was:
00102  * - try always using placement new, with the argument to new being the storage
00103  *   allocated from MEM_POOL_Alloc. E.g.
00104  *    #define CXX_NEW(type, pool) new (MEM_POOL_Alloc(sizeof(type), pool)) type
00105  *   But this doesn't work since "type" might have arguments to the constructor
00106  * - so then we pass the memory pool as an argument to a placement new 
00107  *   operator that takes arguments.
00108  *    #define CXX_NEW(constructor, mempool)  (new (mempool) constructor)
00109  * - for arrays there are no arguments to constructors, so we allocate
00110  *   8 extra bytes, store the number of elements, and then call the above
00111  *   new to allocate an array. Since it's placement new, the compiler does
00112  *   nothing for arrays.
00113  * - for CXX_DELETE is easy - the operator delete is defined to do NOTHING.
00114  *   the macro first calls the destructor, then calls MEM_POOL_FREE to free
00115  *   the storage.
00116  * - for CXX_DELETE_ARRAY there is a loop -- look for the number of elements,
00117  *   call the destructor for each element of the array, and then call 
00118  *   MEM_POOL_FREE.
00119  * 
00120  * This scheme mostly worked. The problem came because the expansion of the
00121  * CXX_DELETE and CXX_DELETE_ARRAY macros contained the "pointer" argument
00122  * multiple times, and would therefore evaluate it repeatedly. So code like:
00123  *      while (stack.Elements ())
00124  *          CXX_DELETE (stack.Pop ());  // or delete_array
00125  * did not work, since the stack.Pop would happen more than once, lots of
00126  * times.
00127  * The fix for this was to change the macro definition to also pass the 
00128  * type in for the delete macros (at least for CXX_DELETE_ARRAY), but 
00129  * thankfully we found the solution that we now use. Inline functions did
00130  * not work since we need a variable of the type being deleted, and we would
00131  * need an inline function for each type that we want to delete.
00132  * 
00133  * The code for this abandoned scheme is in Rohit's workarea, in
00134  * /hosts/snowy.mti/work/workarea/v7.00/common/util/cxx_memory.{h,cxx}.shank
00135  */
00136 
00137 void* operator new (size_t sz)
00138 #if defined(__GNUC__) && (__GNUC__ < 3)
00139                                throw(std::bad_alloc) 
00140 #endif /* __GNUC__ */
00141 {
00142   void* ptr;
00143   if (_dummy_new_mempool == (MEM_POOL*) -1) {
00144     DevWarn("new: _dummy_new_mempool is not yet set; Using Malloc_Mem_Pool");
00145     _dummy_new_mempool = Malloc_Mem_Pool;
00146   }
00147 
00148   ptr = (void *) MEM_POOL_Alloc_P(_dummy_new_mempool,
00149                                   sz+_dummy_pad,
00150 #ifdef Is_True_On
00151                                   _alloc_callsite_line,
00152                                   _alloc_callsite_file);
00153   _alloc_callsite_file = NULL;
00154   _alloc_callsite_line = 0;
00155 #else
00156                                 0, NULL);
00157 #endif
00158   _dummy_new_mempool = (MEM_POOL*) -1;
00159   _dummy_pad = 0;
00160   return ptr;
00161 }
00162 
00163 void operator delete (void* ptr)
00164 #ifdef __GNUC__
00165                                  throw() 
00166 #endif /* __GNUC__ */
00167 {
00168   if (_dummy_delete_mempool == (MEM_POOL*) -1) {
00169     DevWarn("new: _dummy_delete_mempool is not yet set; Using Malloc_Mem_Pool");
00170     _dummy_delete_mempool = Malloc_Mem_Pool;
00171   }
00172 
00173   MEM_POOL_FREE (_dummy_delete_mempool, ptr);
00174   _dummy_delete_mempool = (MEM_POOL*) -1;
00175 }
00176 
00177 #ifdef __GNUC__
00178 void operator delete[] (void* ptr) throw() {
00179   if (_dummy_delete_mempool == (MEM_POOL*) -1) {
00180     DevWarn("new: _dummy_delete_mempool is not yet set; Using Malloc_Mem_Pool");
00181     _dummy_delete_mempool = Malloc_Mem_Pool;
00182   }
00183 
00184   MEM_POOL_FREE (_dummy_delete_mempool, ptr);
00185   _dummy_delete_mempool = (MEM_POOL*) -1;
00186 }
00187 #endif
00188 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines