197403Sobrien// -*- C++ -*- Allocate exception objects. 2169691Skan// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 3169691Skan// Free Software Foundation, Inc. 497403Sobrien// 5132720Skan// This file is part of GCC. 697403Sobrien// 7132720Skan// GCC is free software; you can redistribute it and/or modify 897403Sobrien// it under the terms of the GNU General Public License as published by 997403Sobrien// the Free Software Foundation; either version 2, or (at your option) 1097403Sobrien// any later version. 1197403Sobrien// 12132720Skan// GCC is distributed in the hope that it will be useful, 1397403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1497403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1597403Sobrien// GNU General Public License for more details. 1697403Sobrien// 1797403Sobrien// You should have received a copy of the GNU General Public License 18132720Skan// along with GCC; see the file COPYING. If not, write to 19169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 20169691Skan// Boston, MA 02110-1301, USA. 2197403Sobrien 2297403Sobrien// As a special exception, you may use this file as part of a free software 2397403Sobrien// library without restriction. Specifically, if other files instantiate 2497403Sobrien// templates or use macros or inline functions from this file, or you compile 2597403Sobrien// this file and link it with other files to produce an executable, this 2697403Sobrien// file does not by itself cause the resulting executable to be covered by 2797403Sobrien// the GNU General Public License. This exception does not however 2897403Sobrien// invalidate any other reasons why the executable file might be covered by 2997403Sobrien// the GNU General Public License. 3097403Sobrien 3197403Sobrien// This is derived from the C++ ABI for IA-64. Where we diverge 3297403Sobrien// for cross-architecture compatibility are noted with "@@@". 3397403Sobrien 34169691Skan#include <bits/c++config.h> 3597403Sobrien#include <cstdlib> 36169691Skan#if _GLIBCXX_HOSTED 3797403Sobrien#include <cstring> 38169691Skan#endif 3997403Sobrien#include <climits> 40102782Skan#include <exception> 4197403Sobrien#include "unwind-cxx.h" 42169691Skan#include <ext/concurrence.h> 4397403Sobrien 44169691Skan#if _GLIBCXX_HOSTED 45169691Skanusing std::free; 46169691Skanusing std::malloc; 47169691Skanusing std::memset; 48169691Skan#else 49169691Skan// In a freestanding environment, these functions may not be available 50169691Skan// -- but for now, we assume that they are. 51169691Skanextern "C" void *malloc (std::size_t); 52169691Skanextern "C" void free(void *); 53169691Skanextern "C" void *memset (void *, int, std::size_t); 54169691Skan#endif 55169691Skan 5697403Sobrienusing namespace __cxxabiv1; 5797403Sobrien 5897403Sobrien// ??? How to control these parameters. 5997403Sobrien 6097403Sobrien// Guess from the size of basic types how large a buffer is reasonable. 6197403Sobrien// Note that the basic c++ exception header has 13 pointers and 2 ints, 6297403Sobrien// so on a system with PSImode pointers we're talking about 56 bytes 6397403Sobrien// just for overhead. 6497403Sobrien 6597403Sobrien#if INT_MAX == 32767 6697403Sobrien# define EMERGENCY_OBJ_SIZE 128 6797403Sobrien# define EMERGENCY_OBJ_COUNT 16 6897403Sobrien#elif LONG_MAX == 2147483647 6997403Sobrien# define EMERGENCY_OBJ_SIZE 512 7097403Sobrien# define EMERGENCY_OBJ_COUNT 32 7197403Sobrien#else 7297403Sobrien# define EMERGENCY_OBJ_SIZE 1024 7397403Sobrien# define EMERGENCY_OBJ_COUNT 64 7497403Sobrien#endif 7597403Sobrien 7697403Sobrien#ifndef __GTHREADS 7797403Sobrien# undef EMERGENCY_OBJ_COUNT 7897403Sobrien# define EMERGENCY_OBJ_COUNT 4 7997403Sobrien#endif 8097403Sobrien 81259694Spfg/* APPLE LOCAL begin reduce emergency buffer size */ 82259694Spfg/* 256 bytes is more than large enough for an std::bad_alloc object */ 83259694Spfg#undef EMERGENCY_OBJ_SIZE 84259694Spfg#undef EMERGENCY_OBJ_COUNT 85259694Spfg#define EMERGENCY_OBJ_SIZE 256 86259694Spfg#define EMERGENCY_OBJ_COUNT 2 87259694Spfg/* APPLE LOCAL end reduce emergency buffer size */ 88259694Spfg 8997403Sobrien#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32 9097403Sobrientypedef unsigned int bitmask_type; 9197403Sobrien#else 9297403Sobrientypedef unsigned long bitmask_type; 9397403Sobrien#endif 9497403Sobrien 9597403Sobrien 9697403Sobrientypedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned)); 9797403Sobrienstatic one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT]; 9897403Sobrienstatic bitmask_type emergency_used; 9997403Sobrien 100169691Skannamespace 10197403Sobrien{ 102169691Skan // A single mutex controlling emergency allocations. 103169691Skan __gnu_cxx::__mutex emergency_mutex; 10497403Sobrien} 10597403Sobrien 10697403Sobrienextern "C" void * 107169691Skan__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() 10897403Sobrien{ 10997403Sobrien void *ret; 11097403Sobrien 11197403Sobrien thrown_size += sizeof (__cxa_exception); 112169691Skan ret = malloc (thrown_size); 11397403Sobrien 11497403Sobrien if (! ret) 11597403Sobrien { 116169691Skan __gnu_cxx::__scoped_lock sentry(emergency_mutex); 11797403Sobrien 11897403Sobrien bitmask_type used = emergency_used; 11997403Sobrien unsigned int which = 0; 12097403Sobrien 12197403Sobrien if (thrown_size > EMERGENCY_OBJ_SIZE) 12297403Sobrien goto failed; 12397403Sobrien while (used & 1) 12497403Sobrien { 12597403Sobrien used >>= 1; 12697403Sobrien if (++which >= EMERGENCY_OBJ_COUNT) 12797403Sobrien goto failed; 12897403Sobrien } 12997403Sobrien 13097403Sobrien emergency_used |= (bitmask_type)1 << which; 13197403Sobrien ret = &emergency_buffer[which][0]; 13297403Sobrien 13397403Sobrien failed:; 134169691Skan 13597403Sobrien if (!ret) 13697403Sobrien std::terminate (); 13797403Sobrien } 13897403Sobrien 139169691Skan // We have an uncaught exception as soon as we allocate memory. This 140169691Skan // yields uncaught_exception() true during the copy-constructor that 141169691Skan // initializes the exception object. See Issue 475. 142169691Skan __cxa_eh_globals *globals = __cxa_get_globals (); 143169691Skan globals->uncaughtExceptions += 1; 14497403Sobrien 145169691Skan memset (ret, 0, sizeof (__cxa_exception)); 146169691Skan 14797403Sobrien return (void *)((char *)ret + sizeof (__cxa_exception)); 14897403Sobrien} 14997403Sobrien 15097403Sobrien 15197403Sobrienextern "C" void 152169691Skan__cxxabiv1::__cxa_free_exception(void *vptr) throw() 15397403Sobrien{ 15497403Sobrien char *ptr = (char *) vptr; 15597403Sobrien if (ptr >= &emergency_buffer[0][0] 15697403Sobrien && ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer)) 15797403Sobrien { 158169691Skan const unsigned int which 15997403Sobrien = (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE; 16097403Sobrien 161169691Skan __gnu_cxx::__scoped_lock sentry(emergency_mutex); 16297403Sobrien emergency_used &= ~((bitmask_type)1 << which); 16397403Sobrien } 16497403Sobrien else 165169691Skan free (ptr - sizeof (__cxa_exception)); 16697403Sobrien} 167