1// -*- C++ -*- Allocate exception objects. 2// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 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 40using std::free; 41using std::malloc; 42using std::memset; 43#else 44// In a freestanding environment, these functions may not be available 45// -- but for now, we assume that they are. 46extern "C" void *malloc (std::size_t); 47extern "C" void free(void *); 48extern "C" void *memset (void *, int, std::size_t); 49#endif 50 51using 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 77typedef unsigned int bitmask_type; 78#else 79typedef unsigned long bitmask_type; 80#endif 81 82 83typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned)); 84static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT]; 85static bitmask_type emergency_used; 86 87static __cxa_dependent_exception dependents_buffer[EMERGENCY_OBJ_COUNT]; 88static bitmask_type dependents_used; 89 90namespace 91{ 92 // A single mutex controlling emergency allocations. 93 __gnu_cxx::__mutex emergency_mutex; 94} 95 96extern "C" void * 97__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() 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 // We have an uncaught exception as soon as we allocate memory. This 130 // yields uncaught_exception() true during the copy-constructor that 131 // initializes the exception object. See Issue 475. 132 __cxa_eh_globals *globals = __cxa_get_globals (); 133 globals->uncaughtExceptions += 1; 134 135 memset (ret, 0, sizeof (__cxa_refcounted_exception)); 136 137 return (void *)((char *)ret + sizeof (__cxa_refcounted_exception)); 138} 139 140 141extern "C" void 142__cxxabiv1::__cxa_free_exception(void *vptr) throw() 143{ 144 char *base = (char *) emergency_buffer; 145 char *ptr = (char *) vptr; 146 if (ptr >= base 147 && ptr < base + sizeof (emergency_buffer)) 148 { 149 const unsigned int which 150 = (unsigned) (ptr - base) / EMERGENCY_OBJ_SIZE; 151 152 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 153 emergency_used &= ~((bitmask_type)1 << which); 154 } 155 else 156 free (ptr - sizeof (__cxa_refcounted_exception)); 157} 158 159 160extern "C" __cxa_dependent_exception* 161__cxxabiv1::__cxa_allocate_dependent_exception() throw() 162{ 163 __cxa_dependent_exception *ret; 164 165 ret = static_cast<__cxa_dependent_exception*> 166 (malloc (sizeof (__cxa_dependent_exception))); 167 168 if (!ret) 169 { 170 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 171 172 bitmask_type used = dependents_used; 173 unsigned int which = 0; 174 175 while (used & 1) 176 { 177 used >>= 1; 178 if (++which >= EMERGENCY_OBJ_COUNT) 179 goto failed; 180 } 181 182 dependents_used |= (bitmask_type)1 << which; 183 ret = &dependents_buffer[which]; 184 185 failed:; 186 187 if (!ret) 188 std::terminate (); 189 } 190 191 // We have an uncaught exception as soon as we allocate memory. This 192 // yields uncaught_exception() true during the copy-constructor that 193 // initializes the exception object. See Issue 475. 194 __cxa_eh_globals *globals = __cxa_get_globals (); 195 globals->uncaughtExceptions += 1; 196 197 memset (ret, 0, sizeof (__cxa_dependent_exception)); 198 199 return ret; 200} 201 202 203extern "C" void 204__cxxabiv1::__cxa_free_dependent_exception 205 (__cxa_dependent_exception *vptr) throw() 206{ 207 char *base = (char *) dependents_buffer; 208 char *ptr = (char *) vptr; 209 if (ptr >= base 210 && ptr < base + sizeof (dependents_buffer)) 211 { 212 const unsigned int which 213 = (unsigned) (ptr - base) / sizeof (__cxa_dependent_exception); 214 215 __gnu_cxx::__scoped_lock sentry(emergency_mutex); 216 dependents_used &= ~((bitmask_type)1 << which); 217 } 218 else 219 free (vptr); 220} 221