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 8197403Sobrien#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32 8297403Sobrientypedef unsigned int bitmask_type; 8397403Sobrien#else 8497403Sobrientypedef unsigned long bitmask_type; 8597403Sobrien#endif 8697403Sobrien 8797403Sobrien 8897403Sobrientypedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned)); 8997403Sobrienstatic one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT]; 9097403Sobrienstatic bitmask_type emergency_used; 9197403Sobrien 92169691Skannamespace 9397403Sobrien{ 94169691Skan // A single mutex controlling emergency allocations. 95169691Skan __gnu_cxx::__mutex emergency_mutex; 9697403Sobrien} 9797403Sobrien 9897403Sobrienextern "C" void * 99169691Skan__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() 10097403Sobrien{ 10197403Sobrien void *ret; 10297403Sobrien 10397403Sobrien thrown_size += sizeof (__cxa_exception); 104169691Skan ret = malloc (thrown_size); 10597403Sobrien 10697403Sobrien if (! ret) 10797403Sobrien { 108169691Skan __gnu_cxx::__scoped_lock sentry(emergency_mutex); 10997403Sobrien 11097403Sobrien bitmask_type used = emergency_used; 11197403Sobrien unsigned int which = 0; 11297403Sobrien 11397403Sobrien if (thrown_size > EMERGENCY_OBJ_SIZE) 11497403Sobrien goto failed; 11597403Sobrien while (used & 1) 11697403Sobrien { 11797403Sobrien used >>= 1; 11897403Sobrien if (++which >= EMERGENCY_OBJ_COUNT) 11997403Sobrien goto failed; 12097403Sobrien } 12197403Sobrien 12297403Sobrien emergency_used |= (bitmask_type)1 << which; 12397403Sobrien ret = &emergency_buffer[which][0]; 12497403Sobrien 12597403Sobrien failed:; 126169691Skan 12797403Sobrien if (!ret) 12897403Sobrien std::terminate (); 12997403Sobrien } 13097403Sobrien 131169691Skan // We have an uncaught exception as soon as we allocate memory. This 132169691Skan // yields uncaught_exception() true during the copy-constructor that 133169691Skan // initializes the exception object. See Issue 475. 134169691Skan __cxa_eh_globals *globals = __cxa_get_globals (); 135169691Skan globals->uncaughtExceptions += 1; 13697403Sobrien 137169691Skan memset (ret, 0, sizeof (__cxa_exception)); 138169691Skan 13997403Sobrien return (void *)((char *)ret + sizeof (__cxa_exception)); 14097403Sobrien} 14197403Sobrien 14297403Sobrien 14397403Sobrienextern "C" void 144169691Skan__cxxabiv1::__cxa_free_exception(void *vptr) throw() 14597403Sobrien{ 14697403Sobrien char *ptr = (char *) vptr; 14797403Sobrien if (ptr >= &emergency_buffer[0][0] 14897403Sobrien && ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer)) 14997403Sobrien { 150169691Skan const unsigned int which 15197403Sobrien = (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE; 15297403Sobrien 153169691Skan __gnu_cxx::__scoped_lock sentry(emergency_mutex); 15497403Sobrien emergency_used &= ~((bitmask_type)1 << which); 15597403Sobrien } 15697403Sobrien else 157169691Skan free (ptr - sizeof (__cxa_exception)); 15897403Sobrien} 159