1 // -*- C++ -*- Allocate exception objects. 2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2011 3 // Free Software Foundation, Inc. 4 // 5 // This file is part of GCC. 6 // 7 // GCC is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License as published by 9 // the Free Software Foundation; either version 3, or (at your option) 10 // any later version. 11 // 12 // GCC is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // GNU General Public License for more details. 16 // 17 // Under Section 7 of GPL version 3, you are granted additional 18 // permissions described in the GCC Runtime Library Exception, version 19 // 3.1, as published by the Free Software Foundation. 20 21 // You should have received a copy of the GNU General Public License and 22 // a copy of the GCC Runtime Library Exception along with this program; 23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 // <http://www.gnu.org/licenses/>. 25 26 // This is derived from the C++ ABI for IA-64. Where we diverge 27 // for cross-architecture compatibility are noted with "@@@". 28 29 #include <bits/c++config.h> 30 #include <cstdlib> 31 #if _GLIBCXX_HOSTED 32 #include <cstring> 33 #endif 34 #include <climits> 35 #include <exception> 36 #include "unwind-cxx.h" 37 #include <ext/concurrence.h> 38 39 #if _GLIBCXX_HOSTED 40 using std::free; 41 using std::malloc; 42 using std::memset; 43 #else 44 // In a freestanding environment, these functions may not be available 45 // -- but for now, we assume that they are. 46 extern "C" void *malloc (std::size_t); 47 extern "C" void free(void *); 48 extern "C" void *memset (void *, int, std::size_t); 49 #endif 50 51 using namespace __cxxabiv1; 52 53 // ??? How to control these parameters. 54 55 // Guess from the size of basic types how large a buffer is reasonable. 56 // Note that the basic c++ exception header has 13 pointers and 2 ints, 57 // so on a system with PSImode pointers we're talking about 56 bytes 58 // just for overhead. 59 60 #if INT_MAX == 32767 61 # define EMERGENCY_OBJ_SIZE 128 62 # define EMERGENCY_OBJ_COUNT 16 63 #elif LONG_MAX == 2147483647 64 # define EMERGENCY_OBJ_SIZE 512 65 # define EMERGENCY_OBJ_COUNT 32 66 #else 67 # define EMERGENCY_OBJ_SIZE 1024 68 # define EMERGENCY_OBJ_COUNT 64 69 #endif 70 71 #ifndef __GTHREADS 72 # undef EMERGENCY_OBJ_COUNT 73 # define EMERGENCY_OBJ_COUNT 4 74 #endif 75 76 #if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32 77 typedef unsigned int bitmask_type; 78 #else 79 typedef unsigned long bitmask_type; 80 #endif 81 82 83 typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned)); 84 static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT]; 85 static bitmask_type emergency_used; 86 87 static __cxa_dependent_exception dependents_buffer[EMERGENCY_OBJ_COUNT]; 88 static bitmask_type dependents_used; 89 90 namespace 91 { 92 // A single mutex controlling emergency allocations. 93 __gnu_cxx::__mutex emergency_mutex; 94 } 95 96 extern "C" void * 97 __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) _GLIBCXX_NOTHROW 98 { 99 void *ret; 100 101 thrown_size += sizeof (__cxa_refcounted_exception); 102 ret = malloc (thrown_size); 103 104 if (! ret) 105 { 106 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 107 108 bitmask_type used = emergency_used; 109 unsigned int which = 0; 110 111 if (thrown_size > EMERGENCY_OBJ_SIZE) 112 goto failed; 113 while (used & 1) 114 { 115 used >>= 1; 116 if (++which >= EMERGENCY_OBJ_COUNT) 117 goto failed; 118 } 119 120 emergency_used |= (bitmask_type)1 << which; 121 ret = &emergency_buffer[which][0]; 122 123 failed:; 124 125 if (!ret) 126 std::terminate (); 127 } 128 129 memset (ret, 0, sizeof (__cxa_refcounted_exception)); 130 131 return (void *)((char *)ret + sizeof (__cxa_refcounted_exception)); 132 } 133 134 135 extern "C" void 136 __cxxabiv1::__cxa_free_exception(void *vptr) _GLIBCXX_NOTHROW 137 { 138 char *base = (char *) emergency_buffer; 139 char *ptr = (char *) vptr; 140 if (ptr >= base 141 && ptr < base + sizeof (emergency_buffer)) 142 { 143 const unsigned int which 144 = (unsigned) (ptr - base) / EMERGENCY_OBJ_SIZE; 145 146 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 147 emergency_used &= ~((bitmask_type)1 << which); 148 } 149 else 150 free (ptr - sizeof (__cxa_refcounted_exception)); 151 } 152 153 154 extern "C" __cxa_dependent_exception* 155 __cxxabiv1::__cxa_allocate_dependent_exception() _GLIBCXX_NOTHROW 156 { 157 __cxa_dependent_exception *ret; 158 159 ret = static_cast<__cxa_dependent_exception*> 160 (malloc (sizeof (__cxa_dependent_exception))); 161 162 if (!ret) 163 { 164 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 165 166 bitmask_type used = dependents_used; 167 unsigned int which = 0; 168 169 while (used & 1) 170 { 171 used >>= 1; 172 if (++which >= EMERGENCY_OBJ_COUNT) 173 goto failed; 174 } 175 176 dependents_used |= (bitmask_type)1 << which; 177 ret = &dependents_buffer[which]; 178 179 failed:; 180 181 if (!ret) 182 std::terminate (); 183 } 184 185 memset (ret, 0, sizeof (__cxa_dependent_exception)); 186 187 return ret; 188 } 189 190 191 extern "C" void 192 __cxxabiv1::__cxa_free_dependent_exception 193 (__cxa_dependent_exception *vptr) _GLIBCXX_NOTHROW 194 { 195 char *base = (char *) dependents_buffer; 196 char *ptr = (char *) vptr; 197 if (ptr >= base 198 && ptr < base + sizeof (dependents_buffer)) 199 { 200 const unsigned int which 201 = (unsigned) (ptr - base) / sizeof (__cxa_dependent_exception); 202 203 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 204 dependents_used &= ~((bitmask_type)1 << which); 205 } 206 else 207 free (vptr); 208 } 209