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