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